Reading the Riot Act To ARM's developers

Reading the Riot Act To ARM's developers

----------------------------------------

I've had the pleasure of writing some ARM code lately and honestly guys it sucks.

Coming from the world of PICs, where every register and flag bit has a name and a data structure that can be used to access it, by comparison ARM code especially the CMIS library code is just utter utter purile crap.

Typically the CMSIS library forces you to write code using hard coded numbers. So you want to set some flag to enable an interrupt it would read something like

SYSCON->INT |= (1

Reply to
7
Loading thread data ...

Huh? Did you neglect to write an include file that maps your chosen port/pin names to their integer equivalents, and then use those names?

Reply to
cassiope

2 paragraphs above your comment:

If I use my own names for the flags by imposing similar structures to that of PIC compiler, that code will not be compatible with other engineers who will use completely different names for the same flags.

Reply to
7

2 paragraphs above your comment:

If I use my own names for the flags by imposing similar structures to that of PIC compiler, that code will not be compatible with other engineers who will use completely different names for the same flags.

Reply to
7

I haven't used CMSIS myself, but I took a brief look at the headers for a sample application using CMSIS (for an STM32f10x). The CM3 core header didn't seem to contain the bit numbering - but instead it provides accessor functions for the fields (mostly as static inline functions), so that you don't need to use magic numbers. The vendor-specific include files had plenty of bit numbers and bit masks.

You keep talking about "the PIC compiler" as though that made sense - there are several different PIC architectures, and lots of compilers, with lots of header files, each written in their own way. You also talk about "structures" - I'm guessing you mean that their headers define bit layouts using bitfields. This is well-known to be a risky technique, especially on the ARM - compilers typically have the choice between implementing them with potentially wrong code, or else very inefficient code. That is why it is more common to use explicit bit mask code (preferably with pre-defined values rather than magic numbers).

Reply to
David Brown

The microchip PIC compiler to be specific (if it needed clarifying).

Define 'risky'. If code doesn't need to be debugged, then you may as well use machine code.

If you must use hard coded numbers for speed along with C for its flexibility then you could just as well leave CMSIS as it is and hard code the numbers, and create barely debuggable programs.

If you start naming the flags yourself, then when you get someone else's source code, it all goes pear shaped thereafter as neither of you called the flags with the same name!

Most applications do not need the speed or efficiency. They need to function properly without crashing or hanging and compile between different CPUs as needed when products and their variants are made.

For that to be standard, the registers and their flags need to be named and incorporated into a data structure that everyone can use. (Example of how to do it is given further below.)

For speed, I use a union between fields that have direct access to the raw register and structs that have bit fields. I can define the known reset values and write directly to the register for speed, but when configuring registers for specific activity I use multiple bit field initialisations. Slow and painful that may be, but it is very important to be able to read code in a verbose way so that it is possible to debug it by walking through the actions the CPU must take.

Recently I found some sample code for RS232 comms, and it was riddled with failure. Because the author didn't take the time to understand how setting the bit fields directly was swallowing interrupts in multi-interrupt scenarios.

However, when the code is written out more verbosely, you could clearly see what would happen if multiple interrupts had taken place because the guy was doing a blanket washing down of all the interrupt flags. You could only spot that after all the numbers had been looked up in a datasheet. Thats just crap!

It does not have to be like that.

The CMSIS libraries have to be written properly with structs and unions. An example is this:

typedef struct tagLED_Register{ union { unsigned long All_LEDs; // this accesses all flags struct { unsigned LED_Power:1; unsigned LED_Fault:1; unsigned :3; // unused - ignore unsigned LED_Amber_Alert:1; }; }; } struct_LED_Register;

struct_LED_Register LED_Register; #define LED_ON 1 #define LED_OFF 0

main() { LED_Register.All_LEDs = 0; // All LEDs off - directly write to all LEDs LED_Register.LED_Amber_Alert = LED_ON; // write to individual LED LED_Register.LED_Fault = LED_ON; // write to individual LED }

From above, it is possible to write directly to registers for speed, or choose to write to individual flags for clarity. The idea of unions was invented to take of issues like this. So ARM's developers will now learn to use it! THANKS!!!!!!!!

Reply to
7

As answered before, it will compile to non-functioning code using some ARM compilers (like GCC). They will create byte access operations to access the

32-bit peripheral registers, thrashing the other bytes. I actually had to rewrite a complete library that used this bit field cra^H^H^H stuff. Just compile it and then look at the resulting assembly code.

Regards, Arie de Muynck

Reply to
Arie de Muynck

Unions were invented to allow flexible data structures that save space. They were /not/ invented for type punning like this - type punning is in fact undefined behaviour according to the C standards. That means if you write data to one field in a union, reading a different field is undefined behaviour. And a compiler could legally implement the union as though it were a struct - it does not have to overlap the memory between the fields.

Having said that, the validity of type punning is an unwritten rule that is implemented by all C compilers, even though it is not in the standards.

Newer versions of gcc have a "-fstrict-volatile-bitfield" flag to avoid this problem (I'm assuming that in a real program, LED_Register would be "volatile").

But it is /exactly/ this sort of thing that makes bitfields risky. There are no standards defining how they are to be accessed - with the above example, the compiler could choose to use 32-bit accesses, since the fields are declared "unsigned" (though no one writing real code would use "unsigned" or "unsigned long" in such circumstances - they would always use size-specific types). It could also choose 8-bit accesses, to avoid affecting neighbouring fields. Or it could choose

32-bit regardless of the field type, because those instructions are faster on the ARM. Or it could pick 16-bit accesses just for fun.
Reply to
David Brown

Are you F'n kidding? This "properly written example" below is how you think how code should be written? It's about as coherent as your usual "babble" above and your nonsense about hosting tampon parties.

During the day you work at a Quickie-Mart and during the night you

**pretend** to be a software engineer.

Why should ARM developers have to learn non-portable poorly written code? The person writing this code should learn a thing or two.

Reply to
Ezekiel

The problem with this is that you are making an assumption about how the compiler will allocate those bit fields. The C standard doesn't say anything about what order they will be in. You may think you know what your compiler does, but unless it is documented somewhere the compiler is free to change things up in the next version or if someone turns on a new optimization level.

Using shifts and masks to access the bits makes it explicit what bits are being manipulated and doesn't depend on the compiler doing things a particular way.

--
Bob Hauck
Reply to
Bob Hauck

There always some ways to align the byte and words in all compilers otherwise they would not be proper compilers.

Whether its with type declarations, or compiler switches, or with __attribute__ decorations or whatever, there is always a way.

Even if that were not the case, the ultimate answer is to keep copies of hardware registers in RAM and then update the flags and then copy the registers when it needs to update the physical hardware. Not so long ago, PICs had to do it that anyway because read/modify/write on an IO port overwrote the output bits with junk if the IO pin was an input. So when you turned that pin into an output, it was no longer predictable what you got. (So today they have separate registers for read and write to avoid that problem.)

Since ARM doesn't address the problem of undefined bits, and expressly states, that undefined bits should not be written with a 1, then read/modify/write register operatiosn such as SYS_CON->INT |=( 1

Reply to
7

You snipped too much and missed an important point.

The above code is just an idea of how to implement direct writes and bit fields in one struct.

Something which is lacking in CMSIS library.

As for alignments, they are standard features of all compilers even if C doesn't go around specifying how it should be implemented. Depending on specific compiler it should be implemented as needed as extras things to build up the idea into workable code. With 7 billion+ ARM sales, it is the job of ARM and CMSIS librarians to go talk to the compiler makers and agree how these finer details get implemented and not go around ducking the issue.

Reply to
7

The bitfield allocation strategy is part of the ABI for the processor, but very often it is not specified by the processor manufacturer. This means that a compiler manufacturer is free to pick the ordering, alignment and padding themselves. But having made that choice, they will stick to it regardless of any changes in the optimisation levels (at least in the absence of other explicit flags), otherwise the compiler would be incompatible with itself on different settings.

I have only once heard of a vendor changing the strategy between compiler versions - that was MS's C compiler on Windows. No /real/ tool vendor would do that without very good reason. But of course, you have no guarantees to that effect.

Some processor manufacturers /do/ specify the bitfield details in their ABI - ARM is one of these, AFIK. This means that the compiler manufacturer is /not/ free to pick a different layout, assuming they want to follow the standard ABI.

Correct - and such code is portable across compilers and different processor architectures.

See above.

Since ARM have 7 billion+ sales, I think the ARM and CMSIS librarians must be doing a reasonably good job. If they were as incompetent as you seem to think, the chips would not be as popular.

Reply to
David Brown

99% wrong there - ARM success is from its IP licensing, not from CMSIS.

Its use is now spreading to general purpose CPU usage and thats where the crunch lies. For wider deployment the base code has to be bolted down with extreme prejudice.

It is their duty to sack the CMSIS librarians and replace them with better more qualifed staff. Also they should meet regularly with compiler makers to make sure everyone is singing from the same song sheet.

Reply to
7

Why is it that with all of the hundreds and thousands of different ARM powered devices out there you seem to be the only one struggling with this?

Somehow it's beyond your mental ability to turn a few LEDs on or off yet real developers are somehow able to control an entire ARM powered cellphone.

This is what happens when a moron who works at Quickie Mart during the day fools himself into thinking that he's a real software engineer because he can almost get an LED to flash on and off.

Reply to
Ezekiel

What rubbish.

ARM is successful because they make good processor cores, along with good tools, documentation and support, and make good deals with hardware manufacturers.

There are two sorts of programmers who work with ARM. There are those that use "big" operating systems, such as Linux or iOS - they couldn't care less about bit numbers in registers because they use the OS APIs. There are the people who use microcontroller ARMs - these are now so popular that they are pushing out many alternatives at both the high end and the low end. People using microcontrollers don't seem to have any problem programming these devices. Often they will use headers from the manufacturer, or perhaps from their tool vendor, and sometimes they will use the CMSIS libraries. It all depends on their preferences (for most embedded uses, compatibility between compilers or target devices is not an issue).

ARM people work with tool vendors and manufacturers. CMSIS is an attempt to provide a certain amount of standardisation for parts of the system - it cannot possibly be some sort of complete library for all ARM devices, since there are lots of ARM cores and thousands of chips using them, each with their own set of peripherals, registers, and bits.

If you simply want to rant and rave, demand that people be fired, shot, and make wild claims about incompetence, please go somewhere else to do it.

Reply to
David Brown

But not good CMSIS libraries for the next phase of world domination

I am assuming you were pricking yourself when you made that up. Have you checked the forums for the average bugs for microcontrollers?

Its always to do with this frikin number thing. A couple of experts may respond, otherwise the average level of response is extremely poor. No one can be bothered to fish out datasheets and provide forum support over code riddled with hard coded numbers. It would be a lot easier to read someone else's code if the CMSIS libraries were properly written with named flags.

Yes it can. No one is stopping them from doing it.

Absolutely lame excuse. An infinite amount of resources (read 9 months or more) goes towards making one CPU compared to frigging one text file in one day to make it safe for everyone to use.

I'd rather not.

Reply to
7

Are you actually using a tool so bad it doesn't let you define your own symbols?

define INT_XMA (1 INT |= INT_XMA

Need to change INT_XMA? Change it in one place, *every* usage of it changes. If your development tools can't cope with this - and, ideally, with include files - then you should consider using a macro preprocessor to generate the compilable code from the maintainable code.

Either way, has nothing to do with ARM, per se; just to do with an apparently crippled toolchain and/or a developer who can't look beyond the trivial tool to see possible solutions.

Reply to
Kelsey Bjarnason

Which matters if you're re-compiling/assembling their sources... in which case you can pre-process their code to use your naming (or vice-versa).

And if they're working on the same codebase, why aren't you sharing a mutually-agreeable set of include files with common definitions, or some equivalent?

If you're not working on the same codebase, why does it matter if the names differ?

Reply to
Kelsey Bjarnason

The other engineers speak a different language and are on a different continent and there is no direct link between all the production and subcontracting centers.

Reply to
7

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.