EEPROM on I2C Bus

Discussion to talk about software related topics only.
Post Reply
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

EEPROM on I2C Bus

Post by SeeCwriter »

I'm writing a function to write data to a serial EEPROM via i2c on a NANO54415. I see how to write the data with NB library functions.

After a write the EEPROM goes into a write-cycle for up to 5ms, during which time it cannot be accessed. Rather than spin for 5ms, I want to use the ACK feature of the device to determine if it was in a write-cycle. If the master does a Start and sends the control byte, if the device is in a write-cycle it will not issue an ACK for the control byte. So, will the following work?

while( I2CStart(addr,0,1) == I2C_NO_LINK_RX_ACK ) ;

I don't have hardware yet to test this on. Just want to get a feel if I'm on the right track.

Steve
mbrown
Posts: 61
Joined: Tue Jan 29, 2013 7:12 pm

Re: EEPROM on I2C Bus

Post by mbrown »

Generally, the I2C statuses are used as return codes for the I2C library functions. With the exception of OK, NEXT_READ_OKAY, NEXT_WRITE_OKAY and MASTER_OKAY, the rest of the states are error return codes.

If I understand you correctly, you have an EEPROM that gives an ACK when it's write cycle is finished. Since the ACK is part of the I2C protocol, the functions won't return until the bus transaction is finished. You shouldn't have to continuously poll a start function, in fact that doesn't really make sense, since our libraries implement interrupts. All the libraries do is set up bus transactions, start them, then pend on a semaphore waiting for the bus to respond. When the bus transaction is completed, the interrupt routine posts to the semaphore and the function completes, returning OK or another sensical state (next read okay means you've sent the address byte with the read bit set, next write okay means you've sent the address byte with the write bit cleared, and master okay means you're in master mode with a repeat start waiting for something else to do). If the transaction fails to complete, say the bus is busy, you'll either run into a time-out or get a bus not available state. Speaking of time-outs, they are settable. So if you think your transaction will take at least 5-10ms to complete, you can set it to 5-10ms in the function.

It sounds like you're trying to treat the functions like polling a busy bit in a register, when that's really not the way they work. Setting up the start function will send the first (address) byte across the bus, read and write will read or write one byte after that. Restart will allow you to do a repeat start and stop will close a transmission on the bus if I remember correctly. The send_buf and read_buf commands handle multiple byte transactions but likely still require start and stop commands before and after. The timeout arguments will be repeatedly sent to send or read functions appropriately. All of these again will either return when the action is completed or some sort of error occurs on the bus. You shouldn't have any need to poll a function, that's essentially what the semaphores are doing.

To get a good idea of what a good setup for an I2C bus will look at, take a look at the I2C2Serial example (this will also redeem me if I've misquoted what some of the functions do), which I realize may not have been included with the NANO/MOD platform. I'll include the one from the MOD5270 here. It should just run on your module without change, but you'll either just be sending bytes across your bus one at a time or you'll need two devices to talk to each other. It should at any rate get you started in the right direction.
Attachments
main.cpp
(7.5 KiB) Downloaded 470 times
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: EEPROM on I2C Bus

Post by SeeCwriter »

Thank you for the extended response. Perhaps I'm not doing this correctly, so I will try to explain how I arrived at my solution.

The function I2CStart(), sets up the interrupt handler, commands the I2C peripheral to issue a START, and waits for the bus to go busy, which means the START was successfully issued. I2CStart() then calls I2CSend() to send the control byte to the selected I2C device, and waits on a semaphore. When the I2C interrupt routine runs at the completion of sending the control byte, I believe it takes the I2C_CR_TX path because I set argument bRead_Not_Write to false in the call of I2CStart(). In that path, the first thing the handler does is to check for an acknowledge from the slave. If one hasn't been detected, it sets variable MASTER_INT_STATUS to I2C_NO_LINK_RX_ACK, posts to the semaphore, and returns. What's not clear to me is that, in I2CSend(), when it gets the semaphore, what value is returned by OSSemPend(). From the manual, it appears to return one of two values, 0 for no error and 10 for a timeout. But since nothing timed-out, I'm not sure. In any case, I2CSend() will return the value of MASTER_INT_STATUS to I2CStart(), which is copied to variable I2CState in I2CStart(), and I2CStart() returns I2CState.

So even though the I2C bus is interrupt driven, it appears that spinning on I2CStart() until I no longer receive a No Acknowledge return value would be one way of determining if the EEPROM had completed its write-cycle. Though I may have to insert a I2CStop() call if OSSemPend() acts differently than I expect.

The other way would be to create a loop that would have to be hand crafted to execute enough do-nothing instructions to delay 5msec. A kludge option.

As you noted, there were no Nano example of I2C usage. I will look through the file you sent and see what I can learn.

Steve
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: EEPROM on I2C Bus

Post by rnixon »

When you call the OS pend function the second parameter is the max time to wait. If you exceed that time the pend will return with a timeout error.
mbrown
Posts: 61
Joined: Tue Jan 29, 2013 7:12 pm

Re: EEPROM on I2C Bus

Post by mbrown »

The function I2CStart(), sets up the interrupt handler, commands the I2C peripheral to issue a START, and waits for the bus to go busy, which means the START was successfully issued. I2CStart() then calls I2CSend() to send the control byte to the selected I2C device, and waits on a semaphore. When the I2C interrupt routine runs at the completion of sending the control byte, I believe it takes the I2C_CR_TX path because I set argument bRead_Not_Write to false in the call of I2CStart(). In that path, the first thing the handler does is to check for an acknowledge from the slave. If one hasn't been detected, it sets variable MASTER_INT_STATUS to I2C_NO_LINK_RX_ACK, posts to the semaphore, and returns.
Good so far.
What's not clear to me is that, in I2CSend(), when it gets the semaphore, what value is returned by OSSemPend(). From the manual, it appears to return one of two values, 0 for no error and 10 for a timeout. But since nothing timed-out, I'm not sure.
So close, you have all the pieces though. You said yourself, you either get no error or timeout. Nothing timed-out, so you get ... no error. Since No Error != OS_TIMEOUT, you skip that conditional.
In any case, I2CSend() will return the value of MASTER_INT_STATUS to I2CStart(), which is copied to variable I2CState in I2CStart(), and I2CStart() returns I2CState.
So at this point, we'll have returned I2C_NO_LINK_RX_ACK. But that's the end of the cycle. If you issue another start command, it doesn't continue the wait in your last byte transfer. It assumes you'll be issuing a second byte. It will likely look at the bus which I assume is still busy and you'll more likely time out. I think what you're interested in is actually covered in section 42.3.7 of the reference manual, Clock Synchronization and Arbitration. After the first byte tranfer, you're device will drag the clock cycle to let the master (Netburner device) know that it's not ready yet. This may slow down your I2C bus, I'm quite honestly not sure. To be honest, I think the only reason I've ever seen a NO_LINK_RX_ACK error, it was because there was simply no slave device on the line.

I had thought your problem fell into the timeout problem, but it seems more likely this will be a clock timing one. You may have to reconsider how fast your bus transfers at, though 1/(5ms) is 200Hz, not a very usable speed. Do you have a datasheet for this part? The behavior is kind of curious. I don't know that I've seen this kind of problem before.
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: EEPROM on I2C Bus

Post by SeeCwriter »

Yes, I understand the OSSemPend() will return with a timeout if the timeout time has expired. But there should be no timeout in my implementation. The interrupt handler with detect that no acknowledge was received and set a NO_ACK status and return immediately. No timeout. In that case I will need to issue an I2CStop() before calling I2CStart() again.

Steve
SeeCwriter
Posts: 630
Joined: Mon May 12, 2008 10:55 am

Re: EEPROM on I2C Bus

Post by SeeCwriter »

I posted my previous response too soon.
I had thought your problem fell into the timeout problem, but it seems more likely this will be a clock timing one. You may have to reconsider how fast your bus transfers at, though 1/(5ms) is 200Hz, not a very usable speed. Do you have a datasheet for this part? The behavior is kind of curious. I don't know that I've seen this kind of problem before.
If you are referring to the EEPROM, then yes I have a datasheet. It's a Microchip 24LC1025. It has a max clock frequency of 400kHz. The issue I'm trying to handle is writing either large blocks of data or multiple non-contiguous parameters of data to the EEPROM. When you write data to an EEPROM, it enters a write-cycle of 5msec when it receives a STOP. During that time, the device cannot be accessed. So if I want to do multiple writes I have to wait for the write-cycle to complete before I can continue. The only method the device provides of detecting when its in a write-cycle is that it won't acknowledge receiving the control/address byte.

Steve
mbrown
Posts: 61
Joined: Tue Jan 29, 2013 7:12 pm

Re: EEPROM on I2C Bus

Post by mbrown »

Okay, now I'm seeing the whole picture. Funny how working with incomplete information will do that.

Yeah, looking at the datasheet, it does appear as though you can continuously send the first control byte and wait for it to acknowledge according to section 7.0. I quite honestly didn't understand what you were saying before. It sounded like you were trying to say, you send the control byte the first time, then wait until it's ready to start writing then send it a new byte then wait and wait, wasn't making all that much sense.

What looks like is going on is you are allowed to write your own byte or one page of data, but then you have to wait for the data to transfer from the buffers to the appropriate memory locations, which makes sense. You won't have to wait to write the first byte/page of data, but subsequent bytes/pages need to wait for the buffers to be cleared first, which means you can indeed write:

Code: Select all

 
while( I2CStart(addr,0,1) == I2C_NO_LINK_RX_ACK ) ;
At any rate, between what you've noted to me, it seems like you've got a pretty good handle on how it all should work. If anything else comes up or if that for some reason doesn't work, let me know what happens instead, I'd be curious.
Post Reply