Arm® TrustZone® Technology Getting Started Application on PIC32CM LS60: Step 5
Add application code to the secure project.
The application is already partially developed and is available in the main.c file under <your unzip folder>/pic32cm_ls60_cpro_tz_getting_started/dev_files/Secure. The main.c file contains the application logic. It also contains placeholders that you will populate with the necessary code in the next step.
Open the tz_pic32cm_ls60_cpro_secure project main.c in MPLAB® X IDE and add the application code by following the steps:
Under the main.c file, in function main, notice the call to the SYS_Initialize function.
The generated SYS_Initialize function initializes all the peripheral modules used in the Secure application, which is configured through MPLAB® Code Configurator (MCC).
In the main() function, below SYS_Initialize(), add the following code to register callback event handlers, flag and a sprintf to indicate toggling LED rate is displayed on the terminal.
RTC_Timer32CallbackRegister(rtcEventHandler, 0);
EIC_CallbackRegister(EIC_PIN_12, sw0_eventHandler, 0);
EIC_CallbackRegister(EIC_PIN_4, sw1_eventHandler, 0);
sprintf((char*)uartTxTempBuffer, "************* Printing Toggling LED rate *************\r\n");
readUartTxStatus = true;
Following the addition of the code above, add the function call:
Implement the registered callback event handlers for Secure RTC, Secure I²C, and Secure EIC PLIBs by adding the following code before the main() function in main.c.
{
changeSamplingRate = true;
}
static void sw1_eventHandler(uintptr_t context)
{
if(false == startTemperatureReading)
{
startTemperatureReading = true;
printTempSampleRate = true;
}
else
{
startTemperatureReading = false;
printLedToggleRate = true;
}
}
static void rtcEventHandler (RTC_TIMER32_INT_MASK intCause, uintptr_t context)
{
if (intCause & RTC_TIMER32_INT_MASK_CMP0)
{
isRTCTimerExpired = true;
}
}
static void i2cEventHandler(uintptr_t contextHandle)
{
if (SERCOM5_I2C_ErrorGet() == SERCOM_I2C_ERROR_NONE)
{
if(i2cAddress == TEMP_SENSOR_SLAVE_ADDR)
{
isTemperatureRead = true;
}
else if(isEEPROMReadReq == true)
{
isEEPROMReadReq = false;
eepromTemperatureDataReadStatus = true;
}
isI2CFree = true;
}
else if (SERCOM5_I2C_ErrorGet() == SERCOM_I2C_ERROR_NAK ||
SERCOM5_I2C_ErrorGet() == SERCOM_I2C_ERROR_BUS)
{
showErrorMsg = true;
}
}
Implement the temperature conversion function to convert the temperature value read from the sensor to a readable format (Degree Celsius) by adding the following code before the main() function in main.c.
{
int16_t temp;
temp = (rawTempValue[0] << 8) | rawTempValue[1];
temp = (temp >> 7) * 0.5;
temp = (temp * 9/5) + 32;
return (uint8_t)temp;
}
Implement the EEPROM write function to write the temperature value read from the sensor into EEPROM by adding the following code before the main() function in main.c.
{
eepromTxBuffer[0] = EEPROM_LOG_MEMORY_ADDR + wrIndex;
eepromTxBuffer[1] = temperature;
SERCOM5_I2C_Write(EEPROM_I2C_SLAVE_ADDR, (void *)eepromTxBuffer, 2);
if (++wrIndex >= EEPROM_MAX_LOG_VALUES)
{
wrIndex = 0;
}
}
Implement the secure application function by adding the following code before the main() function in main.c.
{
/* Basic Functionality: Demonstrates an LED toggle, i.e. LED0 toggles when
* the switch SW0 is pressed on a timeout basis and prints the LED toggling
* rate on the serial terminal.*/
if (startTemperatureReading == false)
{
if (printLedToggleRate == true)
{
memset((char*)uartTxTempBuffer, 0x00, 100);
sprintf((char*)uartTxTempBuffer, "************* Printing Toggling LED rate *************\r\n");
printLedToggleRate = false;
readUartTxStatus = true;
}
if (isRTCTimerExpired == true)
{
isRTCTimerExpired = false;
memset((char*)uartTxTempBuffer, 0x00, 100);
sprintf((char*)uartTxTempBuffer, "Toggling LED at %s rate \r\n", &timeouts[(uint8_t)tempSampleRate][0]);
LED0_Toggle();
readUartTxStatus = true;
}
if(changeSamplingRate == true)
{
changeSamplingRate = false;
if(tempSampleRate == SAMPLING_RATE_500MS)
{
tempSampleRate = SAMPLING_RATE_1S;
RTC_Timer32CompareSet(PERIOD_1S);
}
else if(tempSampleRate == SAMPLING_RATE_1S)
{
tempSampleRate = SAMPLING_RATE_2S;
RTC_Timer32CompareSet(PERIOD_2S);
}
else if(tempSampleRate == SAMPLING_RATE_2S)
{
tempSampleRate = SAMPLING_RATE_4S;
RTC_Timer32CompareSet(PERIOD_4S);
}
else if(tempSampleRate == SAMPLING_RATE_4S)
{
tempSampleRate = SAMPLING_RATE_500MS;
RTC_Timer32CompareSet(PERIOD_500MS);
}
else
{
;
}
RTC_Timer32CounterSet(0);
sprintf((char*)uartTxTempBuffer, "LED Toggling rate is changed to %s\r\n", &timeouts[(uint8_t)tempSampleRate][0]);
readUartTxStatus = true;
}
}
else
{
/* Extended Functionality: Reads and prints the current room temperature
* periodically when the extension header (EXT1) is plugged with the
* I/O1 Xplained Pro Extension Kit. The temperature reading is displayed on
* a serial console periodically every second.*/
if (printTempSampleRate == true)
{
memset((char*)uartTxTempBuffer, 0x00, 100);
sprintf((char*)uartTxTempBuffer, "************* Printing Temperature *************\r\n");
printTempSampleRate = false;
readUartTxStatus = true;
}
if ((isI2CFree == true) &&
(isRTCTimerExpired == true)) //Temperature Reading from Sensor
{
isRTCTimerExpired = false;
isI2CFree = false;
i2cAddress = TEMP_SENSOR_SLAVE_ADDR;
SERCOM5_I2C_WriteRead(TEMP_SENSOR_SLAVE_ADDR, &i2cWrData, 1, i2cRdData, 2);
}
if ((isI2CFree == true) &&
(isTemperatureRead == true))
{
isTemperatureRead = false;
if(changeSamplingRate == false)
{
temperatureVal = getTemperature(i2cRdData);
memset((char*)uartTxTempBuffer, 0x00, 100);
sprintf((char*)uartTxTempBuffer, "Temperature = %02d F\r\n", temperatureVal);
LED0_Toggle();
i2cAddress = EEPROM_I2C_SLAVE_ADDR;
isI2CFree = false;
eepromWrite(temperatureVal);
}
else
{
changeSamplingRate = false;
RTC_Timer32CounterSet(0);
if(tempSampleRate == SAMPLING_RATE_500MS)
{
tempSampleRate = SAMPLING_RATE_1S;
sprintf((char*)uartTxTempBuffer, "Sampling Temperature every 1 second \r\n");
RTC_Timer32CompareSet(PERIOD_1S);
}
else if(tempSampleRate == SAMPLING_RATE_1S)
{
tempSampleRate = SAMPLING_RATE_2S;
sprintf((char*)uartTxTempBuffer, "Sampling Temperature every 2 seconds \r\n");
RTC_Timer32CompareSet(PERIOD_2S);
}
else if(tempSampleRate == SAMPLING_RATE_2S)
{
tempSampleRate = SAMPLING_RATE_4S;
sprintf((char*)uartTxTempBuffer, "Sampling Temperature every 4 seconds \r\n");
RTC_Timer32CompareSet(PERIOD_4S);
}
else if(tempSampleRate == SAMPLING_RATE_4S)
{
tempSampleRate = SAMPLING_RATE_500MS;
sprintf((char*)uartTxTempBuffer, "Sampling Temperature every 500 ms \r\n");
RTC_Timer32CompareSet(PERIOD_500MS);
}
else
{
;
}
}
readUartTxStatus = true;
}
else if (showErrorMsg == true)
{
memset((char*)uartTxTempBuffer, 0x00, 100);
sprintf((char*)uartTxTempBuffer, "Error.! Connect IO1 Xplained Pro board and Restart the device.\r\n");
readUartTxStatus = true;
showErrorMsg = false;
}
if ((isI2CFree == true) &&
(isEEPROMRead == true)) //Temperature Reading from EEPROM
{
isI2CFree = false;
isEEPROMRead = false;
isEEPROMReadReq = true;
i2cAddress = EEPROM_I2C_SLAVE_ADDR;
eepromTxBuffer[0] = EEPROM_LOG_MEMORY_ADDR;
SERCOM5_I2C_WriteRead(EEPROM_I2C_SLAVE_ADDR, eepromTxBuffer, 1, eepromRxBuffer, 6);
}
}
}
Figure 7 shows the code snippet to submit an I²C transfer to read the temperature sensor value when the configured time period (default 500 milliseconds) has elapsed and I²C PLIB is free. The I²C PLIB calls back the callback event handler (registered in Step 2 ) when the submitted request is complete.
Figure 8 shows the code snippet to prepare the received temperature value from the sensor to be displayed on the serial terminal, to store the temperature value in the EEPROM memory. This complete action will happen only if the temperature sensor value is ready and I²C PLIB is free.
Figure 9 shows the code snippet to implement the change of periodicity of the LED Toggling rate and Temperature Sampling rate. Later, prepare a message for the change on the serial terminal when the user presses the SW0 switch.
Figure 9 also shows the code snippet for changing the LED toggling rate.
Figure 10 shows the code snippet to change the temperature sampling rate.
By default, the LED sampling rate (Basic Functionality) is displayed on the terminal. By pressing the switch SW1, the temperature sampling rate (Extended Functionality) is displayed. Switch SW1 press is used toggle from Basic Functionality to Extended Functionality and vice-versa.
Figure 11 shows the code snippet to submit an I²C transfer to read the last five temperature values stored in the EEPROM memory when a read request is received from the non-secure application and I²C PLIB is free.
Under Source Files > trustZone, in the nonsecure_entry.c file, implement the following variables and non-secure callables to access and request the secure application from the non-secure application.
bool __attribute__((cmse_nonsecure_entry)) readUartTxData(uint8_t *lcluartTxBuffer)
{
bool localSecureUartStatus = readUartTxStatus;
if(localSecureUartStatus == true)
{
memset((char*)lcluartTxBuffer, 0x00, 100);
memcpy(lcluartTxBuffer, uartTxTempBuffer, strlen((const char *)&uartTxTempBuffer[0]));
readUartTxStatus = false;
}
return (localSecureUartStatus);
}
void __attribute__((cmse_nonsecure_entry)) readEEPROMTemperatureDataReq(uint8_t *temperatureBuf)
{
isEEPROMRead = true;
eepromRxBuffer = temperatureBuf;
return ;
}
bool __attribute__((cmse_nonsecure_entry)) getEEPROMTemperatureDataReadStatus(uint8_t *LclWrIndex)
{
bool lclEEPROMTempDataReadStatus = eepromTemperatureDataReadStatus;
eepromTemperatureDataReadStatus = false;
*LclWrIndex = wrIndex;
return (lclEEPROMTempDataReadStatus);
}
void __attribute__((cmse_nonsecure_entry)) secureAppEntry(void)
{
secureApp();
}
Following the addition of the code above, add the header:
#include <stddef.h> // Defines NULL