http://www.mikroe.com/forum/viewtopic.p ... highlight=
I have now updated it for the dsPIC Pro compiler with the advantage of using a bit variable to define the CS pin. The EEPROM size is as before defined in the init routine and I kept the SPI init in the calling program to allow flexibility. In this turn it was tested with 25LC1024. It should work with any size of EEPROM below that, for instance 25LC256, provided it is correctly defined.
Test program:
Code: Select all
program EEPROM_SPI_Test;
//******************************************************************************
// Program to test EEPROM_SPI_UTIL unit with 25LC1024 or 25LC256/25LC512 EEprom
// Tested with 10MHz crystal PLL8 at 80 MHz, dsPIC30F4013.
// Will display what is written on LCD line 1 and result of read on line 2.
// CS for EEPROM is is defined as bit variable in Units interface section.
// O. T. 2007-12-04, updated for Pro compiler 2010-01-24
//******************************************************************************
//The test program needs this define if EEPROM size is >512kbits
//- does not affect the unit
{$DEFINE 25LC1024}
Uses EEPROM_SPI_Util;
//EEPROM CS connection
var
CS_EE : sbit at LATA.B11;
CS_EE_direction : sbit at TRISA.B11;
// LCD module connections
// These are with the EasydsPIC2 board, others might need modification
var LCD_RS : sbit at LATD0_bit;
var LCD_EN : sbit at LATD2_bit;
var LCD_D4 : sbit at LATB4_bit;
var LCD_D5 : sbit at LATB5_bit;
var LCD_D6 : sbit at LATB6_bit;
var LCD_D7 : sbit at LATB7_bit;
var LCD_RS_Direction : sbit at TRISD0_bit;
var LCD_EN_Direction : sbit at TRISD2_bit;
var LCD_D4_Direction : sbit at TRISB7_bit;
var LCD_D5_Direction : sbit at TRISB6_bit;
var LCD_D6_Direction : sbit at TRISB5_bit;
var LCD_D7_Direction : sbit at TRISB4_bit;
// End LCD module connections
var
DatWord,datReadWord : Word;
Pos : Word;
EEdataAddr : LongInt;
txt : string[16];
begin
Delay_ms(1000);
ADPCFG := $FFFF;
TRISD := $FFF0;
TrisB := $000F;
LatB:=0;
// 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_2, _SPI_PRESCALE_PRI_1,
_SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_IDLE_2_ACTIVE);
//This init also appears to work:
//Spi1_Init_Advanced(_SPI_MASTER, _SPI_8_BIT, _SPI_PRESCALE_SEC_2, _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(1024);
{$ELSE}
EEPROMSPI_Init(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.
Code: Select all
//******************************************************************************
Unit EEPROM_SPI_Util;
// Unit for use of Microchip series of SPI compatible EEPROMS
// Tested with 10MHz crystal PLL8 at 80 MHz, dsPIC30F4013, 25LC1024 and 25LC256,
// should work with devices from 1Kbits and up.
// CS for EEPROM is is defined as bit variable in Units interface section.
// O. T. 2007-12-04, updated for Pro compiler 2010-01-24
//******************************************************************************
var
CS_EE : sbit; sfr; external;
CS_EE_direction : sbit; sfr; external;
procedure EEPROMSPI_Init(EEKbits:Word);
procedure EEPROMSPI_DeepPowerDwn;
procedure EEPROMSPI_RelDeepPowerDwn;
procedure EEPROMSPI_WriteInProgressPoll;
procedure EEPROMSPI_WriteEnable;
procedure EEPROMSPI_WriteDisable;
procedure EEPROMSPI_ChipErase;
procedure EEPROMSPI_PageErase(EEAddr:LongInt);
procedure EEPROMSPI_WriteByte(databyte: Word; EEdataAddr:LongInt);
function EEPROMSPI_ReadByte(EEdataAddr: LongInt): Word;
procedure EEPROMSPI_WriteWord(dataWord: Word; EEWordAddr:LongInt);
function EEPROMSPI_ReadWord(EEWordAddr: LongInt): Word;
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
EESize : Word; //Eeprom size, number of Kbits.
procedure EEPROMSPI_Init(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
EESize := EEKbits;
CS_EE_direction := 0; // Make CS pin output
CS_EE := 1; // Set CS to inactive
end;
procedure EEPROMSPI_DeepPowerDwn;
begin
while SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
CS_EE := 0;
Spi1_Write(EE_DeepPowerDwn); // Deep power down
while SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 1;
end;
procedure EEPROMSPI_RelDeepPowerDwn;
begin
while SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
CS_EE := 0;
Spi1_Write(EE_RelDeepPowerDwn); // Deep power down
while SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 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
CS_EE:= 0; //Select Device
SPI1_Write(EE_ReadStatusReg); //Read Status Reg OpCode
Status:= SPI1_Read(0); //Read Status Reg
CS_EE:= 1; //Deselect Device
end; //Check for WIP bit Set
end;
procedure EEPROMSPI_WriteEnable;
begin
while SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
CS_EE := 0;
Spi1_Write(EE_WriteEnable); //enable writes
while SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 1;
end;
procedure EEPROMSPI_WriteDisable;
begin
while SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 0;
Spi1_Write(EE_WriteDisable); //disable writes to eeprom
while SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 1;
end;
procedure EEPROMSPI_ChipErase;
begin
while SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
EEPROMSPI_WriteEnable;
CS_EE := 0;
Spi1_Write(EE_ChipErase); // Chip erase command
while SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 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 SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
EEPROMSPI_WriteEnable;
CS_EE := 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 SPITBF_bit = 1 do // Wait for SPI module to finish write
nop;
CS_EE := 1;
EEPROMSPI_WriteInProgressPoll;
EEPROMSPI_WriteDisable;
delay_ms(6);
end;
procedure EEPROMSPI_WriteByte(databyte: Word; EEdataAddr:LongInt);
begin
while SPITBF_bit = 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"
CS_EE := 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;
CS_EE := 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 SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
EEPROMSPI_WriteInProgressPoll; // make sure writing not in progress
CS_EE := 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
CS_EE := 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 SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
EEPROMSPI_WriteEnable; //Make available for writing
CS_EE := 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
CS_EE := 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 SPITBF_bit = 1 do // wait for SPI module to finish, if doing something
nop;
EEPROMSPI_WriteInProgressPoll;
CS_EE := 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;
CS_EE := 1;
EEPROMSPI_ReadWord:=Wread;
end;
End.