LoginSignup
0
0

More than 3 years have passed since last update.

Implementing FIFO to USBUART RX on PSoC 5LP

Last updated at Posted at 2019-08-19

Japanese

In the last article "Implementing FIFO to USBUART TX on PSoC 5LP" FIFO is implemented to the TX side of the USBUART component. Another FIFO is implemented to the RX side in this article.

Idea for RX side FIFO

RX side FIFO is implemented as well as the TX side FIFO as follows.

  1. Periodically monitor the endpoint and fill the buffer with the received data if the buffer is EMPTY.
  2. Get a character from the buffer using a function to get one character.

The behavior using FIFO is same as one using no FIFO. This is because there is no method to get one character from the data arrived at the endpoint and all data must be gotten from the endpoint.

The endpoint monitoring frequency is configured as 2kHz as well as the TX side.

Firmware

The schematic and the component configuration are same as last article's one. The firmware is described as follows.

main.c
#include "project.h"

// Uncomment when Disable the FIFO function.
//#define NOFIFO

// The packet size of the USBUART
// is used for the FIFO buffer size too.
#define     UART_TX_QUEUE_SIZE      (64)
#define     UART_RX_QUEUE_SIZE      (64)

A packet size declaration for RX buffer is added. The FIFO buffer size is equal to the maximum BULK packet size used by the USBUART component as well as the TX side buffer size.

main.c
// TX buffer declaration
uint8       uartTxQueue[UART_TX_QUEUE_SIZE];    // Queue buffer for TX
uint8       uartTxCount = 0;                    // Number of data bytes contained in the TX buffer
CYBIT       uartZlpRequired = 0;                // Flag to indicate the ZLP is required
uint8       uartTxReject = 0;                   // The count of trial rejected by the TX endpoint

// RX buffer declaration
uint8       uartRxQueue[UART_RX_QUEUE_SIZE];    // Queue buffer for RX
uint8       uartRxCount = 0;                    // Number of data bytes contained in the TX buffer
uint8       uartRxIndex = 0;                    // Index on RX buffer to get a byte
CYBIT       uartRxCRDetect = 0;                 // CR detection flag

There is an RX buffer declaration as well as the TX buffer. There is an RX buffer specific variable uartRXCRDetected to indicate that CR is received as the last end of line symbol. When a sequence CR+LF is received as the end of line symbol, LF is received during the uartRXCRDetected flag is asserted. In this case, returns an end of line symbol when CR is detected and the LF following the CR is ignored.

There are TX side descriptions as well as the last article has. The descriptions are omitted in this article.

main.c
#ifdef NOFIFO

// Functio to receive one byte
int16 getch_sub(void) {
    int16 ch = -1;
    uint8 state = CyEnterCriticalSection();

    if (uartRxIndex >= uartRxCount) {
        // RX buffer is empty
        if (USBUART_DataIsReady()) {
            // and data arrives at USBUART
            // receive data to RX buffer
            uartRxCount = USBUART_GetAll(uartRxQueue);
            uartRxIndex = 0;
        }
    }
    if (uartRxIndex < uartRxCount) {
        // If any characters left in RX buffer
        // get a byte from RX buffer
        ch = uartRxQueue[uartRxIndex++];
    }
    CyExitCriticalSection(state);
    return ch;
}

When FIFO is not used, this function is used to receive one byte data. In the first half of the function, it is ensure that the RX buffer has at least one byte data.  In particular the RX buffer is filled by the data from the endpoint when the RX buffer is EMPTY.

In the second half of the function, one byte data is gotten from the RX buffer and is returned as a return value of the function.

When this function is used, the application may be stopped until any character data are received as a USB packet because the next packet is received in this function.

main.c
#else // define(NOFIFO)

// RX side Interrupt Service Routine
void uartRxIsr(void) {
    uint8 state = CyEnterCriticalSection();
    if (uartRxIndex >= uartRxCount) {
        // If RX buffer is EMPTY
        if (USBUART_DataIsReady()) {
            // and data arrives at USBUART
            // receive data to RX buffer
            uartRxCount = USBUART_GetAll(uartRxQueue);
            uartRxIndex = 0;
        }
    }
    CyExitCriticalSection(state);
}

When FIFO is used, the first half procedure is executed in the periodic interrupt service routine, and the second half procedure is executed in the main loop. There is a "Critical Section" in this interrupt service routine to prevent from other interrupts.

main.c
// Function to get one byte from USBUART
int16 getch_sub(void) {
    int16 ch = -1;
    uint8 state = CyEnterCriticalSection();

    if (uartRxIndex < uartRxCount) {
        // If any characters left in RX buffer
        // get a byte from RX buffer
        ch = uartRxQueue[uartRxIndex++];
    }
    CyExitCriticalSection(state);
    return ch;
}

#endif // define(NOFIFO)

The second half procedure is described in the one byte receiving function getch_sub() This is a simple function to get one byte from the RX buffer.

main.c
// Get one character from USBUART
int16 getch(void) {
    int16 ch = getch_sub();
    if (uartRxCRDetect && ch == '\n') {
        uartRxCRDetect = 0;
        ch = getch_sub();
    } else if (ch == '\r') {
        ch = '\n';
        uartRxCRDetect = 1;
    }
    return ch;
}

There is a end of line symbol handling in the function getch() to get one character. With this procedure this function can return a character '\n' for any symbol from CR, LF, and CR+LF.

main.c
#ifndef NOFIFO

// Periodically check the TX and RX of USBUART
CY_ISR(int_uartQueue_isr) {
    uartTxIsr();
    uartRxIsr();
}

#endif // !define(NOFIFO)

The RX side interrupt service function is added to the periodic interrupt service routine in addition to the TX side interrupt service function.

main.c
int main(void) {
    uint32 nLine = 0;           // Line number
    uint32 nChars = 0;          // Number of characters

    CyGlobalIntEnable;                          // Enable interrupts
    USBUART_Start(0, USBUART_5V_OPERATION);     // Initialize USBFS using 5V power supply

#ifndef NOFIFO

    int_uartQueue_StartEx(int_uartQueue_isr);   // Initialize the periodic timer

#endif // !define(NOFIFO)

    for(;;) {
        // Wait for initialization completed
        while (USBUART_GetConfiguration() == 0);

        USBUART_IsConfigurationChanged();       // Ensure to clear the CHANGE flag
        USBUART_CDC_Init();                     // Initialize the CDC feature

        for (;;) {
            // Re-initialize if the configuration is changed
            if (USBUART_IsConfigurationChanged()) {
                break;
            }

            // CDC-OUT : Show the number of characters in a received line.
            {
                int16 ch = getch();
                if (ch >= 0) {
                    nChars++;
                    if (ch == '\n') {
                        putdec32(nLine, 7);
                        putstr(" - ");
                        putdec32(nChars, 7);
                        putstr("\n");
                        nLine++;
                        nChars = 0;
                    }
                }
            }

            // CDC-Control : Ignore all control commands
            (void)USBUART_IsLineChanged();
        }
    }
}

There is a procedure of this application in the main loop. In this application, the number of characters is counted for each line recevied from USBUART and send the line number and the number of characters to USBUART It is available to confirm if any data is missing by monitor the number of characters. And it is also available to calculate the amount of received data from the line number.

Execution

GS001543.png

After building and programming the project, the project is executed. A large text file consisting of 59 characters line is sent from Tera Term Because the end of line symbols are CR+LF the number of characters displayed in Tera Term is 58.

When a 100,000 line text file is sent, it takes 98 seconds. The effective throughput is calculated as 59 kiB/s.

When no FIFO used

GS001544.png

As well as the last article, a configuration not to use FIFO is tried. But the output on the Tera Term is broken. This is because the TX side is not working well.

Related Article

Implementing FIFO to USBUART TX on PSoC 5LP

リポジトリ

GitHub Repository

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0