MPLAB® Harmony v3 Peripheral Libraries on SAM D21: Step 5

Step 5: Add Application Code to the Project

The application is already partially developed and is available in the main_d21.c file under <your unzip folder>/samd21_getting_started/dev_files/sam_d21_xpro. The main_d21.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 samd21_getting_started/dev_files/sam_d21_xpro folder and copy the pre-developed main_d21.c file.
  • Replace the main_d21.c file of your project available at <Your project folder>/samd21_getting_started/firmware/src by over-writing it with the copied file.
  • Open main_d21.c in MPLAB® X IDE and add the application code by following the steps below:

1

Under the main_d21.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, which is configured through 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 in the accompanying image.

app_code1.png

Note: The NVMCTRL_Initialize, PM_Initialize, and EVSYS_Initialize are system-specific initialization functions. MCC 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.

2

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

SERCOM2_I2C_CallbackRegister(i2cEventHandler, 0);
DMAC_ChannelCallbackRegister(DMAC_CHANNEL_0, usartDmaChannelHandler, 0);
RTC_Timer32CallbackRegister(rtcEventHandler, 0);
EIC_CallbackRegister(EIC_PIN_15,EIC_User_Handler, 0);

Following the addition of the previous code, add the function call:

RTC_Timer32Start();
app_code2.png

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 transfer is complete.

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 RTC_Timer32CallbackRegister registers a Real-Time Clock (RTC) callback event handler with the RTC PLIB. The callback event handler is called by the RTC PLIB when the configured time period has elapsed.

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 SW0 switch.

3

Implement the registered callback event handlers for RTC, I²C, Universal Synchronous Asynchronous Receiver Transmitter (USART), and EIC PLIBs by adding the following code before the main() function in main_d21.c.

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

static void rtcEventHandler (RTC_TIMER32_INT_MASK intCause, uintptr_t context)
{
    if (intCause & RTC_MODE0_INTENSET_CMP0_Msk)
    {            
        isRTCTimerExpired = true;                              
    }
}

static void i2cEventHandler(uintptr_t contextHandle)
{
    if (SERCOM2_I2C_ErrorGet() == SERCOM_I2C_ERROR_NONE)
    {
        isTemperatureRead = true;
    }
}

static void usartDmaChannelHandler(DMAC_TRANSFER_EVENT event, uintptr_t contextHandle)
{
    if (event == DMAC_TRANSFER_EVENT_COMPLETE)
    {
        isUSARTTxComplete = true;
    }
}
app_code3.png

4

Add the following code to submit an I²C transfer to read temperature sensor value when the configured time period (default 500 milliseconds) has elapsed. The I²C PLIB calls back the callback event handler (registered in Step 2 above) when the submitted request is complete.

isRTCTimerExpired = false;
SERCOM2_I2C_WriteRead(TEMP_SENSOR_SLAVE_ADDR, &i2cWrData, 1, i2cRdData, 2);
app_code4.png

5

Add the following code to prepare the received temperature value from the sensor to be shown on the serial terminal.

temperatureVal = getTemperature(i2cRdData);
sprintf((char*)uartTxBuffer, "Temperature = %02d F\r\n", temperatureVal);
LED_Toggle();
app_code5.png

6

Add the following code to implement the change of sampling rate and prepare a message for the change on the serial terminal when the user presses the SW0 switch.

changeTempSamplingRate = false;
if(tempSampleRate == TEMP_SAMPLING_RATE_500MS)
{
    tempSampleRate = TEMP_SAMPLING_RATE_1S;
    sprintf((char*)uartTxBuffer, "Sampling Temperature every 1 second \r\n");
    RTC_Timer32CompareSet(PERIOD_1S);
}
else if(tempSampleRate == TEMP_SAMPLING_RATE_1S)
{
    tempSampleRate = TEMP_SAMPLING_RATE_2S;
    sprintf((char*)uartTxBuffer, "Sampling Temperature every 2 seconds \r\n");        
    RTC_Timer32CompareSet(PERIOD_2S);                        
}
else if(tempSampleRate == TEMP_SAMPLING_RATE_2S)
{
    tempSampleRate = TEMP_SAMPLING_RATE_4S;
    sprintf((char*)uartTxBuffer, "Sampling Temperature every 4 seconds \r\n");        
    RTC_Timer32CompareSet(PERIOD_4S);                                        
}    
else if(tempSampleRate == TEMP_SAMPLING_RATE_4S)
{
   tempSampleRate = TEMP_SAMPLING_RATE_500MS;
   sprintf((char*)uartTxBuffer, "Sampling Temperature every 500 ms \r\n");        
   RTC_Timer32CompareSet(PERIOD_500MS);
}
else
{
    ;
}
app_code6.png

7

Add code to transfer the buffer containing either:

  • the latest temperature value in the format “Temperature = XX F\r\n”, or
  • the message mentioning the change of sampling rate over USART using DMA.
DMAC_ChannelTransfer(DMAC_CHANNEL_0, uartTxBuffer, (const void *)&(SERCOM3_REGS->USART_INT.SERCOM_DATA), strlen((const char*)uartTxBuffer));
app_code7.png

You are now ready to build the code!


Next Step >

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.