UART non blocking send seems to get stuck

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

UART non blocking send seems to get stuck

2,403 Views
Joao_Roscoe
Contributor III

Hi all,

 

I'm porting an existing code base from another MCU. The existing code uses a UartAccessSend(UART_INSTANCE_t uart_inst, uint8_t datum) function to send a single byte from a software fifo, and expects to called back by ISR to send another byte, if any. My current implementation of UartAccessSend() function is as follows:

--------

/* Get Tx transfer status */
tx_status = LPUART_DRV_GetTransmitStatus(uart_inst, &remaining_bytes);
if ((0U) == remaining_bytes)
{
/* Update Tx byte */
uart_inst_state[uart_index].tx_byte = datum;
/* Check Tx transfer status */
if (STATUS_BUSY == tx_status)
{
/* Transfer still running, just reset buffer for next byte */
LPUART_DRV_SetTxBuffer(uart_inst, &(uart_inst_state[uart_index].tx_byte), (1U));
}
else
{
/* Transfer has stopped, restart it */
LPUART_DRV_SendData(uart_inst, &(uart_inst_state[uart_index].tx_byte), (1U));
}
/* Report success to caller */
result = STATUS_OK;
}

--------

Also, my ISR callback function (for both buffer empty e transmission end events) includes:

--------

/* Get next datum from queue (but don't remove it from queue, yet) */
if (STATUS_OK == ByteFifoReadSingleByte(terminal_tx_queue, 0U, &datum))
{
/* Request IRQ driven transmission */
if (STATUS_OK == UartAccessSend(TERMINAL_UART_INSTANCE, datum))
{
/* If successfully requested transmission, remove datum from queue */
ByteFifoGetSingleByte(&terminal_tx_queue, NULL);
}
}

--------

With the code above, Tx works, as far as I insert a single byte at a time, into the fifo. If I queue several bytes at once, however, lpuart driver gets stuck in a IRQ deadloop and my registered callback is never called. What am I missing/doing wrong?

Best regards,

Joao

 

UPDATE:

Have just found what seems to be some kind of race condition.

Code gets stuck because LPUART_DRV_TxCompleteIrqHandler() does nothing, due to if (lpuartState->txSize == 0U) failure. So it seems that I'm sending the next character at the wrong time, somehow.

Since this is a 'end of tx' processing, I tried changing port speed to 9600, and that seems to mask the issue. So I guess I'm getting the 'end of tx' event while I'm still processing the 'buffer empty' irq.

0 Kudos
7 Replies

801 Views
Jay_Starter
Contributor I

What to do if my buffer gets updated even before LPUART transmission gets completed , I cannot use a blocking method since I have other processes which might get affected . Can anyone share an example , I am fine with byte by byte transmission as well .

0 Kudos

2,354 Views
Senlent
NXP TechSupport
NXP TechSupport

Hi@Joao_Roscoe

     Happy to see you find the problem!

     I don't think it is necessary to trigger a send operation when a new data enters the queue.
You can set the timing to send data, and check whether the queue data is empty every time you send data. The length of the queue can be set as required, so that the program can avoid competition.

 

BR!

      Jim,

0 Kudos

2,270 Views
Joao_Roscoe
Contributor III

Update:

I have done some progress, and now my code is not getting stuck anymore. However, I still have a number of glitches to solve, and obviously, I still do not have a complete understanding of how to use lpuart driver properly. Could anyone give me a pointer to exemple code using IRQs -  no polling or waiting at all - to control UART Tx and Rx, using single byte buffers?

A simple 'one character at a time' UART echo would do.

Best regards,

João

0 Kudos

799 Views
Jay_Starter
Contributor I
Could you please help me with this, I am stuck at a similar problem.
0 Kudos

2,262 Views
Senlent
NXP TechSupport
NXP TechSupport

Hi@Joao_Roscoe

     There is a routine about LPUART in S32 DS IDE,I don't know if you know it before.

     Currently I don’t have more routines about LPUART and hope this routine can help you.

BR!

     Jim,

0 Kudos

2,254 Views
Joao_Roscoe
Contributor III

Yes, I have seen the exemple packed with the SDK itself. Unfortunately, that exemple does not use interrupts for UART transmission, only for updating Rx buffer/pointer.

Thank you for your time,

João

0 Kudos

2,231 Views
Senlent
NXP TechSupport
NXP TechSupport

Hi@Joao_Roscoe

       I tried to write some demo code for you , hope these can help you.

/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "pin_mux.h"
#include "dmaController1.h"
#include "clockMan1.h"
#include "lpuart1.h"

/* User includes (#include below this line is not maintained by Processor Expert) */
#include <string.h>
#include <stdint.h>
#include <stdbool.h>

/* Welcome message displayed at the console */
#define welcomeMsg "This example is an simple echo using LPUART\r\n\
it will send back any character you send to it.\r\n\
The board will greet you if you send 'Hello Board'\r\
\nNow you can begin typing:\r\n"

/* Timeout in ms for blocking operations */
#define TIMEOUT     100U

/* Receive buffer size */
#define BUFFER_SIZE 256U

/* Buffer used to receive data from the console */
uint8_t txBuffer[BUFFER_SIZE];
uint8_t txBufferIdx;

uint8_t rxBuffer[BUFFER_SIZE];
uint8_t rxBufferIdx;

/* UART rx callback for continuous reception, byte by byte */
void rxCallback(void *driverState, uart_event_t event, void *userData)
{
    /* Unused parameters */
    (void)driverState;
    (void)userData;
		uint32_t bytesRemaining;

    /* Check the event type */
    if (event == UART_EVENT_RX_FULL)
    {				
		/* The reception stops when newline is received or the buffer is full */
			if ((rxBuffer[rxBufferIdx] != '\n') && (rxBufferIdx != (BUFFER_SIZE - 2U)))
		 {
				/* Update the buffer index and the rx buffer */
				rxBufferIdx++;
				LPUART_DRV_SetRxBuffer(INST_LPUART1, &rxBuffer[rxBufferIdx], 1U);
		 }
    }
}


void txCallback(void *driverState,uart_event_t event,void * userData)
{
	if(event == UART_EVENT_TX_EMPTY)
	{
		txBufferIdx++;
		LPUART_DRV_SendData(INST_LPUART1,&txBuffer[txBufferIdx],1);
		if(txBufferIdx > BUFFER_SIZE - 1)
		{
			txBufferIdx = 0;
		}
	};
	
	if(event == UART_EVENT_END_TRANSFER)
	{
		;
	};
	
	if(event == UART_EVENT_ERROR)
	{
		;
	};
}

/*!
 \brief The main function for the project.
 \details The startup initialization sequence is the following:
 * - startup asm routine
 * - main()
 */
int main(void)
{
  /* Write your local variable definition here */
  status_t status;
  /* Declare a buffer used to store the received data */
  uint32_t bytesRemaining;

  CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
  CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);

  PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
  
  /* Initialize LPUART instance */
  LPUART_DRV_Init(INST_LPUART1, &lpuart1_State, &lpuart1_InitConfig0);
  /* Install the callback for rx events */
  LPUART_DRV_InstallRxCallback(INST_LPUART1, rxCallback, NULL);
	
	LPUART_DRV_InstallTxCallback(INST_LPUART1, txCallback,NULL);
  /* Send a welcome message */
  LPUART_DRV_SendDataBlocking(INST_LPUART1, (uint8_t *)welcomeMsg, strlen(welcomeMsg), TIMEOUT);
	
	LPUART_DRV_ReceiveData(INST_LPUART1, rxBuffer, 1U);
	
  while (1)
  {
		OSIF_TimeDelay(100);
		uint8_t test = 12;
		LPUART_DRV_SendData(INST_LPUART1,&test,1);
  }
}

BR!

     Jim,

0 Kudos