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.
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 .
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,
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
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
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,