I want to sample a 4kHz signal that is produced by a signal generator.
I read 2000 samples in a row and then I send it to computer via virtual serial that is provided by USB of STM32F103C8T6. I set timer 3 in order to trigger the ADC and then I set up a 2000 length buffer for DMA.
When I plot signal on the computer the data is not continuous and there is a problem between the signal.
I also stop ADC at the beginning of the PeriodElapsedCallback and start it again at the end of it.
Here is the image of my signal:
The ADC clock is 12MHz. The cycles is set to 28.5 and I use a 12bit ADC. My timer clock is 48MHZ and it counts 30 clocks to trigger the ADC. DMA is set to circular mode. I do not expect these disruptions in my signal because I am taking 2000 samples without any stop.
EDIT: This is my code. As I mentioned before I stop the DMA in the beginning of the interrupt and start it again at the end.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
HAL_ADC_Stop_DMA(&hadc1);
HAL_TIM_Base_Stop(&htim3);
usb_put_arr_int(arr,ARRAY_LENGTH);
HAL_GPIO_TogglePin(GPIOC, 1<<13);
HAL_TIM_Base_Start(&htim3);
HAL_ADC_Start_DMA(&hadc1, arr , ARRAY_LENGTH);
}
I also change the timer period from 30 to 400 and I got a better result but the problem still occurs. I am suspicious about DMA speed.
Based on my calculation, the timer triggers the interrupt every: 400/48000000 = 8.33us and the speed of my ADC is about (28.5+12.5+2.5)/12000000 = 3.62us
So the ADC speed is faster than the timer. Thus, I expect the timer cannot trigger the ADC before the last sampling had completed.
I changed the CDC function according to what @JiříMaier said (I did not change my interrupt code.)
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if (hcdc->TxState != 0){
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
for (uint32_t usbTimeout = 100000; usbTimeout > 0; usbTimeout--) {
if (hcdc->TxState == 0)
break;
}
/* USER CODE END 7 */
return result;
}
I also changed my code structure and changed my interrupt code according to @JiříMaier advice and I got the following result. The problem is that if I do not open the serial plotter on the computer in the beginning of the microcontroller start, microcontroller gets stuck if I open the serial plotter later.
When I change the buffer size from 2000 to 1000 everything is OK but I do not know why it has problem with the size of 2000.
In order to complete the documentation, this is put_arr_int
function:
void usb_put_arr_int(uint16_t * number,int len)
{
#define batch_size 50
for (int j=0; j < (len/batch_size) ; j++)
{
count += j*batch_size;
char f[batch_size*7];
sprintf(f,"%hu\n",number[0 + j*batch_size]);
for(int i=1;i<(batch_size);i++)
{
sprintf(f,"%s%hu\n",f,number[i + j*batch_size]);
count+=i;
}
CDC_Transmit_FS(f,strlen(f));
}
len
is always bigger than batch size
.