Low Power Application on PIC32CM LE00 Using MPLAB® Harmony v3 Peripheral Libraries: Step 6

Last modified by Microchip on 2023/11/16 06:56

Add Application Code to the Project

The application is already developed and is available in the main_pic32cm_le00.c file under <your unzip folder>/pic32cm_le00_low_power/dev_files/pic32cm_le00_cpro. The main_pic32cm_le00.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 pic32cm_le00_low_power/dev_files/pic32cm_le00_cpro folder and copy the pre-developed main_pic32cm_le00.c file.
  • Replace (over-write) the main.c file of your project available at < Your project folder>/pic32cm-le00_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:

Implement temperature sensor slave address by adding the following code before the int main (void) function in main.c.

#define TEMP_SENSOR_SLAVE_ADDR                         0x004F
#define TEMP_SENSOR_REG_ADDR                           0x00

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

Tip: Press the CTRL key and left-click on the SYS_Initialize function. This will open the implementation for the SYS_Initialize function as shown.

sys initialize function


In the main() function, below SYS_Initialize(), add the following code to register callback event handlers, enable the ADC, start the RTC timer, display the message, and enter Standby mode.

EIC_CallbackRegister (EIC_PIN_4, EIC_User_Handler, 0);

SERCOM5_I2C_CallbackRegister (i2cEventHandler, 0);

DMAC_ChannelCallbackRegister (DMAC_CHANNEL_0, dmaChannel0Handler, 0);

ADC_CallbackRegister (adcEventHandler, 0);

ADC_Enable ();

RTC_Timer32Start ();

printf ("\n\n\r---------------------------------------------------------");
printf ("\n\r           Low-power Application on PIC32CM LE00 Cpro         ");
printf ("\n\r---------------------------------------------------------\n\n\r");

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

app code2

Note:

a) The function call EIC_CallbackRegister registers an EIC callback interrupt handler with the EIC PLIB. The interrupt handler is called by EIC PLIB when the switch button SW1 is pressed to enter into Idle mode.

b) The function call SERCOM5_I2C_CallbackRegister 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.

c) The function call DMAC_ChannelCallbackRegister 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.

d) The function call ADC_CallbackRegister 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 MCC.

e) The function call ADC_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 interrupt handlers for DMA, I²C, ADC, and EIC PLIBs by adding the following code before the int main (void) 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(SERCOM5_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");
    }
}

static void adcEventHandler (ADC_STATUS status, uintptr_t context)
{
    isADCWinMonitorEvent = true;
}

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

app code3


Inside the while loop, add the code below 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 2 is called.

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

app code4


Inside the while loop, add the code below 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 SERCOM3 USART peripheral by using the DMA.

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

app code5


Inside the while loop, add the code below 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. Entering in Standby sleep mode.\n\n\r");
    LED0_Set ();
    PM_StandbyModeEnter ();
}

app code6


Inside the while loop, add the code below to unset the sleepMode flag, toggle pin PC28, 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 ("SW1 button pressed. Entering Idle sleep mode.\n\n\r");
    LED0_Set ();
    PM_IdleModeEnter ();
}

app code7

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

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