cancel
Showing results for 
Search instead for 
Did you mean: 

Is it possible to use UART with more than one buffer?

EYako.1
Associate III

I have no idea why this code is not working. I am sending chunks of a file with UART followed by short instructions of 2 bytes to tell the MCU whether another chunk is coming or to start playing the file.

The MCU receives the first chunk without an issue, but gets stuck on HAL_UART_Receive_IT (&huart2, inst, 2). After this instruction, the MCU does not react to anything coming from the computer via UART. What am I doing wrong?

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();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
  GPIOC->ODR =0;
 
 
   uint8_t buffer_in0 [BUFFER_SZ] = {0};
   uint8_t buffer_in1 [BUFFER_SZ] = {0};
   uint8_t buffer_in2 [BUFFER_SZ] = {0};
   uint8_t buffer_in3 [BUFFER_SZ] = {0};
   uint8_t buffer_in4 [BUFFER_SZ] = {0};
   uint8_t buffer_in5 [BUFFER_SZ] = {0};
   uint8_t buffer_in6 [BUFFER_SZ] = {0};
 
   uint8_t *buffer_in [7];
   buffer_in[0] = buffer_in0;
   buffer_in[1] = buffer_in1;
   buffer_in[2] = buffer_in2;
   buffer_in[3] = buffer_in3;
   buffer_in[4] = buffer_in4;
   buffer_in[5] = buffer_in5;
   buffer_in[6] = buffer_in6;
 
 
 
  uint8_t data_out[4] = {0};
 
  uint16_t* msg_pointer = (uint16_t*) data_out;
 
  *msg_pointer = STOP;
 
  uint8_t num_of_chunks = 0;
  uint32_t c = 0;
 
  uint8_t inst [2] = {0};
  uint16_t* inst_point = (uint16_t*) inst;
 
 
 
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
 
	  uint8_t* data_in = buffer_in [num_of_chunks];
 
	 	  uint16_t* magic_number_pointer =(uint16_t*) data_in;
	 	  uint32_t* checksum_pointer = (uint32_t*) (data_in +2);
	 	  uint16_t* len_pointer = (uint16_t*) (data_in + 6);
 
 
	 	 HAL_UART_Receive_IT (&huart2, data_in, BUFFER_SZ);
	 	 while (*magic_number_pointer != magic_number) {
	 		 __NOP();
	 	 }
 
	 	  c= chksm (data_in+8,*len_pointer);
	 	  uint8_t correct = c == *checksum_pointer;
 
 
	    	  if (correct)
	 	  {
	    		  *msg_pointer = OK;
	    		  HAL_UART_Transmit (&huart2, data_out, sizeof (data_out), 2);
	    		  num_of_chunks++;
 
 
	    		  HAL_UART_Receive_IT (&huart2, inst, 2);
	    		  while (*inst_point != START && *inst_point != NEXT) {
	    			  __NOP();
	    		  }
 
 
 
	 			  *msg_pointer = *inst_point;
	 		  	  HAL_UART_Transmit (&huart2, data_out, sizeof (data_out), 2);
 
	    		  if (*inst_point == START) {
 
	    			  play_all(buffer_in, num_of_chunks);
 
	 		  	  num_of_chunks = 0;
	 		  	  data_in = buffer_in[0];
	 		  	  data_in [0] = 0 ; //override magic number;
	 		  	  data_in [1] = 0 ;
 
	 		  	  *msg_pointer = STOP; // finish
	    		  	  HAL_UART_Transmit (&huart2, data_out, sizeof (data_out), 2);
	    		  }
	    		  *inst_point = 0;
	 	  }
	 	  else
	 	  {
	 		  *msg_pointer = chksmErr;
	 		  HAL_UART_Transmit (&huart2, data_out, sizeof (data_out), 2);
	 	  }
 
 
  }
  /* USER CODE END 3 */
}

9 REPLIES 9
TDK
Guru

The logic here is pretty complicated. Monitor the return value from HAL functions. You may be trying to restart a RX before the last has finished. And/or pause the program when it's "stuck" and verify the values in the UART handle are as expected.

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

I tried checking the return values for the UART transfer and only continue if its 0. It seems to solve the first issue, but when I continue with the second chunk, even though the return value is 0, it still doesn't react to any incoming data

 busy = 2;
while (busy != 0) 
           busy = HAL_UART_Receive_IT (&huart2, data_in, BUFFER_SZ);
	 	  

EYako.1
Associate III

I tried checking the return values for the UART transfer and only continue if its 0. It seems to solve the first issue, but when I continue with the second chunk, even though the return value is 0, it still doesn't react to any incoming data

 busy = 2;
while (busy != 0) 
           busy = HAL_UART_Receive_IT (&huart2, data_in, BUFFER_SZ);

TDK
Guru

Check for the overrun error flags in the USART_SR register.

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

Its set to 1 when I get it, but what does it mean?

It means data is coming in when you're not ready to receive it. You need to clear the interrupt flag, but more importantly, you need to rework your program so you don't end up in that state and lose data.
The HAL UART implementation is sub-par. Reading characters as they come in would be better, or using a circular DMA.
The HAL receive-to-idle functions are better. Call it once to start and again at the rx complete event so it's always ready to receive data.
If you feel a post has answered your question, please click "Accept as Solution".

I did something. I have absolutely no idea what, but for some reason it works now.

I wish I could tell what that was so that other people can learn from it, but I guess it's like that sometimes

MM..1
Chief II

Primary fail is

	 	 while (*magic_number_pointer != magic_number) {
	 		 __NOP();
	 	 }

you dont handle no magic received...

ssipa.1
Associate II

yes you can use as a double buffer.

The double buffer can be thought of as two completely separate units where the interrupt routine works with one unit and the program works with another unit. For the sake of modeling, the interrupt routine will be referred to as the “Kernel�? and functions + programs that do not make up the interrupt routine will be referred to as the “User�? (they use the data, the Kernel handles the hardware).