1
votes

I am trying to stream sampled values from 8 bit ADC through UART on the STM32 nucleo board.

I use ADC with DMA. Sample rate is around 6kHz to fill a buffer with 100 converted values takes me around 17 ms.

After that I want to send those values through UART with baudrate 115200. Since the ADC converted value is HALF_WORD for 100 converted values I have to send 1600 bits. That means I can send them for 14 ms without overwritting data.

This is my attempt in code:

/* Private variables*/

#define ADC_BUF_LEN 100

uint16_t adc_buf[ADC_BUF_LEN];


uint8_t flag = 0;

 /* USER CODE BEGIN 2 */

HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buf, ADC_BUF_LEN);

HAL_TIM_Base_Start(&htim2);

while (1)

  {
    
    if (flag==1)

        {

        HAL_UART_Transmit(&huart4,(uint8_t*)adc_buf,100,1);

        flag = 0;

        HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_9);

        }

        else

        {}

  }

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) 
{
  
    HAL_GPIO_TogglePin(GPIOA,LED_GREEN_Pin);

    
  flag = 1;

    
}

toggled pins

terminal data

I have attached picture with the transmitted data to the terminal. For input the ADC meet 1 kHz sine wave 2 V p-pk. I can see with naked eye that my system is not working.

If i plot that data it wont be sine wave.
The project is for EMG signal processing: I need to sample the signal and then process it in Python.

1
Your time calculation is incorrect. Transmission of 200 bytes at 115200 baud and 8N1 would require 17.36ms at a minimum. Whereas the data are generated every 16.67ms. Your scheme cannot keep up. Seems like you neglected to account for the start and stop bits that frames each transmitted byte.sawdust
i speed up UART to 460800 bits/s, and still not working. There is something more.Ilia Hadzhiev

1 Answers

0
votes

Setting the Timeout parameter of HAL_UART_Transmit to 1 is not correct. You have already calculated it is going to take 14 ms! This means the function will give up and return after only a small proportion of the data has transmitted.

To do this more than once without gaps in the data you are going to need to use DMA on both the ADC and UART at the same time.

Enable the half-transfer interrupt for the ADC DMA, or poll for the half-transfer flag. When you receive it start the UART in DMA mode on the first half of the buffer. It should complete in 7ms, which is 1.5ms before the ADC DMA starts overwriting the data it contains. When you get the ADC DMA complete interrupt or flag, start the UART DMA on the second half of the buffer.

Alternatively, the DMA on most STM32 also support "double-buffer" mode which works more-or-less the same but you only use the complete interrupt and you have two separate data pointers rather than calculating the offset of half a buffer.