Harmony v3 Drivers and System Services on SAM E70/S70/V70/V71: Step 5

Last modified by Microchip on 2023/11/09 09:08

Add Application Code to the Project

The application is already developed and is available in the files main_e70.capp_sensor.capp_eeprom.c, and usart_common.c under
<your unzip folder>/getting_started_drv/dev_files/sam_e70_xult.
The application files app_sensor.c and app_eeprom.c contain the application logic. They also contain placeholders that you will populate with the necessary code in the next step.

  • Go to the getting_started_drv/dev_files/sam_e70_xult folder and copy the pre-developed files main_e70.capp_sensor.capp_eeprom.cusart_common.capp_sensor.happ_eeprom.h, and usart_common.h file.
  • Paste and replace (over-write) the files of your project available at <Your project folder>/getting_started_drv/firmware/src with the copied files.
  • Add the application file usart_common.c to your project.

usart  commonusart commonusart common

For an Harmony v3 application, MPLAB® Harmony Configurator (MHC) generates the application template files (app_sensor.capp_sensor.happ_eeprom.capp_eeprom.h, and main_e70.c). The main_e70.c file calls the SYS_Tasks() routine which runs the sensor and the EEPROM application tasks (and driver/middleware tasks if added to the project).

main task


The app_sensor.h and app_eeprom.h files define the states of the application.Try to relate the states with the state diagram shown at the beginning of this lab.

app states


The app_sensor.h and app_eeprom.h files also define the application data structure APP_SENSOR_DATA and APP_EEPROM_DATA.

app data structures


The APP_SENSOR_Tasks() function in the app_sensor.c file and the APP_EEPROM_Tasks() in app_eeprom.c file implement the application state machine.

The sensor application task in app_sensor.c and the EEPROM application task in app_eeprom.c acts as the two clients to the I²C driver instance 0.

Open app_sensor.c and add application code by following the below steps.

Open the I²C driver instance 0 (which is associated with TWIHS0). The call to DRV_I2C_Open() Application Programming Interface (API) will associate the sensor client with the I²C driver instance 0. The returned handle will be used by the application in all the subsequent calls (related to the sensor client) to the driver.

app_sensorData.i2cHandle = DRV_I2C_Open( DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE );

i2c open sensor

Set the transfer parameters for the sensor client after a valid handle to the driver is obtained. The transfer parameter sets the I²C clock speed to 100 kHz for this client.

DRV_I2C_TransferSetup(app_sensorData.i2cHandle, &app_sensorData.i2cSetup);

i2c set transfer sensor

Register an event handler (callback) with the I²C driver for the sensor client. The event handler is called by the I²C driver when any request submitted by the sensor application client is completed.

DRV_I2C_TransferEventHandlerSet(app_sensorData.i2cHandle,
               APP_SENSOR_I2CEventHandler, 0);

i2c event handler

Register a periodic callback with the Timer System Service for every 1000 milliseconds.

SYS_TIME_CallbackRegisterMS(APP_SENSOR_TimerEventHandler, 0,
         (1000*APP_SENSOR_SAMPLING_RATE_IN_HZ), SYS_TIME_PERIODIC);

timer ss callback

Open the Universal Synchronous Asynchronous Receiver Transmitter (USART) driver instance 0 (which is associated with USART1). 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 application (by sensor task and EEPROM task) in all the subsequent calls to the driver.

usartHandle = DRV_USART_Open(DRV_USART_INDEX_0, DRV_IO_INTENT_READWRITE);

usart open sensor

Register an event handler (callback) with the USART driver. The event handler is called by the USART driver when any request submitted by the sensor or EEPROM application tasks is completed.

DRV_USART_BufferEventHandlerSet(usartHandle, APP_USARTBufferEventHandler, 0);

usart set transfer sensor

Set a flag in the periodic timer event handler. The sensor task will read the temperature when the flag is set and also toggle an LED.

app_sensorData.isTimerExpired = true;

LED_Toggle();

timer flag sensor

When the periodic timer expires, submit an I²C transfer to read the temperature sensor value using the I²C driver write-then-read API. The I²C driver calls back the sensor event handler (registered in step 6.3 above) when the submitted request is complete.

DRV_I2C_WriteReadTransferAdd( app_sensorData.i2cHandle,
         APP_SENSOR_I2C_SLAVE_ADDR,
         (void*)app_sensorData.i2cTxBuffer, 1,  
         (void *) app_sensorData.i2cRxBuffer, 2,
        &app_sensorData.transferHandle );

i2c sensor write read

In the I²C event handler for sensor client, set a flag to indicate that the I²C read (temperature sensor value) is completed.

app_sensorData.isTemperatureReadComplete = true;

i2c sensor read complete

Print the latest temperature value and notify the EEPROM application task to log the temperature value to EEPROM.

APP_SENSOR_PrintTemperature(app_sensorData.usartTxBuffer,
                      (int8_t *)"Temperature = %d F\r\n",
                      app_sensorData.temperature);   

APP_EEPROM_SetTempWriteRequest(app_sensorData.temperature);

snesor print notify

The implementation of APP_SENSOR_PrintTemperature makes a call to USART driver function DRV_USART_WriteBufferAdd.

app sensor printf

  • The DRV_USART_WriteBufferAdd function performs transfers for the formatted message with temperature value from data memory to the serial terminal using Direct Memory Access (DMA).
  • If the USART driver was not configured (in MHC) to use DMA for TX operation, the same function (DRV_USART_WriteBufferAdd) would be used to transfer the formatted message with temperature value from data memory to the serial terminal.
  • The above points imply if a Harmony v3 driver is configured to use DMA or not for data transfer operation, the application code remains unchanged. The Harmony data transfer APIs seamlessly handle the data transfer operation through the same API.

Open app_eeprom.c and add the application code by following the below steps.

Associate the second client (the EEPROM client), with the I²C driver instance 0. This is done by opening the I²C driver instance 0 again. The call to DRV_I2C_Open () API will now associate the EEPROM client with the I²C driver instance 0. The returned handle will be used by the application in all the subsequent calls (related to the EEPROM client) to the driver.

app_eepromData.i2cHandle = DRV_I2C_Open( DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE );

i2c open eeprom

Like the sensor client, setup the transfer parameters for the EEPROM client after a valid handle to the driver is obtained. The transfer parameters sets the I²C clock speed to 400 kHz for this client.

DRV_I2C_TransferSetup(app_eepromData.i2cHandle, &app_eepromData.i2cSetup);

i2c set transfer eeprom

  • The call to DRV_I2C_TransferSetup overrides the baud rate set in the I²C driver configuration using MHC.
  • I²C was configured to run at 400 kHz using MHC. While in the application, the sensor task has reconfigured it to run at 100 kHz and the EEPROM task configured it to run at 400 kHz. This illustrates how the Harmony I²C driver handles the peripheral module-specific configuration depending on the client accessing the peripheral.

Like the sensor client, register an event handler (callback) with the I²C driver for the EEPROM client. The event handler would be called by the I²C driver when any request submitted by the EEPROM application client is completed.

DRV_I2C_TransferEventHandlerSet(app_eepromData.i2cHandle, APP_EEPROM_I2CEventHandler, 0);

i2c eeprom transfer set

Submit a USART read request to receive a character on the serial terminal. When the user enters a character, a USART interrupt occurs. In the USART event handler the application sets the usartReadRequest flag to true.

DRV_USART_ReadBufferAdd(usartHandle, (void*)app_eepromData.usartRxBuffer, 1, &usartReadBufferHandle);

usart read buffer add

The DRV_USART_ReadBufferAdd API submits a read request to read a character from the serial terminal. The USART driver responds to a character read by interrupting the CPU and calling back the registered event handler (APP_USARTBufferEventHandler).

When the user enters a character on the serial terminal, submit an I²C transfer to read back the written temperature sensor values from the EEPROM, using the write-then-read API. The I²C driver calls back the EEPROM event handler (APP_EEPROM_I2CEventHandler) when the submitted request is complete.

DRV_I2C_WriteReadTransferAdd(app_eepromData.i2cHandle,
              APP_EEPROM_I2C_SLAVE_ADDR, app_eepromData.i2cTxBuffer,
             1, app_eepromData.i2cRxBuffer, 5, &app_eepromData.transferHandle);

i2c eeprom read

In the I²C event handler of the EEPROM client, update the status to indicate that the I²C read/write (corresponding to EEPROM read/write) is completed.

app_eepromData.reqStatus = APP_EEPROM_REQ_STATUS_DONE;

eeprom read complete

Print the temperature values read from the EEPROM and submit a USART read request to receive subsequent character on the serial terminal.

APP_EEPROM_PrintTemperature(app_eepromData.i2cRxBuffer, app_eepromData.wrIndex);  

DRV_USART_ReadBufferAdd(usartHandle, (void*)app_eepromData.usartRxBuffer, 1, &usartReadBufferHandle);

print eeprom values

Similar to the implementation APP_SENSOR_PrintTemperature, the implementation of APP_EEPROM_PrintTemperature makes a call to USART driver function DRV_USART_WriteBufferAdd.

The DRV_USART_WriteBufferAdd function performs transfer for the formatted message with the last five temperature values from data memory (read from EEPROM) to the serial terminal using DMA.

You are now ready to build the code!