We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I have several Microchip 8K EEPROMs on my Cypress FX2LP's I2C bus. To read from these larger ROM chips, a specific I2C protocol must be followed...
* Start token Write 2-byte mem location to I2C address * Start token Read n data bytes from I2C address * Stop token
Unfortunately, using the default EXUSB.lib functions results in a "Stop" token placed on the bus after the EZUSB_WriteI2C() function is called...
* Start token Write 2-byte mem read-location to I2C address 0xA6 * Stop token * Start token Read data from I2C address 0xA6 * Stop token
Looking at the EZUSB.lib source code, most of the work is done by an ISR called "i2c_isr()". Obviously, I must modify this function to omit the "Stop" token under certain conditions while writing to the I2C bus.
The problem is, I can't seem to remap the I2C interrupt vector to my new function. I've rebuilt the EZUSB library without the I2C related functions. But when I build my project, a warning message claims my "new_i2c_isr()" function is unused and will be omitted from the image. In other words, the Keil "interrupt" language extension doesn't seem to work in my code...
void new_i2c_isr (void) interrupt 9 { // new code here }
So how do I map my new_i2c_isr() function to the I2C interrupt vector? Has anyone ever modified the I2C behavior of the EZUSB lib?
I was able to use the CSEG assembly command to map my renamed ISR to the I2C vector. I now generate the correct protocol required by the Microchip EEPROM, although it's still not reading back the correct values yet. I'll have to keep plugging away for now.
I am curious why the "interrupt 9" didn't work, though.
"Unfortunately, using the default EXUSB.lib functions results in a "Stop" token placed on the bus after the EZUSB_WriteI2C() function is called...
* Start token Write 2-byte mem read-location to I2C address 0xA6 * Stop token * Start token Read data from I2C address 0xA6 * Stop token"
This sequence also works. The first WRITE sets up the address register on the EEPROM, and the second READ works as Current Address Read.
"I am curious why the "interrupt 9" didn't work, though."
You added your new_i2c_isr code into a sample source file, which has this pragma at the top of the file.
#pragma NOIV // Do not generate interrupt vector
Cypress examples uses this pragma to generates a custom jump table for the extended interrupt vectors of the USB ISRs, which is supported by EZ-USB hardware.
'#pragma NOIV' affects just to the source file on which it is declared. Make a new source file for your ISR, and you don't need to add the asm code.
Tsuneo
Thanks for the fast comments Tsuneo!
"This sequence also works..."
I did modify the read-process so that the "stop" is not output until the entire read is finished, as required by the EEPROM's manual.
As you predicted, I get the same wrong results as before. So I expect you are right. The problem is not the extra "stop" between the memory location write and the data read. I'll switch back to the default EZUSB.lib functions.
So I'm now back to square one: the EEPROM's internal address pointer is always off by 17 when I read back data. If I write 0x00 through 0x1F (32 values) starting at memory location 0x0000, the first data value is 0x10 (instead of 0x00) when reading from location 0x0000. Very weird
I've put in a support request with Microchip because I'm totally stuck. Hopefully, this behavior is symptomatic of a common mistake that I've made.
"the EEPROM's internal address pointer is always off by 17"
The memory of I2C EEPROM has page, as usual FLASH. The page size depends on the EEPROM size. For 24LC08, the page size is 16 bytes. For sequential WRITE, you can't go over this page boundary in a single session. Sequential READ works regardless of the page boundary.
I was sure the docs said the 24AA64 had a 32-byte page buffer. Hold on a second...
Yep, it has a 32-byte page write buffer.
But that would explain the weird 17th byte thing. Hm. I wonder if the hardware guy soldered on the wrong chip?
Anyway, thanks again.
"Microchip 8K EEPROMs... I wonder if the hardware guy soldered on the wrong chip?"
I2C EEPROM is called after bits, not bytes. If you said just 8K to the guy, he would take it 8K bits, ie. 24LC08 or 24AA08
Confirm the chip marking by your eyes :-)
The hardware guy spec'd the 8KByte chip. We only have two chips in stock, and the other is the tiny 128 bit model. These chips are so tiny I can't read anything.
A bit later...
I just ran a test with a 16-byte write and read. I indeed get the correct data back, except the 16th value is read back wrong.
Either the PDF docs are wrong for the 24AA64 (unlikely) or the wrong chip was used in the build. Since the 16th byte is read back wrong, I suspect the latter.
Thanks for the help Tsuneo.
It's working now. Here's what happened...
#1) The wrong chip was soldered on the board initially so that a 16-byte write buffer was needed. I kept getting weird buffer wrap-around errors when writing.
#2) After putting on the correct 24AA64, the 32-byte buffer still didn't work.
#3) Everything worked as expected once I switched back to the default EXUSB_WriteI2C() function when setting the memory read location.
I was initially led off-trail by the 24AA64 docs. The "Stop" token IS REQUIRED when setting the memory read location. The internal address pointer does not update correctly unless the write is framed with the "Stop" token.
Thanks for the help Tsuneo!
As you seem to conclude this I2C EEPROM problem, this comment may be unnecessary,
"The "Stop" token IS REQUIRED when setting the memory read location."
The repeated START (without STOP) also works. But you need an another state variable (flag) to control the flow in the I2C ISR. It takes fare amount of changes from the source code of the Cypress I2C library.
Both methods work. Then, choose one, good for you :-)