I am building a UART Kernel Module with the RTDM API. For the datasheet of this AUART, I worked with chapter 30 of the following link: Link of datasheet
The driver is very basic, it only has to send a buffer which is passed to it in user-space with write
function. It works like this:
- In
open
function, activate UART with UARTEN
bit of UART Control Register - In
write
function, I activate the Transmitter with TXE bit of UART Control Register - Then, start sending characters with:
static void rt_mxs_auart_tx_chars(struct rt_mxs_auart_ctx *ctx){ int ch; pr_info("Start transmitting\n"); while (ctx->out_npend > 0 && !(mxs_read(ctx->port, REG_STAT) & AUART_STAT_TXFF)) { ch = ctx->out_buf[ctx->out_head++]; mxs_write(ch, ctx->port, REG_DATA); ctx->out_head &= (OUT_BUFFER_SIZE - 1); ctx->out_npend--; } if (mxs_read(ctx->port, REG_STAT) & AUART_STAT_TXFF){ pr_info("We've stopped transmitting because FIFO is full, remains: %d to be sent (bytes pending)\n", ctx->out_npend); } if(ctx->out_npend > 0 ) { mxs_set(AUART_INTR_TXIEN, ctx->port, REG_INTR); pr_info("%d bytes pending, setting AUART_INTR_TXIEN\n", ctx->out_npend); } else { mxs_clr(AUART_INTR_TXIEN, ctx->port, REG_INTR); pr_info("%d bytes pending, clearing AUART_INTR_TXIEN\n", ctx->out_npend); }}
TXIEN
corresponds to Transmit Interrupt Enable
, and AUART_STAT_TXFF
means that the transmit FIFO is full. Here's the ctx structure:
struct rt_mxs_auart_ctx { struct rtser_config config; /* current device configuration */ rtdm_irq_t irq_handle; /* device IRQ handle */ rtdm_lock_t lock; /* lock to protect context struct */ int in_head; /* RX ring buffer, head pointer */ int in_tail; /* RX ring buffer, tail pointer */ size_t in_npend; /* pending bytes in RX ring */ int in_nwait; /* bytes the user waits for */ rtdm_event_t in_event; /* raised to unblock reader */ char in_buf[IN_BUFFER_SIZE]; /* RX ring buffer */ volatile unsigned long in_lock; /* single-reader lock */ uint64_t *in_history; /* RX timestamp buffer */ int out_head; /* TX ring buffer, head pointer */ int out_tail; /* TX ring buffer, tail pointer */ size_t out_npend; /* pending bytes in TX ring */ rtdm_event_t out_event; /* raised to unblock writer */ char out_buf[OUT_BUFFER_SIZE]; /* TX ring buffer */ rtdm_mutex_t out_lock; /* single-writer mutex */ uint64_t last_timestamp; /* timestamp of last event */ int ioc_events; /* recorded events */ rtdm_event_t ioc_event; /* raised to unblock event waiter */ volatile unsigned long ioc_event_lock; /* single-waiter lock */ int ier_status; /* IER cache */ int mcr_status; /* MCR cache */ int status; /* cache for LSR + soft-states */ int saved_errors; /* error cache for RTIOC_GET_STATUS */ /* * The port structure holds all the information about the UART * port like base address, and so on. */ struct rt_mxs_auart_port *port;};
In my interrupt handler, I do this:
if (istat & AUART_INTR_TXIS){ pr_info("Transmit Interrupt Status enabled\n"); rt_mxs_auart_tx_chars(ctx); istat &= ~AUART_INTR_TXIS; ret = RTDM_IRQ_HANDLED; }
which means that if the interrupt status flag is active, we send data again with the same function rt_mxs_auart_tx_chars
My problem is that I do not seem to receive the end of my message. For example, if I try to send "This... is my second message" (29 char) I only get "This... is my sec" (17 char). The log is the following:
Calling open functionCalling write functionEnabling TransmitterStart transmittingWe've stopped transmitting because FIFO is full, remains: 12 to be sent (bytes pending)12 bytes pending, setting AUART_INTR_TXIENIRQ handler calledTransmit Interrupt Status enabledStart transmittingWe've stopped transmitting because FIFO is full, remains: 4 to be sent (bytes pending)4 bytes pending, setting AUART_INTR_TXIENReceive Interrupt Status or Receive Timeout Interrupt Status enabledIRQ handler calledTransmit Interrupt Status enabledStart transmitting0 bytes pending, clearing AUART_INTR_TXIENDisabling Transmitter
How do you think can I correct this?