Getting Started With MPLAB® Harmony v3 Peripheral Libraries on PIC32CM JH (Arm® Cortex®-M0+) MCUs: Step 5

Last modified by Microchip on 2025/09/29 12:52

Information

Note: This video shows an overview on how to add the application code logic.

Add Application Code to the Project

The application is already pre-developed and is available in the main.c file under <your unzip folder>\pic32cm_jh_vl_cnano_getting_started\dev_files. The main.c file contains the application logic and the placeholders that you will populate with the necessary code in the next step.

Extract pic32cm_jh_vl_cnano_getting_started.zip and go to the pic32cm_jh_vl_cnano_getting_started\dev_files\pic32cm_jh_vl_cnano\main.c folder and copy the pre-developed main.c file.

Replace the main.c file of your project available at <Your project folder>\pic32cm_jh_vl_cnano_getting_started\firmware\src by overwriting it with the copied file.

Open the pic32cm_jh_vl_cnano_getting_started 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 application, which is configured through MPLAB Code Configurator (MCC).

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 accompanying image.

Code snippet showing the SYS_Initialize function

Information

Note: EVSYS_Initialize is a system-specific initialization function necessary to run the device. 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.

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.

DMAC_ChannelCallbackRegister(DMAC_CHANNEL_0, usartDmaChannelHandler, 0);
    EIC_CallbackRegister(EIC_PIN_0, EIC_User_Handler, 0);
    RTC_Timer32CallbackRegister(rtcEventHandler, 0);

    sprintf((char*)uartTxBuffer, "Toggling LED at 500 milliseconds rate \r\n");

Following the addition of the code above, add the function call.

RTC_Timer32Start();

secure app code 2

Information

Note:

  • The DMAC_ChannelCallbackRegister function registers a callback handler (usartDmaChannelHandler) with the Direct Memory Access Controller (DMAC) for channel 0. This handler is invoked upon completion of the DMA transfer associated with the Universal Synchronous Asynchronous Receiver Transmitter (USART).
  • The EIC_CallbackRegister function registers a callback handler (EIC_User_Handler) with the External Interrupt Controller (EIC) for EIC_PIN_0. This handler is called when an interrupt is triggered on the specified external pin, typically by a user action such as pressing a button.
  • The RTC_Timer32CallbackRegister function registers a callback handler (rtcEventHandler) with the Real-Time Clock (RTC) PLIB. This handler is called when the configured 32-bit timer period elapses.
  • The sprintf function formats a string message into the uartTxBuffer, which will later be transmitted via USART.

To implement the registered callback event handlers for the  RTC, EIC, USART DMA PLIBs and declare LED sampling rate, add the following code before the main() function in main.c file:

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

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

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

app code 3

In the main.c file, macros should be defined, and all required declarations and initializations should be positioned after the header file inclusions to be utilized in this application code.

#define PERIOD_500MS                            512
#define PERIOD_1S                               1024
#define PERIOD_2S                               2048
#define PERIOD_4S                               4096

typedef enum
{
    LED_SAMPLING_RATE_500MS = 0,
    LED_SAMPLING_RATE_1S = 1,
    LED_SAMPLING_RATE_2S = 2,
    LED_SAMPLING_RATE_4S = 3,
} LED_SAMPLING_RATE;

static LED_SAMPLING_RATE ledSampleRate = LED_SAMPLING_RATE_500MS;
static const char timeouts[4][20] = {"500 milliSeconds", "1 Second",  "2 Seconds",  "4 Seconds"};

Following the addition of the previous code, add the flags that will be used in the application code:

static volatile bool isRTCExpired = false;
static volatile bool changeLedSamplingRate = false;
static volatile bool isUSARTTxComplete = true;
static uint8_t uartTxBuffer[100] = {0};

application code

Information

Note: Here the definition, declarations, and initializations are based on the LED toggling rate time period.​​​​​

Implement the LED toggling application function and Universal Asynchronous Receiver Transmitter (UART) message transfer by adding the following code after the main() function in main.c:

while ( true )
    {
       if ((isRTCExpired == true) && (true == isUSARTTxComplete))
        {
           isRTCExpired = false;
           isUSARTTxComplete = false;
           LED_Toggle();
           DMAC_ChannelTransfer(DMAC_CHANNEL_0, uartTxBuffer, \
                   (const void *)&(SERCOM1_REGS->USART_INT.SERCOM_DATA), \
                   strlen((const char*)uartTxBuffer));
        }
       /* Maintain state machines of all polled MPLAB Harmony modules. */
       if(changeLedSamplingRate == true)
        {
           changeLedSamplingRate = false;
           if(ledSampleRate == LED_SAMPLING_RATE_500MS)
            {
               ledSampleRate = LED_SAMPLING_RATE_1S;
               RTC_Timer32CompareSet(PERIOD_1S);
            }
           else if(ledSampleRate == LED_SAMPLING_RATE_1S)
            {
               ledSampleRate = LED_SAMPLING_RATE_2S;
               RTC_Timer32CompareSet(PERIOD_2S);
            }
           else if(ledSampleRate == LED_SAMPLING_RATE_2S)
            {
               ledSampleRate = LED_SAMPLING_RATE_4S;
               RTC_Timer32CompareSet(PERIOD_4S);
            }
           else if(ledSampleRate == LED_SAMPLING_RATE_4S)
            {
              ledSampleRate = LED_SAMPLING_RATE_500MS;
              RTC_Timer32CompareSet(PERIOD_500MS);
            }
           else
            {
               ;
            }
           RTC_Timer32CounterSet(0);
           sprintf((char*)uartLocalTxBuffer, "LED Toggling rate is changed to %s\r\n", &timeouts[(uint8_t)ledSampleRate][0]);
           DMAC_ChannelTransfer(DMAC_CHANNEL_0, uartLocalTxBuffer, \
                   (const void *)&(SERCOM1_REGS->USART_INT.SERCOM_DATA), \
                   strlen((const char*)uartLocalTxBuffer));
           sprintf((char*)uartTxBuffer, "Toggling LED at %s rate \r\n", &timeouts[(uint8_t)ledSampleRate][0]);
        }
    }

secure app code 6

The accompanying image shows the code snippet for changing LED toggling rate.

code snippet for changing LED toggling rate

Build the project by clicking the drop-down arrow next to the Clean and Build icon and verify that the project builds successfully. 

Click the clean and build button

Back to Top