SC16IS752 Trigger Levels

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

SC16IS752 Trigger Levels

1,047 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by manoffline on Wed Oct 08 10:51:50 MST 2014
Hello Folks,

I've been using this SPI-UART bridge for years and faced and resolver issues with the driver during all this time. But now I'm facing a problem I can't solve.

The RX trigger level is always triggering at 60 bytes, not at the configured level, causing data loss.

This is the function to open external UARTs (from bridge):
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
}


When the interrupt source is RHR (trigger level reached), the RXLVL is 60, which means the IRQ was triggered when 60 bytes were at the RX FIFO. If I place a breakpoint and right read the RXLVL again, the value increases to 64 (FIFO full).

This is the IRQ handler:
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;
  }
}


Thanks in advance,
Mariano.
Labels (1)
0 Kudos
2 Replies

625 Views
svavo
Contributor I

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?

0 Kudos

625 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by manoffline on Wed Oct 08 11:18:56 MST 2014
I found the problem.

I have a function to flush all RX/TX data, and it was corrupting the FCR register value. It was solved after I fixed this.
0 Kudos