Multichannel ADC using DMA on STM32

Last time we have tried to do single conversion of one channel. We were waiting for result in a loop which isn’t effective way of using processor resources. It is better to trigger conversion and wait for conversion complete interrupt. During this time processor can do other tasks rather than wait for ADC conversion complete. So this time we will go through another example where we will set up more than one channel and read ADC values within interrupt service routine.

testing_stm32_ADC_DMA

If we need to convert several channels continuously, we need to set up Sequence registers (ADC_SQRx). There are three sequence registers: ADC_SQR1, ADC_SQR2 and ADC_SQR3 where we can set up maximum 16 channels in any order. Conversion sequence starts with SQ1[4:0] settings in ADC_SQR3 register. Bits [4:0] hold the number of ADC channel. Continue reading

Use fixed integer types to enhance portability

If you have programmed anything with C you should be familiar with common data types like char, unsigned char, int, unsigned int, long int, long long int, etc. It is really hard to tell by looks of type how many bytes this variable takes on memory and how it looks in different system. For instance in 8-bit AVR-GCC compiler int is 16-bit type, while in ARM-GCC int is 32-bit. So int size is dependent on platform, compiler and runtime libraries. And switching between systems may trick you if you are not careful enough.

standard_int_types

You can always check the size of variable by using sizeof() function. What to do if you need your code to be portable between different systems. Some great libraries could work on any system including 8-bit, 16-bit, 32-bit or 64-bit. In order avoid this annoying problem the ISO C99 standard introduced portable data types that are defined in stdint.h header file. If you open this header file of your default compiler tool-set you will find how things are organized. First of all it checks the length of int types and then defines portable types by using special naming format [u]intN_t. If number is for unsigned number you add u in front of type name and if do not add anything is unsigned. N indicates number of bits the variable will take. So this is simple table of common portable integer types: Continue reading

Introducing to STM32 ADC programming. Part2

After we had a quick overview of STM32 ADC peripheral we can start digging deeper in to specifics. In order to understand simple things lets go with simplest case – single conversion mode. In this mode ADC does one conversion and then stops. After ADC conversion result is stored in to 16-bit ADC_DR data register (remember that conversion result is 12-bit), then End of Conversion (EOC) flag is set and interrupt is generated if EOCIE flag is set. Same situation is if injected channel is converted. The difference is that result is stored in to corresponding ADC_DRJx register, JEOC flag is set and interrupt generated if JEOCIE flag is set.

STM_internal_temperature_sensor

In our example we are going to measure the internal temperature sensor value and send it using USART. Temperature sensor is internally connected to ADC1_IN16 channel. Algorithm will start single conversion and wait for conversion complete flag EOC. Then we are going to read ADC value from ADC_DR register, which later will be used to calculate in temperature value in Celsius and sent via USART. So we should see value in terminal screen. Continue reading

Introducing to STM32 ADC programming. Part1

STM32 ADC is pretty complex peripheral. It is designed to be flexible enough to accomplish complex tasks. We are going to dedicate few posts where we will try to cover main features and give working examples of code.

stm32_adc_block

The block schematic may look scary at first time but if you look closer it can be split in to several pieces that are responsible for different functions. Will will go through them step by step to make it look more clear.

Continue reading