' ' sermem.bas ' ' This file is full of routines for dealing with serial EEPROM ' such as the Atmel 25128 or the Microchip 25C320 ' ' Almost all of these parts operate in the same way. The variables ' are the page write size, and the block protection sizes. These can be ' passed in during initialization ' ' ' ' Some constants ' const SERMEM_INST_WREN = $06 const SERMEM_INST_WRDI = $04 const SERMEM_INST_RDSR = $05 const SERMEM_INST_WRSR = $01 const SERMEM_INST_READ = $03 const SERMEM_INST_WRITE = $02 ' The variable sermem_page_size is used to flush pages during a write ' operation. It is set by sermem_Init. declare sermem_page_mask declare sermem_write_address ' ' sermem_init must be called to initialize the port. Pass in the page size ' as a variable. The variable is removed from the stack by this routine ' ' To call: ' gosub sermem_Init, ' ' must be a power of 2. 16, 32, or 64 are the common values ' sermem_Init: ' Save the page size - 1 as a mask sermem_page_mask = pop() - 1 ' Set the DDRD5 bit so that SS is an output pin pokeb PORTD, peekb(PORTD) OR $38 pokeb DDRD, peek(DDRD) OR $38 ' Setup the SPI register to be MASTER, CPOL=0, CPHA=0 pokeb SPCR, $50 ' On a 68HC11, ECLOCK is 2mhz (assume 8mhz clock) which is OK ' On a 68HC12, ECLOCK is 8mhz, which is too fast. A prescale ' may be required on a 68HC12 return sermem_spi_select: pokeb SPCR, $50 pokeb PORTD, peekb(PORTD) AND $DF return sermem_spi_deselect: pokeb PORTD, peekb(PORTD) OR $20 return sermem_spi_xfer: pokeb SPDR, pop() do while (peekb(SPSR) AND $80) = 0 loop return peekb(SPDR) ' ' sermem_WriteEnable sends a write enable command ' ' Invoke by using ' ' gosub sermem_WriteEnable ' ' or ' ' gosub sermem_WriteDisable sermem_WriteEnable: gosub sermem_spi_select gosub sermem_spi_xfer, SERMEM_INST_WREN gosub sermem_spi_deselect return sermem_WriteDisable: gosub sermem_spi_select gosub sermem_spi_xfer, SERMEM_INST_WRDI gosub sermem_spi_deselect return ' This routine sets the block protection level. Check out the docuementation ' for your part. Most have 4 levels of protection (0 to 3), meaning that ' protection level 3 is all protected, level 2 protects the upper 1/4, ' level 1 protects the upper half, and level 0 leaves everything fair game. ' sermem_BlockProt: gosub sermem_spi_select gosub sermem_spi_xfer, SERMEM_INST_WRSR gosub sermem_spi_xfer, LSHFT(LSHFT(pop())) gosub sermem_spi_deselect return ' ' For the most part, to write data to the EEPROM, you want to use the ' sermem_WriteBlock(...) command. This allows you to write and commit a ' block of memory to the EEPROM. This is useful in most cases. There are, ' however, cases where you will want to write a stream of data instead. ' ' The serial EEPROM's allow you to send streams of bytes in a write command. ' I have written these routines to allow you access to the serial EEPROM ' if you are streaming data. The basic sequence is: ' ' sermem_StartWrite ' sermem_Write ' sermem_StopWrite ' ' Note that to insure that your data is actually committed, you need to call ' StopWrite to end this operation. Otherwise, the last page will not be ' committed to memory. ' ' Note that this sequence cannot be interrupted by other EEPROM operations. ' Specifically, once StartWrite() has been called, you can only call Write() ' or StopWrite(). Most any other operation will fail because the chip has ' been left in a write mode. ' ' ' sermem_StartWrite accepts ' sermem_StartWrite: ' Remember the starting address sermem_write_address = pop() ' Send the WRITE command followed by the address, MSB first gosub sermem_WriteEnable gosub sermem_spi_select gosub sermem_spi_xfer, SERMEM_INST_WRITE gosub sermem_spi_xfer, sermem_write_address / 256 gosub sermem_spi_xfer, sermem_write_address AND $ff ' StartWrite leaves the EEPROM selectd return ' ' ' sermem_Write ' ' Invoke using: ' ' gosub sermem_Write, , ' ' where is the address of the memory buffer to write ' and is the number of bytes to write ' sermem_Write: do while pick(0) <> 0 gosub sermem_spi_xfer, peekb( pick(1)) place 1, pick(1) + 1 place 0, pick(0) - 1 sermem_write_address = sermem_write_address + 1 if (sermem_write_address AND sermem_page_mask) = 0 gosub sermem_StopWrite gosub sermem_StartWrite, sermem_write_address endif loop drop 2 return sermem_StopWrite: do gosub sermem_spi_deselect gosub sermem_spi_select gosub sermem_spi_xfer, SERMEM_INST_RDSR loop while ( usr(sermem_spi_xfer,0) AND $01) = $01 gosub sermem_spi_deselect gosub sermem_WriteDisable return ' ' ' gosub sermem_WriteBlock
, , ' sermem_WriteBlock: gosub sermem_StartWrite, pick(2) ' ' Warning: Serious slime attack! Since SBASIC doesn't have local ' variables, I am going to let the _Write command take what exists ' on the stack. It will remove the top two arguments from the stack ' I tried using pick(), but it didn't work correctly because the ' data stack changed during the subroutine call. gosub sermem_Write gosub sermem_StopWrite ' Now get rid of
drop 1 return ' ' On occasion, you may want to just fill the EEPROM array with a byte ' value. This routine does just that! ' ' gosub sermem_Fill , , ' sermem_Fill: gosub sermem_StartWrite, pick(2) do while pick(0) <> 0 ' Send the byte to the part gosub sermem_spi_xfer, peekb(pick(1)) place 0, pick(0) - 1 sermem_write_address = sermem_write_address + 1 if (sermem_write_address AND sermem_page_mask) = 0 ' We have page wrapped! gosub sermem_StopWrite gosub sermem_StartWrite, sermem_write_address endif loop gosub sermem_StopWrite drop 3 return ' ' For the most part, to read data from the EEPROM, you want to use the ' sermem_ReadBlock command. This allows you to read a ' block of memory from the EEPROM. This is useful in most cases. There are, ' however, cases where you will want to read a stream of data instead. ' ' The serial EEPROM's allow you to read streams of bytes in a read command. ' I have written these routines to allow you access to the serial EEPROM ' if you are streaming data. The basic sequence is: ' ' sermem_StartRead ' sermem_Read ' sermem_StopRead ' ' ' Note that this sequence cannot be interrupted by other EEPROM operations. ' Specifically, once StartRead() has been called, you can only call Read() ' or StopRead(). Most any other operation will fail because the chip has ' been left in a read mode. ' sermem_StartRead: ' StartRead begins by enabling the EEPROM gosub sermem_spi_select ' Now send the Read command followed by the address, MSB first gosub sermem_spi_xfer, SERMEM_INST_READ gosub sermem_spi_xfer, pick(0) / $0100 gosub sermem_spi_xfer, pop() AND $FF return sermem_Read: do while pick(0) <> 0 pokeb pick(1), usr(sermem_spi_xfer,0) place 1, pick(1) + 1 place 0, pick(0) - 1 loop drop 2 return sermem_StopRead: gosub sermem_spi_deselect return ' ' ' gosub sermem_ReadBlock
, , ' sermem_ReadBlock: gosub sermem_StartRead, pick(2) ' ' Warning: Serious slime attack! Since SBASIC doesn't have local ' variables, I am going to let the _Read command take what exists ' on the stack. It will remove the top two arguments from the stack ' I tried using pick(), but it didn't work correctly because the ' data stack changed during the subroutine call. gosub sermem_Read gosub sermem_StopRead ' Now get rid of
drop 1 return