MPLAB® Harmony v3 Drivers on SAM E54 MCUs Using FreeRTOS™: Step 5

Last modified by Microchip on 2023/11/15 13:28

Add Application Code to the Project

 The application is already developed and is available in the files:

  • app_sensor_thread.c,
  • app_sensor_thread.h,
  • app_eeprom_thread.c,
  • app_eeprom_thread.h,
  • app_user_input_thread.c, and
  • app_user_input_thread.h.
They are available under:
<your unzip folder>/same54_getting_started_freertos/dev_files/sam_e54_xpro.

The application files app_sensor_thread.capp_eeprom_thread.c, and app_user_input_thread.c contain the application logic. They also contain placeholders that you will populate with the necessary code in the next step.

Go to the same54_getting_started_freertos/dev_files/sam_e54_xpro folder and copy the pre-developed files:

  • app_sensor_thread.c,
  • app_sensor_thread.h,
  • app_eeprom_thread.c,
  • app_eeprom_thread.h
  • app_user_input_thread.c, and
  • app_user_input_thread.h.

Paste and replace (over-write) the files of your project available at <Your project folder>/same54_getting_started_freertos/firmware/src with the copied files.

The main_e54.c file calls the SYS_Tasks() routine, which creates the sensor, Electrically Erasable Programmable Read-Only Memory (EEPROM), and user input threads and makes a call to FreeRTOS™ Application Programming Interface (API) vTaskStartScheduler() to start the scheduler.

Start the scheduler

Observe that each application task runs in its individual RTOS thread.

The app_eeprom_thread.happ_sensor_thread.h and app_user_input_thread.h files define the states and data structures of these application threads.

Individual application threads

The APP_SENSOR_THREAD_Tasks() function in app_sensor_thread.c, the APP_EEPROM_THREAD_Tasks() function in app_eeprom_thread.c, and the APP_USER_INPUT_THREAD_Tasks() function in app_user_input_thread.c implements the application thread functionality.
The sensor application thread in app_sensor_thread.c and the EEPROM application thread in app_eeprom_thread.c acts as the two clients to the Synchronous I2C driver instance 0.

The sensor application thread in app_sensor_thread.c, EEPROM application thread in app_eeprom_thread.c, and user input application thread in app_user_input_thread.c act as the three clients to the synchronous Universal Synchronous Asynchronous Receiver Transmitter (USART) driver instance 0.

In the application source files, the code for the application threads is already developed. In the following steps, you will add the missing code snippets.

Open app_sensor_thread.c and add application code referring to the comments in the screenshots as shown in the following steps.

  • Open the Inter-Integrated Circuit (I2C) driver instance 0, which is associated with SERCOM3. The call to DRV_I2C_Open() API will associate the sensor client with the I2C driver instance 0. The returned handle will be used by the application in all the subsequent calls to the driver to read temperature values from the sensor.
app_sensorData.i2cHandle = DRV_I2C_Open( DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE );

Open I2C driver to interact with the the temp sensor

  • Set the transfer parameters for the sensor application thread client after a valid handle to the driver is obtained. The transfer parameter sets the I2C clock speed to 100 kHz for this client.
DRV_I2C_TransferSetup(app_sensorData.i2cHandle, &app_sensorData.i2cSetup);

Setup I2C transfer at 100 kHz to interface with sensor

  • Open the USART synchronous driver instance 0 (which is associated with SERCOM2). The call to DRV_USART_Open() API will return a handle to the USART driver instance 0. The returned handle will be used by the sensor application thread in all the subsequent calls to the driver to print the temperature values on the serial terminal for this client.
app_sensorData.usartHandle = DRV_USART_Open(DRV_USART_INDEX_0, 0);

Open the USART driver to print temp values

Allow other threads to run until it's time to read temp

  • Submit a blocking I2C request to read temperature from the sensor. The calling thread will be blocked until the request is completed thereby allowing other threads to run.
if (true == DRV_I2C_WriteReadTransfer(app_sensorData.i2cHandle, APP_SENSOR_I2C_SLAVE_ADDR, (void*)&registerAddr, 1, (void*)app_sensorData.i2cRxBuffer, 2))

Submit a blocking I2C write-read request

  • Communicate the temperature ready event and the temperature value to the EEPROM thread using the RTOS queue. The EEPROM task unblocks when an event/data is available in the RTOS queue.
xQueueSend( eventQueue, (void*)&app_sensorData.eventInfo, portMAX_DELAY);

Use FreeRTOS Queue to notify the temp write event and temp value to EEPROM thread

  • Print the latest temperature value by making a call to DRV_USART_WriteBuffer() API, which submits a blocking USART write request.
DRV_USART_WriteBuffer(app_sensorData.usartHandle, app_sensorData.usartTxBuffer, strlen );

Print the temperature value by submitting a blocking USART write request

Open app_eeprom_thread.c and add application code referring to the comments in the screenshots as shown in the following steps.

  • Associate the second client (EEPROM application thread client), with the I2C driver instance 0. This is done by opening the I2C driver instance 0 again. The call to DRV_I2C_Open () API will now associate the EEPROM application thread client with the I2C driver instance 0. The returned handle will be used by the application in all the subsequent calls (related to the EEPROM application thread client) to the driver to write/read temperature values to/from EEPROM.
app_eepromData.i2cHandle = DRV_I2C_Open( DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE );

Open I2C driver to interact with the EEPROM

  • Like the sensor application thread client, set up the transfer parameters for the EEPROM application thread client after a valid handle to the driver is obtained. The transfer parameters set the I2C clock speed to 100 kHz for this client.
DRV_I2C_TransferSetup(app_eepromData.i2cHandle, &app_eepromData.i2cSetup);

Setup I2C transfer at 100 kHz to interface with EEPROM

Information
  • The call to DRV_I2C_TransferSetup overrides the baud rate set in the I²C driver configuration using MPLAB® Code Configurator (MCC).
  • I²C was configured to run at 100 kHz using MCC. While in the application, the sensor thread reconfigured it to run at 100 kHz and the EEPROM thread configured it to run at 100 kHz. This illustrates how the MPLAB ​​Harmony I²C driver handles the peripheral module-specific configuration depending on the client accessing the peripheral.
  • Associate the second client (EEPROM application thread client) to USART synchronous driver instance 0 (which is associated with SERCOM2). The call to DRV_USART_Open() API will return a handle to the USART driver instance 0. The returned handle will be used by the EEPROM application thread in all the subsequent calls to the driver to print the temperature values from the EEPROM on the serial terminal.
app_eepromData.usartHandle = DRV_USART_Open(DRV_USART_INDEX_0, 0);

Open the USART driver to print logged temperature values from EEPROM

  • Block the EEPROM application thread until a request is available in the RTOS queue. The scheduler will unblock the EEPROM thread when an event/data is available in the RTOS queue. Depending on the event received in the RTOS queue, the EEPROM task either writes or reads temperature value from the EEPROM.
xQueueReceive( eventQueue, &app_eepromData.eventInfo, portMAX_DELAY );

Wait for the temperature write request OR EEPROM read request

  • Submit blocking I2C requests to write temperature from the sensor to EEPROM. The calling thread will be blocked until the request is completed thereby allowing other threads to run.
        if (true == DRV_I2C_WriteTransfer(app_eepromData.i2cHandle, APP_EEPROM_I2C_SLAVE_ADDR, (void *)app_eepromData.i2cTxBuffer, 2))
        {                
           /* Check if EEPROM has completed the write operation */
           while (false == DRV_I2C_WriteTransfer(app_eepromData.i2cHandle, APP_EEPROM_I2C_SLAVE_ADDR, (void *)&dummyData, 1));
        }

Write temperature to EEPROM

  • Submit blocking I2C request to read the temperature from the EEPROM to submit for printing on the serial terminal. The calling thread will be blocked until the request is completed thereby allowing other threads to run.
if (true == DRV_I2C_WriteReadTransfer(app_eepromData.i2cHandle, \
               APP_EEPROM_I2C_SLAVE_ADDR, app_eepromData.i2cTxBuffer, 1,\
               app_eepromData.i2cRxBuffer, 5))

Read the logged temperature values from the EEPROM

  • Print the logged temperature value from EEPROM by making a call to DRV_USART_WriteBuffer() API by calling the EPPROM application thread function APP_EEPROM_PrintTemperature(), which submits a blocking USART write request.
APP_EEPROM_PrintTemperature(app_eepromData.i2cRxBuffer, app_eepromData.wrIndex);

Print the log values on the terminal

Open app_user_input_thread.c and add application code referring to the comments in the screenshots as shown in the following steps.

  • Associate the third client (user input application thread client) to USART synchronous driver instance 0 (which is associated with SERCOM2). The call to DRV_USART_Open() API will return a handle to the USART driver instance 0. The returned handle will be used by the user input application thread in all the subsequent calls to the driver to read a user key press on the serial terminal.

app_user_inputData.usartHandle = DRV_USART_Open(DRV_USART_INDEX_0, 0);

Open the USART driver to read user key press

  • Submit a blocking USART read request. The user input thread will be unblocked when a character is received on the USART. After unblocking, it communicates the request to read data from EEPROM to the EEPROM thread via the RTOS queue.
if (DRV_USART_ReadBuffer(app_user_inputData.usartHandle, &usartData, 1 ) == true)

Submit a blocking USART read request

xQueueSend( eventQueue, &app_user_inputData.eventInfo, portMAX_DELAY );

Use FreeRTOS queue to notify the EEPROM task to print the logged temp values

You have used FreeRTOS to implement your application. You are now ready to build and run your RTOS based application!

Back to Top