20X2 hardware i2c setup for two slave modules

B4Lamb

Active member
I'm Most confused about how set up for two slave devices (ds3231clock and its associated 24C32B EE prom. The change slave address option in a hi2cin and out basic command doesn't seem to pass the syntax check stage. The details in tech manual 2 is not very good at describing the options or give good examples.

Can you give a simple explanation of how to flip between one address and the other
 
Hi,

As far as I recall, you just need to issue a new HI2CSETUP command each time that you want to change the destination Slave device. This allows the addressing to be changed from I2CBYTE to I2CWORD format as is needed when switching between the RTC and EEPROM.

There are probably better (and shorter) examples elsewhere on the forum, but this thread includes switching between an OLED display and an EEPROM, with a reasonable structure. Basically search through the Code to find references to the two Slave ADdresses, symbolised as OLEDSAD and EPROMSAD.

Cheers, Alan.
 
Several years ago, I wrote a 20X2 program that logged the temperatures of three locations in my house (using 3 x DS18B20s) into an EEPROM. The code relating to the two i2c devices involved is included below: reading the time from a DS1307 and writing a single record to the 24LC256 EEPROM. Note that the two hi2cSetUp commands are specific to the two devices that I used.
Rich (BB code):
#Picaxe 20x2
#Terminal 9600    'Open PE Terminal immediately
'
'--------- Variable Definitions
'
   Symbol EEPROMPtr       = w5  'b10,11   24LC256 i2c EEPROM Chip
   Symbol TemperatureHi   = b13 'w6
   Symbol TempRoofSpace   = w7  'b14,15
   Symbol TempRoofSpaceLo = b14 'w7
   Symbol TempRoofSpaceHi = b15 'w7
   Symbol TempCeiling     = w8  'b16,17
   Symbol TempCeilingLo   = b16 'w8
   Symbol TempCeilingHi   = b17 'b16,17
   Symbol TempRoom        = w9  'b18,19
   Symbol TempRoomLo      = b18 'w9
   Symbol TempRoomHi      = b19 'w9
'
   Symbol bcdSeconds      = b20 'w10   DS1307 data is BCD format.
   Symbol bcdMinutes      = b21 'w10
   Symbol bcdHours        = b22 'w11
   Symbol bcdDay          = b23 'w11
   Symbol bcdDate         = b24 'w12
   Symbol bcdMonth        = b25 'w12
   Symbol bcdYear         = b26 'w13
   Symbol Control         = b27 'w13
'
   Symbol i2cAddrDS1307 = %11010000 '$D0: i2c address of the DS1307 RTC chip
   Symbol i2cAddr24LC256= %10100000 '$A0: i2c upper nibble of 24LC256 EEPROM Chip address
' ----- GetTime: Read time and update variables
'
GetTime:    hi2cSetUp i2cMaster, i2cAddrDS1307, i2cslow, i2cbyte  ' set DS1307 slave address with byte addressing
            hi2cIn [noparse][[/noparse]i2cAddrDS1307[noparse]][/noparse], 0, (bcdSeconds, bcdMinutes, bcdHours, bcdDay, bcdDate, bcdMonth, bcdYear)
            hi2cSetUp i2cMaster, i2cAddr24LC256, i2cslow, i2cword ' set 24LC256 slave address with word addressing
            Return
'
' ----- SaveRecord: Write one record to the 24LC256 EEPROM
'
'  Entry:   tRoofSpace  (word) 12-bit roofspace temperature in 
'           tCeiling    (word) 12-bit temperature below ceiling
'           tRoom       (word) 12-bit temperature in laundry
'           EEPROMPtr   (word) 15-bit address pointer into 24LC256 EEPROM
'  Exit:    EEPROMPtr          updated to next free location
'
SaveRecord: hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdYear)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdMonth)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdDate)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdHours)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdMinutes)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoofSpaceHi)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoofSpaceLo)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempCeilingHi)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempCeilingLo)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoomHi)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoomLo)
            Inc EEPROMPtr
            Return
 
Hi,

As far as I recall, you just need to issue a new HI2CSETUP command each time that you want to change the destination Slave device. This allows the addressing to be changed from I2CBYTE to I2CWORD format as is needed when switching between the RTC and EEPROM.

There are probably better (and shorter) examples elsewhere on the forum, but this thread includes switching between an OLED display and an EEPROM, with a reasonable structure. Basically search through the Code to find references to the two Slave ADdresses, symbolised as OLEDSAD and EPROMSAD.

Cheers, Alan.
Thank you Alan, my mistake which was evident when I read your code example was that i was using byte length address and not word in the master set up for the EEPROM. It was a school boy error.
Thank you.
John
 
Several years ago, I wrote a 20X2 program that logged the temperatures of three locations in my house (using 3 x DS18B20s) into an EEPROM. The code relating to the two i2c devices involved is included below: reading the time from a DS1307 and writing a single record to the 24LC256 EEPROM. Note that the two hi2cSetUp commands are specific to the two devices that I used.
Rich (BB code):
#Picaxe 20x2
#Terminal 9600    'Open PE Terminal immediately
'
'--------- Variable Definitions
'
   Symbol EEPROMPtr       = w5  'b10,11   24LC256 i2c EEPROM Chip
   Symbol TemperatureHi   = b13 'w6
   Symbol TempRoofSpace   = w7  'b14,15
   Symbol TempRoofSpaceLo = b14 'w7
   Symbol TempRoofSpaceHi = b15 'w7
   Symbol TempCeiling     = w8  'b16,17
   Symbol TempCeilingLo   = b16 'w8
   Symbol TempCeilingHi   = b17 'b16,17
   Symbol TempRoom        = w9  'b18,19
   Symbol TempRoomLo      = b18 'w9
   Symbol TempRoomHi      = b19 'w9
'
   Symbol bcdSeconds      = b20 'w10   DS1307 data is BCD format.
   Symbol bcdMinutes      = b21 'w10
   Symbol bcdHours        = b22 'w11
   Symbol bcdDay          = b23 'w11
   Symbol bcdDate         = b24 'w12
   Symbol bcdMonth        = b25 'w12
   Symbol bcdYear         = b26 'w13
   Symbol Control         = b27 'w13
'
   Symbol i2cAddrDS1307 = %11010000 '$D0: i2c address of the DS1307 RTC chip
   Symbol i2cAddr24LC256= %10100000 '$A0: i2c upper nibble of 24LC256 EEPROM Chip address
' ----- GetTime: Read time and update variables
'
GetTime:    hi2cSetUp i2cMaster, i2cAddrDS1307, i2cslow, i2cbyte  ' set DS1307 slave address with byte addressing
            hi2cIn [noparse][[/noparse]i2cAddrDS1307[noparse]][/noparse], 0, (bcdSeconds, bcdMinutes, bcdHours, bcdDay, bcdDate, bcdMonth, bcdYear)
            hi2cSetUp i2cMaster, i2cAddr24LC256, i2cslow, i2cword ' set 24LC256 slave address with word addressing
            Return
'
' ----- SaveRecord: Write one record to the 24LC256 EEPROM
'
'  Entry:   tRoofSpace  (word) 12-bit roofspace temperature in 
'           tCeiling    (word) 12-bit temperature below ceiling
'           tRoom       (word) 12-bit temperature in laundry
'           EEPROMPtr   (word) 15-bit address pointer into 24LC256 EEPROM
'  Exit:    EEPROMPtr          updated to next free location
'
SaveRecord: hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdYear)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdMonth)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdDate)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdHours)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (bcdMinutes)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoofSpaceHi)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoofSpaceLo)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempCeilingHi)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempCeilingLo)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoomHi)
            Inc EEPROMPtr
            Pause 6
            hi2cOut [noparse][[/noparse]i2cAddr24LC256[noparse]][/noparse], EEPROMPtr, (TempRoomLo)
            Inc EEPROMPtr
            Return
Thanks Rich
The main issue for me was I didn't realise, stupidly, I needed word format address for eeprom i2c data transfer.

I don't understand why you needed the [noparse] [/noparse] on each hi2cout instruction and why you could not send all variables to the eeprom as one page as the 24LC××× has 32 byte page lengths.
Regards
John
 
Hi,

Hmm, the [ noparse] may have been a feature/requirement of previous forum software and/or the "Rich" text format. Personally, I avoid the RichText header, because it can consume far too many of the maximum 10,000 characters permitted in a forum post. Also, it looks as if the current forum software might require [ plain] .. [ /plain] instead ?

AFAIK, the "page boundaries" in these serial EEPROMs are not just a "maximum size" for the data, they are "hard" boundaries (which wrap back to the start of each page). It appears that Pete was writing 11 bytes for each record, with the next record being concatonated (from the next pointer position). 11 bytes is just about the most "inconvenient" number, but I would probably pad out each record with 5 nul/zero bytes, or perhaps divide the data into blocks of 4 bytes (with one nul added every 12).

A potential problem with writing individual bytes is not only the slow speed, but I believe each requires a separate page write, so contributes one more cycle to the "Wear Out" of the EEPROM. So it might be being Worn Out ten times faster than necessary, but this may be irrelevant, because the practical lifetime can be into the millions of cycles.

Cheers, Alan.
 
Last edited:
Thanks Rich
The main issue for me was I didn't realise, stupidly, I needed word format address for eeprom i2c data transfer.

I don't understand why you needed the [noparse] [/noparse] on each hi2cout instruction and why you could not send all variables to the eeprom as one page as the 24LC××× has 32 byte page lengths.
Regards
John
Dunno who "Rich" is🙄.

I saw those 'html' style [noparse] [/noparse] statements in the original code when I posted it, so I overwrote that copy with a not-rich formatted version. Somehow the original version has persisted on-line. Anyway, if you need to copy parts of the code, just omit or delete the formatting statements. You just need to put square brackets around the i2c address value.

The code that I didn't post here was for the temperatures to be recorded every 15 minutes. The project ran for a year so that it read the hottest day in summer and the coldest night in winter. It didn't wear out during the year that it ran: Microchip say that they are good for 1,000,000 cycles.
 
Hi,

Hmm, the [ noparse] may have been a feature/requirement of previous forum software and/or the "Rich" text format. Personally, I avoid the RichText header, because it can consume far too many of the maximum 10,000 characters permitted in a forum post. Also, it looks as if the current forum software might require [ plain] .. [ /plain] instead ?

AFAIK, the "page boundaries" in these serial EEPROMs are not just a "maximum size" for the data, they are "hard" boundaries (which wrap back to the start of each page). It appears that Pete was writing 11 bytes for each record, with the next record being concatonated (from the next pointer position). 11 bytes is just about the most "inconvenient" number, but I would probably pad out each record with 5 nul/zero bytes, or perhaps divide the data into blocks of 4 bytes (with one nul added every 12).

A potential problem with writing individual bytes is not only the slow speed, but I believe each requires a separate page write, so contributes one more cycle to the "Wear Out" of the EEPROM. So it might be being Worn Out ten times faster than necessary, but this may be irrelevant, because the practical lifetime can be into the millions of cycles.

Cheers, Alan.
Hi Alan,
The 24L32B eeprom fitted to the DS3231 clock module has 32 bit pages. I'm not sure its correct that only one write to a page is possible if the address is adjusted to avid overriding previous bytes or cause a page boundary wrap around. I'll do some tests later.
The good thing is I'm able to read and write to the eeprom with ease thanks to your help
 
Hi,

I'm not sure its correct that only one write to a page is possible if the address is adjusted to avid overriding previous bytes or cause a page boundary wrap around.
No, that's not what I'm saying. A (Re-)Write of a page always "updates" all 32 bytes (and thus potentially "Wears Out" all 256 bit-cells) within that page.

If the First Address is, for example, $20 then all 32 bytes in the page can be Changed/Updated. But if the First Address is specified as $3F, then the (internal 5-bit hardware) address wraps around to $20 and the remaining 31 bytes (if they have been sent to the chip) will write to $20 to $3E.

The problem with an 11 byte record is that as a prime number it's only possible to write single bytes, or at some time a wrap-around will occur. Thus an 11-byte write to address 22 will wrap the last byte back to address 0, but adding 10 bytes of padding, to start at the next page boundary is rather inefficient.

From the 24C32 Microchip Data Sheet : 4.3 Page Write:

After the receipt of each word*, the six lower order address pointer bits are internally incremented by one. The higher order seven bits of the word address remain constant. ( * Where "word" appears to refer to 4 bits ! )


Cheers, Alan.
 
Hi,


No, that's not what I'm saying. A (Re-)Write of a page always "updates" all 32 bytes (and thus potentially "Wears Out" all 256 bit-cells) within that page.

If the First Address is, for example, $20 then all 32 bytes in the page can be Changed/Updated. But if the First Address is specified as $3F, then the (internal 5-bit hardware) address wraps around to $20 and the remaining 31 bytes (if they have been sent to the chip) will write to $20 to $3E.

The problem with an 11 byte record is that as a prime number it's only possible to write single bytes, or at some time a wrap-around will occur. Thus an 11-byte write to address 22 will wrap the last byte back to address 0, but adding 10 bytes of padding, to start at the next page boundary is rather inefficient.

From the 24C32 Microchip Data Sheet : 4.3 Page Write:

After the receipt of each word*, the six lower order address pointer bits are internally incremented by one. The higher order seven bits of the word address remain constant. ( * Where "word" appears to refer to 4 bits ! )


Cheers, Alan.
Oh now that has totally confused me. Its hard to get my head around it.
my need for data storage in NV memory is indeed very limited. I will always wite 8 bytes to a page and there will be no more than 6 pages needed so just 48 bytes in total. I can afford to be very wasteful of eeprom cells. I'm hoping you say that's very simple.
Cheers,
John
 
Hi,
... I will always write 8 bytes to a page and there will be no more than 6 pages needed so just 48 bytes in total.

Yes, at least by my standards, that is very simple. For just 48 bytes you don't even need to use an external serial EEPROM. All PICaxes have 256 bytes of internal EEPROM which is simply accessed by WRITE and READ instructions. I don't believe there are any Page Boundary restrictions, but its resistance to Wear Out (which applies only when Writing) might be a little shorter. The only thing to be aware of is when/if you Re-Program the PICaxe, its EEPROM will be cleared (to all zeros), unless you put a #NO_DATA directive near the top of the (new) program.

However, there should be no issues using an external serial EEPROM either. If you start from a page boundary address (e.g. 0) and always write blocks of bytes of the same size and a power of 2 up to 32 (e.g. 4 , 8 or16) then the Write will never cross a page boundary. Or simply start each block of data (up to 32 bytes) from the next page boundary ($0 , $20 , $40 , etc.).

Similarly, EEPROM Wear Out is rarely an issue in practice. If you wrote a "bad" program that Wrote to the same address once every second, and ran the PICaxe continuously (24/7), then the EEPROM might wear out after a few weeks. But it's very unlikely to occur even in a long-term, conventional data logging application.

Cheers, Alan.
 
Hi,


Yes, at least by my standards, that is very simple. For just 48 bytes you don't even need to use an external serial EEPROM. All PICaxes have 256 bytes of internal EEPROM which is simply accessed by WRITE and READ instructions. I don't believe there are any Page Boundary restrictions, but its resistance to Wear Out (which applies only when Writing) might be a little shorter. The only thing to be aware of is when/if you Re-Program the PICaxe, its EEPROM will be cleared (to all zeros), unless you put a #NO_DATA directive near the top of the (new) program.

However, there should be no issues using an external serial EEPROM either. If you start from a page boundary address (e.g. 0) and always write blocks of bytes of the same size and a power of 2 up to 32 (e.g. 4 , 8 or16) then the Write will never cross a page boundary. Or simply start each block of data (up to 32 bytes) from the next page boundary ($0 , $20 , $40 , etc.).

Similarly, EEPROM Wear Out is rarely an issue in practice. If you wrote a "bad" program that Wrote to the same address once every second, and ran the PICaxe continuously (24/7), then the EEPROM might wear out after a few weeks. But it's very unlikely to occur even in a long-term, conventional data logging application.

Cheers, Alan.
Good Morning and thank you for your detailed description and options. I had forgotten about the in-built eerom within the Pic. I think though I'll use the simple page boundary address option in the external eeprpm (.... simply start each block of data (up to 32 bytes) from the next page boundary ($0 , $20 , $40 , etc.). That gives me adequate and a simple room to expand if I need it. Yes im totally aware of the 'Wear our' risk due to a bad program that keeps writing unnecessarily to the same address. It will only be used strictly when needed and to avoid loops.
Thank you for your valuables time and effort Alan.
Kind regards ... John
 
Back
Top