Low Power Application on SAMC2x using MPLAB® Harmony v3 Peripheral Libraries: Step 6

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

Add application code to the project

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

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

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

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 below.

Code Example 1​​​

In the main.c function, below SYS_Initialize(), add the following code to register callback event handlers.

EIC_CallbackRegister(EIC_PIN_8,EIC_User_Handler, 0);

    SERCOM2_I2C_CallbackRegister(i2cEventHandler,0);

    DMAC_ChannelCallbackRegister(DMAC_CHANNEL_0,dmaChannel0Handler,0);

    ADC1_CallbackRegister(adcEventHandler,0);

Add below lines of code to enable the Analog-to-Digital Converter (ADC), start Timer, and to move the device from Standby to Sleep mode.

ADC1_Enable();

    RTC_Timer32Start();

    PM_StandbyModeEnter();

Code Example 2

Note:

a. The function call SERCOM2_I2C_CallbackRegister registers a callback event handler with the I²C Peripheral Library (PLIB). The event handler is called by the I²C PLIB, when the I²C reads the temperature value from the temperature sensor.

b. The function call DMAC_ChannelCallbackRegister registers a callback event handler with the Direct Memory Access (DMA) PLIB. The callback event handler is called by the DMA PLIB when the DMA transfer (of temperature sensor data to serial terminal) is complete.

c. The function call ADC1_CallbackRegister registers an ADC callback event handler with the ADC PLIB. The event 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 254, set when configuring the ADC PLIB in MCC.

d. The function call EIC_CallbackRegister registers an External Interrupt Controller (EIC) callback event handler with the EIC PLIB. The callback event handler is called by EIC PLIB when the user presses the switch SW0 to enter into Idle mode.

e. The function call ADC1_Enable 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.

f. The function call RTC_Timer32Start starts the Real-Time Clock (RTC) timer. The event output from RTC is fed as input to the Event System and is used to trigger the ADC conversion.

g. The function call PM_StandbyModeEnter 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 event handlers for ADC, I²C, Universal Synchronous Asynchronous Receiver Transmitter (USART), and EIC PLIBs by adding the following code before main() function in main.c.

static void dmaChannel0Handler(DMAC_TRANSFER_EVENT event, uintptr_t contextHandle){
   if(event == DMAC_TRANSFER_EVENT_COMPLETE)
    {
        isDMATransferComplete = true;
    }
}

static void i2cEventHandler(uintptr_t contextHandle){

   if(SERCOM2_I2C_ErrorGet() == SERCOM_I2C_ERROR_NONE)
    {
        isTemperatureRead = true;
    }
}

static void adcEventHandler(ADC_STATUS status, uintptr_t context)
{  
   if(status & ADC_STATUS_WINMON){
        adcResult = ADC1_ConversionResultGet();
        isADCWinMonitorEvent = true;
    }
}

static void EIC_User_Handler(uintptr_t context)
{
    sleepMode = true;
}

Code Example 3

Inside the while loop, add the code below to submit an I²C transfer to read temperature sensor value when the ADC triggers an interrupt (i.e when the user covers the light sensor). The I²C PLIB calls back the callback event handler (registered in Step 2 above) when the submitted request is complete.

if(isADCWinMonitorEvent == true){

            isADCWinMonitorEvent = false;
            SERCOM2_I2C_WriteRead(TEMP_SENSOR_SLAVE_ADDR,&i2cWrData,1,i2cRdData,2 );
        }

Code Example 4

Add the below code to prepare the received temperature value from the sensor to be printed on the serial terminal and code to transfer the buffer containing either the latest temperature value in the format Temperature = XX F\r\n below ADC window monitor event if loop.

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

Code Example 5

Add the code below to enter into Standby mode once DMA completes the transfer and add the code snippet to enter into Idle Sleep mode when the user presses switch SW0.

  if(isDMATransferComplete == true){

            isDMATransferComplete = false;

            LED_Set();

            PM_StandbyModeEnter();
        }

       if(sleepMode == true)
        {
           sleepMode = false;
           PM_IdleModeEnter();
        }

Code Example 6

Under the Source Files, src/config/samc21_lowpow_demo/peripheral/eic/plib_eic.c. Notice the plib_eic.c file, add #include definitions.h at the top and in EIC_InterruptHandler function add WAKEUP_TEST_Toogle() function. This General Purpose Input/Output (GPIO) is toggled in the Interrupt Service Routine (ISR) of the switch press event to measure wake-up time. The time between the switch press and the GPIO toggle in the ISR is the wake-up time.

WAKEUP_TEST_Toggle();

Code Example 7You are now ready to build the code!

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

Back to Top