Tool/software:
Hi,
I’m currently implementing interrupt-based UART APIs to handle transmitting and receiving strings using DriverLib functions.
For some reason, when I use the uart_puts() function after uart_putc(), the first characters of the strings I'm transmitting using uart_puts() are missing.(This is not observed when I print multiple strings using uart_puts() without the preceding uart_putc(), so I suspect some operations in the uart_putc() might be affecting the subsequent operations in uart_puts().)
Please find the test code, implementation of the APIs and the result described below:
Here's the test code in main().
#include "ti_msp_dl_config.h"
#include "uart.h"
static void sys_init(void);
int main(void)
{
sys_init();
uart_putc('c');
uart_puts("123\r\n");
uart_puts("456\r\n");
while (1)
{
/* Do nothing. */
}
} /* main() */
/*!
* @brief Initializes the system.
*/
void sys_init(void)
{
SYSCFG_DL_init();
uart_init();
} /* sys_init() */
Here's the implementation of the custom 'uart_putc()' and the 'uart_puts()' functions:
#include "uart.h"
#include "ti_msp_dl_config.h"
static volatile const char * g_p_char = NULL;
static volatile uart_comm_status_t g_uart_comm_status = UART_STATUS_INIT;
static volatile char g_rx_char = 0;
/*!
* @brief Performs any additional initializations necessary for the UART
* peripheral.
*
* @par
* The UART peripheral initialization is performed by the initialization
* functions automatically generated by the sysconfig tool. See
* 'ti_msp_dl_config.c' for more details.
*/
void uart_init(void)
{
/* Disable interrupts and clear interrupt statuses until necessary. */
DL_UART_Main_disableInterrupt(UART_COMM_INST, DL_UART_MAIN_INTERRUPT_TX);
DL_UART_clearInterruptStatus(UART_COMM_INST, DL_UART_MAIN_INTERRUPT_TX);
DL_UART_Main_disableInterrupt(UART_COMM_INST, DL_UART_MAIN_INTERRUPT_RX);
DL_UART_clearInterruptStatus(UART_COMM_INST, DL_UART_MAIN_INTERRUPT_RX);
/* To prevent any unexpected pending IRQ from triggering an interrupt when
* enabling the IRQ, clear the pending IRQ before enabling it. */
NVIC_ClearPendingIRQ(UART_COMM_INST_INT_IRQN);
NVIC_EnableIRQ(UART_COMM_INST_INT_IRQN);
} /* uart_init() */
/*!
* @brief Sends a character over UART.
*
* @par
* This function by itself does not trigger the UART TX interrupt.
*/
void uart_putc(const char c)
{
/* Wait until the TXDATA register is empty and there is no ongoing data
* reception before proceeding with transmission. */
while (DL_UART_Main_isBusy(UART_COMM_INST))
{
/* Do nothing. */
}
DL_UART_Main_transmitData(UART_COMM_INST, c);
} /* uart_putc() */
/*!
* @brief Sends a null-terminated string over UART.
* @param[in] p_str A pointer to a null-terminated string to be transmitted over
* UART.
*/
void uart_puts(const char * p_str)
{
/* Enable the interrupt to perform data transmission over UART using
* interrupts. */
DL_UART_Main_enableInterrupt(UART_COMM_INST, DL_UART_MAIN_INTERRUPT_TX);
/* NOTE: Ensure that the 'g_p_char' setting is performed after enabling the
* TX interrupt. This is because, when the TX interrupt is enabled while
* the TXDATA register of the UART peripheral is empty, the TXINT bit will
* be set and trigger the interrupt immediately. For the interrupt handler
* to handle this case 'g_p_char' must be a null pointer. */
g_p_char = p_str;
g_uart_comm_status = UART_STATUS_TX_STARTED;
/* Wait until the TXDATA register is empty and there is no ongoing data
* reception before proceeding with transmission. */
while (DL_UART_Main_isBusy(UART_COMM_INST))
{
/* Do nothing. */
}
/* Initiate data transmission. */
DL_UART_Main_transmitData(UART_COMM_INST, *g_p_char);
/* Wait for the entire transmission to complete. */
while (g_uart_comm_status != UART_STATUS_TX_COMPLETE)
{
/* Do nothing. */
}
} /* uart_puts() */
/*!
* @brief Interrupt handler for UART_COMM instance.
*
* @par
* This handler processes UART interrupts based on the type of interrupt pending
* (RX or TX). For TX interrupts, it handles the transmission of the next
* character or completes the transmission when the end of the string is
* reached.
*/
void UART_COMM_INST_IRQHandler(void)
{
/* Check the pending interrupt type for the UART instance. */
switch (DL_UART_Main_getPendingInterrupt(UART_COMM_INST))
{
case DL_UART_MAIN_IIDX_RX:
{
if (UART_STATUS_RX_STARTED != g_uart_comm_status)
{
/* Interrupt or user input(s) uncalled for. Ignore. */
return;
}
g_rx_char = DL_UART_Main_receiveData(UART_COMM_INST);
DL_UART_Main_disableInterrupt(UART_COMM_INST,
DL_UART_MAIN_INTERRUPT_RX);
g_uart_comm_status = UART_STATUS_RX_COMPLETE;
break;
}
case DL_UART_MAIN_IIDX_TX:
{
if (NULL == g_p_char)
{
/* No character is pending to be transmitted, return. */
return;
}
g_uart_comm_status = UART_STATUS_TX_INPROGRESS;
/* Proceed to the next character to send. */
g_p_char++;
if (*g_p_char != '\0')
{
/* Wait until the TXDATA register is empty and there is no ongoing data
* reception before proceeding with transmission. */
while (DL_UART_Main_isBusy(UART_COMM_INST))
{
/* Do nothing. */
}
/* There are more characters to send, transmit the next one. */
DL_UART_Main_transmitData(UART_COMM_INST, *g_p_char);
}
else
{
/* If the string is finished, disable TX interrupt and update
* status. */
DL_UART_Main_disableInterrupt(UART_COMM_INST,
DL_UART_MAIN_INTERRUPT_TX);
g_p_char = NULL;
g_uart_comm_status = UART_STATUS_TX_COMPLETE;
}
break;
}
default:
break;
}
} /* UART_COMM_INST_IRQHandler() */
Here's the result:
1 and 4 are missing.
c23 56
When I'm epecting:
c123 456
I would appreciate it if anyone could help me understand if there's any point where I'm using the DriverLib functions incorrectly.
Thank you,
Kyungjae Lee