Lesson 006: UART Input

Today we will be looking at getting input from the UART module. The code is an extension from Lesson 005.

We will need an additional buffer as well as an index pointer to the current location within the buffer, and finally an additional flag for when reception of data is complete.

In our callback function, we will also need to handle the new event for when a UART character is received. Initially it would seem that the event UART_EVENT_RX_COMPLETE would be the correct choice, but this event only occurs when we use a transfer instance (see 11.1.316.7 in the Renesas Synergy Software Package User Manual for additional details).

Instead of the UART_EVENT_RX_COMPLETE event, we will be handling the UART_EVENT_RX_CHAR which is called when a character is received on the UART device.

Inside the callback function, we will place the received character in the buffer and advance the buffer index. If a new line or carriage return character is received or if an overflow occurs, we will set the receive flag to true.

/* HAL-only entry function */
#include "hal_data.h"

#include 
#include 
#include 

// Buffer Sizes
#define OUTPUT_BUFFER_SIZE 1024
#define INPUT_BUFFER_SIZE 1024

// Buffers
char outputBuffer[OUTPUT_BUFFER_SIZE];
char inputBuffer[INPUT_BUFFER_SIZE];

volatile int inputBufferIndex;

volatile bool transmitComplete;
volatile bool receiveComplete;

// Custom printf prototype
int _printf (const char *format, ...);

// Custom printf Implementation
int _printf (const char *format, ...)
{
    // Temporary Buffer
   char buffer[OUTPUT_BUFFER_SIZE];

   // Variable Argument List
   va_list arg;

   int done;

   // Get Variable Arguments
   va_start (arg, format);

   // Pass format string and arguments to string formatter
   done = vsnprintf(buffer, OUTPUT_BUFFER_SIZE, format, arg);

   // Start Transmission
   transmitComplete = false;
   g_uart.p_api->write (g_uart.p_ctrl, buffer, done);

   while (!transmitComplete)
   {
   }

   // End Variable Arguments
   va_end (arg);

   return done;
}

// Callback Function for UART interrupts
void user_uart_callback(uart_callback_args_t * p_args)
{
    // Get Event Type
    switch (p_args->event)
    {
        // Transmission Complete
        case UART_EVENT_TX_COMPLETE:
            transmitComplete = true;
        break;

        // Received Character
        case UART_EVENT_RX_CHAR:
            // Add data to input Buffer
            inputBuffer[inputBufferIndex] = p_args->data;

            // Check for end of data (new line or carriage return)
            if ( (inputBuffer[inputBufferIndex] == '\n') || (inputBuffer[inputBufferIndex] == '\r'))
            {
                // Replace new line/carriage return with NULL
                inputBuffer[inputBufferIndex] = NULL;

                // Set Flag
                receiveComplete = true;
            }

            // Increment Buffer Index
            inputBufferIndex++;

            // Check for overflow
            if (inputBufferIndex >= INPUT_BUFFER_SIZE)
            {
                // Overflow occurred, set flag and reset buffer index.
                receiveComplete = true;
                inputBufferIndex = 0;
            }

            break;
        defaut: break;
    }
}

void hal_entry(void)
{
    inputBufferIndex = 0;

    // Open UART
    g_uart.p_api->open(g_uart.p_ctrl, g_uart.p_cfg);

    // Use TTY100 commands to clear screen and reset screen pointer
    _printf("\033[2J"); // Clear Screen
    _printf("\033[H"); // Return Home
    _printf("\033[3J"); // Clear Back Buffer

    // Print Header
    _printf("Day Seven - UART Input\r\n");

    while (true)
    {
        _printf("\r\nInput: ");

        // Receive all characters up to new line/carriage return.
        receiveComplete = false;
        g_uart.p_api->read(g_uart.p_ctrl, NULL, NULL);
        while (!receiveComplete){}

        // Reset Input Buffer => This does not detect or handle overflow events.
        // If there is an overflow, only the first INPUT_BUFFER_SIZE characters are printed, the rest are lost
        inputBufferIndex = 0;

        // Print Results
        _printf("%s", inputBuffer);
    }
}

This code echo’s what ever is received on the UART device.

Full code is also on GitHub at https://github.com/lycannon/ajwrs/tree/master/DaySeven.

Advertisements

10 thoughts on “Lesson 006: UART Input

    1. Peter,

      I would love to continue to write, but I’ve been working 60-70 hours weeks for the last month, so I don’t have time to continue 😦

      The project ends in a few weeks, so I hope to start writing again!

      Like

    1. I plan too! Work has been crazy busy. I hope to finish up my projects soon so I can continue to write.

      Thanks for the encouragement!

      Like

  1. Thank you for the update and the determination to complete the objective. There is a Synergy Software update (v1.1.0) in mid-May. Is maybe worth your time to review these updates before you jump back into the project..

    Like

  2. I have another update to this section too. After speaking with Renesas support, they told me about the _write and _read overrides, which is exactly what I was looking for. I’m looking forward to updating the code to match accepted standards.

    Expect more here in a few weeks!

    Like

  3. Hi Eric,
    This is Jim again. As you can see, I am moving along with your notes and now on class 6 now.
    I have 2 questions regarding the reading uart in your code.

    Question 1: You have put the g_uart.p_api->read() call inside the “while” loop. Is this the actual call to read the UART? If so, this will be a busy-waiting read and block the code. I don’t want to do the blocking read (I am not using thread either due to project requirement), but rather just let the interrupt handler (in this case, the call back function) to handle anything read in by the UART driver. If I don’t issue this call in the code, will input into the UART cause the call back function be invoked?

    Question 2: In your call back function, does the UART_EVENT_RX_CHAR mean a byte is received by the UART or does have to be a character of some sort of encoding?

    Thanks for sparing your time answering my question.
    Jim

    Like

    1. Jim,

      Thanks for continuing to read!

      Question 1: No, the call to g_uart.p_api->read() does not block. In fact, based on digging through the SSP code, the call does nothing…I should probably test this. If you right click on the read() part of g_uart.p_api->read() and click go to definition, it will take you to the r_uart_api.h file and the read definition. Then, expand the comment section out and right click on R_SCI_UartRead() and go to definition again. This takes you to the actual code that is called when the read() function is invoked.

      In this example, I pass NULL as the third parameter to the function, and get a warning too since NULL is defined as ((void *)0). This is a pointer, not an integer. It should instead pass 0 as the third parameter. In that case, on line 354 of r_sci_uart.c, it checks if bytes (the third parameter) is 0. If it is, then there is nothing to do, so it returns SSP_SUCCESS.

      If the pointer cast doesn’t evaluate to 0, then line 369 “if (NULL != p_ctrl->p_transfer_rx)” returns false, since p_ctrl->p_transfer_rx gets defined to NULL since I am not using a transfer driver (check the file hal_data.c and search for .p_transfer_rx).

      Since the if block is not executed, the function returns err, which at the top, gets set to SSP_SUCCESS, and as long as the parameter check goes OK, does not get changed later.

      So, from what I can see, the read function does nothing (you can try setting a breakpoint at read() and stepping through the code).

      In this case, the line while (!receiveComplete){} is actually what blocks and will continue to do so until the callback function sets receiveComplete to true.

      To make this a non-blocking program, change the flag to something like dataInBuffer or check the inputBufferIndex for a non-zero value, then process the data in the hal_entry function.

      =====================================================

      Question 2: The UART_EVENT_RX_CHAR was defined by the SSP. It does not imply any type of encoding. Once a byte is received (either 8 or 9 bits depending on how you’ve setup your UART device), p_args->event is set to UART_EVENT_RX_CHAR.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s