Step 4: Add Application Code to the Project
This example application on the PIC32CM LS00 Curiosity Nano+ Touch Evaluation Kit demonstrates the interrupt-driven method for Universal Synchronous Asynchronous Receiver Transmitter (USART) serial communication. In this demonstration, application code is added to the generated project’s main file to implement data transmission and reception using interrupt-driven techniques. Add the following code to enable interrupt-driven USART operation.
Application Code for the Project
Open the main.c source file in the Non-Secure project. Include the <string.h> header file, and then add the required macros and global variables immediately after the header file inclusions, as shown in the accompanying image. Insert the provided code into the project at the specified location.
#define RX_BUFFER_SIZE 10
#define LED_ON LED_Clear
#define LED_OFF LED_Set
char messageStart[] = "**** USART echo demo: Non-blocking Transfer with the interrupt ****\r\n\
**** Type 10 characters. The received characters are echoed back, and the LED is toggled ****\r\n";
char receiveBuffer[RX_BUFFER_SIZE] = {};
char echoBuffer[RX_BUFFER_SIZE+4] = {};
char messageError[] = "**** USART error occurred ****\r\n";
static bool errorStatus = false;
static bool writeStatus = false;
static bool readStatus = false;

The macros RX_BUFFER_SIZE, LED_ON, and LED_OFF are used to define the receive buffer size and simplify LED control operations in the program. The messageStart string stores the startup message that is transmitted through the USART interface to inform the user about the echo demonstration. The receiveBuffer and echoBuffer arrays are used to store the received data and the echoed response that will be sent back to the terminal. The messageError string is transmitted if a USART communication error occurs. The Boolean status flags errorStatus, writeStatus, and readStatus are used to monitor the current status of USART operations when operating in non-blocking interrupt mode.
Add the SERCOM3_USART_WriteCallbackRegister and SERCOM3_USART_ReadCallbackRegister function calls after SYS_Initialize(NULL); inside the int main(void) function. This callback registration enables the application to automatically execute a specified function when an interrupt occurs, such as a receive or transmit data. SERCOM3_USART_Write is used to write the start message of this project.
SERCOM3_USART_WriteCallbackRegister(APP_WriteCallback, 0);
SERCOM3_USART_ReadCallbackRegister(APP_ReadCallback, 0);
SERCOM3_USART_Write(&messageStart[0], sizeof(messageStart));

The code registers callback functions to enable interrupt-driven USART communication and initiates data transmission. The SERCOM3_USART_WriteCallbackRegister function registers APP_WriteCallback as the handler for USART write operations, which is automatically invoked when a write operation completes. Similarly, the SERCOM3_USART_ReadCallbackRegister function registers APP_ReadCallback as the handler for USART read operations, allowing immediate processing of incoming data upon reception. The SERCOM3_USART_Write function initiates an asynchronous write operation to transmit the contents of the messageStart array over the USART interface. Upon completion of the transmission, the registered write callback function is executed.
Define the APP_WriteCallback function before the int main() function. The APP_WriteCallback function is a user-defined callback registered as the USART write handler. It is automatically invoked upon completion of a USART write operation and sets the writeStatus flag to true, indicating successful completion of the write process.
void APP_WriteCallback(uintptr_t context)
{
writeStatus = true;
}

Add the APP_ReadCallback function before the int main() function. The APP_ReadCallback function is triggered when a USART read operation completes. It checks for USART errors using the SERCOM3_USART_ErrorGet() function; if an error is detected, the errorStatus flag is set, otherwise, the readStatus flag is set to indicate successful data reception.
void APP_ReadCallback(uintptr_t context)
{
if(SERCOM3_USART_ErrorGet() != USART_ERROR_NONE)
{
/* ErrorGet clears errors, set error flag to notify console */
errorStatus = true;
}
else
{
readStatus = true;
}
}
Inside the infinite while(true) loop, use conditional statements (if-else blocks) to manage data transmission, data reception, and error handling for the application.
The first conditional if statement checks for errors by evaluating the errorStatus flag. If an error is detected, it sends an error message to the console using the SERCOM3_USART_Write function and then resets the errorStatus flag to false to prevent repeated error notifications.
if(errorStatus == true)
{
/* Send error message to console */
errorStatus = false;
SERCOM3_USART_Write(&messageError[0], sizeof(messageError));
}

Add the following else-if statement to handle the event when new data is received via the USART interface. The received data is echoed back to the sender with appropriate formatting. Additionally, the LED_Toggle() function is called to indicate that data reception and echoing have occurred. Finally, the readStatus flag is reset to ensure the event is processed only once per data reception.
else if(readStatus == true)
{
/* Echo back received buffer and Toggle LED */
readStatus = false;
echoBuffer[0] = '\n';
echoBuffer[1] = '\r';
memcpy(&echoBuffer[2], receiveBuffer,sizeof(receiveBuffer));
echoBuffer[RX_BUFFER_SIZE+2] = '\n';
echoBuffer[RX_BUFFER_SIZE+3] = '\r';
SERCOM3_USART_Write(&echoBuffer[0], sizeof(echoBuffer));
LED_Toggle();
}

Add the final else if statement to initiate a new data reception process over the USART interface when the system is ready to receive additional data. This statement submits a buffer to the USART read function using SERCOM3_USART_Read, preparing the system to receive new user data and store it in receiveBuffer. The writeStatus flag is then reset to indicate that the write event has been handled and to prevent repeated execution.
else if(writeStatus == true)
{
/* Submit buffer to read user data */
writeStatus = false;
SERCOM3_USART_Read(&receiveBuffer[0], sizeof(receiveBuffer));
}
