// ****************************************************************************** // // * Copyright: // (c) Mustangpeak Software 2012. // // The contents of this file are subject to the GNU GPL v3 licence/ you maynot use // this file except in compliance with the License. You may obtain a copy of the // License at http://www.gnu.org/licenses/gpl.html // // * Revision History: // 2012-02-01: 1.0.0.0 Created // 2012-03-24: 1.0.0.1 Generalized so would work with any PIC micro and the ME SPI Libraries // 2012-10-07: Version 1.0 // // * Description: // Implements an interface for 25AA1024, 512, 256, etc SPI EEPROM Chips // // ****************************************************************************** (****************************************************************************** Usage: program AA25xxxx; { Declarations section } uses _25AAxxxx; var CS_Bank_0: sbit at LATB12_bit; CS_Bank_1: sbit at LATB11_bit; CS_Bank_0_Direction: sbit at TRISB12_bit; CS_Bank_1_Direction: sbit at TRISB11_bit; Buffer: array[0..99] of Byte; var i: LongInt; begin CS_Bank_1_Direction := 0; CS_Bank_1 := 1; CS_Bank_0_Direction := 0; CS_Bank_0 := 1; _25AAxxxx_Initialize; SPI1_Init(); for i := 0 to 99 do Buffer[i] := i; _25AAxxxx_Write(EEPROM_BANK_0, $000000, 100, @Buffer[0]); while _25AAxxxx_Busy(EEPROM_BANK_0) do Delay_us(1000); begin while true do begin _25AAxxxx_Read(EEPROM_BANK_1, $000000, 100, @Buffer[0]); end end end. ******************************************************************************) unit _25AAxxxx; {$DEFINE dsPIC30F} {$DEFINE EEPROM_ONE_BANK} {.$DEFINE EEPROM_TWO_BANK} {.$DEFINE EEPROM_THREE_BANK} {.$DEFINE EEPROM_FOUR_BANK} const {$IFDEF EEPROM_ONE_BANK}EEPROM_BANK_0 = 0; {$ENDIF} {$IFDEF EEPROM_TWO_BANK} EEPROM_BANK_1 = 1; {$ENDIF} {$IFDEF EEPROM_THREE_BANK}EEPROM_BANK_2 = 3;{$ENDIF} {$IFDEF EEPROM_FOUR_BANK}EEPROM_BANK_3 = 4; {$ENDIF} type PByte = ^Byte; var // Assign the Chip Select output Pin in the main code for each device used // BE SURE TO USE THE LATCH and the PORT, i.e. // var CS_Bank_0: sbit at LATD0; {$IFDEF EEPROM_ONE_BANK}CS_Bank_0: sbit; sfr; external; {$ENDIF} {$IFDEF EEPROM_TWO_BANK}CS_Bank_1: sbit; sfr; external; {$ENDIF} {$IFDEF EEPROM_THREE_BANK}CS_Bank_2: sbit; sfr; external; {$ENDIF} {$IFDEF EEPROM_FOUR_BANK}CS_Bank_3: sbit; sfr; external; {$ENDIF} EE_PROM_Hold : sbit; sfr; external; EEPROM_Hold_Direction : sbit; sfr; external; // Assign the Chip Select pin direction // i.e. // var CS_Bank_0_Direction: sbit at TRISD0; {$IFDEF EEPROM_ONE_BANK}CS_Bank_0_Direction: sbit; sfr; external; {$ENDIF} {$IFDEF EEPROM_TWO_BANK}CS_Bank_1_Direction: sbit; sfr; external; {$ENDIF} {$IFDEF EEPROM_THREE_BANK}CS_Bank_2_Direction: sbit; sfr; external; {$ENDIF} {$IFDEF EEPROM_FOUR_BANK}CS_Bank_3_Direction: sbit; sfr; external; {$ENDIF} // Call early in the code startup to initialize the CS pins procedure _25AAxxxx_Initialize; procedure _25AAxxxx_Read(Bank: Word; Address: DWORD; Count: Word; Buffer: PByte); procedure _25AAxxxx_Write(Bank: Word; Address: DWORD; Count: Word; Buffer: PByte); function _25AAxxxx_Busy(Bank: Word): Boolean; function _25AAxxxx_WriteEnabled(Bank: Word): Boolean; procedure _25AAxxxx_Erase(Bank: Word); implementation function LocalSPI_Read: Byte; var Dummy: Byte; begin {$IFDEF dsPIC30F} // This version is MUCH faster than the ME library // We have waited for the SPI to empty before returning so the buffer is empty on entry Result := SPI1BUF; // Force the SPIRBF flag to clear Dummy := 0; SPI1BUF := Dummy; // This will set the SPITBF flag until the byte is written into the output latch to be sent. while SPIRBF_bit = 0 do; Result := SPI1BUF; {$ELSE} Result := SPI_Read(Dummy) {$ENDIF} end; function LocalSPI_Write(DataByte: Byte): Byte; begin {$IFDEF dsPIC30F} // This version is MUCH faster than the ME library // We have waited for the SPI to empty before returning so the buffer is empty on entry Result := SPI1BUF; // Force the SPIRBF flag to clear nop; SPI1BUF := DataByte; // This will set the SPITBF flag until the byte is written into the output latch to be sent. while SPIRBF_bit = 0 do; Result := SPI1BUF; {$ELSE} Result := DataByte; SPI_Write(DataByte); {$ENDIF} end; procedure SetBank_CS(Bank: Word; CS_State: Word); begin {$IFDEF EEPROM_ONE_BANK} if Bank = EEPROM_BANK_0 then CS_Bank_0 := CS_State {$ENDIF} {$IFDEF EEPROM_TWO_BANK} else if Bank = EEPROM_BANK_1 then CS_Bank_1 := CS_State {$ENDIF} {$IFDEF EEPROM_THREE_BANK} else if Bank = EEPROM_BANK_2 then CS_Bank_2 := CS_State {$ENDIF} {$IFDEF EEPROM_FOUR_BANK} else if Bank = EEPROM_BANK_3 then CS_Bank_3 := CS_State; {$ENDIF} end; procedure WriteAddress(Address: DWORD); begin LocalSPI_Write(Address shr 16); LocalSPI_Write(Address shr 8); LocalSPI_Write(Address); end; //****************************************************************************** // procedure _25AAxxxx_Read; // // Parameters: Bank: What EEPROM IC to address, see the EEPROM_BANK_x constants // Address: The 24Bit address offset of the EEPROM // Count: The number of Bytes to read // Buffer: Pointer to where to place the data read in // // Result: None // // Description: // //****************************************************************************** procedure _25AAxxxx_Read(Bank: Word; Address: DWORD; Count: Word; Buffer: PByte); var i: Integer; Dummy: Byte; begin SetBank_CS(Bank, 0); LocalSPI_Write($03); // Read Instruction WriteAddress(Address); i := 0; while i < Count do begin {$IFDEF dsPIC30F} // Much faster than ME Libraries Dummy := 0; SPI1BUF := Dummy; // This will set the SPITBF flag until the byte is written into the output latch to be sent. while SPIRBF_bit = 0 do; Buffer^ := SPI1BUF; {$ELSE} Buffer^ := LocalSPI_Read; {$ENDIF} Inc(Buffer); Inc(i); end; SetBank_CS(Bank, 1); end; //****************************************************************************** // procedure _25AAxxxx_Write; // // Parameters: Bank: What EEPROM IC to address, see the EEPROM_BANK_x constants // Address: The 24Bit address offset of the EEPROM // Count: The number of Bytes to write, MAX 256 Bytes and in the SAME PAGE!!!!!! // Buffer: Pointer to where to retrieve the data from to write // // Result: None // // Description: // //****************************************************************************** procedure _25AAxxxx_Write(Bank: Word; Address: DWORD; Count: Word; Buffer: PByte); var i: Integer; begin SetBank_CS(Bank, 0); LocalSPI_Write($06); // WREN (Write Enable) Instruction SetBank_CS(Bank, 1); SetBank_CS(Bank, 0); LocalSPI_Write($02); // Write Instruction WriteAddress(Address); // Can not check for Write Enabled in the Status here! i := 0; while i < Count do begin LocalSPI_Write(Buffer^); Inc(Buffer); Inc(i); end; SetBank_CS(Bank, 1); end; //****************************************************************************** // procedure _25AAxxxx_Busy; // // Parameters: Bank: What EEPROM IC to address, see the EEPROM_BANK_x constants // // Result: True if the device can be accessed // // Description: // //****************************************************************************** function _25AAxxxx_Busy(Bank: Word): Boolean; begin SetBank_CS(Bank, 0); LocalSPI_Write($05); Result := LocalSPI_Read and $01 <> 0; SetBank_CS(Bank, 1); end; //****************************************************************************** // procedure _25AAxxxx_WriteEnabled; // // Parameters: Bank: What EEPROM IC to address, see the EEPROM_BANK_x constants // // Result: True if the device can be accessed // // Description: // //****************************************************************************** function _25AAxxxx_WriteEnabled(Bank: Word): Boolean; begin SetBank_CS(Bank, 0); LocalSPI_Write($05); Result := LocalSPI_Read and $02 <> 0 end; procedure _25AAxxxx_Erase(Bank: Word); begin SetBank_CS(Bank, 0); LocalSPI_Write($06); // WREN (Write Enable) Instruction SetBank_CS(Bank, 1); SetBank_CS(Bank, 0); LocalSPI_Write($C7); // Chip Erase SetBank_CS(Bank, 1); end; procedure _25AAxxxx_Initialize; begin {$IFDEF EEPROM_ONE_BANK}CS_Bank_0 := 1; {$ENDIF} // Output {$IFDEF EEPROM_TWO_BANK}CS_Bank_1 := 1; {$ENDIF} // Output {$IFDEF EEPROM_THREE_BANK}CS_Bank_2 := 1; {$ENDIF} // Output {$IFDEF EEPROM_FOUR_BANK}CS_Bank_3 := 1; {$ENDIF} // Output {$IFDEF EEPROM_ONE_BANK}CS_Bank_0_Direction := 0; {$ENDIF} // Output {$IFDEF EEPROM_TWO_BANK}CS_Bank_1_Direction := 0; {$ENDIF} // Output {$IFDEF EEPROM_THREE_BANK}CS_Bank_2_Direction := 0; {$ENDIF} // Output {$IFDEF EEPROM_FOUR_BANK}CS_Bank_3_Direction := 0; {$ENDIF} // Output EE_PROM_Hold := 1; // No Hold EEPROM_Hold_Direction := 0 // Output end; end.