cancel
Showing results for 
Search instead for 
Did you mean: 

sprintf not working when ADC started

JS8
Senior

I'm trying to send ADC results over to a receiver via UART, but somewhy the program freezes on sprintf() IF I have called HAL_ADC_Start_DMA() before. If I call sprintf() before HAL_ADC_Start_DMA() it works fine. However, I need to call it after starting the DMA. How can I fix this?

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

/* Configure the peripherals common clocks */
  PeriphCommonClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_MEMORYMAP_Init();
  MX_ADC1_Init();
  MX_LPUART1_UART_Init();
  /* USER CODE BEGIN 2 */

  uint32_t values[4] = {0, 0, 0, 0};
  HAL_ADC_Start_DMA(&hadc1, values, 4);

  char str[100];
  sprintf(str, "TEMP_ADC: %d\n", values[1]);
  int size = (int)(ceil(log10(values[1]))+12)*sizeof(char);
  HAL_UART_Transmit(&hlpuart1, str, size, 100);

  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, SET);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

10 REPLIES 10

>>How can I fix this?

You debug it, dig into what's actually happening.

Start by stopping the MCU in the debugger and see where it is stuck.

Instrument Hard Fault and Error Handlers so you know if it died there.

Make sure you have the appropriate IRQ Handlers and callbacks to service the interrupts that might occur. 

Make sure there aren't excessive interrupts to the point it saturates the processor, ie > few hundred KHz, or that your handlers/callbacks block

Doubt it is memory related, but don't be using auto/local variables for DMA buffers

Code shown is superficial, issue likely other places.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Bob S
Principal

Are you sure it is hanging on the sprintf call?  Never reaches a breakpoint set on the next line?  Debug the code, halt the CPU when it is "hung" and see where it is.  Might be deep in the sprintf library/assembly code, might be in a interrupt handler that is getting called repeatedly (probably this).

FYI, sprintf() will return the number of bytes written to the buffer (not including the trailing NULL).  You don't need to calculate it.  And even if you DO need to calculate it, strlen() would be more foolproof in case you change the fixed text in the output string.

FYI #2 - use snprintf() instead of sprintf().  Always.  It is just good programming practice.

It just crashes once I attempt to move forward from sprintf(). I can't step in the function, as soon is I press it the buttons go gray and the program just stops. The integer variable into sprintf() is completely reasonable. The code you saw was all the code I've written. Everything else is by CubeIDE or C standard library.

Yes I am 100% sure it is hanging on the sprintf call. As soon as I attempt to step into the function the program crashes.

I can't get the return value of sprintf() because it never returns.

Same issue is with snprintf().

When the program hangs the program counter register just remains at the sprintf() call. How do I find where it really hangs?

Ok, but presumably the DMA is going to cause an interrupt, so you need a handler to catch that, and call back into the HAL. And then a callback routine on your side for the HAL to call upon completion.

>>The code you saw was all the code I've written

But that's not enough, and likely not the direct cause. It's not that sprintf() isn't working, it that' you've broken the MCU with the task you've assigned it.

The code presented doesn't help me see what's going to happen. The buffer is awfully small and I have no idea of the sample rate, or channels, etc.

Make the DMA buffer static/global, and decimate interrupt loading by making it 10x or 100x larger

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

When you run the program, don't step. Just hit play, then, when the program "hangs", hit pause, see where the cpu is at. Likely it's spinning its wheels in an interrupt somewhere. It's certainly not doing nothing. Use the information in the call stack to identify and fix the problem. If you can't, post a screenshot of the state of the call stack after such a pause.

sprintf does use the heap, could be the issue, hard to tell from the information presented.

If you feel a post has answered your question, please click "Accept as Solution".

Are you talking about a DMA interrupt or an ADC interrupt, because they appear as separate in the NVIC settings. There is no weak callback function in stm32wbxx_hal_dma.c for me to replace, but there is a few in stm32wbxx_hal_adc.c.

Which buffer are you talking about? the 'values' buffer holds 4 single-ended ADC inputs, that's why its length is 4. 'str' buffer has a length of 100 because I don't plan on transmitting over 100 bytes of data at a time, and it's more than enough for what it's being used for here. The ADC should do a full conversion every second.

I made 'values' global and changed the size to 400. Do I also need to change the 'Number of Conversions' in the .ioc?

When I started doing this, the code started working out of nowhere. I'm guessing there was bad contact somewhere.