mps2_an521 UART interrupt issue


Michael Eskowitz
 
Edited

 
I am running Zephyr on an mps2_an521.  I am having trouble with a very simple example that has three UARTs that are active.  
 
One UART serves as a console and the other two UARTs provide a bidirectional passthrough.  When the callback function is invoked due to data transfer, a single character at a time is read out of the UART's input FIFO and is pushed to the output FIFO of the other UART.  I have tested this connection by pushing data through the UART at close to 1Mbaud without error.
 
If I enable the TX interrupt for one of the UARTs by calling uart_irq_tx_enable, I lose the bidirectional passthrough capability.  Data is able to be pushed in one direction only.  I am on occasion able to see a single byte pass through in the other direction after which no data passes through.
 
Why does enabling the tx interrupt break the receive interrupt?  
 
I am using the default mps2_an521-common.dtsi and I don't see any interrupts that are shared.
 
 
 
 
void serial_cb(const struct device *dev, void *user_data)
{
  uint8_t c;
 
  if (!uart_irq_update(dev)) {
    return;
  }
 
  while (uart_irq_rx_ready(dev)) {
    uart_fifo_read(dev, &c, 1);
 
    if (dev == uart_ros2) {
      uart_fifo_fill(uart_tmc, &c, 1);
    }
    else if (dev == uart_tmc) {
      uart_fifo_fill(uart_ros2, &c, 1);
    }
    else {
      uart_fifo_fill(uart_ros2, &c, 1);
      uart_fifo_fill(uart_tmc, &c, 1);
    }
  }
}
 
void main(void)
{
  check_uart_ready(uart_console, "console");
  check_uart_ready(uart_ros2, "ros2");
  check_uart_ready(uart_tmc, "tmc");
 
  /* configure interrupt and callback to receive data */
  uart_irq_callback_user_data_set(uart_ros2, serial_cb, NULL);
  uart_irq_rx_enable(uart_ros2);
 
  /* The passthrough breaks if I uncomment the line below */
//  uart_irq_tx_enable(uart_ros2);
 
  uart_irq_callback_user_data_set(uart_tmc, serial_cb, NULL);
  uart_irq_rx_enable(uart_tmc);
 
  uart_irq_callback_user_data_set(uart_console, serial_cb, NULL);
  uart_irq_rx_enable(uart_console);
 
  while(true) {
    ;
  }
}
 


nandojve@...
 

I got problems with mps2_an521. My workaround is:

Define ISR handler:
uart_irq_callback_user_data_set(dev, interrupt_handler, mydata);

At ISR handle process loop as below:
void interrupt_handler(const struct device *dev, void *dt)
{
    struct user_data *data;
    data = (struct user_data *) dt;

    do {
        uart_irq_update(dev);

        if (uart_irq_rx_ready(dev)) {
            process_rx(dev, data);
        }

        if (uart_irq_tx_ready(dev)) {
            process_tx(dev, data);
        }
    } while (uart_irq_is_pending(dev));
}

See:

Em sex., 14 de out. de 2022 às 04:29, Michael Eskowitz via lists.zephyrproject.org <Michael_Eskowitz=yahoo.com@...> escreveu:

[Edited Message Follows]

 
I am running Zephyr on an mps2_an521.  I am having trouble with a very simple example that has three UARTs that are active.  
 
One UART serves as a console and the other two UARTs provide a bidirectional passthrough.  When the callback function is invoked due to data transfer, a single character at a time is read out of the UART's input FIFO and is pushed to the output FIFO of the other UART.  I have tested this connection by pushing data through the UART at close to 1Mbaud without error.
 
If I enable the TX interrupt for one of the UARTs by calling uart_irq_tx_enable, I lose the bidirectional passthrough capability.  Data is able to be pushed in one direction only.  I am on occasion able to see a single byte pass through in the other direction after which no data passes through.
 
Why does enabling the tx interrupt break the receive interrupt?  
 
I am using the default mps2_an521-common.dtsi and I don't see any interrupts that are shared.
 
 
 
 
void serial_cb(const struct device *dev, void *user_data)
{
  uint8_t c;
 
  if (!uart_irq_update(dev)) {
    return;
  }
 
  while (uart_irq_rx_ready(dev)) {
    uart_fifo_read(dev, &c, 1);
 
    if (dev == uart_ros2) {
      uart_fifo_fill(uart_tmc, &c, 1);
    }
    else if (dev == uart_tmc) {
      uart_fifo_fill(uart_ros2, &c, 1);
    }
    else {
      uart_fifo_fill(uart_ros2, &c, 1);
      uart_fifo_fill(uart_tmc, &c, 1);
    }
  }
}
 
void main(void)
{
  check_uart_ready(uart_console, "console");
  check_uart_ready(uart_ros2, "ros2");
  check_uart_ready(uart_tmc, "tmc");
 
  /* configure interrupt and callback to receive data */
  uart_irq_callback_user_data_set(uart_ros2, serial_cb, NULL);
  uart_irq_rx_enable(uart_ros2);
 
  /* The passthrough breaks if I uncomment the line below */
//  uart_irq_tx_enable(uart_ros2);
 
  uart_irq_callback_user_data_set(uart_tmc, serial_cb, NULL);
  uart_irq_rx_enable(uart_tmc);
 
  uart_irq_callback_user_data_set(uart_console, serial_cb, NULL);
  uart_irq_rx_enable(uart_console);
 
  while(true) {
    ;
  }
}