SPI-Based M95M04 Serial Flash Read/Write
In the previous post, we discussed the basic SPI interface structure and how to design device-specific extension classes. In this post, we’ll extend that concept into a practical example — implementing the M95M04 Serial Flash device as a C++ class and demonstrating how to read and write data through SPI.
M95M04 Serial Flash Overview
The M95M04 is a 4-Mbit (512KB) SPI-based serial flash memory device provided by STMicroelectronics.
- Capacity: 4Mbit (512KB)
- SPI Interface: up to 20MHz
- Page size: 256 bytes per write
- Command Set: Read(0x03), Write(0x02), Write Enable(0x06), Read Status Register(0x05), etc.
- Data Retention: Over 20 year and Over 1,000,000 write/erase cycles
- Protection: WP(Write Protect), HOLD pin supported.
Thanks to these features, M95M04 is ideal for firmware storage, log data recording, or retaining system configuration data.
Class Design
The M95M04SPI class inherits from BaseSPI and implements the M95M04-specific protocol.
Main Member Variables
pSPI: Pointer to the SPI interface instancenCS: Chip Select pinnWP: Write Protect pinnHOLD: Hold pinCTask: Console task for debug log output
Main Member Functions
WriteEnable() / WriteDisable(): Switch between writable and protected statesWriteByte(), ReadByte(): Single-byte transfer functionssendCommand(), sendAddress(): Send command and 24-bit address sequencesWriteData(addr, buf, len): Write data to a specific addressReadData(addr, buf, len): Read data from a specific addressEEPROM_Test(addr, size): Test routine including write, read, and data verification
Code Examples
1. Object Declaration and Initialization
#include "M95M04SPI.h"
M95M04SPI eepSpi;
...
void InitSerialFlash(void);
...
/*
*
*/
void InitSerialFlash(void)
{
#if defined(_SPI_EEP_)
eepSpi = M95M04SPI(SPI6, EEP_nCS_1, &CTask);
eepSpi.setWPPin(EEP_nWP_1);
eepSpi.setHOLDPin(EEP_nHOLD_1);
#endif
}
2. Writing Data
this->pEEPSPI->WriteData(this->pEEPos->FlashingSize.getPosition(), tmpBuf, this->pEEPos->FlashingSize.getLength());
3. Reading Data
this->pEEPSPI->ReadData(this->pEEPos->bDebug.getPosition(), (uint8_t *)&(this->pSysinfo->General.bDebug), this->pEEPos->bDebug.getLength());
4. Using the Test Function
The EEPROM_Test() routine automatically writes and reads data at a specified address, verifying correctness and printing logs to the console.
void AT24CTask::EEPROMEraseAll(void)
{
int i, j;
uint8_t data[32];
for(i=0; i<32; i++)
data[i] = 0xFF;
for(i=0; i<16*1024; i++)
{
this->pEEPSPI->WriteData(32*i, (uint8_t *)&i, 1);
}
for(i=0; i<16*1024; i++)
{
this->pEEPSPI->ReadData(32*i, data, 32);
for(j=0; j<32; j++)
this->CTask->PRINTF((char *)"%02X ", data[j]);
this->CTask->PRINTF((char *)"\r\n");
this->CTask->flushTxBuf();
}
}
Troubleshooting
- Write not working
- Cause: Missing Write Enable (WREN) command
- Solution: Verify
WriteData()handles WREN before data transmission
- Read data mismatch
- Cause: Address transmission error (24-bit addressing issue)
- Solution: Check implementation of
sendAddress()function
- No SPI response
- Cause: CS pin not toggled correctly
- Solution: Inspect
csEnable()andcsDisable()functions
Conclusion
In this post, we implemented the M95M04SPI class derived from BaseSPI and demonstrated how to communicate with a real SPI-based Serial Flash device.
Key Takeaways:
- M95M04 is a 512KB SPI flash that requires command-based access.
- M95M04SPI class implements full read, write, and test routines.
- Using routines like
EEPROM_Test()makes it easy to verify data integrity in real-world projects.
0 Comments