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 instance
  • nCS : Chip Select pin
  • nWP : Write Protect pin
  • nHOLD : Hold pin
  • CTask : Console task for debug log output

Main Member Functions

  • WriteEnable() / WriteDisable() : Switch between writable and protected states
  • WriteByte(), ReadByte() : Single-byte transfer functions
  • sendCommand(), sendAddress() : Send command and 24-bit address sequences
  • WriteData(addr, buf, len) : Write data to a specific address
  • ReadData(addr, buf, len) : Read data from a specific address
  • EEPROM_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

  1. Write not working
    • Cause: Missing Write Enable (WREN) command
    • Solution: Verify WriteData() handles WREN before data transmission
  2. Read data mismatch
    • Cause: Address transmission error (24-bit addressing issue)
    • Solution: Check implementation of sendAddress() function
  3. No SPI response
    • Cause: CS pin not toggled correctly
    • Solution: Inspect csEnable() and csDisable() 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

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

en_USEnglish