EEVblog Electronics Community Forum

Computing => Programming => Topic started by: techman-001 on May 29, 2019, 06:55:52 pm

Title: CMSIS-SVD and C ambiguities
Post by: techman-001 on May 29, 2019, 06:55:52 pm
I initially had a lot of trouble referring to Internet C code examples for STM32xx, (when that MCU series was new to me) as I found them ambiguous and lacking in information, here is one example.

A C code example recently posted on this forum by a very knowledgeable poster showed how to  set the timer #3 "counter enable" bit as " TIM3->CR |= TIM_CR_EN"

However according to CMSIS-SVD, there is no "CR" Register in Timer 3, there are only registers CR1 and CR2, There is also no "EN" bit, there is only the "CEN" bit.

My CMSIS-SVD auto-generated Forth Word to set the timer #3 "counter enable" bit is  "TIM3_CR1_CEN".

For instance when consulting the STM databook and searching for "EN", there is only "CEN" ? or "CR", there is only "CR1" is this not confusing for a C programmer, or is the STM databook not widely used ?

Or am I missing something obvious here (not unusual for me), such as "we are told all the ambiguous names when using Atollic Studio" ?

Note: I like C as it was my first decent HLL embedded programming language as a electronics technician.
Title: Re: CMSIS-SVD and C ambiguities
Post by: oPossum on May 29, 2019, 07:34:54 pm
CMSIS is too low level to allow code portability. Code for one part won't necessarily work on another. This is true even for parts within the same family from the same manufacturer.
Title: Re: CMSIS-SVD and C ambiguities
Post by: ataradov on May 29, 2019, 08:24:33 pm
Yes, you need to make sure that the code was for exactly the same part. Or just make necessary changes to the code.
Title: Re: CMSIS-SVD and C ambiguities
Post by: techman-001 on May 30, 2019, 05:30:32 am
CMSIS is too low level to allow code portability. Code for one part won't necessarily work on another. This is true even for parts within the same family from the same manufacturer.

Thanks for your reply. It's possible I wasn't specific enough, after all this is a complex area.

I have 44 files of different STM32xxxx MCU  SVD's and I've just run a grep -i -w "tim._cr" on them all  and I get zero hits.

However grep -i -w "tim._cr."  gives 321 hits which shows that there is no TIMx_CR bit in these MCUS. All hits are CR1,CR2,CR3 ... etc.
I also get zero hits on "TIM._EN", but many on "TIM._CEN"

In other words if you search the STM32xxxx documents across all their parts, you won't find a TIMx_CR bit, so it appears the example code of " TIM3->CR |= TIM_CR_EN" was in error  at least in terms of CMSIS-SVD compliance.

The correct C language CMSIS-SVD syntax is most likely: "TIM3->CR1 |= TIM_CR1_CEN"

This test tends to indicate that CMSIS-SVD syntax is consistent across all STM32xx MCU's providing the nomenclature of "peripheral_register_bitfield" is applied.

That's unless anyone has an example to the contrary ?

Title: Re: CMSIS-SVD and C ambiguities
Post by: ataradov on May 30, 2019, 05:38:40 am
SVD files have versions. It is possible that naming has changed over the years. It is really hard to tell. Atmel definitely changed naming of things over time, primarily due to strange conflicts in naming with some libraries/built in defines.

Right now it seems like  TIM_CRx_CEN is the correct naming. But that also does not mean that the code is wrong, unless it was just typed from memory as an example.
Title: Re: CMSIS-SVD and C ambiguities
Post by: techman-001 on May 30, 2019, 05:50:29 am
Quote
SVD files have versions. It is possible that naming has changed over the years. It is really hard to tell. Atmel definitely changed naming of things over time, primarily due to strange conflicts in naming with some libraries/built in defines.
CMSIS-SVD's aren't always consistent among different ARM licensees even as far as the XML is concerned. I've had to rewrite parsers that work perfectly on STM32xx SVD's but bomb badly on Nordic.

Quote
Right now it seems like  TIM_CRx_CEN is the correct naming. But that also does not mean that the code is wrong, unless it was just typed from memory as an example.
I'm sure it was probably just typed from memory, or it's possible the user has their own set of syntax, headers etc and tend to use a limited number of Peripherals, avoiding CMSIS-SVD altogether.

I have observed this in many cases, especially STM32xx assembly.

Then you get the types who say " I don't want no f*****g CMSIS! damn them for trying to cramp my style"  :palm:
Title: Re: CMSIS-SVD and C ambiguities
Post by: westfw on June 05, 2019, 10:32:01 am
Um.  An offhand comment like:
Quote
they define all of the registers and register fields so you can write things like TIM3->CR |= TIM_CR_EN in your code, to set the enable bit on timer #3.
is hardly a "code example."
In general, Forum comments aren't "code examples" either - if the author didn't specifically say "I compiles and tested this and it works", I wouldn't count on that being the case - more like "as hint, it goes something like this."Actual source code project repositories (github, etc) are probably a bit better, but there's still a lot of code that worked under some specific narrow circumstance, and has aged (along with the developer) in ways where it might not work any more (for example, I bet you can find a lot of Arduino code that still does "#include <WProgram.h>", written by people who have lost interest in supporting that code...
I don't see what this has to do with "SVD and C ambiguities", either.  It's just "there are bad code examples out there."
Title: Re: CMSIS-SVD and C ambiguities
Post by: Siwastaja on June 23, 2019, 09:30:34 pm
It has very little to do with C, and everything to do with general consistency.

It's completely normal that ST doesn't keep track of the names they chose properly. A reference manual may have one name in one place, another name on another page, then the official header file may have a slightly different name again for the same thing. Sometimes it's very much different.

Sucks, but such is life. There's no deep meaning behind this. People make mistakes, and people suck at correcting them.

For example, ST documents are almost never revisioned. If something is done in a hurry when the product is launched, it stays that way for the whole product lifetime of over a decade. They may add a note to a separate errata document, if the documentation error is serious enough, and if they feel like it.

They also fix header files (for example: by adding forgotten "static inline" qualifiers for intended inline functions!), but most "wrong names" stay like that, because fixing them would break existing code using said headers.
Title: Re: CMSIS-SVD and C ambiguities
Post by: mark03 on June 27, 2019, 08:19:52 pm
Pretty sure that "knowledgeable user" was me.

As I recall, at the end of the thread I did post a complete working example lifted from one of my projects, so you should probably give that more weight than my offhand comment which, indeed, was from memory.

Anyway, the gist of that reply was that if you code directly from the Reference Manual (without the ST driver library), 99% of the time you can get by with just that one document open:  no need to constantly look at miscellaneous source and header files for the correct syntax, function arguments, register and bit-field names, etc.  The other 1% are the cases @Siwastaja is talking about, where the CMSIS-SVD register or bitfield names differ from the ones in the Reference Manual.  But those situations are unusual.
Title: Re: CMSIS-SVD and C ambiguities
Post by: techman-001 on June 27, 2019, 11:23:36 pm

Anyway, the gist of that reply was that if you code directly from the Reference Manual (without the ST driver library), 99% of the time you can get by with just that one document open:  no need to constantly look at miscellaneous source and header files for the correct syntax, function arguments, register and bit-field names, etc.
 
The other 1% are the cases @Siwastaja is talking about, where the CMSIS-SVD register or bitfield names differ from the ones in the Reference Manual.  But those situations are unusual.

I'm somewhat familiar with CMSIS-SVD now after creating several CMSIS-SVD parsers for different MCU's in the last few years. I have formed the opinion that the STM Reference Manual(s) register and bitfield names come directly from the CMSIS-SVD and given the massive quantities of each in every STM32 device that makes perfect sense to me.

STM 'C' header names also come directly from the CMSIS-SVD as evidenced by the free STM (Windows only) header generator exe file. STM didn't write a converter or Forth, or Pascal or any other programming language hence my parser creation above.

In a earlier post I ask for a example to the contrary, however no one has done so. Basically so far it's been opinions only, and unless your suggestion that there may be a 1% discrepancy is due to typos in the STM Reference Manuals, personally I feel that your figure may be too high.

My grepping of 44 files of different STM32Xxxx MCU  SVD's (as mentioned below) returned 100% consistent results regarding the timer naming therefore I'm beginning to believe that the source of this attitude about STM inconsistency comes from programmers here and elsewhere.

Certainly 'C' Coders seem to be very carefree regarding STM32 register and bitfield naming but before you flame me, it was worse in Forth programmer land where no one had a handy source of CMSIS-SVD compliant register and bitfield memory mapping so they *had* to make up their own.

Certainly one cannot shorten the PERIPHERAL_REGISTER_BITFIELD naming strategy to PERIPHERAL_BITFIELD or duplicate names will appear. Take the GPIO's.
GPIOA_BRR_BR0  cannot be shortened to GPIOA_BRO because there is also a GPIOA_BSRR_BR0.

STM isn't perfect however, as there are some issues I still have with the SVD's:

The STM32F0xx SVD gives *TWO*  TIMX_CCMR1 registers at the same memory address depending whether they are used as 'input' or 'output'.  TIM1 is shown here for example and this kind of thing is bound to lead to problems, at least for me.

$40012C00 constant TIM1 ( Advanced-timers )
TIM1 $18 + constant TIM1_CCMR1_Output ( capture/compare mode register output  mode )
TIM1 $18 + constant TIM1_CCMR1_Input ( capture/compare mode register 1 input  mode )

So in summary, my opinion is that the STM peripheral, register and bitfield naming is perfectly consistent between the SVD's and the Technical Reference, with possible typos being the few exceptions.

If anyone has actual traceable examples to the contrary, I'd be pleased to see them.


Title: Re: CMSIS-SVD and C ambiguities
Post by: mark03 on June 27, 2019, 11:51:57 pm
Well you'll have no argument from me.  Certainly 1% was a round number and, I agree, on the high side.  Although I have encountered the odd discrepancy, I did not write it down, so if it makes you happier, assume the agreement is perfect until you find a counterexample ;)

Again from the programmer point of view, using nothing but the Reference Manual and expecting to hit the right identifiers without needing to refer to the C header files, etc...  this is generally successful, but the one which gets me most often is register groups.  I.e. they could have implemented this using an array FOO[], or using names FOO1, FOO2, etc. and it's not always obvious from the manual.  But this is a minor quibble.
Title: Re: CMSIS-SVD and C ambiguities
Post by: techman-001 on June 28, 2019, 12:38:25 am
Well you'll have no argument from me.  Certainly 1% was a round number and, I agree, on the high side.  Although I have encountered the odd discrepancy, I did not write it down, so if it makes you happier, assume the agreement is perfect until you find a counterexample ;)

Again from the programmer point of view, using nothing but the Reference Manual and expecting to hit the right identifiers without needing to refer to the C header files, etc...  this is generally successful, but the one which gets me most often is register groups.  I.e. they could have implemented this using an array FOO[], or using names FOO1, FOO2, etc. and it's not always obvious from the manual.  But this is a minor quibble.

I'm just lucky I wrote that duplicate example into my changelog (after stumbling over it) or it would have been lost forever. Your point is sound, who can remember this stuff in thousands of register names ?

I started this thread because I was genuinely trying to understand these differences I kept finding between C code and the CMSIS-SVD syntax.

I personally think the STM Reference Manuals are pretty good however the sheer numbers of documents one can have open for STM32 design can sure take up all the screen real estate!

At least CMSIS-SVD is XMl and allows the automatic creation of specialized documents to assist the programmer for any programming language. For me as a Forth programmer this is heaps easier than the usual bunch of header files for C. For instance I've included the SVD 'description fields' into my project files so I don't have to refer to the Reference Manual as much as I did at the start.

Without the CMSIS-SVD ( or a similar facility) Forth use on STM32 would have been near impossible.

Here is a Forth memmap example for RCC:
$40021000 constant RCC ( Reset and clock control )
RCC $0 + constant RCC_CR ( Clock control register )
RCC $4 + constant RCC_CFGR ( Clock configuration register  RCC_CFGR )
RCC $8 + constant RCC_CIR ( Clock interrupt register  RCC_CIR )
RCC $C + constant RCC_APB2RSTR ( APB2 peripheral reset register  RCC_APB2RSTR )
RCC $10 + constant RCC_APB1RSTR ( APB1 peripheral reset register  RCC_APB1RSTR )
RCC $14 + constant RCC_AHBENR ( AHB Peripheral Clock enable register  RCC_AHBENR )
RCC $18 + constant RCC_APB2ENR ( APB2 peripheral clock enable register  RCC_APB2ENR )
RCC $1C + constant RCC_APB1ENR ( APB1 peripheral clock enable register  RCC_APB1ENR )
RCC $20 + constant RCC_BDCR ( Backup domain control register  RCC_BDCR )
RCC $24 + constant RCC_CSR ( Control/status register  RCC_CSR )
RCC $28 + constant RCC_AHBRSTR ( AHB peripheral reset register )
RCC $2C + constant RCC_CFGR2 ( Clock configuration register 2 )
RCC $30 + constant RCC_CFGR3 ( Clock configuration register 3 )
RCC $34 + constant RCC_CR2 ( Clock control register 2 )

A Forth bitfield example for RCC__AHBENR:
\ RCC_AHBENR (read-write)
: RCC_AHBENR_DMAEN   %1 0 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_DMAEN    DMA1 clock enable
: RCC_AHBENR_SRAMEN   %1 2 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_SRAMEN    SRAM interface clock  enable
: RCC_AHBENR_FLITFEN   %1 4 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_FLITFEN    FLITF clock enable
: RCC_AHBENR_CRCEN   %1 6 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_CRCEN    CRC clock enable
: RCC_AHBENR_IOPAEN   %1 17 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_IOPAEN    I/O port A clock enable
: RCC_AHBENR_IOPBEN   %1 18 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_IOPBEN    I/O port B clock enable
: RCC_AHBENR_IOPCEN   %1 19 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_IOPCEN    I/O port C clock enable
: RCC_AHBENR_IOPDEN   %1 20 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_IOPDEN    I/O port D clock enable
: RCC_AHBENR_IOPFEN   %1 22 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_IOPFEN    I/O port F clock enable
: RCC_AHBENR_TSCEN   %1 24 lshift RCC_AHBENR bis! ;  \ RCC_AHBENR_TSCEN    Touch sensing controller clock  enable