Author Topic: starting with STM32 CMSIS  (Read 12960 times)

0 Members and 1 Guest are viewing this topic.

Offline vixoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
starting with STM32 CMSIS
« on: July 15, 2019, 01:31:51 pm »
I want to start programming the STM32 chips and have bought a STM32F4 discovery board. I'm using the cubeMX and Atollic truestudio. I have succesfully programmed a blink sketch (hooray) using the HAL, but as I understand a) the HAL is often inefficient b) I want to learn about the chip itself and c) I have a bit of experience programming 8-bit AVRs so direct register access or something lower level feels comfortable to me.

So if I understand correctly you can use HAL and CMSIS in the same file no problem, so I'm trying to use cubeMX to set up my project and set all the output pins etc. then i want to use the CMSIS only in the main program loop only to toggle the bits of the output register, but I can't find anywhere which has a list of all the registers for my chip. I just need to find which register is should talk to (im assuming its something like GPIOA) but i can't find that information anywhere in the stm32f407xx.h file linked in the CMSIS and I can't find an authoritative resource anywhere online that tells me either.

Secondly, i'm not sure what syntax my compiler will support - normally if i was using AVR-GCC i would use something like

Code: [Select]
PORTA ^= 0xFF;
but does this work for the CMSIS? Can i just replace PORTA with the appropriate register names?

any help much appreciated
 

Offline MasterT

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: ca
Re: starting with STM32 CMSIS
« Reply #1 on: July 15, 2019, 02:03:22 pm »
Not sure about discovery, if  it's stm32f407 based than you need to download :
"RM0090
Reference manual
STM32F405/415, STM32F407/417, STM32F427/437 and
STM32F429/439 advanced ArmĀ®-based 32-bit MCUs"

To drive GPIO pin with HAL:
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET); 
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); 

Or you can locate HAL_GPIO_WritePin() subfunction and dissect it down to direct port manipulation.
 
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14297
  • Country: fr
Re: starting with STM32 CMSIS
« Reply #2 on: July 15, 2019, 02:30:43 pm »
Under the hood, those functions use the GPIOx_BRR and GPIOx_BSRR registers for I/O bitwise handling (you need to check out the reference manual to understand how that works). On ARM Cortex MCUs, you don't directly write to output latches for bitwise writes, unlike other MCUs. There are bit set and reset registers. You can also write a whole port through the ODR register, but that's not recommended for setting and resetting individual bits as it would be clunky and not necessarily atomic.

Using the CMSIS header file for your specific MCU, writing to individual I/O bits would look something like, for instance:
(defining the proper target in your project and including the "stm32f4xx.h" header should do.)

GPIOA->BSRR = xxx;

That's basically what the HAL functions do.
« Last Edit: July 15, 2019, 02:37:10 pm by SiliconWizard »
 

Offline vixoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
Re: starting with STM32 CMSIS
« Reply #3 on: July 15, 2019, 02:43:46 pm »
Not sure about discovery, if  it's stm32f407 based than you need to download :
"RM0090
Reference manual
STM32F405/415, STM32F407/417, STM32F427/437 and
STM32F429/439 advanced ArmĀ®-based 32-bit MCUs"

thanks! as i understand it though, CMSIS is all designed by ARM itself - this seems like proprietary ST stuff? Is there a difference between what is listed here? 

Using the CMSIS header file for your specific MCU, writing to individual I/O bits would look something like, for instance:
(defining the proper target in your project and including the "stm32f4xx.h" header should do.)

GPIOA->BSRR = xxx;

That's basically what the HAL functions do.


stupid question - what does this syntax mean? I'm not sure what the -> is for. is there a resource to tell me any syntax meanings I dont yet understand?
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14297
  • Country: fr
Re: starting with STM32 CMSIS
« Reply #4 on: July 15, 2019, 02:49:07 pm »
stupid question - what does this syntax mean? I'm not sure what the -> is for. is there a resource to tell me any syntax meanings I dont yet understand?

This is accessing a struct field through a pointer. This is basic C. So I'd suggest you begin with a decent C book.
 

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 4208
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: starting with STM32 CMSIS
« Reply #5 on: July 15, 2019, 02:50:21 pm »
The -> operator is pure C, there's nothing proprietary or unique to CMSIS about it.

In this case, "GPIOA" is a pointer to a structure, so GPIOA->BSRR refers to the element called BSRR of the structure pointed to by GPIOA.

Offline vixoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
Re: starting with STM32 CMSIS
« Reply #6 on: July 15, 2019, 03:00:06 pm »
ok great I'll look it up.

Out of curiosity, what is the reason you don't just write direct to registers?
 

Offline MasterT

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: ca
Re: starting with STM32 CMSIS
« Reply #7 on: July 15, 2019, 03:52:00 pm »
No reason, except  of using alphabetical acronyms (GPIOA) instead of 32-bits binary address. You can write directly:
    (*(uint32_t*)adres_reg) = temp2;
For example, if I want to change PWM settings of timer-2 :
    (*(uint32_t*) 40000034) = 1;
I always do reading-writing directly down to specific bit for debugging  purposes, though it's require some precaution :
1. there are registers read-only/ write-only;
2. there are registers that must be set/ unset in specific order - sequence,
3. PLL, analog circuits may require specific timing or delay in between set-reset.
 This is why programming reference manual from manufacturer is important .
 
The following users thanked this post: boB

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3781
  • Country: de
Re: starting with STM32 CMSIS
« Reply #8 on: July 15, 2019, 04:17:31 pm »
There is a very nice C++ library that handles the which bit in which register is read/write-only and that the literals you are writing to specific places have correct width (if you screw up you get a compile error instead of a runtime bug/crash):

http://kvasir.io/

It is all templated C++, so runtime/memory cost is zero - multiple register bit manipulations all get optimized down into a single large register write like: foo = 0x12345678;

The advantage is readability of the code, which, unless you copiously document your register manipulations, tends to be worse when doing direct register programming than when using some sort of abstraction (like HAL), especially on complex chips like ARMs where some peripherals are controlled by tens of different registers and bits.

The only disadvantage is the documentation but the basics are not difficult to learn. The library is generic, it works with any MCU that has a published SVD file describing the registers (most MCUs have these files published). 
« Last Edit: July 15, 2019, 04:21:55 pm by janoc »
 
The following users thanked this post: boB

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 4208
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: starting with STM32 CMSIS
« Reply #9 on: July 15, 2019, 04:27:07 pm »
ok great I'll look it up.

Out of curiosity, what is the reason you don't just write direct to registers?

Does your IDE allow you to view the C code after it's been through the pre-processor? You might find that your code *is* just writing direct to registers, but thanks to the header files, those registers have relatively easy to remember, portable names.

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14297
  • Country: fr
Re: starting with STM32 CMSIS
« Reply #10 on: July 15, 2019, 04:36:10 pm »
It also makes the declarations themselves much more compact, and thus, less error-prone for the manufacturer writing the headers.

Registers are memory-mapped. GPIO ports each have a set of associated registers that all have the same function and same offset relative to the base address of  the port's register, so it's a lot easier to just declare the base address through a base pointer (such as GPIOA) and nothing else needs to be declared except a single typedef for the struct defining the registers for each port.

On those MCUs, there are again many registers for each port, and not just a single register for accessing it like on some older/simpler MCUs.

Declaring each register individually is of course possible, but it would look kind of clunky: eg: GPIOA_BSRR (well to each their own), would make a very long list of declarations in the headers and again, would be more error-prone.
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4391
  • Country: dk
Re: starting with STM32 CMSIS
« Reply #11 on: July 15, 2019, 05:01:01 pm »
The -> operator is pure C, there's nothing proprietary or unique to CMSIS about it.

In this case, "GPIOA" is a pointer to a structure, so GPIOA->BSRR refers to the element called BSRR of the structure pointed to by GPIOA.

iow shorthand for (*GPIOA).BSRR
 
The following users thanked this post: boB

Offline mark03

  • Frequent Contributor
  • **
  • Posts: 708
  • Country: us
Re: starting with STM32 CMSIS
« Reply #12 on: July 15, 2019, 06:02:51 pm »
Out of curiosity, what is the reason you don't just write direct to registers?

As others have pointed out, this *is* writing directly to the registers.  It may help to skim through stm32f4xx.h and see how the identifiers like "GPIOA" are defined.  (Actually, you may need to go one level deeper as I think that file just #includes the model-specific file.  You'll know you've found the right one when it's many thousands of lines long.)  You will see that each peripheral in the chip has its own base address, which is what identifiers like GPIOA or SPI3 are pointers to.  Then the registers inside the peripheral all have some offset from this base address, so it is natural to define those as a structure, so you access a specific register by using a [plain old C] construction like GPIOA->BSRR.  Otherwise, this is pretty much the same as what you're used to from AVR.  Just remember that most registers are now 32 bits wide.

To answer your question about ST proprietary vs ARM, understand that CMSIS is a standard for [among other things] how the features and peripherals of any Cortex M processor should be exposed in software.  It doesn't mean that different processors from different vendors will have the same peripherals and registers!  It defines naming standards, and some helper functions, e.g. calls to enable or disable an interrupt.  So that huge header file with all of the register stuff in it complies with CMSIS, but the register details are all ST.

Someone already pointed you to the reference manual.  For ST processors, that's where you find the register details.  The big advantage of programming the way you are trying to do, is that 99.9% of the time the names of registers and bit fields are the same between the reference manual and the C header file.  So you can program with just the reference manual PDF open on one screen and your IDE on the other.  You rarely if ever need to look anything up in the header file because you already know the exact names to type in.  Compare that to the HAL where it's anybody's guess what the function to toggle a GPIO is called... thus you're always having to search in the HAL files for the right names.
 
The following users thanked this post: boB

Offline vixoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
Re: starting with STM32 CMSIS
« Reply #13 on: July 15, 2019, 07:39:40 pm »
brilliant. thankyou
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4195
  • Country: us
Re: starting with STM32 CMSIS
« Reply #14 on: July 15, 2019, 08:47:15 pm »
Heh.  I just posted a long response on the same subject on another forum (although, with an Atmel SAMD flavor.)
Here it is.  It sounds like you particularly need to study that first reference: Representing and Manipulating Hardware in Standard C and C++
A nice part about this is that since ARM "standardized" the general style in CMSIS, what you learn will be applicable to other ARM chips as well.  (And elsewhere.  The new AVR Mega-0, Tiny-0, and Tiny-1 series are moving to this sort of structure-based peripheral definition.)-

Quote
The definitions follow CMSIS conventions.

CMSIS is an ARM standard, the most important parts of which are:

  • Peripheral registers are accessed as memory (ARM doesn't have any separate "peripheral" instructions, so everything is located somewhere inside the 32bit address space.)
  • The memory space for each particular peripheral is described by a C "structure" whose start address is at the beginning peripheral.   This is a very common technique for accesses memory-mapped peripherals, but may seem strange if you haven't seen it before.   See http://www.open-std.org/jtc1/sc22/wg21/docs/ESC_SF_02_465_paper.pdf for example.  The newer AVR chips are also setting things up like this.
  •   ARM "standard" peripherals get names and content defined by ARM.  This is things like the Systick timer and the Interrupt Controller.
  • Individual vendors have a lot of latitude on the details of their vendor-specific peripherals.  Atmel has the convention that each peripheral register has a .reg and .bits union for each register - use the .reg to access the "full" register at once, use .bits to access individual bitfields within the register.  (accessing bitfields can be somewhat prone to unexpected behavior, since the chip itself will need to access full registers.)  Sometimes vendors do a poor (IMO) job.
All this usually involves some pretty ugly C code that is somewhat compiler dependent and causes Language experts to groan, but in general end users don't need to worry about that - the necessary include files for a particular compiler are provided, and they'll work.
-
So for PORT->Group[0].DIR.reg:
PORT is where all of the SAMD gpio ports start, defined in ...tools/CMSIS-Atmel/1.2.0/CMSIS/Device/ATMEL/samd51/include/samd51j19a.h:
Code: [Select]
#define PORT              ((Port     *)0x41008000UL) /**< \brief (PORT) APB Base Address */-
They're evenly spaced, and implemented as an array of PortGroup members (one for each of PORTA, etc), in
.../tools/CMSIS-Atmel/1.2.0/CMSIS/Device/ATMEL/samd51/include/component/port.h:
Code: [Select]
typedef struct {
       PortGroup                 Group[4];    /**< \brief Offset: 0x00 PortGroup groups [GROUPS] */
} Port;
-
(Yeah: PORT is actually 4 ports, a single port is called a PortGroup, and what's in the datasheet as PORTA should be referred to as PORT.Group[0].  That's the sort of thing I meant by "Poor descisions.")

PortGroup is defined (also in port.h) with the individual registers:
Code: [Select]
typedef struct {
  __IO PORT_DIR_Type             DIR;         /**< \brief Offset: 0x00 (R/W 32) Data Direction */
  __IO PORT_DIRCLR_Type          DIRCLR;      /**< \brief Offset: 0x04 (R/W 32) Data Direction Clear */
  __IO PORT_DIRSET_Type          DIRSET;      /**< \brief Offset: 0x08 (R/W 32) Data Direction Set */
  __IO PORT_DIRTGL_Type          DIRTGL;      /**< \brief Offset: 0x0C (R/W 32) Data Direction Toggle */
  __IO PORT_OUT_Type             OUT;         /**< \brief Offset: 0x10 (R/W 32) Data Output Value */
  __IO PORT_OUTCLR_Type          OUTCLR;      /**< \brief Offset: 0x14 (R/W 32) Data Output Value Clear */
  __IO PORT_OUTSET_Type          OUTSET;      /**< \brief Offset: 0x18 (R/W 32) Data Output Value Set */
  __IO PORT_OUTTGL_Type          OUTTGL;      /**< \brief Offset: 0x1C (R/W 32) Data Output Value Toggle */
  __I  PORT_IN_Type              IN;          /**< \brief Offset: 0x20 (R/  32) Data Input Value */
  __IO PORT_CTRL_Type            CTRL;        /**< \brief Offset: 0x24 (R/W 32) Control */
  __O  PORT_WRCONFIG_Type        WRCONFIG;    /**< \brief Offset: 0x28 ( /W 32) Write Configuration */
  __IO PORT_EVCTRL_Type          EVCTRL;      /**< \brief Offset: 0x2C (R/W 32) Event Input Control */
  __IO PORT_PMUX_Type            PMUX[16];    /**< \brief Offset: 0x30 (R/W  8) Peripheral Multiplexing */
  __IO PORT_PINCFG_Type          PINCFG[32];  /**< \brief Offset: 0x40 (R/W  8) Pin Configuration */
       RoReg8                    Reserved1[0x20];
} PortGroup;
-
And then each register is also defined in port.h  (the __IO vs __I is elsewhere, though.)
-
Also note the comparatively huge number of individual registers assigned to each peripheral.  And the unallocated space ("Reserved") that makes the arrays come out even.   You can get pretty creative when you have a couple of gigabytes of address space to throw at things...
-
This all works pretty well, in the end.   Note that the compiler will normally optimize away what looks like it might be inefficient ("array accesses just to find the port??"), so the resulting binary code is about as good as it could be if you did it any other way...
« Last Edit: July 15, 2019, 08:50:20 pm by westfw »
 
The following users thanked this post: boB

Offline techman-001

  • Frequent Contributor
  • **
  • !
  • Posts: 748
  • Country: au
  • Electronics technician for the last 50 years
    • Mecrisp Stellaris Unofficial UserDoc
Re: starting with STM32 CMSIS
« Reply #15 on: July 16, 2019, 12:47:39 pm »
I want to start programming the STM32 chips and have bought a STM32F4 discovery board. I'm using the cubeMX and Atollic truestudio. I have succesfully programmed a blink sketch (hooray) using the HAL, but as I understand a) the HAL is often inefficient b) I want to learn about the chip itself and c) I have a bit of experience programming 8-bit AVRs so direct register access or something lower level feels comfortable to me.

So if I understand correctly you can use HAL and CMSIS in the same file no problem, so I'm trying to use cubeMX to set up my project and set all the output pins etc. then i want to use the CMSIS only in the main program loop only to toggle the bits of the output register, but I can't find anywhere which has a list of all the registers for my chip. I just need to find which register is should talk to (im assuming its something like GPIOA) but i can't find that information anywhere in the stm32f407xx.h file linked in the CMSIS and I can't find an authoritative resource anywhere online that tells me either.

Secondly, i'm not sure what syntax my compiler will support - normally if i was using AVR-GCC i would use something like

Code: [Select]
PORTA ^= 0xFF;
but does this work for the CMSIS? Can i just replace PORTA with the appropriate register names?

any help much appreciated

If you're interested in the hardware itself why use the 'C' programming language, it's not made for hardware interaction.

The Forth programming language is made for hardware interaction yet allows the programmer to start at the bare metal and proceed to the actual Problem Definition Language as they go.

Mecrisp-Stellaris Forth happily uses CMSIS-SVD and we have a parser for all the various STM32 chips.

The syntax is consistent and takes the form of "peripheral_register_bitfield" for example to set GPIOA-10

: GPIOA_BSRR_BS10   %1 10 lshift GPIOA_BSRR bis! ;     \  Port A set bit 10

Then executing "GPIOA_BSRR_BS10" sets Port A set bit 10, providing it is set as a OUTPUT elsewhere.

This is just one way and there are many alternative choices, but no HAL, no C compiler and no assembler are required with Forth, you talk to the chip directly via a serial terminal in real time INTERACTIVELY.

For more information please see the main Mecrisp-Stellaris Homepage at http://mecrisp.sourceforge.net/
and my blog site at https://mecrisp-stellaris-folkdoc.sourceforge.io

Cheers,
Terry
 
The following users thanked this post: Muffins

Offline mark03

  • Frequent Contributor
  • **
  • Posts: 708
  • Country: us
Re: starting with STM32 CMSIS
« Reply #16 on: July 16, 2019, 05:27:27 pm »
If you're interested in the hardware itself why use the 'C' programming language, it's not made for hardware interaction.

Pretty sure Messrs Kernighan and Ritchie would disagree with you on that ;)  Not to mention all the language purists who bash on C for being too closely tied to hardware considerations.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14297
  • Country: fr
Re: starting with STM32 CMSIS
« Reply #17 on: July 16, 2019, 05:32:52 pm »
Yes that was a good one. A bit of shameless advertising. ;D
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: starting with STM32 CMSIS
« Reply #18 on: July 16, 2019, 08:08:52 pm »
: GPIOA_BSRR_BS10   %1 10 lshift GPIOA_BSRR bis! ;     \  Port A set bit 10

Clear as mud...  >:D
The further a society drifts from truth, the more it will hate those who speak it.
 
The following users thanked this post: thm_w

Offline techman-001

  • Frequent Contributor
  • **
  • !
  • Posts: 748
  • Country: au
  • Electronics technician for the last 50 years
    • Mecrisp Stellaris Unofficial UserDoc
Re: starting with STM32 CMSIS
« Reply #19 on: July 17, 2019, 04:47:00 am »
If you're interested in the hardware itself why use the 'C' programming language, it's not made for hardware interaction.

Pretty sure Messrs Kernighan and Ritchie would disagree with you on that ;)  Not to mention all the language purists who bash on C for being too closely tied to hardware considerations.

Perhaps my use of the term "hardware interaction" is a bit ambiguous.

For example a forth user can turn a led ( or anything) on or off on the actual hardware without a 'C' compile and download cycle, read a register, modify a register etc, no compile and download cycle, it's all in real time on the hardware via a interactive Terminal connection.

If one is unsure what will happen when a Bitfield is changed, they can see it immediately with Forth, in real time.

This is 'interactivity with the hardware' as enjoyed by a Forth user.

 

Offline techman-001

  • Frequent Contributor
  • **
  • !
  • Posts: 748
  • Country: au
  • Electronics technician for the last 50 years
    • Mecrisp Stellaris Unofficial UserDoc
Re: starting with STM32 CMSIS
« Reply #20 on: July 17, 2019, 04:59:36 am »
: GPIOA_BSRR_BS10   %1 10 lshift GPIOA_BSRR bis! ;     \  Port A set bit 10

Clear as mud...  >:D

George wishes us all to know that he can't program in Forth, or read Forth code.

Grazie per averlo condiviso, George.
 
The following users thanked this post: GeorgeOfTheJungle

Offline techman-001

  • Frequent Contributor
  • **
  • !
  • Posts: 748
  • Country: au
  • Electronics technician for the last 50 years
    • Mecrisp Stellaris Unofficial UserDoc
Re: starting with STM32 CMSIS
« Reply #21 on: July 17, 2019, 05:08:04 am »
Yes that was a good one. A bit of shameless advertising. ;D

Was that directed at me ?

Mecrisp-Stellaris is Free and Open Source Software, licensed under the GPL. It's totally Free to download and use.

I'm not 'advertizing' it, I'm announcing it's existence and benefits to those that may find it useful, specifically the OP of this topic.
 

Offline MasterT

  • Frequent Contributor
  • **
  • Posts: 783
  • Country: ca
Re: starting with STM32 CMSIS
« Reply #22 on: July 17, 2019, 12:51:24 pm »
Perhaps my use of the term "hardware interaction" is a bit ambiguous.

For example a forth user can turn a led ( or anything) on or off on the actual hardware without a 'C' compile and download cycle, read a register, modify a register etc, no compile and download cycle, it's all in real time on the hardware via a interactive Terminal connection.

If one is unsure what will happen when a Bitfield is changed, they can see it immediately with Forth, in real time.

This is 'interactivity with the hardware' as enjoyed by a Forth user.
No need for a Forth, reading-mod-writing all could be done in arduino IDE environment on the fly. A while ago I posted a sketch:
http://www.stm32duino.com/viewtopic.php?f=18&t=4405
Interesting things happened when I change timers period w/o autoload-preload active, than it takes long time to roll-over and get new settings. 
Changing common GPIO drive strength (frequency) and watch on a scope till satisfy with rising /falling  timing.
 

Offline noweare

  • Newbie
  • Posts: 3
  • Country: us
Re: starting with STM32 CMSIS
« Reply #23 on: July 19, 2019, 01:23:14 am »
When I got started using stm32 boards I programmed in direct register access because thats the way the manual is written so it was easy to follow. After a while doing that I could look at the HAL code and understand whats going on. Initially HAL is intimidating, at least to me. The Low Level functions are really awesome though. A bit higher level than direct register programming and kind of self documenting.  TrueStudio is really nice to work in also.
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3321
  • Country: nl
Re: starting with STM32 CMSIS
« Reply #24 on: July 22, 2019, 11:02:01 am »
If you are interested in the very low level stuf of compiling anything for STM32, then I highly recommend http://www.pandafruits.com/stm32_primer/stm32_primer_hardware.php

It is a very short and concise tutorial, yet It handles everything from linkerscripts, makefiles and compiling to working with STM32 registers and clock distribution, and even a bit of programming and debugging.

It is a very good overview of all the low level stuff that IDE's usually do under the hood.
Knowing how this stuff all fits together helps wen working (and trouble shooting) more "advanced" tools.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf