static void sc16is752_uarts_open(uid_type uid, uint32_t baudrate, uint32_t format) { uint8_t DLL_value; vuart_map_t *vuart = get_uart(uid); uint8_t channel = uid % 2; NVIC_DisableIRQ(EINT1_IRQn); #if BSP_EINT2_EN == 1 NVIC_DisableIRQ(EINT2_IRQn); #endif //Most common baud rates values //divisor = 1.8432MHz / (baud rate * 16 * prescaler), prescaler = 1 spi_wr_sc16is752(SC16IS752_LCR, 0x80, channel, vuart); /* 0x80 to program baud-rate */ switch (baudrate) { case 1200: DLL_value = 0x60; break; case 1800: DLL_value = 0x40; break; case 2400: DLL_value = 0x30; break; case 3600: DLL_value = 0x20; break; case 4800: DLL_value = 0x18; break; case 7200: DLL_value = 0x10; break; case 9600: DLL_value = 0x0C; break; case 19200: DLL_value = 0x06; break; case 38400: DLL_value = 0x03; break; case 115200: DLL_value = 0x01; break; default: /* default baud rate is 9600 */ DLL_value = 0x0C; } spi_wr_sc16is752(SC16IS752_DLL, DLL_value, channel, vuart); spi_wr_sc16is752(SC16IS752_DLH, 0x0, channel, vuart); spi_wr_sc16is752(SC16IS752_LCR, 0xBF, channel, vuart); /* 0xBF to access EFR register */ spi_wr_sc16is752(SC16IS752_EFR, 0x10, channel, vuart); /* Enable enhanced registers */ // spi_wr_sc16is752(SC16IS752_MCR, 0x04, channel, vuart); /* Enable TLR register writing */ // spi_wr_sc16is752(SC16IS752_TLR, 0x20, channel, vuart); /* setting it to 0 uses the FCR levels */ // spi_wr_sc16is752(SC16IS752_MCR, 0x00, channel, vuart); /* Disable TLR register writing */ /* set UART data communication format */ spi_wr_sc16is752(SC16IS752_LCR, format, channel, vuart); spi_wr_sc16is752(SC16IS752_EFCR, 0x30, channel, vuart); /* inverted, RS485 RTS dir control */ spi_wr_sc16is752(SC16IS752_IER, SC16IS752_IER_RHRI|SC16IS752_IER_RLSI, channel, vuart); /* enable reception interrupt */ /* Clears the contents of the receive and transmit FIFO, set trigger levels */ spi_wr_sc16is752(SC16IS752_FCR, SC16IS752_FCR_FIFO_FLSH, channel, vuart); spi_wr_sc16is752(SC16IS752_FCR, SC16IS752_FCR_FIFO_CONF, channel, vuart); /* Enable FIFO mode */ // spi_wr_sc16is752(SC16IS752_FCR, SC16IS752_FCR_FIFO_EN, channel, vuart); NVIC_EnableIRQ(EINT1_IRQn); #if BSP_EINT2_EN == 1 NVIC_EnableIRQ(EINT2_IRQn); #endif } |
void sc16is752_irq_handler(uid_type uid) { uint8_t IIR_value, LSR_value, IER_value, RXLVL_value, count, read_byte, channel = uid%2; #if VUART_EN == 1 vuart_map_t *vuart = get_uart(uid); #endif LSR_value = spi_rd_sc16is752(SC16IS752_LSR, channel, vuart); uart_lines[uid].line_status |= (LSR_value & LSR_OE); if (LSR_value & SC16IS752_LSR_OE) { log_string(LOG_ERROR, "OVERRUN EXTERNAL UART %u.", uid); } switch ((IIR_value = spi_rd_sc16is752(SC16IS752_IIR, channel, vuart)) & 0x0F) { case SC16IS752_IIR_RLS: // receiver line status (LSR) case SC16IS752_IIR_RTI: // receiver time-out interrupt case SC16IS752_IIR_RHR: // receive hold register (RHR) interrupt RXLVL_value = spi_rd_sc16is752(SC16IS752_RXLVL, channel, vuart); if ((IIR_value & 0x0F) == SC16IS752_IIR_RHR) { __asm("NOP\n") ; } RXLVL_value = spi_rd_sc16is752(SC16IS752_RXLVL, channel, vuart); /* this will only happen when the chip loose the interrupt sync, dummy read for re-sync */ if (!(LSR_value & SC16IS752_LSR_RHR)) { spi_rd_sc16is752(SC16IS752_RHR, channel, vuart); log_string(LOG_WARN, "EXTERNAL UART %u OUT OF SYNC, RE-SYNC.", uid); } /* Repeat until receiver FIFO is empty */ count = 0; while (LSR_value & SC16IS752_LSR_RHR) { /* Get errors */ uart_lines[uid].line_status |= (LSR_value & (LSR_BI|LSR_FE|LSR_PE)); /* Get the byte */ read_byte = spi_rd_sc16is752(SC16IS752_RHR, channel, vuart); /* if the queue is full, don't increment the in index */ if (((uart_lines[uid].in + 1) & INPUT_QUEUE_MASK) == uart_lines[uid].out) { uart_lines[uid].line_status |= U_ST_CQOE; /* Overrun Error */ log_string(LOG_ERROR, "OVERRUN UART %u.", uid); } else { uart_lines[uid].ibuf[uart_lines[uid].in] = read_byte; uart_lines[uid].in = (uart_lines[uid].in + 1) & INPUT_QUEUE_MASK; } count++; LSR_value = spi_rd_sc16is752(SC16IS752_LSR, channel, vuart); // isr_PostSem(uart_lines[uid].semRx, 1); } /* Increment the semaphore. This tells the task that the incoming bytes have been read. */ isr_PostSem(uart_lines[uid].semRx, count); break; case SC16IS752_IIR_THR: // transmit hold register (THR) interrupt read_byte = spi_rd_sc16is752(SC16IS752_TXLVL, channel, vuart); fill_output_fifo(uid, read_byte); if (uart_lines[uid].olen == 0) /* All bytes transmitted? */ { //disable transmission interrupt IER_value = spi_rd_sc16is752(SC16IS752_IER, channel, vuart); IER_value &= ~SC16IS752_IER_THRI; spi_wr_sc16is752(SC16IS752_IER, IER_value, uid%2, vuart); /* Release the semaphore. This tells the task that its output buffer has beencopied to the uart fifo. */ isr_PostSem(uart_lines[uid].semTx, 1); } break; default: break; } } |
Could You please explain me why there is NOP in irq receive handler and RXLVL register is readed twice? When I read RXLVL register and there is 2 more bytes received (ie. 10) then trigger level (ie. 8), RXLVL returns trigger level bytes qty (ie 8 insteed of 10). There is no problem if there is more bytes in FIFO. Could it be because of reading RXLVL while receiving data?