Electronic – STM32 timing critical ADC outline code

armmicrocontrollerstm32

I intend to use an STM32F401RE (on a nucleo board) to capture some time based data.

I am new to ARM and have an 8bit uC (AVR) background. I have a toolchain set up (using gcc as part of AC6 SW4STM32) and have used the HAL Library provided by ST to do simple binking LEDs etc.

I have been importing CubeMX projects into SW4STM32.

I am looking at measuring voltage at 10kS/s for a period if 3 seconds. I want to use the full 12bit ADC.

I would be great full if anyone could help me with the high level code structure before I invest the time learning the functions etc and get bogged down in the coding…

I have something like the below in my head, the interupt being triggered every time a sample is required…

ISR every 1/10000s
    if measure > 0
        read ADC and ouptut to UART        
        measure++
        if measure == 30000
            measure = 0

main
    loop forever
        if measure==0
            if start_button == 1
                measure = 1

How does this look as a starting point? Also, what is the general opinion on the use of libraries? In 8bit a 'library' is little more than some labels for registers, they seem much more commonly used in ARM… Should I just accept using the HAL from ST, try and restrict to the CMSIS or really try and continue to poke memory as in 8bit?

Any guidance is greatly received…

Best Answer

the simplest would be to set up a timer and in the timer start the adc.

you can set the timer interrupt to the highest / higher priority.

In 8bit a 'library' is little more than some labels for registers,

plenty of libraries are used in the 8-bit world as well. you may be thinking about macros vs. libraries.

they seem much more commonly used in ARM...

due to their complexity and much steeper learning curve.

Should I just accept using the HAL from ST, try and restrict to the CMSIS or really try and continue to poke memory as in 8bit?

it is very difficult to NOT use cmsis to start up the device.

as to library, give it a shot and it may help you get started sooner / quicker.

I typically start with oem libraries but box them in a way that in the future I can replace them with my own code if I so desire.

with an oem library, you typically get quality code + working examples. they do come with a little bit overhead (1-2KB typical) but that's nothing for a typical ARM chip.

edit: here is what I typically do for all of my timer related routines -> they are identically structured but differently implemented on 8/16/32 chips:

ISR:
  clear the flag;
  _isrptr(); //execute the user handler

timer initialization (prescaler, period)
  stop the timer
  initialize the timer for user-specified prescaler and period
  start the timer - interrupt still disabled

timer activation (isrptr)
  _isrptr = isrptr; //install user handler
  clear the flag
  enable the interrupt

it allow the installation of a user-specified routine in the timer isr. in your case, that user installed routine could be turning on / off the adc, saving / processing the data, setting up a flag ...

this set of routines will be generic and can be ported from chip to chip. it can be implemented via libraries or you can roll your own - completely transparent to the user space code, meaning that you can switch between implementations freely without the need to change user code.

edit 2: here is an example. the following code,

tim1_init(1000, 1000);                  //run tim1 at 1000 prescaler + 1000 period = 1M
tim1_act(led_flp);                      //install user handler

runs on STM8S -> it sets up timer1 to overflow every 1M cycles and then on timer1 overflow it executes led_flp(), installed by tim1_act().

Substantially the same code runs on PIC, AVR, MSP430, PIC24, and various ARM chips. Some versions of it runs of ST's SPL (for STM8 and STM32), others run off Luminary's driverlib, and others run off hard coded code -> in the case of STM8, some off IAR's header files and others off the stm8s.h from the SPL, without actually using the SPL.

This is to show that the question of whether a vendor library should be used is quite moot, if you structure your code appropriately. To the user code, it doesn't make one bit of a difference whether those routines were implemented off a vendor library or rolled by modifying the registers. End of the day, it gets the job done, hopefully done right.

So instead of wasting time on if you should take a particular approach, just take one approach and make sure you do it right.