Updated Code: EEPROM_SPI_UTIL for Microchip SPI EEPROMs

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

Updated Code: EEPROM_SPI_UTIL for Microchip SPI EEPROMs

#1 Post by OT » 25 Jan 2010 00:26

I previously posted a unit with EEPROM routines for Microchip EEPROMS like the 25LC1024:
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. 
unit:

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.

Post Reply

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