This example project demonstrates basic SPI communication with the external EEPROM on the Curiosity Nano Explorer Board using the SERCOM peripheral on a PIC32CM JH00 device. The application enables write access, stores a single byte of data into the EEPROM, polls the device until the write completes, and then reads the value back. The result is then transmitted over UART, which is also implemented using a SERCOM peripheral, to a terminal window to provide confirmation of successful write and read operations.
While this project uses a PIC32CM JH00 device, the same initialization and communication principles apply to other PIC32CM M0+ devices that support SERCOM-based SPI and UART.
- MPLAB® X IDE 6.25.0 or newer
- MPLAB® XC32 4.60 or newer
- MPLAB® Code Configurator (MCC) v5.6.2
- MPLAB® Harmony v3 v5.8.2
This example project was developed in MPLAB X IDE and can also be opened in VSCode® using the MPLAB Extension Pack. Follow the provided instructions here to import and run the project in VSCode®.
For a step-by-step walkthrough on importing the project, watch the following video: Importing an MPLAB® X Project into Microsoft® VS Code®
- Getting Started: Serial Communication
- Arm® Cortex®-Based Microcontrollers (MCUs)
- 25CSM04 4Mb SPI Serial EEPROM
The SPI communication uses a high-speed four-wire bus that connects a host device to one or more clients. The bus consists of an SDO (Serial Data Out) for sending data from the host, an SDI (Serial Data In) for receiving data from the client, an SCK (Serial Clock) to synchronize transfers, and an SS (Serial Select) to enable a specific device on the bus.
Unlike I²C, which uses addresses on a shared two-wire bus, SPI relies on the Serial Select line to determine which device the host is communicating with. Only the device whose Serial Select line is driven low will respond, while all other devices on the bus remain inactive.
This makes SPI a straightforward and fast way to exchange data with external peripherals, such as the EEPROM on the Curiosity Nano Explorer Board, using only these four pins.
In this example, the concept is applied using SERCOM0 configured for SPI on a PIC32CM JH00 device. The SPI lines: SDO, SDI, SCK, and SS (Serial Select) connect to the 25CSM04 4 Mb SPI Serial EEPROM on the Curiosity Nano Explorer Board. A second SERCOM (e.g., SERCOM1) runs UART to print results to a terminal.
The PIC32CM JH00 acts as the SPI host: it writes a byte to the 25CSM04 at a chosen address, waits for the write to finish, reads the byte back, and reports the value over UART.
- Initialize: Sets up SPI to talking to the EEPROM and configures UART so the MCU can send messages to a terminal window.
- Program & Verify: Enables writes on the EEPROM, stores a byte of data at a chosen address, waits until the device finishes writing, then reads the same address back to confirm the value was saved correctly..
- Report: Sends a success message and the value read from the EEPROM to the terminal over UART.
Once programmed, the MCU communicates with the 25CSM04 EEPROM over the SPI bus to carry out the write-and-verify cycle. The terminal output confirms the operation by showing the value 0x52 read back from memory, and the SPI signals can also be observed with a logic analyzer on SDO, SDI, SCK, and SS (Serial Select).
- Connect the Debug USB port of the PIC32CM JH00 Curiosity Nano to a PC using a Micro-USB to USB 2.0 cable.
- If not already installed, download and install MPLAB X IDE version 6.25 or newer.
- If not already installed, download and install the XC32 C-Compiler version 4.60 or newer.
- Clone or download this project from GitHub to the local machine.
- If downloaded as a
.zipfile, extract the files to a location preferably as close as possible to the root directory. - In MPLAB X IDE, go to File → Open Project. Navigate to the extracted location and select the following project file:

- Click the Make and Program Device button in the MPLAB X IDE toolbar to program the device. Then, verify that the device is successfully programmed.

After programming the device, the output can be viewed in the MPLAB Data Visualizer terminal window. The message shown below indicates that the byte 0x52 was written into the EEPROM and then read back correctly. This verifies that the entire write–verify cycle worked as intended using the MCC-generated drivers and helper functions.
This example project is already provided as a preconfigured MPLAB X project. Start by opening the project in MPLAB X IDE. Once the project is loaded, launch the MPLAB® Code Configurator (MCC) in Harmony to review the configuration.
For detailed instructions on how to create and set up a new MPLAB X project and open MCC Harmony, refer to the this Microchip online reference here
When opened in MCC Harmony, the Project Graph provides a visual overview of the project, showing the active components and their interactions.
With the Project Graph open, review the configuration step by step. Use the following checklist to confirm each setting before proceeding:
Open the Clock Configurator from the Plugins section in the Project Graph to verify the system clock is set to 48 MHz.
To check the system clock, go to Project Graph → Plugins → Clock Configurator
Note: Most Harmony v3 projects default to the 48 MHz internal oscillator.
The PIC32CM JH00 Curiosity Nano includes multiple SERCOM peripherals that can be configured for UART, SPI, or I²C communication. For this lab, SERCOM0 is used as SPI interface, since it connects directly to the Explorer Board’s SPI bus and the on board 25CSM04 SPI EEPROM.
This mapping is shown in the PIC32CM JH00 Curiosity Nano Hardware User Guide; similar guides are available for all Curiosity Nano products.

To add and configure SERCOM0:
-
Once added, select SERCOM0 in the Project Graph. In the Configuration Options panel, apply the following settings:
- Operation Mode: SPI Host. Configures the selected SERCOM instance as SPI controller, which drives the clock and manages communication with the external EEPROM.
- SPI Data In Pad: PAD[2]. Assigns the input pad used for the SDI (Serial Data In) line so the MCU can receive data from the EEPROM.
- All other settings can remain default for this project.

After configuring SERCOM0 for SPI, the signal pins (SDO, SDI, SCK, and SS) must be mapped to the correct I/O lines that connect to the Explorer Board’s EEPROM. This ensures the microcontroller can communicate properly with the on board 25CSM04 SPI EEPROM.
According to the Curiosity Nano hardware user guide mentioned previously and Explorer Board documentation:
- PA04 → SERCOM0 PAD0 MOSI (SDO): Serial Data Out, used by the MCU to send commands and data to the EEPROM.
- PA05 → SERCOM0 PAD1 SCK: Serial Clock, generated by the MCU to synchronize data transfers.
- PA06 → SERCOM0 PAD3 MISO (SDI): Serial Data In, used by the MCU to receive data back from the EEPROM.
- PA07 → SERCOM0 PAD2 CS1 (SS): Lets the MCU choose which SPI device to talk to by pulling its line low.
To assign the pins:
- In the Pin Settings tab, locate PA04 (Pin #13), PA05 (Pin #14), PA06 (Pin #15), and PA07 (Pin #16) in the Pin table.
- Set the following:
- PA04 → SERCOM0_PAD0 (SDO) – Serial Data Out from the MCU to the EEPROM
- PA05 → SERCOM0_PAD1 (SCK) – Serial Clock generated by the MCU
- PA06 → SERCOM0_PAD2 (SDI) – Serial Data In from the EEPROM to the MCU
- PA07 → GPIO (rename to EEPROM_CS, set as Output) – Serial Select line controlled by the MCU.
- Renaming makes the signal easier to identify in code. Configuring it as an output lets the MCU actively drive the line low to enable the EEPROM during communication, and high to deselect it when Idle.

- Set the following:
The PIC32CM JH00 Curiosity Nano includes multiple SERCOM peripherals. For this lab, SERCOM1 is used as a UART interface to print EEPROM results to a terminal.
This mapping is shown in the PIC32CM JH00 Curiosity Nano Hardware User Guide; similar guides are available for all Curiosity Nano products.

To add and configure SERCOM1:
-
Once added, select SERCOM1 in the Project Graph. In the Configuration Options panel, apply the following settings:
- Operation Mode: USART with internal Clock. Enables UART mode for the selected SERCOM instance using the internal clock.
- Transmit/Receive Enable: Enable both. Transmit is required to send data to the terminal; receive is optional but recommended for flexibility.
- Baud Rate: Set to match your terminal (e.g., 9600 or 115200).
- All other settings can remain default.

After configuring SERCOM1, the TX (transmit) and RX (receive) pins must be assigned to the correct I/O lines connected to the debugger’s CDC interface. This allows UART messages to be sent and received through the Curiosity Nano’s USB connection.
According to the Curiosity Nano user guide, PA17 is used for RX and PA16 is used for TX.
To assign the pins:
- In the Pin Settings tab. Locate PA16 (Pin #35) and PA17 (Pin #36) in the Pin table.
With SPI, UART, and pin mappings configured, the final step is to generate code. MCC creates the initialization files, peripheral drivers, and APIs, preparing the project for EEPROM communication and UART output.

This project combines MCC-generated functions with custom helpers to manage the 25CSM04 SPI EEPROM on the Curiosity Nano Explorer Board.
- MCC provides:
SYS_Initialize,SERCOM0_SPI_Write,SERCOM0_SPI_Read,SERCOM0_SPI_IsBusy,SERCOM1_USART_Write, andSERCOM1_USART_WriteIsBusy. - Custom code manages the EEPROM chip select (GPIO) and wraps the SPI operations into clear functions like write-enable, write, poll, and read.
#define success_msg "EEPROM Write and Read Complete\r\n"
uint8_t Write_EN = 0x06; // Write Enable
uint8_t Write_DIS = 0x04; // Write Disable (not used here)
uint8_t READ_OP = 0x03; // Read
uint8_t WRITE_OP = 0x02; // Write
uint8_t WRBP_OP = 0x08; // Status opcode for polling
uint8_t DATA_R = 0x00; // Holds received status/dataThese opcodes come directly from the EEPROM data sheet and tell the device which action to perform.
-
UART_SendString: Prints a string to the terminal using SERCOM1. It waits withSERCOM1_USART_WriteIsBusybefore sending each byte withSERCOM1_USART_Write. This ensures messages appear clean without being cut off. -
EEPROM_Write_Enable: Toggles chip select and sends the Write Enable opcode (0x06). This is mandatory before any write; without it, the EEPROM ignores program commands. -
EEPROM_WRITE: Wraps a complete program sequence: chip select low →WRITE_OP(0x02) → three address bytes → the data byte → chip select high. This stores one byte into the EEPROM memory. -
EEPROM_CHECK_STATUS: Sends a status command (WRBP_OP) and reads one byte intoDATA_R. Returns True only when the device signals it has finished writing. This polling prevents moving ahead before the data is actually stored. -
EEPROM_READ: Sends a read command (READ_OP) plus the target address, then captures one byte intoDATA_R. This retrieves the value just written so it can be verified.
Each helper makes use of MCC SPI generated functions (SERCOM0_SPI_Write, SERCOM0_SPI_Read, SERCOM0_SPI_IsBusy) while keeping chip select control explicit.
The main() routine ties everything together: it writes a known byte to EEPROM, waits for the device to complete the operation, reads it back, and prints the result over UART.
int main(void) {
SYS_Initialize(NULL); // initialize clocks, pins, SERCOM0 (SPI), SERCOM1 (UART)
EEPROM_Write_Enable(); // allow EEPROM programming
EEPROM_WRITE(0xAAAAAA, 0x52); // write 0x52 to address 0x00AAAAAA
while (!EEPROM_CHECK_STATUS()); // block until write is finished
EEPROM_READ(0xAAAAAA); // DATA_R now contains the stored byte
SERCOM1_USART_Write(success_msg, sizeof(success_msg)); // confirmation message
char msg[64];
snprintf(msg, sizeof(msg), "EEPROM Data: 0x%02X\r\n", DATA_R);
UART_SendString(msg); // e.g., "EEPROM Data: 0x52"
while (true) { } // idle loop
return (EXIT_FAILURE);
}- SPI (SERCOM0) issues the low-level commands that control the 25CSM04 EEPROM.
- Custom helpers simplify these commands into readable operations like “enable write,” “write byte,” “check status,” and “read byte.”
- UART (SERCOM1) reports the result to the terminal, proving that the EEPROM write and read sequence worked.
By combining MCC-generated drivers with focused custom functions, the application demonstrates the complete write–verify–report cycle on the Explorer Board EEPROM.
This demo highlights how SPI communication enables reliable interaction with an external EEPROM. By using MCC-generated drivers and helper functions, it demonstrates a complete write–verify cycle over SPI, confirming proper data storage and retrieval.
- Getting Started with Blink LED on PIC32CM M0+ Devices
- Getting Started with Analog-to-Digital Converters (ADC) on PIC32CM M0+ Devices
- Getting Started with SERCOM (UART) Communication on PIC32CM M0+ Devices
- Getting Started with SERCOM (I²C) Communication on PIC32CM M0+ Devices
- Getting Started with QTouch® Button and Peripheral Touch Controller on PIC32CM M0+ Devices










