Step 4: Add Application Code to the Project
This example application on the PIC32CM LS00 Curiosity Nano+ Touch Evaluation Kit demonstrates communication between Secure and Non-Secure regions in an Arm® TrustZone®-enabled project. The External Interrupt Controller (EIC) peripheral is configured as Non-Secure, while the LED peripheral is set as Secure. A Non-Secure interrupt triggers a Secure LED toggle operation via a Secure Gateway function, using the cmse_nonsecure_entry attribute. Secure Gateway function declarations are included in the nonsecure_entry.c and nonsecure_entry.h files.
Application Code for the Project
Open the main.c file in the Non-Secure project and add the EIC_CallbackRegister function call after SYS_Initialize(NULL) within the int main(void) function. This callback registration allows the application to automatically execute a specified function when an external interrupt occurs, such as a button press.
Code: (Non-Secure - main.c)

Add the user-defined EIC handler function above the int main(void) function and declare the secureAppEntry_Led function below the inclusion of the header files.
Code: (Non-Secure - main.c)
static void EIC_User_Handler(uintptr_t context)
{
secureAppEntry_Led();
}

To invoke a Secure function from the Non-Secure project, first declare the Secure function prototype in the Non-Secure source file using the extern keyword, which informs the compiler that the function is defined in the Secure project. Then, call this function within the Non-Secure interrupt handler, such as the EIC callback. This approach enables the Non-Secure application to access a Secure function located in the Non-Secure Callable (NSC) region via the Secure Gateway mechanism, ensuring secure and isolated cross-domain communication when an interrupt event occurs.
Open the nonsecure_entry.h file from lab14_trustzone_basic Non-Secure project. To do this, navigate to the Header Files section, then open the trustZone folder, and double-click on nonsecure_entry.h to access the Non-Secure Callable header file. Next, add the prototype for the Non-Secure Callable function secureAppEntry_Led, using the extern keyword. This allows the Non-Secure region to access the Secure region through this function.
Code: (nonsecure_entry.h)

Open the nonsecure_entry.c file from the Secure project, lab14_trustzone_basic_secure. To do this, navigate to the Source Files section, then open the trustZone folder, and double-click on the nonsecure_entry.c file.
Code: (nonsecure_entry.c)
void __attribute__((cmse_nonsecure_entry)) secureAppEntry_Led(void)
{
LED_Toggle_Func();
}

In the Secure project, the code described above is added to the nonsecure_entry.c file to enable the Non-Secure application to toggle an LED located in the Secure region. The declaration extern void LED_Toggle_Func(void); references the Secure LED toggle function, which is defined elsewhere in the Secure code. The function secureAppEntry_Led() is annotated with the cmse_nonsecure_entry attribute, placing it in the NSC region and allowing access through the Secure Gateway mechanism. When this function is called from the Non-Secure side, the processor safely transitions to the Secure state.
Now open the main.c file located under the Source Files section of the Secure project. Add the LED toggle function definition under the typedef for the Non-Secure callback function.
Code: (Secure main.c)
{
LED_Toggle();
}

The function LED_Toggle_Func() is implemented in the Secure main.c file and is responsible for controlling the LED configured in the Secure region. It internally calls LED_Toggle() to perform the actual General Purpose Input/Output (GPIO) toggle operation. When an EIC interrupt occurs in the Non-Secure region, the Non-Secure callback invokes the Secure Gateway function, which then calls LED_Toggle_Func(). This ensures that the LED is accessed only through a controlled Secure entry point, maintaining proper TrustZone isolation.
Access Violation Between Secure/Non-Secure Zones
To demonstrate a manual violation, intentionally bypass the Secure Gateway mechanism by omitting nonsecure_entry.h and nonsecure_entry.c, and attempt to call the Secure LED_Toggle_Func directly from the Non-Secure code in the EIC callback handler. This approach will cause a build failure in MPLAB® X IDE, clearly illustrating that direct access to Secure functions from the Non-Secure region is not permitted. This exercise highlights the importance of using the Secure Gateway interface for proper Non-Secure to Secure communication and maintaining TrustZone isolation.
In the above image, the Secure Gateway interface is not used; instead, the function in the Secure region is called directly from the Non-Secure region. This results in a BUILD FAILED message, as shown in the following image. This violation occurs due to the security enforcement of the TrustZone architecture, which prevents unauthorized direct access between Secure and Non-Secure regions.