3 Implementation

The application design with FreeRTOS using the MPLAB Harmony v3 Synchronous driver is shown in the following figure.

Figure 3-1. Application Threads
  • Sensor Thread: To read and display the temperature periodically.
  • EEPROM Thread: To write the temperature values to the EEPROM and display it on the Serial COM-port terminal when requested by the user.
  • User Input Thread: To read the character entered on the Serial COM-port terminal to retrieve the last five stored values in the EEPROM.

The Sensor Thread, EEPROM Thread, and User Input Thread run the corresponding application functions in an infinite loop. These threads are created from SYS_Tasks routine. Following the creation of these threads, the FreeRTOS scheduler is invoked. The scheduler performs the preemptive scheduling of these threads based on the waiting, ready, and running state of each of them. Once the scheduler is invoked, the threads will run based on the default scheduling method (preemptive).

The inter-thread communication between the three threads using the FreeRTOS queue is shown in the following figure.

Figure 3-2. Application Inter-Thread Communication

By default, the Sensor Thread is blocked and wakes up every time the temperature sampling period gets expired (1 second). Once active, the Sensor Thread reads the latest room temperature value from the temperature sensor and prints the value on the serial terminal. It also notifies the EEPROM Thread through the RTOS queue of the availability of the latest temperature value which needs to be stored in the EEPROM. Once notified, the Sensor Threads block again for temperature sampling period duration. The following code examples illustrate this with the usage of the FreeRTOS APIs and the MPLAB Harmony v3 driver APIs in Synchronous mode.

/* Allow other threads to run until it's time to read temperature */
vTaskDelay(APP_SENSOR_SAMPLING_RATE_IN_MSEC / portTICK_PERIOD_MS);
LED_Toggle();
/* Submit a blocking I2C write-read request (for temperature). */
if (true == DRV_I2C_WriteReadTransfer(app_sensorData.i2cHandle,
        APP_SENSOR_I2C_SLAVE_ADDR, (void*) &registerAddr, 1,
        (void *) app_sensorData.i2cRxBuffer, 2)) 
{
    /* ………… Application code ………… */
    /* Use FreeRTOS Queue to notify the temperature write event and temperature
     * value to EEPROM thread. */
    xQueueSend(eventQueue, (void*) &app_sensorData.eventInfo, portMAX_DELAY);

    /* ………… Application code ………… */
    /* Print the temperature value by submitting a blocking USART write request. */
    DRV_USART_WriteBuffer(app_sensorData.usartHandle,
            app_sensorData.usartTxBuffer, strlen);
}    

By default, the EEPROM Thread is in the waiting state for an event to occur. It wakes up when there is an event in the RTOS queue to either write the latest temperature value, or the read last 5 temperature values. Based on the event, the EEPROM Thread performs writing or reading, and goes back to the waiting state. The following code examples illustrate this with the usage of FreeRTOS APIs and the MPLAB Harmony v3 driver APIs in Synchronous mode.

/* Wait for the temperature write request OR EEPROM read request. */
xQueueReceive(eventQueue, &app_eepromData.eventInfo, portMAX_DELAY);

if (app_eepromData.eventInfo.eventType == EVENT_TYPE_TEMP_WRITE_REQ) 
{
    /* ………… Application code ………… */
    /* Write temperature to EEPROM */        
    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));
    }
    
    /* ………… Application code ………… */
}
if (app_eepromData.eventInfo.eventType == EVENT_TYPE_TEMP_READ_REQ)
{                        
    app_eepromData.i2cTxBuffer[0] = APP_EEPROM_LOG_MEMORY_ADDR;
    if (true == DRV_I2C_WriteReadTransfer(app_eepromData.i2cHandle, \
            APP_EEPROM_I2C_SLAVE_ADDR, app_eepromData.i2cTxBuffer, 1,\
            app_eepromData.i2cRxBuffer, 5)) 
    {
        /* Print the log values on the terminal */
        APP_EEPROM_PrintTemperature(app_eepromData.i2cRxBuffer,
                app_eepromData.wrIndex);
    }
}    

By default, the User Input Thread is blocked to receive a character on the USART receive line. Once a character is received, the User Input Thread becomes active and submits an EEPROM read request to the EEPROM Thread through the RTOS queue to read the last five temperature values stored in the EEPROM. After serving the user input request, the thread goes back to the blocking state to receive another character on the USART receive line. The following code examples illustrate this with the use of FreeRTOS APIs and the MPLAB Harmony v3 driver APIs in Synchronous mode.


    /* Submit a blocking USART read request (user input). */    
    if (DRV_USART_ReadBuffer(app_user_inputData.usartHandle, &usartData, 1 ) == true)
    {
        app_user_inputData.eventInfo.eventType = EVENT_TYPE_TEMP_READ_REQ;
        app_user_inputData.eventInfo.eventData = usartData;

        /* Use FreeRTOS queue to notify the EEPROM task to print the logged 
    temperature values */
        xQueueSend( eventQueue, &app_user_inputData.eventInfo, portMAX_DELAY );  
    }