Stm32 Array Declaration

If we’re using the STM32 HAL, by default, SysTick will be used for things like HALDelay and HALGetTick. As a result, the STM32 HAL framework gives SysTick a very high priority. However, FreeRTOS needs SysTick for its scheduler, and it requires SysTick to be a much lower priority. STM32 is a not different breed and as expected it also has several GPIO ports. These ports are usually named GPIOA, GPIOB, etc. But unlike most 8/16-bit micros these ports are 16 bit wide. Thus, in general, every port has 16 IO pins.

  1. Stm32 Array Declaration Tool
  2. Stm32 Initialize Array
Stm32 Array Declaration

The STM32 Open Development Environment (STM32 ODE) is an open, flexible, easy and affordable way to develop innovative devices and applications based on the STM32 32-bit microcontroller family combined with other state-of-the-art ST components connected via expansion boards.

In many microcontroller projects, you need to read and write data. It can be reading data from the peripheral unit like ADC and writing values to RAM. In another case, maybe you need to send chunks of data using SPI. Again you need to read it from RAM and continuously write to the SPI data register. When you do this using processor – you lose a significant amount of processing time. To avoid occupying the CPU, most advanced microcontrollers have a Direct Memory Access (DMA) controller. As its name says – DMA does data transfers between memory locations without the need for a CPU.

Stm32 array declaration codes

Low and medium density ST32 microcontrollers have a single 7 channel DMA unit, while high-density devices have two DMA controllers with 12 independent channels. In STM32VLDiscovery, their ST32F100RB microcontroller with a single DMA unit having 7 channels.

DMA controller can do automated memory to memory data transfers, also do peripheral to memory and peripheral to peripheral. DMA channels can be assigned one of four priority levels: very high, high, medium, and low. And if two same priority channels are requested simultaneously – the lowest number of the channel gets priority. DMA channel can be configured to transfer data into the circular buffer. So DMA is an ideal solution for any peripheral data stream.

Speaking of physical DMA bus access, it is important to note that DMA only accesses bus for actual data transfer. Because of the DMA request phase, address computation and Ack pulse are performed during other DMA channel bus transfers. So when one DMA channel finishes bus transfer, another channel is already ready to do transfer immediately. This ensures minimal bus occupation and fast transfers. Another exciting feature of DMA bus access is that it doesn’t occupy 100% of bus time. DMA takes 5 AHB bus cycles for single word transfer between memory – three of them are still left for CPU access. This means that DMA only takes a maximum of 40% of bus time. So even if DMA is doing intense data transfer, the CPU can access any memory area, peripheral. If you look at the block diagram, you will see that the CPU has a separate Ibus for Flash access. So program fetch isn’t affected by DMA.

Programming DMA controller

Simply speaking, programming DMA is relatively easy. Each channel can be controlled using four registers: Memory address, peripheral address, number of data, and configuration. And all channels have two dedicated registers: DMA interrupts the status register and interrupts the clear flag register. Once set, DMA takes care of memory address increment without disturbing the CPU. DMA channels can generate three interrupts: transfer finished, half-finished, and transfer error.

As an example, let’s write a simple program that transfers data between two arrays. To make it more exciting, let’s do the same task using DMA and without it. Then we can compare the time taken in both cases.

Here is a code of DMA memory to memory transfer:

First of all, we create two arrays: source and destination. Size of length is determined by ARRAYSIZE, which in our example is equal to 800

We use the LED library from the previous tutorial – they indicate a start and stop-transfer for both modes – DMA and CPU. As we see in the code, we must turn on the DMA1 clock to make it functional. Then we start loading settings into DMA_InitStructure. For this example, we selected DMA1 Channel1, so first of all, we call DMA_DeInit(DMA1_Channel1) function, which makes sure DMA is reset to its default values. Then turn on memory to memory mode, then we select normal DMA mode (also, we could select circular buffer mode). As priority mode, we assign Medium. Then we choose the data size to be transferred (32-bit word). This needs to be done for both – peripheral and memory addresses.

NOTE! If one of the memory sizes would be different, say source 32-bit and destination 8- bit – then DMA would cycle four times in 8-bit chunks.

Stm32 Array DeclarationStm32 array declaration tool

Then we load destination, source start addresses, and amount of data to be sent. Afterload these values using DMA_Init(DMA_Channel1, &DMA_InitStructure). After this operation, DMA is prepared to do transfers. Any time DMA can be fired using DMA_Cmd(DMA_Channel1, ENABLE) command.

Stm32 Array Declaration Tool

Stm32 array declaration code

To catch the end of DMA transfer, we initialized DMA transfer Complete on channel1 interrupt.

Where we could toggle the LED and change the status flag giving a signal to start the CPU transfer test.

CPU based memory copy routine is simple:

Measuring DMA and CPU based transfer speeds

Since LEDG is connected to GPIOC pin 9 and LEDB is connected to GPIOC pin 8 we could track start and end pulses using scope:

So using 800 32-bit word transfer using DMA took 214μs:

While using the CPU memory copy algorithm, it took 544μs:

This shows a significant increase in data transfer speed (more than two times). And with DMA most considerable benefit is that the CPU is unoccupied during transfer and may do other intense tasks or go into sleep mode.

I hope this example gives an idea of DMA’s importance. With DMA we can do loads of work only on the hardware level. We will get back to it when we get to other STM32 features like ADC.

Stm32 Initialize Array

Download Sourcery G++ Lite Eclipse project files here: STM32DiscoveryDMA.zip

In any microcontroller there is at least one general purpose input-output port. STM32 is a not different breed and as expected it also has several GPIO ports. These ports are usually named GPIOA, GPIOB, etc. but unlike most 8/16-bit micros these ports are 16 bit wide. Thus, in general, every port has 16 IO pins. Port pins have several modes of operation and this is what that makes them both robust and complex at first. In development boards the IO port pin naming is cut short and so we’ll find PA0, PB12, etc. instead of GPIOA0, GPIOB12, etc. Even in the reference manuals this short naming is used widely. In the end every I/O pin is general purpose in nature.

Key points with STM32’s GPIO

  • Upon any reset event all GPIOs are floating inputs. This prevents any accidental damage to GPIOs in the event of emergency.
  • All GPIO registers are needed to be accessed with 32 bit words. This is mandatory.
  • Reserved bits for any GPIO register are kept at reset values i.e. 0.
  • For every GPIO port there are seven registers but the only the first four are the most important ones. The rest can be ignored most of the times.
  • These important GPIO registers per port are CRL, CRH, IDR and ODR. The rest three registers for GPIO ports can be avoided at the beginning.
  • For bit set and for bit clear, operations REGx |= (1 << bit) and REGx &= ~ (1 << bit) respectively are very handy and efficient. However MikroC compiler provides bit level access though its internal header file coding like this GPIOB_BSRRbits.BS15. We can use this method or the other one.
  • Some IOs are 5V tolerant and are label “FT” in datasheets and other docs. The rest of the I/O pins are not that tolerant and so 3.3V operation should always be ensured. STM32 has a maximum VDD tolerance of 4V but this value shouldn’t be used in any situation for safe operation. Best is to avoid 5V use with GPIOs whenever possible. This will help in avoiding accidental damage to the micro due to common mistakes.
  • Unused GPIO pins should be kept at reset state or tied to ground with 10kΩ resistors so that they remain either as floating inputs or safely connected to ground though it’s not a must.
  • I/O pins can source or sink currents up to 25mA. Thus direct LED drive is possible with them. To drive loads that need more than this value, we must use external BJTs, MOSFETs, optocouplers, transistor arrays or other driver devices.
  • I/O pins should not directly drive inductive or capacitive loads.
  • Care should be taken to avoid driving outputs beyond 50MHz. This is the maximum I/O pin frequency rating.
  • CRL/H registers essential set GPIO pin operating mode independently as according to the table below:
  • CRL sets GPIOs from 0 – 7 while CRH sets from 8 – 15. All IO ports are 16 bit wide unlike common 8 bit micros like PIC or AVR.


CRL Register:

CRH Register: