Low Power Application on SAM E54 Using Harmony v3 Peripheral Libraries: Step 6

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

Add Application Code to the Project

The application is already partially developed and is available in the main_e54.c file under <your unzip folder>/same54_low_power/dev_files/sam_e54_xpro. The main_e54.c file contains the application logic. It also contains placeholders that you will populate with necessary code in the next step.

  • Go to the same54_low_power/dev_files/sam_e54_xpro folder and copy the pre-developed main_e54.c file.
  • Replace (over-write) the main_e54.c file of your project available at <Your project folder>/same54_low_power/firmware/src with the copied file.
  • Open main_e54.c in MPLAB® X IDE and add the application code by following the steps below.

Under the main_e54.c file, in the main() function, notice the call to the SYS_Initialize function. The generated SYS_Initialize function initializes all the peripheral modules used in the application, configured through MPLAB Harmony Configurator (MHC).

Information

Tip: Press the CTRL key and left click on the SYS_Initialize function. The click will open the implementation for the SYS_Initialize function as shown in the following image.

SYS_Initialize function

Information

The NVMCTRL_InitializeNVIC_Initialize, and EVSYS_Initialize are system-specific initialization functions necessary to run the device. MHC adds these modules by default to the project graph and generates code. These modules will be initialized to user configurations if the user configures them explicitly.

In the int main (void) function, below the SYS_Initialize() function call, add the following code to register callback event handlers, enable the Analog-to-Digital Converter (ADC), start the Real-Time Clock (RTC) timer, display the message, and enter Standby mode.

EIC_CallbackRegister (EIC_PIN_15, EIC_User_Handler, 0);

SERCOM3_I2C_CallbackRegister (i2cEventHandler, 0);

DMAC_ChannelCallbackRegister (DMAC_CHANNEL_0, dmaChannel0Handler, 0);

ADC1_CallbackRegister (adcEventHandler, 0);

ADC1_Enable ();

RTC_Timer32Start ();

printf ("\n\n\r---------------------------------------------------------");
printf ("\n\r           Low-power Application on SAM E54 Xpro           ");
printf ("\n\r---------------------------------------------------------\n\n\r");

printf ("Enter Standby sleep mode\n\n\r");
PM_StandbyModeEnter ();
 

int main (void) function

Information

Note:

  • The EIC_CallbackRegister function call registers an External Interrupt Controller (EIC) callback interrupt handler with the EIC Peripheral Library (PLIB). The interrupt handler is called by EIC PLIB when switch button SW0 is pressed to enter into Idle mode.
  • The SERCOM3_I2C_CallbackRegister function call registers a callback interrupt handler with the I²C PLIB. The interrupt handler is called by the I²C PLIB when the I²C reads the temperature value from the temperature sensor.
  • The DMAC_ChannelCallbackRegister function call registers a callback interrupt handler with the Direct Memory Access (DMA) PLIB. The callback interrupt handler is called by the DMA PLIB when the DMA transfer (of temperature sensor data to the serial terminal) is complete
  • The ADC1_CallbackRegister function call registers an ADC callback interrupt handler with the ADC PLIB. The interrupt handler is called by the ADC PLIB when the ADC Window Monitor event occurs. The ADC Window Monitor event occurs when the ADC result exceeds the lower threshold value of 3000, set when configuring the ADC PLIB in MHC.
  • The ADC1_Enable function call enables the ADC module. The ADC is used to sample the light sensor when a trigger is received from the Event System Channel 0, every 500 milliseconds.
  • The RTC_Timer32Start function call starts the RTC timer. The event output from RTC is fed as input to the Event System and is used to trigger the ADC conversion.
  • The PM_StandbyModeEnter function call moves the device to Standby mode. After a call to the PM_IdleModeEnter Application Programming Interface (API), the CPU will enter Idle Sleep mode. The ADC Window Monitor interrupt will bring the CPU out of the Sleep mode.

Implement the registered callback interrupt handlers for DMA, I²C, ADC, and EIC PLIBs by adding the following code before the int main (void) function in main_e54.c.

/* Handler for DMA channel transfer interrupt */
static void dmaChannel0Handler (DMAC_TRANSFER_EVENT event, uintptr_t contextHandle)
{
   if(event == DMAC_TRANSFER_EVENT_COMPLETE)
    {
        isDMATransferComplete = true;
    }
}

/* Handler for I²C interrupt */
static void i2cEventHandler (uintptr_t contextHandle)
{
   if(SERCOM3_I2C_ErrorGet() == SERCOM_I2C_ERROR_NONE)
    {
        isTemperatureRead = true;
    }

   else
    {
        printf ("There were an error during I2C Transmit. Please ensure that the I/O1 Xplained Pro is connected to the board.\n\n\r");
    }
}

/* Handler for ADC Window Monitor Interrupt */
static void adcEventHandler (ADC_STATUS status, uintptr_t context)
{
    isADCWinMonitorEvent = true;
}

/* Handler for button switch interrupt using EIC peripheral */
static void EIC_User_Handler (uintptr_t context)
{
    sleepMode = true;
}

Implement the registered callback interrupt handlers for DMA, I²C, ADC, and EIC PLIBs

Inside the while loop, add the following code to unset the isADCWinMonitorEvent flag, turn on the LED0, print the message, and submit an I²C transfer to read the temperature sensor value. When the submitted request is completed, the i2cEventHandler callback function declared in step 1b. is called. 

if (isADCWinMonitorEvent == true)
{            
    isADCWinMonitorEvent = false;
    LED0_Clear ();
    printf ("ADC_WINMON Interrupt Detected. Wake-up from sleep mode.\n\r");
    SERCOM3_I2C_WriteRead (TEMP_SENSOR_SLAVE_ADDR, &i2cWrData, 1, i2cRdData, 2);
}

isADCWinMonitorEvent flag

Inside the while loop, add the following code to unset the isTemperatureRead flag, store the temperature read into the temperatureVal variable, fill uartTxBuffer with the converted temperature value in degrees Fahrenheit and transmit this value to the terminal through the SERCOM2 USART peripheral by using the DMA.

if (isTemperatureRead == true)
{
    isTemperatureRead = false;
    temperatureVal = getTemperature (i2cRdData);
    sprintf ((char*)uartTxBuffer, "Temperature = %02d F \r\n", temperatureVal);
   while (!SERCOM2_USART_TransmitterIsReady());
    DMAC_ChannelTransfer (DMAC_CHANNEL_0, uartTxBuffer, (const void*)&(SERCOM2_REGS->USART_INT.SERCOM_DATA), sizeof(uartTxBuffer));
}

isTemperatureRead flag

Inside the while loop, add the following code to unset the isDMATransferComplete flag, print the message, turn off the LED0, and put the device in Standby mode by using the PM_StandbyModeEnter () function.

if (isDMATransferComplete == true)
{      
    isDMATransferComplete = false;
    printf("DMA transfer completed. Enter Standby sleep mode.\n\n\r");
    LED0_Set ();
    PM_StandbyModeEnter ();
}

isDMATransferComplete flag

Inside the while loop, add the following code to print the message, turn off the LED0, and put the device in Idle mode by using the PM_IdleModeEnter () function.

if (sleepMode == true)
{
    sleepMode = false;
    printf ("SW0 button pressed. Enter Idle sleep mode.\n\n\r");
    LED0_Set ();
    PM_IdleModeEnter ();
}

sleepMode flag

You are now ready to build the code and observe the results!

Information

DMA, I²C, and USART transfers can also be configured to run in Sleep mode using the Event System and Run in Standby options available in the peripheral.

Back to Top