[ Prev ] [ Index ] [ Next ]

8CH ADC + 4CH PWM

Created Tuesday 22 August 2023


https://youtu.be/MBn6LdFENE8


Creating project, configuring MCU clock and enabling SWDIO

  1. Open STM32CubeIDE
  2. Select "File" → "New" → "STM32 Project"
  3. In "Commercial Part Number" field type STM32F103C8T6
  4. From the MCUs/MPUs List select STM32F103C8T6 (shipped in plastic trays) or STM32F103C8T6TR (shipped in tapes on reels)
  5. Click "Next >" button
  6. Enter Project Name, e.g. "How to use FFT on STM32F103C8T6" → Click "Finish" button
  7. In "Pinout & Configuration" tab, open "System Core" → "RCC"
  8. Set "High Speed Clock (HSE)" to "Crystal/Ceramic Resonator"
  9. Open "Clock Configuration" tab
  10. Check that "Input frequency" is equal to resonator on STM32F103C8T6 board (usually 8MHz)
  11. Set "PLL Source Mux" to HSE
  12. Set "System Clock Mux" to PLLCLK
  13. Set PLLMul to "X 9"
  14. Set APB1 Prescaler to "/ 2"
  15. Now, microcontroller clocks are set for maximum performance (72 MHz max)

Adding 8 ADC channels

  1. Go to "Pinout & Configuration" → "Analog" → "ADC1"
  2. Set checkboxes for IN0, IN1, IN2, IN3, IN4, IN5, IN6, IN7 (eight checkboxes for eight channels)
  3. Open "Clock Configuration" tab, set "ADC prescaler" to "/6", so ADC frequency becomes 12 MHz (maximum is 14MHz, but I want to keep HCLK at 72MHz)
  4. Go back to "Pinout & Configuration" → "Analog" → "ADC1"
  5. Open "DMA Settings", add "ADC1" DMA Request
  6. Set "Mode" to "Circular"
  7. Open "Parameter Settings" → "ADC_Settings", set "Continuous Conversion" to "Enabled"
  8. In "ADC_Regular_ConversionMode", set "Number Of Conversion" to 8
  9. Eight "Rank" slots appear, set "Channel" for each Rank from 0 to 7 ("Channel 0", "Channel 1", ... , "Channel 7")
  10. Set "Sampling Time" for each slot to "7.5 Cycles" for each Rank
  11. Note: Default "Sampling Time" is "1.5 Cycles", we using "7.5 Cycles" for illustrative purposes, so all frequencies will be whole numbers
  12. Note: Tconv=7.5+12.5=20, and ADC Clock of 12MHz / 20 = 600 [kHz]. Then single channel sampling frequency is 600 [kHz] / 8 = 75 [kHz]


Adding 4 PWM outputs

  1. Go back to "Pinout & Configuration" → "Timers" → "TIM1"
  2. Set "Clock Source" to "Internal Clock" (TIM1 is on APB2 which is 72MHz as shown on "Clock Configuration" tab)
  3. Set "Prescaler" to 1439
  4. Set "Counter Period" to 9
  5. This will give timer counting frequency of 72MHz / (1439+1) / (9+1) = 72000000 / 14400 = 5000 [Hz] = 5 [kHz]
  6. Set "Channel1", "Channel2", "Channel3" and "Channel4" to "PWM Generation CHxxx" (CH1, CH2, CH3 and CH4)
  7. Scroll down to "PWM Generation Channel 1" in TIM1 "Parameter Settings"
  8. Set "Pulse (16bits value) to 2, 4, 6 and 8 for Channel 1,2,3 and 4.
  9. From menu select "Project" → "Generate Code"

Adding Code

  1. In main.c, under "USER CODE BEGIN PV" add
  2. #define ADC_BUFFER_SIZE 60
  3. #define ADC_CHANNELS 8
  4. #define DMA_ADC_BUFFER_SIZE (ADC_CHANNELS*ADC_BUFFER_SIZE)
  5. __IO uint16_t dmaAdcBuffer[DMA_ADC_BUFFER_SIZE];
  6. __IO uint16_t dmaAdcBufferSafe[DMA_ADC_BUFFER_SIZE];
  7. eight arrays __IO uint16_t safeArray0 [ADC_BUFFER_SIZE]; with index 0 to 7
  8. uint8_t myState=3; // waiting state variable
  9. // myState = 0 - trigger, need to take ADC snapshot
  10. // myState = 1 - first half of ADC buffer saved
  11. // myState = 2 - second half of ADC buffer saved
  12. // myState = 3 - buffer is de-interlaced to 8 separate arrays,
  13. // waiting next "0" trigger written by Cube Monitor
  14. Under "USER CODE BEGIN 2" add
  15. HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &dmaAdcBuffer, DMA_ADC_BUFFER_SIZE);
  16. HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); for channels 1 to 4
  17. HAL_TIM_Base_Start(&htim1);
  18. Under "USER CODE BEGIN 4"
  19. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
  20. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
  21. if (myState==0) {memmove( (void *)&dmaAdcBufferSafe[0], (void *)&dmaAdcBuffer[0], sizeof(dmaAdcBuffer)/2); myState=1; }
  22. if (myState==1) {memmove( (void *)&dmaAdcBufferSafe[DMA_ADC_BUFFER_SIZE/2],(void *)&dmaAdcBuffer[DMA_ADC_BUFFER_SIZE/2],sizeof(dmaAdcBuffer)/2);myState=2;}
  23. Under "USER CODE BEGIN WHILE"
  24. if (myState==2) {... myState=3;}
  25. for (int k=0; k<ADC_CHANNELS;k++)
  26. for (int i=0; i<ADC_BUFFER_SIZE;i++)
  27. switch (k) {}
  28. case 0: safeArray0[i]=dmaAdcBufferSafe[i*ADC_CHANNELS+k]; break; for arrays 0 to 7
  29. Compile program

Adding Cube Monitor nodes

  1. Open STM32CubeMonitor, find three stripes / hamburger in up-right corner and press it to open menu → Import
  2. "Import nodes" windows select "Local" → STM32CubeMonitor_BasicFlow.json → press Import button
  3. Delete "show notification", "myChart" and "Clear Graphs" nodes
  4. Three stripes / hamurger → Import → Clipboard tab → "select a file to import" button → find and select cubearrays10.json → Import button
  5. Three stripes / hamurger → Import → Clipboard tab → "select a file to import" button → find and select cubetrigger10.json→ Import button
  6. Connect variables node upper output to "CubeArrays v1.0" function node input
  7. Double-click on "myVariables", and add ELF file for STM32CubeIDE FFT project
  8. Use "Expand Variable List" checkbox and filter field to find all elements of safeArrayXXX (0 to 7), and add them using "Select All" button. Add single myState variable.
  9. Double-click "CubeArrays v1.0" function node, select "On Message" tab, scroll down to const arrayNames=["arrayName1","arrayName2",...
  10. Replace "arrayName1", "arrayName2" and so on with safeArray0, safeArray1, ... , safeArray7
  11. Open "Setup" tab and set "Outputs" to 8
  12. Double-click Chart #1, set "OR points" to 60, set "Y-axis" min to 0 and max to 4096
  13. Repeat for Chart #2 to Chart #8
  14. Double-click CubeTrigger function, set watchVariableName to myState
  15. Set watchVariableWaitValue to 3
  16. Set watchVariableSetValue to 0
  17. Press "Deploy" button
  18. Press "Dashboard" button, in opened window press "Start monitoring"

cubearrays10.json and cubetrigger10.json files can be found in in nodes10.zip archive here.