Code: EEPROM_SPI_UTIL for Microchip SPI EEPROMs

General discussion on mikroPascal for dsPIC30/33 and PIC24.
Post Reply
Author
Message
OT
Posts: 581
Joined: 19 May 2005 05:08
Location: Fairbanks, Alaska

Code: EEPROM_SPI_UTIL for Microchip SPI EEPROMs

#1 Post by OT » 05 Dec 2007 07:33

I converted my EEPROM routines for the 25LC1024 to a unit that should work on all sizes of Microchip EEPROMs from 1Kbit and up. The posting below includes EEPROM_SPI_UTIL unit and EEPROM_SPI_test program and has been tested with 25LC256 and 25LC1024. It includes Write and Read of Byte and Word, Deep power down/wake-up, Chip Erase and Page Erase. A limitation is that the chip select port is hard coded to PortF (pin selectable in init procedure). If anyone knows how to pass port in the init procedure call and use in a unit as for instance in ME's LCD/GLCD libraries without too much overhead I would interested...
Comments or improvements would be appreciated.

EEPROM_SPI_UTIL unit:

Code: Select all

unit EEPROM_SPI_Util;
//******************************************************************************
// Unit for use of Microchip series of SPI compatible EEPROMS
// tested with 25LC1024 and 25LC256, EasydsPIC2 at FRC 7.37 MHz, dsPIC30F4013.
// should work with devices from 1Kbits and up.
// CS for EEPROM is connected at PortF, change in code if other ports needed
// O. T. 2007-12-04
//******************************************************************************
implementation
const
 //Commands
  EE_ReadCmd            = $03;     //read data from selected address
  EE_WriteCmd           = $02;     //write data to selected address
  EE_WriteEnable        = $06;     //set write enable latch (enable write ops)
  EE_WriteDisable       = $04;     //reset the write enable latch (disable write ops)
  EE_ReadStatusReg      = $05;     //read status register
  EE_WriteStatusReg     = $01;     //write status register
  EE_PageErase          = $42;     //page erase
  EE_SectorErase        = $D8;     //sector erase
  EE_ChipErase          = $C7;     //chip erase
  EE_RelDeepPowerDwn    = $AB;     //release from deep power down and possilby read ID
  EE_DeepPowerDwn       = $B9;     //enter deep power down mode


var
   EECSPin    : Word;   //chip select pin
   EESize     : Word;   //Eeprom size, number of Kbits.

procedure EEPROMSPI_Init(CSPin,EEKbits:Word);
//Note: SPI must be initiated separately. PortF is hard coded.
//EEPROM notes:
//  >4Kbits 16 bit address
//>512Kbits 24 bit address
//Size,Kbit   Page size
//   1       16 Bytes
//  16A      16 Bytes
//  16B      32 Bytes
// 256       64 Bytes
// 512      128 Bytes
//1024      128 Bytes
begin
  EECSPin := CSPin;
  EESize  := EEKbits;
  TrisF.EECSPin := 0;        // Make CS pin output
  LatF.EECSPin  := 1;        // Set CS to inactive
end;

procedure EEPROMSPI_DeepPowerDwn;
begin
  while SPI1STAT.1 = 1 do                // wait for SPI module to finish, if doing something
   nop;
  LatF.EECSPin := 0;
  Spi1_Write(EE_DeepPowerDwn);           // Deep power down
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 1;
end;

procedure EEPROMSPI_RelDeepPowerDwn;
begin
  while SPI1STAT.1 = 1 do                // wait for SPI module to finish, if doing something
   nop;
  LatF.EECSPin := 0;
  Spi1_Write(EE_RelDeepPowerDwn);        // Deep power down
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 1;
  Delay_us(200);
end;


procedure EEPROMSPI_WriteInProgressPoll;
//This routine loops until WIP:= 0
var
  Status: Byte;
begin
  while (Status and $01) do               //The WIP bit is bit 0.
    begin
      LatF.EECSPin:= 0;                   //Select Device
      SPI1_Write(EE_ReadStatusReg);       //Read Status Reg OpCode
      Status:= SPI1_Read(0);              //Read Status Reg
      LatF.EECSPin:= 1;                   //Deselect Device
    end;                                  //Check for WIP bit Set
end;


procedure EEPROMSPI_WriteEnable;
begin
  while SPI1STAT.1 = 1 do                // wait for SPI module to finish, if doing something
   nop;
  LatF.EECSPin := 0;
  Spi1_Write(EE_WriteEnable);            //enable writes
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 1;
end;


procedure EEPROMSPI_WriteDisable;
begin
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 0;
  Spi1_Write(EE_WriteDisable);           //disable writes to eeprom
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 1;
end;


procedure EEPROMSPI_ChipErase;
begin
  while SPI1STAT.1 = 1 do                // wait for SPI module to finish, if doing something
   nop;
  EEPROMSPI_WriteEnable;
  LatF.EECSPin := 0;
  Spi1_Write(EE_ChipErase);              // Chip erase command
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 1;
  EEPROMSPI_WriteInProgressPoll;
  EEPROMSPI_WriteDisable;
  delay_ms(10);                           //need 8 ms minimum
end;


procedure EEPROMSPI_PageErase(EEAddr:LongInt);
//Erase a 64 kbit page
begin
  while SPI1STAT.1 = 1 do                // wait for SPI module to finish, if doing something
   nop;
  EEPROMSPI_WriteEnable;
  LatF.EECSPin := 0;
  Spi1_Write(EE_PageErase);              // Page erase command
  If EESize>4 then begin
    If EESize>512 then begin
     Spi1_Write(Higher(EEAddr));         //send Upper byte of 24 bit address
    end;
    Spi1_Write(Hi(EEAddr));              //send lower  16 bits of address
  end;
  Spi1_Write(Lo(EEAddr));
  while SPI1STAT.1 = 1 do                // Wait for SPI module to finish write
   nop;
  LatF.EECSPin := 1;
  EEPROMSPI_WriteInProgressPoll;
  EEPROMSPI_WriteDisable;
  delay_ms(6);
end;




procedure EEPROMSPI_WriteByte(databyte: Word; EEdataAddr:LongInt);
begin
  while SPI1STAT.1 = 1 do             // wait for SPI module to finish, if doing something
   nop;
  EEPROMSPI_WriteEnable;              //"A write enable instruction must be issued to set
                                      //the write enable latch  After a byte write, page
                                      //write or STATUS register write, the write enable
                                      //latch is reset"
  LatF.EECSPin := 0;
  Spi1_Write(EE_WriteCmd);            //write command
  If EESize>4 then begin
    If EESize>512 then begin
      Spi1_Write(Higher(EEdataAddr)); //send Upper byte of 24 bit address
    end;
    Spi1_Write(Hi(EEdataAddr));       //send lower  16 bits of address
  end;
  Spi1_Write(Lo(EEdataAddr));
  Spi1_Write(databyte);               //write data

  // EEPROMSPI_ChipDeSelect;
  LatF.EECSPin := 1;
  EEPROMSPI_WriteInProgressPoll;      //write cycle (page or less) is 6 ms, wait to finish.
//  EEPROMSPI_WriteDisable;           //not needed, latch is automatically reset
end;


function EEPROMSPI_ReadByte(EEdataAddr: LongInt): Word;
var
  datareadbyte: Word;
begin
  while SPI1STAT.1 = 1 do             // wait for SPI module to finish, if doing something
    nop;
  EEPROMSPI_WriteInProgressPoll;      // make sure writing not in progress
  LatF.EECSPin := 0;
  Spi1_Write(EE_ReadCmd);             //issue the READ command
  If EESize>4 then begin
    If EESize>512 then begin
     Spi1_Write(Higher(EEdataAddr));  //send Upper byte of 24 bit address
    end;
    Spi1_Write(Hi(EEdataAddr));       //send lower  16 bits of address
  end;
  Spi1_Write(Lo(EEdataAddr));
  dataReadByte := SPI1_read(0);       //read the eeprom
  LatF.EECSPin := 1;
  EEPROMSPI_ReadByte:=dataReadByte;
end;


procedure EEPROMSPI_WriteWord(dataWord: Word; EEWordAddr:LongInt);
//EEword address is now the count of words, not bytes
var
  BAddr: LongInt;
begin
  BAddr:=2*EEWordAddr;
  while SPI1STAT.1 = 1 do             // wait for SPI module to finish, if doing something
   nop;
  EEPROMSPI_WriteEnable;              //Make available for writing
  LatF.EECSPin := 0;
  Spi1_Write(EE_WriteCmd);            //write command
   If EESize>4 then begin
    If EESize>512 then begin
      Spi1_Write(Higher(BAddr));      //send Upper byte of 24 bit address
    end;
    Spi1_Write(Hi(BAddr));            //send lower  16 bits of address
  end;
  Spi1_Write(Lo(BAddr));
  Spi1_Write(Hi(dataWord));           //write data
  Spi1_Write(Lo(dataWord));           //write data
  LatF.EECSPin := 1;
  EEPROMSPI_WriteInProgressPoll;
  //EEPROMSPI_WriteDisable;           //not needed, latch is automatically reset
end;


function EEPROMSPI_ReadWord(EEWordAddr: LongInt): Word;
//EEword address is now the count of words, not bytes
var
  BAddr: LongInt;
  Bread: Byte;
  Wread: Word;
begin
  BAddr:=2*EEWordAddr;
  while SPI1STAT.1 = 1 do             // wait for SPI module to finish, if doing something
    nop;
  EEPROMSPI_WriteInProgressPoll;
  LatF.EECSPin := 0;
  Spi1_Write(EE_ReadCmd);             //issue the READ command
    If EESize>4 then begin
    If EESize>512 then begin
      Spi1_Write(Higher(BAddr));      //send Upper byte of 24 bit address
    end;
    Spi1_Write(Hi(BAddr));            //send lower  16 bits of address
  end;
  Spi1_Write(Lo(BAddr));
  Bread := SPI1_read(0);              //read the eeprom
  Wread:=Bread shl 8;
  Bread := SPI1_read(0);              //read the eeprom
  Wread:=Wread or Bread;
  LatF.EECSPin := 1;
  EEPROMSPI_ReadWord:=Wread;
end;

end.
Test program EEPROM_SPI_Test:

Code: Select all

program EEPROM_SPI_Test;
//******************************************************************************
// Program to test EEPROM_SPI_UTIL unit with 25LC1024 or 25LC256/25LC512 EEprom
// Tested with EasydsPIC2 at FRC 7.37 MHz, dsPIC30F4013.
// Will display what is written on LCD line 1 and result of read on line 2.
// CS for EEPROM is connected to port F pin 4.
// O. T. 2007-12-04
//******************************************************************************

{$DEFINE 25LC1024}

Uses EEPROM_SPI_Util;

const
  CS_PIN_EEPROM           = 4;     //Chip enable pin portF

var
   DatWord,datReadWord  : Word;
   Pos                   : Word;
   EEdataAddr            : LongInt;
   txt                   : string[16];

begin
  Delay_ms(1000);
  ADPCFG := $FFFF;
  TRISD  := $FFF0;
  TrisB  := $000F;
  LatB:=0;

  TRISF.2 := 1;     //input  SPI
  TRISF.3 := 0;     //output SPI


// SPI setup, chip takes max 10MHz. If MCU clock frequency is >40MHz
// set SPI prescaler:  80MHz use _SPI_PRESCALE_SEC_2   ((80/4)/2=10MHz
//                    120MHz use _SPI_PRESCALE_SEC_4
  Spi1_Init_Advanced(_SPI_MASTER, _SPI_8_BIT, _SPI_PRESCALE_SEC_1, _SPI_PRESCALE_PRI_1,
                   _SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_ACTIVE_2_IDLE);

  Delay_ms(200);

 //Init EEPROM with CS on Pin4 on portF, memory size 1024Kbits, initiates trisF and inistal CS setting.
{$IFDEF 25LC1024}
  EEPROMSPI_Init(CS_PIN_EEPROM,1024);
{$ELSE}
  EEPROMSPI_Init(CS_PIN_EEPROM,256);
{$ENDIF}
  EEPROMSPI_DeepPowerDwn; //Max reduction of power cons to nominal 1 uA
  Lcd_Init(LATB, 7, 6, 5, 4, LATD, 0, 1, 2);
  Lcd_Cmd(LCD_CURSOR_OFF);
  Lcd_Cmd(LCD_CLEAR);
  LCD_out(1,1,'Sleeping for 3s.');
  Delay_ms(3000);
  LCD_out(1,1,'Wake-up         ');
  EEPROMSPI_RelDeepPowerDwn;
  Delay_ms(500);
  Lcd_Cmd(LCD_CLEAR);

  EEPROMSPI_ChipErase;
 //Write single bytes to external eeprom and display written chars on LCD line 1

  EEdataAddr :=  128;
  DatWord    := 65;
  while EEdataAddr < 144 do begin
    EEPROMSPI_WriteByte(datWord,EEdataAddr);
    Pos:=EEdataAddr-127;
    lcd_Chr(1,Pos,DatWord);
    Inc(EEdataAddr);
    Inc(DatWord);
  end;
  Delay_ms(1000);

 //Read single bytes from external eeprom and display the chars on LCD line 2
  EEdataAddr := 128;
  while EEdataAddr < 144 do begin
    datReadWord:=EEPROMSPI_ReadByte(EEdataAddr);
    delay_ms(10);
    Pos:=EEdataAddr-127;
    lcd_Chr(2,Pos,datReadWord);
    Inc(EEdataAddr);
  end;
  Delay_ms(3000);

  lcd_out(1,2,' Erasing page ');
 //Read single bytes from external eeprom and display the chars on LCD line 2
  EEdataAddr := 128;
  EEPROMSPI_pageErase(EEdataAddr);
  while EEdataAddr < 144 do begin
    datReadWord:=EEPROMSPI_ReadByte(EEdataAddr);
    delay_ms(10);
    Pos:=EEdataAddr-127;
    lcd_Chr(2,Pos,datReadWord);
    Inc(EEdataAddr);
  end;
  Delay_ms(3000);
  Lcd_Cmd(LCD_CLEAR);

   //Write single word to external eeprom and display written chars on LCD
  //note that address now is the number of word counts. As long as address starts
  //at 0 or an even address, there should not be problems with page boundaries
  DatWord    := 55000;
{$IFDEF 25LC1024}
  EEdataAddr := 60000;
  While EEdataAddr<60101 do begin
{$ELSE}
  EEdataAddr := 10000;
  While EEdataAddr<10101 do begin
{$ENDIF}
   //Write single word to external eeprom and display the value on LCD line 1
    EEPROMSPI_WriteInProgressPoll;
    EEPROMSPI_WriteWord(datWord,EEdataAddr);
    WordToStr(datWord, txt);
    lcd_out(1,1,txt);
    EEPROMSPI_WriteInProgressPoll;
    Delay_ms(10);
   //Read single word from external eeprom and display value LCD on LCD line 2
    datReadWord:=EEPROMSPI_ReadWord(EEdataAddr);
     WordToStr(datReadWord, txt);
    lcd_out(2,1,txt);
    Inc(EEdataAddr);
    Inc(DatWord);
  end;
  Delay_ms(1000);
  lcd_out(2,7,'end, sleep');
  EEPROMSPI_DeepPowerDwn; //Max reduction of power cons to nominal 1 uA
  //finished, do nothing more
  While true do begin
    nop;
  end;
end.

A previous discussion can be found here:
http://www.mikroe.com/forum/viewtopic.php?t=12586

User avatar
zristic
mikroElektronika team
Posts: 6608
Joined: 03 Aug 2004 12:59
Contact:

Re: Code: EEPROM_SPI_UTIL for Microchip SPI EEPROMs

#2 Post by zristic » 05 Dec 2007 09:25

Thank you.

Post Reply

Return to “mikroPascal for dsPIC30/33 and PIC24 General”