PDA

View Full Version : 16F690 and 24LC16B memory - can't WRITE 8 different bytes in a row



flotulopex
- 29th December 2020, 20:47
Hi there,

I'm having trouble writing 8 bytes to a 24LC16B memory chip.

In fact, I can write 8 consecutive bytes but it seems only the last byte I want to program is written to all 8 positions.

Even after reading the DS many times knowing there is something particular when writing less than 16 bytes (...don't still understand everything for sure :D), I can't see what am I missing.

8979

Any clue?


'======= FUSES ================================================== ==================================
' PIC 16F690 Fuses (MPASM)

' Internal oscillator
@ __config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_INTRC_OSC_NOCLKOUT &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF

@ ERRORLEVEL -306

'======= REGISTERS ================================================== ===============================
' Registers 76543210
OPTION_REG = %10000000 ' Pull-Ups disabled
OSCCON = %01110000 ' Internal oscillator
ANSEL = %00000000 ' analog inputs Channels 0 to 7
ANSELH = %00000000 ' analog inputs Channels 8 to 11
WPUA = %00000000 ' weak pull-ups
WPUB = %00000000 ' weak pull-ups
ADCON0 = %00000000 ' Select the VP6 channel as ADC input bits5:2 (xx1101xx)
ADCON1 = %00000000 ' Set FRC
VRCON = %00000000 ' VP6 reference
CM1CON0 = %00000000 ' Comparator1 Module
CM2CON0 = %00000000 ' Comparator2 Module

TRISA = %00000000 ' Input/Output (0 to 5)
PORTA = %00000100 ' High/Low (0 to 5)
TRISB = %00000000 ' Input/Output (4 to 7)
PORTB = %00000000 ' High/Low (4 to 7)
TRISC = %00000000 ' Input/Output (0 to 7)
PORTC = %01000000 ' High/Low (0 to 7)

'======= DEFINES ================================================== ================================
DEFINE OSC 8
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE NO_CLRWDT 1 ' Don't waste cycles clearing WDT

'======= VARIABLES ================================================== ==============================
Ser_Out VAR PORTA.2 ' Serial Out
EeWP VAR PORTC.3 ' memory Write Protect
SCL VAR PORTC.6 ' i2c Clock pin [6]
SDA VAR PORTC.7 ' i2c Data pin [5]
Cntr VAR BYTE ' just a counter
Ser_Mode VAR word ' serial com baudrate
Mem_Loc var BYTE ' holds the user's code memory place (000..255)
Temp VAR WORD ' for WORD sized calculation
EeVal VAR BYTE(8) ' array that holds the numbers in the Eeprom
EeCtrl var BYTE ' 4 control bits + 3 memory block selector bits
EeAddress var BYTE ' 24LC16B address (0..255)
EeBlock var BYTE ' holds memory block number (0..7)

'======= INITIALIZE ================================================== =============================
Cntr = 0
Ser_Mode = 84 ' 9600bps
Mem_loc = 0
Temp = 0
EeCtrl = 0
EeAddress = 0
EeBlock = 0
For Cntr = 0 to 7
EeVal(Cntr) = Cntr ' initialize EeVal
NEXT
HIGH Ser_Out ' avoid serial data garbage @ startup

'======= TEST ================================================== ===================================
Mem_loc = 45 ' put here an address between 0..255 to write the data to

'======= PROGRAM ================================================== ================================
MAIN:
' Calculate control byte
Temp = Mem_loc * 8 ' 24LC16B's starting memory position
EeBlock = Temp / 256 ' 24LC16B's 0..7 memory block number
EeAddress = Temp // 256 ' 24LC16B's 0..255 memory position

' Get the control byte according to block [ 0..2047] [0..255]
IF Eeblock = 0 THEN EeCtrl = $A0 ' 0..255 0..31
IF Eeblock = 1 THEN EeCtrl = $A2 ' 256..511 32..63
IF Eeblock = 2 THEN EeCtrl = $A4 ' 512..767 64..95
IF Eeblock = 3 THEN EeCtrl = $A6 ' 768..1023 96..127
IF Eeblock = 4 THEN EeCtrl = $A8 ' 1024..1279 128..159
IF Eeblock = 5 THEN EeCtrl = $AA ' 1280..1535 160..191
IF Eeblock = 6 THEN EeCtrl = $AC ' 1536..1791 192..223
IF Eeblock = 7 THEN EeCtrl = $AE ' 1792..2047 224..255

' Show the input I'm using for this test
SEROUT2 Ser_Out, Ser_Mode,["Mem_Loc : ",DEC Mem_Loc,10,"EeBlock : ",_
DEC3 EeBlock,10,"EeAddress: ",DEC3 EeAddress,10,"CTRL : ",BIN EeCtrl,13,10]

' VARIANT 1 - WRITE 8 same bytes to memory = works but...
EeWP = 0
PAUSE 10
For Cntr = 0 to 7
i2cwrite SDA,SCL,EeCtrl,EeAddress,[33]
PAUSE 10
NEXT Cntr
EeWP = 1

'' VARIANT 2 - WRITE 8 different bytes to memory = not working
'EeWP = 0 ' Unprotect memory
'PAUSE 10
'For Cntr = 0 to 7
' i2cwrite SDA,SCL,EeCtrl,EeAddress,[Cntr]
' PAUSE 10
'NEXT Cntr
'EeWP = 1

'' VARIANT 3 - WRITE 8 different bytes to memory = not working
'EeWP = 0
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[EeVal(0),EeVal(1),EeVal(2),EeVal(3),_
' EeVal(4),EeVal(5),EeVal(6),EeVal(7)]
'EeWP = 1

'' VARIANT 4 - WRITE 8 different bytes to memory = not working
'EeWP = 0 ' Unprotect memory
'PAUSE 10
'For Cntr = 0 to 7
' i2cwrite SDA,SCL,EeCtrl,EeAddress,[EeVal(Cntr)]
' PAUSE 10
'NEXT Cntr
'EeWP = 1

'' VARIANT 5 - WRITE 8 different bytes to memory = not working
'EeWP = 0
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[1]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[2]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[3]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[4]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[5]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[6]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[7]
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[8]
'PAUSE 10
'EeWP = 1

' READ 8 bytes from memory
For Cntr = 0 to 7
i2cread SDA,SCL,EeCtrl,EeAddress,[EeVal(Cntr)]
NEXT Cntr

' display what's in the memory chip
SEROUT2 Ser_Out, Ser_Mode,[DEC3 EeVal(0)," ",DEC3 EeVal(1)," ",DEC3 EeVal(2)," ",_
DEC3 EeVal(3)," ",DEC3 EeVal(4)," ",DEC3 EeVal(5)," ",DEC3 EeVal(6)," ",DEC3 EeVal(7),13,10,10]

end

richard
- 29th December 2020, 23:19
try




' VARIANT 5 - WRITE 8 different bytes to memory
EeWP = 0
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[1]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[2]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[3]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[4]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[5]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[6]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[7]
EeAddress=EeAddress+1
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[8]
PAUSE 10
EeWP = 1


or just
i2cwrite SDA,SCL,EeCtrl,EeAddress,[1,2,3................] ;within block boundary

flotulopex
- 30th December 2020, 07:57
Thanks Richard,

I already corrected the address incrementing and also forgot to mention I already tried the ..[1,2,3,..] variant too.

All without any success... :confused:

See the results in two different memory locations (45 and 0)...

>>> Variant 5
8981
8983


>>> Variant 6
8982
8984




'======= FUSES ================================================== ==================================
' PIC 16F690 Fuses (MPASM)

' Internal oscillator
@ __config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_INTRC_OSC_NOCLKOUT &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF

@ ERRORLEVEL -306

'======= REGISTERS ================================================== ===============================
' Registers 76543210
OPTION_REG = %10000000 ' Pull-Ups disabled
OSCCON = %01110000 ' Internal oscillator
ANSEL = %00000000 ' analog inputs Channels 0 to 7
ANSELH = %00000000 ' analog inputs Channels 8 to 11
WPUA = %00000000 ' weak pull-ups
WPUB = %00000000 ' weak pull-ups
ADCON0 = %00000000 ' Select the VP6 channel as ADC input bits5:2 (xx1101xx)
ADCON1 = %00000000 ' Set FRC
VRCON = %00000000 ' VP6 reference
CM1CON0 = %00000000 ' Comparator1 Module
CM2CON0 = %00000000 ' Comparator2 Module

TRISA = %00000000 ' Input/Output (0 to 5)
PORTA = %00000100 ' High/Low (0 to 5)
TRISB = %00000000 ' Input/Output (4 to 7)
PORTB = %00000000 ' High/Low (4 to 7)
TRISC = %00000000 ' Input/Output (0 to 7)
PORTC = %01000000 ' High/Low (0 to 7)

'======= DEFINES ================================================== ================================
DEFINE OSC 8
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE NO_CLRWDT 1 ' Don't waste cycles clearing WDT

'======= VARIABLES ================================================== ==============================
Ser_Out VAR PORTA.2 ' Serial Out
EeWP VAR PORTC.3 ' memory Write Protect
SCL VAR PORTC.6 ' i2c Clock pin [6]
SDA VAR PORTC.7 ' i2c Data pin [5]
Cntr VAR BYTE ' just a counter
Ser_Mode VAR word ' serial com baudrate
Mem_Loc var BYTE ' holds the user's code memory place (000..255)
Temp VAR WORD ' for WORD sized calculation
EeVal VAR BYTE(8) ' array that holds the numbers in the Eeprom
EeCtrl var BYTE ' 4 control bits + 3 memory block selector bits
EeAddress var BYTE ' 24LC16B address (0..255)
EeBlock var BYTE ' holds memory block number (0..7)

'======= INITIALIZE ================================================== =============================
Cntr = 0
Ser_Mode = 84 ' 9600bps
Mem_loc = 0
Temp = 0
EeCtrl = 0
EeAddress = 0
EeBlock = 0
For Cntr = 0 to 7
EeVal(Cntr) = Cntr ' initialize EeVal
NEXT
HIGH Ser_Out ' avoid serial data garbage @ startup

'======= TEST ================================================== ===================================
Mem_loc = 45 ' put here an address between 0..255 to write the data to

'======= PROGRAM ================================================== ================================
MAIN:
' Calculate control byte
Temp = Mem_loc * 8 ' 24LC16B's starting memory position
EeBlock = Temp / 256 ' 24LC16B's 0..7 memory block number
EeAddress = Temp // 256 ' 24LC16B's 0..255 memory position

' Get the control byte according to block [ 0..2047] [0..255]
IF Eeblock = 0 THEN EeCtrl = $A0 ' 0..255 0..31
IF Eeblock = 1 THEN EeCtrl = $A2 ' 256..511 32..63
IF Eeblock = 2 THEN EeCtrl = $A4 ' 512..767 64..95
IF Eeblock = 3 THEN EeCtrl = $A6 ' 768..1023 96..127
IF Eeblock = 4 THEN EeCtrl = $A8 ' 1024..1279 128..159
IF Eeblock = 5 THEN EeCtrl = $AA ' 1280..1535 160..191
IF Eeblock = 6 THEN EeCtrl = $AC ' 1536..1791 192..223
IF Eeblock = 7 THEN EeCtrl = $AE ' 1792..2047 224..255

' Show the input I'm using for this test
SEROUT2 Ser_Out, Ser_Mode,["Mem_Loc : ",DEC Mem_Loc,10,"EeBlock : ",_
DEC3 EeBlock,10,"EeAddress: ",DEC3 EeAddress,10,"CTRL : ",BIN EeCtrl,13,10]

' VARIANT 1 - WRITE 8 same bytes to memory = works
'EeWP = 0
'PAUSE 10
'For Cntr = 0 to 7
' i2cwrite SDA,SCL,EeCtrl,EeAddress,[33]
' PAUSE 10
'NEXT Cntr
'EeWP = 1

'' VARIANT 2 - WRITE 8 different bytes to memory = not working
'EeWP = 0 ' Unprotect memory
'PAUSE 10
'For Cntr = 0 to 7
' i2cwrite SDA,SCL,EeCtrl,EeAddress,[Cntr]
' PAUSE 10
'NEXT Cntr
'EeWP = 1

'' VARIANT 3 - WRITE 8 different bytes to memory = not working
'EeWP = 0
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[EeVal(0),EeVal(1),EeVal(2),EeVal(3),_
' EeVal(4),EeVal(5),EeVal(6),EeVal(7)]
'EeWP = 1

'' VARIANT 4 - WRITE 8 different bytes to memory = not working
'EeWP = 0 ' Unprotect memory
'PAUSE 10
'For Cntr = 0 to 7
' i2cwrite SDA,SCL,EeCtrl,EeAddress,[EeVal(Cntr)]
' PAUSE 10
'NEXT Cntr
'EeWP = 1

'' VARIANT 5 - WRITE 8 different bytes to memory = not working
'EeWP = 0
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[1]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[2]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[3]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[4]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[5]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[6]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[7]
'EeAddress=EeAddress+1
'PAUSE 10
'i2cwrite SDA,SCL,EeCtrl,EeAddress,[8]
'EeAddress=EeAddress+1
'PAUSE 10
'EeWP = 1

' VARIANT 6 - WRITE 8 different bytes to memory = not working
EeWP = 0
PAUSE 10
i2cwrite SDA,SCL,EeCtrl,EeAddress,[1,2,3,4,5,6,7,8]
EeWP = 1


' READ 8 bytes from memory
For Cntr = 0 to 7
i2cread SDA,SCL,EeCtrl,EeAddress,[EeVal(Cntr)]
NEXT Cntr

' display what's in the memory chip
SEROUT2 Ser_Out, Ser_Mode,[DEC3 EeVal(0)," ",DEC3 EeVal(1)," ",DEC3 EeVal(2)," ",_
DEC3 EeVal(3)," ",DEC3 EeVal(4)," ",DEC3 EeVal(5)," ",DEC3 EeVal(6)," ",DEC3 EeVal(7),13,10,10]

' List all memory locations (0..255)
' Mem_Loc = Mem_Loc + 1
' IF Mem_Loc = 0 THEN END

' GOTO MAIN

end

richard
- 30th December 2020, 08:13
keep is simple and clear/concise you need to supply 16 bit address $a0 + block <<1 + r/rw [0 for pbp] + eeaddress [0-255]

' VARIANT 6 - WRITE 8 different bytes to memory = not working
EeWP = 0
PAUSE 10

EeCtrl=$a0 + 2 ;using block 1 ie 1<<1=2
i2cwrite SDA,SCL,EeCtrl,EeAddress,[1,2,3,4,5,6,7,8]
EeWP = 1

flotulopex
- 30th December 2020, 10:03
This is what I get with your suggestion:

EeCtrl=$a0 + 2 ;using block 1 ie 1<<1=2
i2cwrite SDA,SCL,EeCtrl,0,[1,2,3,4,5,6,7,8]
EeWP = 18986


Something is also even more confusing to me. As you wrote, the address has to be WORD sized - this is also stated in the DS.

In my code, I have it ("EeCtrl") as a BYTE. If I change it to a WORD, it doesn't make any difference.

Your last suggestion with a WORD sized EeCtrl var gives this result:

8987


Maybe I'm messing things up in the I2CWRITE command because I understand it this way and both vars (EeCtrl and EeAddress) are looking to be BYTE long:
8988


To be honnest, I don't get that thing with the WORD sized address...

richard
- 30th December 2020, 10:28
the closest eprom i have is a xc24c16 which is pretty similar


this works for me


DEFINE OSC 8
sda var portc.1
sck var portc.2
TMP VAR byte[3]



osccon=$70 '8 mhz
ansel=0 'dig i/o
CMCON0=7 ' compare off
trisa=%001110
trisc=%111111


serout2 porta.0,84, ["ready ",13,10]

i2cwrite sda,sck,$aa,$38,[1,30,52]



main:







i2cread sda,sck,$aa,$38,[str tmp \3 ]


serout2 porta.0,84, ["d " , #tmp[0] ,"," , #tmp[1] ,"," , #tmp[2] ,",",13,10]

pause 4000
goto main

richard
- 30th December 2020, 10:37
To be honnest, I don't get that thing with the WORD sized address...
it's constructed as i stated and sent via i2cwrite as to single bytes ,big end first

flotulopex
- 30th December 2020, 14:32
the closest eprom i have is a xc24c16...

Thank you very much Richard.

Unfortunately, even with your code example, it looks hopeless :frown:

I should be able to grab another identical chip (or maybe a 24LC64...) by tomorrow or the day after.

flotulopex
- 30th December 2020, 15:58
Sorry to ask again Richard, but I really don't understand this "WORD" story. I'm french speaking so I may not fully understand your explanation :o

In "i2cwrite sda,sck,$aa,$38,[1,30,52]", $AA (=EeCtrl) and $38 (=EeAddress) have BYTE sizes, no?

Do you mean the I2C command will transform the two BYTE variables in one WORD sized one?

richard
- 30th December 2020, 21:04
the control word to address an individual memory cell is 16 bits long for that eeprom
made up as ->
$a0 + block <<1 + r/rw [0 for pbp] + eeaddress [0-255]
for example block=5,cell 0x38
0xA0 + 5<<1 + 0 = 0xAA , high byte of word
address=0x38 , low byte of word
this word is transmitted as two bytes, big end first ,

other eeproms have other schemes where cell address is a word and the device control address byte is a constant
based on address pins plus device code.
address =0x538
i2cwrite sda,sck,$a0,address,[1,30,52]


Do you mean the I2C command will transform the two BYTE variables in one WORD sized one?
no , the eeprom will interpret the two bytes as a 16 bit value

flotulopex
- 31st December 2020, 21:45
Thanks a lot for your patience and clear explanation :wink:

BTW, I changed my chip...and all is working fine now.

I've put my last working test program in attachment.