mcp25lc256_spi_eeprom.c - Demonstrate SPI usageΒΆ

SPI Example: Demonstrates SPI functions by reading/writing from that Microchip 25LC256 serial EEPROM that is on the Explorer-16 board. This is not tied to a particular textbook example, but has a similar structure to the Chapter 10 mcp24lc515_i2c_eeprom.c example that uses I2C.

 
#include "pic24_all.h"



#define CONFIG_SLAVE_ENABLE() CONFIG_RD12_AS_DIG_OUTPUT()
#define SLAVE_ENABLE()        _LATD12 = 0  //low true assertion
#define SLAVE_DISABLE()       _LATD12 = 1

#define EEPROM_RDSR  0x05   //read status register command
#define EEPROM_READ  0x03   //read command
#define EEPROM_WRITE 0x02   //write command
#define EEPROM_WENABLE 0x06   //write command

#define BLKSIZE 64

void configSPI2(void) {
  //spi clock = 40MHz/1*4*4 = 40MHz/16 = 2.5 MHz
  SPI2CON1 = SEC_PRESCAL_4_1 |     //4:1 secondary prescale
             PRI_PRESCAL_4_1 |     //4:1 primary prescale
             CLK_POL_ACTIVE_HIGH | //clock active high (CKP = 0)
             SPI_CKE_ON          | //out changes active to inactive (CKE=1)
             SPI_MODE8_ON        | //8-bit mode
             MASTER_ENABLE_ON;     //master mode
  SPI2STATbits.SPIEN = 1;  //enable SPI mode
  CONFIG_SLAVE_ENABLE();       //chip select for MCP41xxx
  SLAVE_DISABLE();             //disable the chip select
}

//Assumes WDT is configured for longer than EEPROM write time
void waitForWriteCompletion() {
  uint8_t u8_spidata,u8_savedSWDTEN;
  u8_savedSWDTEN = _SWDTEN;
  _SWDTEN = 1; //enable WDT so that do not get stuck in infinite loop!
  do {
    SLAVE_ENABLE();
    u8_spidata = ioMasterSPI2(EEPROM_RDSR); //send read status command
    u8_spidata = ioMasterSPI2(0);   //get status back
    SLAVE_DISABLE();
  } while (u8_spidata & 0x01);  //LSB of status is write-in-progress flag
  _SWDTEN = u8_savedSWDTEN;  //restore WDT to original state
}

//Write enable must be done before attempting a write.
void writeEnable() {
  SLAVE_ENABLE();
  ioMasterSPI2(EEPROM_WENABLE);
  SLAVE_DISABLE();
}

void memWrite25LC256(uint16_t u16_MemAddr, uint8_t *pu8_buf) {
  uint8_t u8_AddrLo, u8_AddrHi;
  uint8_t u8_i;

  u8_AddrLo = u16_MemAddr & 0x00FF;
  u8_AddrHi = (u16_MemAddr >> 8);

  waitForWriteCompletion();
  writeEnable(); //enable the write
  SLAVE_ENABLE();
  ioMasterSPI2(EEPROM_WRITE);
  ioMasterSPI2(u8_AddrHi);
  ioMasterSPI2(u8_AddrLo);
  for (u8_i=0; u8_i< BLKSIZE; u8_i++) {
    ioMasterSPI2(pu8_buf[u8_i]);
  }
  SLAVE_DISABLE();
}

void memRead25LC256(uint16_t u16_MemAddr, uint8_t *pu8_buf) {
  uint8_t u8_AddrLo, u8_AddrHi;
  uint8_t u8_i;

  waitForWriteCompletion();
  u8_AddrLo = u16_MemAddr & 0x00FF;
  u8_AddrHi = (u16_MemAddr >> 8);
  SLAVE_ENABLE();
  ioMasterSPI2(EEPROM_READ);
  ioMasterSPI2(u8_AddrHi);
  ioMasterSPI2(u8_AddrLo);
  for (u8_i=0; u8_i<BLKSIZE ; u8_i++) {
    pu8_buf[u8_i] = ioMasterSPI2(0) ;  //get one byte
  }
  SLAVE_DISABLE();
}


int main (void) {
  uint8_t au8_buf[BLKSIZE];  //holds data for EEPROM I/O
  uint16_t u16_MemAddr;
  uint8_t u8_Mode;

  configBasic(HELLO_MSG);
  configSPI2();             //configure SPI2 Module
  outString("\nEnter 'w' for write mode, anything else reads: ");
  u8_Mode = inCharEcho();
  outString("\n");
  u16_MemAddr = 0;     //start at location 0 in memory
  while (1) {
    uint8_t u8_i;
    if (u8_Mode == 'w') {
      outString("Enter 64 chars.\n");
      //first two buffer locations reserved for starting address
      for (u8_i = 0; u8_i< BLKSIZE; u8_i++) {
        au8_buf[u8_i] = inCharEcho();
      }
      outString("\nDoing Write\n");

write same string twice to check Write Busy polling

      memWrite25LC256(u16_MemAddr, au8_buf); // do write
      u16_MemAddr = u16_MemAddr + BLKSIZE;
      memWrite25LC256(u16_MemAddr,au8_buf); // do write
      u16_MemAddr = u16_MemAddr + BLKSIZE;
    } else {
      memRead25LC256(u16_MemAddr,au8_buf); // do read
      for (u8_i = 0; u8_i< BLKSIZE; u8_i++) outChar(au8_buf[u8_i]);
      outString("\nAny key continues read...\n");
      inChar();
      u16_MemAddr = u16_MemAddr + BLKSIZE;
    }
  }
}