More UART issues/questions

I've hit a wall trying to get UART to function, so hoping someone can see what I'm doing wrong.  S5D9/SSP1.6.3.

The UART is configured on SCI6 with external RTS.  TX is P305, RX is P505, CTS is P503, and GPIO P501 is RTS.  RTS is configured as CMOS output.

For debugging I'm using my operating USB interface on Teraterm; these diagnostic messages are in code below  The UART/RS232 is in a different Teraterm window.

The code is simple: wait to receive variable-length data terminated with a CR (13), then parse/handle and return to wait for next receive.

The main problem: I see diagnostics from UART initialization and from user_RTS_callback (only once), but never see messages from user_uart_callback.  Things I've tried:

  • checked spelling/names for agreement, rechecked UART configuration parameters.
  • re-generated project content and done clean-builds
  • switched RTS low and high logic
  • duplicated diagnostic messages to also appear on UART window (the same ones appear as do in USB window)
  • Made sure Error Interrupt Priority was not disabled

Any suggestions much appreciated!!

CONFIG SCREEN:

CODE:

<initialization>

while (receive_complete == 0)   //receive_complete set =1 when CR is detected

    {g_uart.p_api->read(g_uart.p_ctrl, (uint8_t *)msg3,1u);}  //read and process each character individually
receive_complete=0;

<parse data, perform action, return>

void user_RTS_callback(uint32_t channel, uint32_t plevel)
{  if(channel == g_uart.p_cfg->channel)
   {
   switch(plevel)
       {
       case 1U:
         g_ioport.p_api->pinWrite(UART_RTS_pin, IOPORT_LEVEL_LOW);
         snprintf(msg3, sizeof(msg3)," RTS set low \r\n\n");
         g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)msg3, (uint32_t)sizeof(msg3), TX_WAIT_FOREVER);
       break;
       case 0U:
         g_ioport.p_api->pinWrite(UART_RTS_pin, IOPORT_LEVEL_HIGH);
         snprintf(msg3, sizeof(msg3)," RTS set high\r\n\n");
         g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)msg3, (uint32_t)strlen(msg3), TX_WAIT_FOREVER);
      break;
      default:
      break;
      }
   }
}
/*************************************************************/
void user_uart_callback(uart_callback_args_t * p_args)
{
static int8_t receive_num = 0;
static int8_t loop_num;

g_sf_comms.p_api->write(g_sf_comms.p_ctrl, "CALLBACK\r\n\n", 30, TX_WAIT_FOREVER);

switch (p_args->event)
{
case UART_EVENT_RX_COMPLETE:
   snprintf(msg3, sizeof(msg3),"RX_COMP \r\n\n");
   g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)msg3, (uint32_t)strlen(msg3), TX_WAIT_FOREVER);
   break;
case UART_EVENT_TX_COMPLETE:
   snprintf(msg3, sizeof(msg3),">>>>>>>>>>>>>TX_COMPLETE \r\n");
   g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)msg3, (uint32_t)strlen(msg3), TX_WAIT_FOREVER);

break;
case UART_EVENT_RX_CHAR:
// Store each character of received data into buffer
  uart_buf[receive_num] = (uint8_t)p_args->data;
   receive_num ++;  //count on characters received
   if (uart_buf[receive_num] == 13)  //check for CR
       {   receive_complete = 1;  //set complete flag for main loop
           for (i=0;i<receive_num;i++)
          {  cmd2[i] = uart_buf[i]; }    //move data
        g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)cmd2, (uint32_t)sizeof(cmd2), TX_WAIT_FOREVER);
       }
break;
default:
break;
}
g_sf_comms.p_api->write(g_sf_comms.p_ctrl, "END CALLBACK\r\n\n", 30, TX_WAIT_FOREVER);  //depart message

}


/*********** * uart initialization */

void uart_module_init()
{
{
static int8_t loop_num;
// ssp_version_t uart_version;
uart_info_t uart_info;

// Initialize UART232 Driver (RTS and CTS function is used)
g_uart.p_api->open(g_uart.p_ctrl, g_uart.p_cfg);

// Change baud rate from 15200 to 9600, the same rate as external device
g_uart.p_api->baudSet(g_uart.p_ctrl, (uint32_t)9600);

g_uart.p_api->infoGet(g_uart.p_ctrl, &uart_info);

g_ioport.p_api->pinWrite((ioport_port_pin_t)IOPORT_PORT_05_PIN_01, IOPORT_LEVEL_LOW);
sprintf((char *)uart_buf, "COM 232 working on UART \n\r\n");
g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)uart_buf, (uint32_t)sizeof(uart_buf), TX_WAIT_FOREVER);

snprintf((char *)uart_buf, sizeof(uart_buf),"Maximum read at one time is: 0x%lx\n\r\n",(uint32_t)uart_info.read_bytes_max);
g_sf_comms.p_api->write(g_sf_comms.p_ctrl, (uint8_t *)uart_buf, (uint32_t)sizeof(uart_buf), TX_WAIT_FOREVER);

}

}

Parents
  • You are not checking the return value from any of the API calls to the SSP drivers, do any of them return an error?

    You are calling the USB comms framework in the callbacks, the user_uart_callback() is only called from the SCI interrupt handers and the RTS callback is called from the SCI interrupt handler, and it is also called in one place that is not in an interrupt hander.

    Calling the USB comms framework in an interrupt handler is not reccomended (and might not even work, as some ThreadX API can only be called in an interrupt handler with the wait parameter set to TX_NO_WAIT).

  • Thanks again Jeremy.  Checking the return values showed me some of the problems.  

    Now it is somewhat working.  If I type in Teraterm the number of characters specified in the uart read then the UART_EVENT_RX_COMPLETE case in the callback runs.  But the UART_EVENT_RX_CHAR case seems to not work most of the time (oddly will run occasionally, haven't figured out why just occasionally.)  I moved the RX_CHAR case to be above the RX_COMPLETE in the switch statement but no difference.

    Thanks for pointing out the USB comms issue, I was wondering why it seemed to work intermittently. Will modify. 

  • When a read API is active, the data is received into memory specified in the call to the read API, then when the number of bytes specified in the call to read have been received, the callback is called with the event UART_EVENT_RX_COMPLETE. When a read is not active, the callback is called for each character received, with the the event UART_EVENT_RX_CHAR, and the data is in the callback argument p_args->data

  • That's my understanding: that once you open and configure the UART, then each time a character arrives at the port the callback will fire with UART_EVENT_RX_CHAR.  Specifically this occurs without ever using the read API?

    I'm still trying different things.  If I use the read API with a 1 byte length it seems to mostly call UART_EVENT_RX_COMPLETE.  The downside of this is I have put the read in a while loop that repetitively processes each character while waiting for the terminating character.  This causes the delay/slow behavior in the response after each character is typed.

  • If you look at the source code for the driver you can see that reception is enabled when the SCI Uart driver is opened (as long as the driver is configured for reception at build time).

    Characters can be received even without calling the Read() API, with the event UART_EVENT_RX_CHAR, after the driver has been opened.

  • Still working on this issue.  Generally everything works as expected except the UART_EVENT_RX_CHAR event in the callback.  So questions:

    -Does the RTS state have any effect on this?
    -Besides enabling reception, are there any configuration settings that would interfere?
    -What should the receive interrupt priority be set to?

  • If you are using the CTSn_RTSn pin for CTS functionality, then the RTS pin is a GPIO and is not linked in HW to the operation of the SCI (the driver is changing the state of the RTS pin, not the SCI peripheral, this can be seen if the SCI UART driver code is inspected).

    The RTS callback is called from R_SCI_UartOpen() to setup the RTS pin state (in the call to r_sci_uart_external_rts_operation_enable() ),  then the RTS callback is only called RXI interrupt handler :-

    The receive interrupt priority that should be set is dependant on the set up of your system, and what priorities other interrupts are set to, how much code is in the interrupt handlers for the other interrupts.

Reply
  • If you are using the CTSn_RTSn pin for CTS functionality, then the RTS pin is a GPIO and is not linked in HW to the operation of the SCI (the driver is changing the state of the RTS pin, not the SCI peripheral, this can be seen if the SCI UART driver code is inspected).

    The RTS callback is called from R_SCI_UartOpen() to setup the RTS pin state (in the call to r_sci_uart_external_rts_operation_enable() ),  then the RTS callback is only called RXI interrupt handler :-

    The receive interrupt priority that should be set is dependant on the set up of your system, and what priorities other interrupts are set to, how much code is in the interrupt handlers for the other interrupts.

Children
  • The RTS explanation makes sense- thanks.

    Interrupt priority seems to not make a difference- set it to 0 and still no UART_EVENT_RX_CHAR event.

    I've got it to work using the read(1 character buffer) but it sits in a while loop, concatenating 1 character at a time, waiting for the terminating character.  this seems like bad programming style.

    also i'm seeing some issues with writing to UART.  after receiving command string and terminating character, the main loop runs through a switch statement, forms a response string, and then sends the response back out the UART.  i'm seeing sometimes the response string is partial or doesn't appear at all.  are delays that needed, or other approaches, that would help improve transmit operations.  (in some places I'll send the response string to the USB and then to the UART- it will appear on USB but not UART.)

  • That's why you run it in a separate thread. I tried polling a serial channel (i.e. repeatedly calling p_api->read (TX_NO_WAIT) and it was always unreliable, dropping characters all over the place. Instead, I call p_api->read (TX_WAIT_FOREVER) and stuff whatever it returns (which is always 1 byte) into a buffer. Once I see the terminating character, I set a flag that lets the main process do something with all the data I've buffered.

    I don't know why TX_NO_WAIT doesn't work, since there's a nice que already set up for serial chars; I expected it to catch everything. Which reminds me: check that your Read Input Que size in the SSC module properties for your Communications Framework is 16. I tried other values and they do not work!

  • Thanks, glad someone else sees similar behavior.  I'm doing the same thing, reading one byte at a time and looking for the terminating character, then setting a flag that releases it from the while-read loop.

    I'm migrating it over to a new thread.  Also I'm using the driver form of UART because it gives more control than the framework.