/STM32F103-ADC-DMA-example

Primary LanguageCGNU General Public License v3.0GPL-3.0

STM32F103-ADC-DMA-example

It is possible to build a simple data acquisition system using the STM32F103 processor. A few analog ports are sampled at the frequency defined by the user and the result is sent over USB configured as a virtual com port, in human readable format to a computer. This project demonstrates a few things:

  • Sample signals with a fairly precise sampling time,
  • Use ADC, DMA and a timer for analog to digiral conversion in hardware, completely independent from software,
  • How to use the CubeMX graphical configuration and code generation tool,
  • Create a USB CDC device (virtual com port, actually a virtual modem device),
  • Show what can be done using only a $3 microprocessor board.

The system uses a timer to trigger the ADC, which automatically takes one sequence of the channels you specify, stores them using DMA into your array. It finally sets a flag in an interrupt service routine (ISR).

At the same time, an USB CDC device is also set-up, so this appears to the computer as a serial port (actually a modem device). All that the user needs to do is to check the ADC sequence complete flag, and if it is true, format a string from the ADC results and send it to the host computer over a virtual serial port. Since a standard class is used, it should work on most modern OS'es without a driver.

The project also demonstrates how to use STM32 CubeMX to create a fairly complex system using the graphical user interface (GUI). The USB device setup can be simply created, as well as the timer, ADC, DMA, the links between them and the interrupts that they generate. After this, we only need to fill up a few locations, typically in main.c. Since STM32 CubeMX auto-generates the project sources, you must not interfere with its code. It must not interfere with what you write either. To deal with this, ST has come up with a method, where they seperated the generated code with this type of comments:

/* USER CODE BEGIN Includes */
  -> you code goes between these comments and survives CubeMX source re-generation.
/* USER CODE END Includes */
 -> whatever you write outside gets erased the next time CubeMX re-generates your project source.

If you write between them, STM32 CubeMX does not touch your code even if you re-generate it using the GUI. Well, it does make for bloated code. But at the end, if you are sure that you will not go through another re-generation iteration, you can delete all those markers and you will be fine and your code senile and readable (ask the OCD in me!).

This is built as a GCC project using gnu make. The Makefile is modified a bit from the original, because the autogenerated one has too much repetition in file paths etc. I also added a "make jflash" extension so that you can use Texane's excellent st-util for ST-Link V2 programmer. To compile on your own, you should have a GNU-ARM-Embedded toolchain installed (such as from the Launchpad site). Edit Makefile to point to your toolchain path.

After you program the chip, power it down and plug it back in through the USB port. It should appear as a CDC device (such as /dev/ttyACM0). Connect to it using a terminal emulator (I like kermit). After you set the port (no need to set connection speed in ACM devices) and connect, you should see the readings coming from ADC1, 2, 3 as:

...
200: ADC1=0, ADC2=4029, ADC3=4030
201: ADC1=1039, ADC2=4029, ADC3=4029
202: ADC1=2353, ADC2=4030, ADC3=4030
203: ADC1=3503, ADC2=4030, ADC3=4030
...

The first number is sample sequence. How you format the data is up to you. The above format is just for clarity; in a normal application a comma separated list is probably better. You can send data in binary form also. You can even build a simple oscilloscope of sorts by using the excellent SerialPlot program. Give it a try!

There are a few things that can be changed:

  • Add or remove ADC channels -> See the ADC section in CubeMX
  • Change the sample and hold duration -> See the ADC section in CubeMX
  • Change sampling time -> See TIM3 section in CubeMX. The processor runs at 72MHz. This is first divided in the prescaler (it is set to 7200), and further in the ARR (max count limit of timer) which is set to 1000. The overall sampling time is 100ms. You can modify them either in the source code or in CubeMX. If you modify in CubeMX, your changes will disappear the next time you re-generate the source from CubeMX. So it is better to do it from CubeMX.

"Share and Enjoy!"