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.
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