cancel
Showing results for 
Search instead for 
Did you mean: 

Issue in sending ADC data by USB

GSant.1
Associate II

I have a code that uses a timer to generate an interrupt every 100ms which enables the acquisition of one sample from the ADC. After the sample is obtained, it is transferred to a PC by USB. The problem is that the board gets stuck after a fixed amount of time (few seconds, which is independent of the timer setting). Without sending the data by USB the code works fine. Any idea about the issue? Thanks in advance!

7 REPLIES 7
Bob S
Principal

You've given us nothing useful to go on.

What debugging have you done? Where does the code get "stuck"? Why do you think the code is getting stuck there (i.e. what is supposed to happen, but doesn't, or isn't supposed to happen but does)? Does the other end of the USB connection ever receive data? What chip are you using? What board are you using (NUCLEO or DISCO boards or a custom board)? Using CubeMX-generated HAL or LL code or your own? Are you using an RTOS? How about some code samples showing how you send the data.

GSant.1
Associate II

Thanks, Bob, for your reply and I'm sorry for the lack of information, but there was an issue in the Chrome window and actually I thought that the post was not submitted. Here the answers to your questions. I'm blinking one of the LED of the Discovery board STM32F411 (MCU STM32F411VE) every time the timer generates the interrupt for acquiring an ADC value. After a couple of seconds, the LED stops to blink. From STM studio I can see that there are some conversions done, but I do not have enough time to see the received data, neither in RealTerm nor with my python code. I'm using the code generated by CubeMX; in particular, I first tested the data transmission code and the ADC by interrupt code, then I merged them. I'm not using any RTOS and here some important pieces of code:

/*Inside the main*/
 HAL_Init();
 SystemClock_Config();
 MX_GPIO_Init();
 MX_ADC1_Init();
 MX_USB_DEVICE_Init();
 MX_TIM2_Init();
 HAL_TIM_Base_Start(&htim2);
 HAL_ADC_Start_IT(&hadc1);
 while(1){}
  
 
/*Interrupt routine*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  UNUSED(hadc);
  ADCvalue=HAL_ADC_GetValue(&hadc1);
  integ2buffer(myBuf,ADC_value);
  USB_staturs=CDC_Transmit_FS(myBuf,strlen((char *)myBuf));
  HAL_G_PIO_TogglePin(GPIOD, GPIO_PIN_12);
}
 
/*Code added in usbd_cdc_if.c*/
__weak void CDC_RececeiveCallBack(uint8_t *buf, uint32_t len)
{
}
 
/*Code added in usbd_cdc_if.h*/
__weak void CDC_RececeiveCallBack(uint8_t *buf, uint32_t len);
 
 

Thanks in advance for your help!

> I'm blinking one of the LED of the Discovery board STM32F411 (MCU STM32F411VE) every

> time the timer generates the interrupt for acquiring an ADC value.

Your timer interrupt may be toggling the LED, but I don't know because you don't show your timer interrupt code. Do you even have a timer interrupt, or does the timer hardware simply trigger the ADC to start a conversion? But your ADC callback DOES toggle an LED. Do you really toggle this in two places? Or is it really only the ADC callback that toggles the LED. How about your integ2buffer() function? Could you be overflowing the buffer some how? Can you post that code? And how is "myBuf" declared?

Are you only using that one ADC? I notice you ignore the "hadc" param passed to the callback function and always assume it was your hadc1 that caused the interrupt.

This should not affect your code, but I don't recall seeing a "CDC_ReceiveCallback()" function in the HAL USB CDC libraries for the L4xx/G4xx/F4xx. Is that function actually called from anywhere? My CubeMX F4xx install is somehow broken and I can't go back and generate code for that family to double check. But I know it is not in the L4xx or G4xx code generated by CubeMX (at least in CubeMX 5.4, maybe in 5.5 or 5.6).

So, back to my original questions: Where does the code get "stuck"? If you halt the debugger once the LED stops toggling, where is the program? Or is this a case that the main polling loop continues to run, but the timer/ADC interrupt appears to stop? If so, read out the timer configuration registers and see if anything looks wrong. Try running your code with the CDC_Transmit_FS() line commented out. Does the timer interrupt still appear to stop after a couple of seconds? Does your PC side (you python code?) *EVER* receive any data via the USB CDC connection? Check the return value from CDC_Transmit_FS() and do something to report the error if it is not HAL_OK.

GSant.1
Associate II

Regarding the first section of your answer. I set the ADC to be triggered by timer 2 (I did this in CubeMX), so every time the timer triggers the ADC, the ADC interrupt code (the one that I have already posted) is executed. "myBuf" is declared globally and ADC values are not appended to the buffer but just replaced. To be more clear, here the code of the integ2buffer() function:

uint8_t i;
	for(i=0; i<3; i++)
		buffer[i]=' ';
	i=2;
	do{
		buffer[i] = (value % 10)+'0';
        value /= 10;
		i--;
    } while (value != 0);

My board has only one ADC and the reference is automatically generated by CubeMX.

Concerning the "CDC_ReceiveCallback()"  function, I followed the instructions shown at this link https://www.youtube.com/watch?v=7oED-m34EKk&list=PLfExI9i0v1sn_lQjCFJHrDSpvZ8F2CpkA&index=15 .

I'm investigating more where the MCU gets stuck. Despite this, I can tell you that if I either comment the "CDC_Transmit_FS" function or I disconnect the USB cable from my PC, then everything works fine. As said, I have tested both the ADC conversion and USB data transfer separately, and they work fine.

Thanks for your help!

You integ2buffer() has a problem. This may be not THE problem, but it is a problem. And you STILL didn't show how myBuf was defined. So for now I am going to presume it is declared as something like "uint8_t myBuf[SOME_NUMBER]", where "SOME_NUMBER" Is please please please greater than 3 (see below).

The problem is the string created by integ2buffer() is *NOT* NULL terminated. At least not unless myBuf[] is larger than 3 bytes and you zero-fill myBuf at the beginning of you program (you haven't shown enough of your code). So the strlen() call will return some ever-changing value that is most likely larger than 3, depending an where in memory AFTER myBuf[] strlen finds a NULL byte.

Also, do you have your ADC configured for 8-bit mode? Aligned to LSB (I presume) or MSB? Again, you don't show enough of your code. How can you guarantee that the value read from your ADC results in a decimal value <= 999? OK, if your ADC is set for 8 bits or 6 bits it will be, but not 10 or 12 bits. It is ALWAYS better to be safe (validate the value before translating) than sorry ("gee boss, its never done THAT before" is a bad thing to have to say, specially in the demo for the customer 🙂 Hint - if you are using the gcc compiler. it supports itoa() which WILL NULL terminate the resulting string, but you still have to make sure your buffer is large enough.

OK - back to debugging Again... Does your PC program EVER receive data? Does CDC_Transmit_FS() ever return anything other than HAL_OK? Running in the debugger, when the LED stops toggling pause the program. Where is the program? Look at the stack trace to see what chain of functions got called. Look at the timer registers, are they still configured as you expect? Look at the ADC configuration registers, are they still set as you would expect?

GSant.1
Associate II

Hi Bob, thanks for your answer. I attached the entire code.

Your guest about the myBuf was right and you can read the attached code to understand how I implemented integ2buffer.

Concerning the big problem, unfortunately I cannot read the data since the MCU get stuck quite soon after reset. By running in the debug mode, I have found out that the MCU goes inside a function called "HardFault_Handler", inside STM32F4xx_it.c file, which should handle hard fault interrupt (in according to the comment just before the function). The content of "HardFault_Handler" is a while(1){} which explain why the MCU is stuck; however, I cannot understand why it happens.

If I run the code step by step, I think I run in some timout problems and the MCU behaves differently.

I will investigate more which operation could have generated the hard fault.

Bob S
Principal

Wait - so is it "runs for a few seconds then stops" or ""get stuck quite soon after reset"?

If you are in the hard fault handler, you need to look at the fault registers and figure out what caused the fault. It looks like you are using the Keil IDE, doesn't that expand the fault registers when you hit a fault? If not, search this forum for "hard fault handler" (including the quotes) for a post from @Community member​ for code to put in your fault handler to display the registers (I found one post in a thread called "STM32L412 hardfault while using minimal CubeIDE example" from June 2019, but there are others). If needed, get a copy of the STM32 Cortex M4 MCU and MPU Programming Manual (PM0214) and look up what the fault registers mean. One of them contains the address of the instruction, or the address of the data access that caused the fault.

In fact, I think the stack call trace should show at least which function was executing when the fault happened. I saw an "MDK" directory in the source. Are you using the Keil IDE? I don't have any direct experience with that for ARM CPUs, but I thought the IDE had features that would help diagnose/explain the fault registers.