|
|
View previous topic :: View next topic |
Author |
Message |
valemike Guest
|
i2c: howto make the slave inhibit master's read? |
Posted: Tue Feb 22, 2005 5:49 pm |
|
|
Using a pair of PIC18F chips (with MSSP module), I use CCS's libraries for the Master i2c node, and used Microchip's application note AN735(?) to make interrupt driven i2c functions for the slave.
However, i find that i have to inject a couple ms delays on the Master side to let the slave do its internal computations; otherwise, the master ends up reading 0xFF.
e.g.
1. Master: i2c_start()
2. Master: i2c_write(SLAVE_ADDRESS)
3. Master: i2c_write(COMMAND_ID) // tells the slave i want XX info.
4. Master: i2c_start(); // restart
5. DELAY_MS(xxx)
6. Master: i2c_read();
You see, i need to issue the delay in step #5 in order to let the slave catch up before issuing the i2c_read. How do i configure the slave to force the master to wait? (Is the answer "clock stretching"? If so, then at what point do i set that CKP bit in the slave code?) |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Feb 22, 2005 9:42 pm |
|
|
Step 5 should be i2c_write(SLAVE_ADDRESS + 1)
This is read mode. This will put the slave into read mode where the slave will hold the clock line low. In the interrupt routine, you will load the value into the buffer and then release the clock. Take a look at the SSPSTAT register and the CKP bit. |
|
|
valemike Guest
|
|
Posted: Wed Feb 23, 2005 8:52 am |
|
|
Thanks Mark. I meant to put step "4 1/2" where i send the odd-numbered slave address.
So it is after receiving this odd-numbered slave address write where the slave would set the CKP bit in its ISR? Then based on the preceding write, which is interpreted as a command, then the slave knows what to calculate and return? So it is the i2c_read() that will be locked up until the slave decides to release the CKP bit?
That's my interpretation on your previous answer.
-Mike |
|
|
valemike Guest
|
|
Posted: Wed Feb 23, 2005 4:28 pm |
|
|
1. Master: i2c_start()
2. Master: i2c_write(SLAVE_ADDRESS)
3. Master: i2c_write(COMMAND_ID) // tells the slave i want XX info.
4. Master: i2c_start(); // restart
5. DELAY_MS(xxx)
6. Master: i2c_read();
I'm finding that if i were to halt the PIC slave (using an ICD breakpoint) in the ISR as a response to (2), then there is no clock stretching and the Master zooms right thru this thru 3,4,5,6 and ends up reading 0xFF.
After some experimentation, i found that if i were to stretch the clock in the isr corresponding to (2), (3), (there is an automatic stretch already in (6)), then all goes well without the need for delays in the master code.
Would this liberal sprinkling of stretches and releases in several parts of the isr cause anything to malfunction? So far i haven't found that to be a problem. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Feb 23, 2005 5:36 pm |
|
|
There would be no clock stretching for your step 2. Again, step 5 should be writing to the device with its address +1 or what it really means it with the LSB set. Slave addresses must be even for this reason. Look at the ex_slave example. This is very similar to what you want. Think about how you access a serial eeprom.
1. start
2. write device addr
3. write eeprom addr - this is just like your command
4. start
5. device addr read mode
6. read
7. stop |
|
|
valemike Guest
|
|
Posted: Wed Feb 23, 2005 7:11 pm |
|
|
Mark wrote: |
1. start
2. write device addr
3. write eeprom addr - this is just like your command
4. start
5. device addr read mode
6. read
7. stop |
Oops, forgot to include the device addr read again.
So from the Master side, the code would look like this:
Code: |
void main(void)
{
[snip]
i2c_start(); // send START sequence
i2c_write(SLAVE_ADDRESS); // SLAVE_ADDRESS is even
i2c_write(EEPROM_ADDRESS); // just like command **** READ BELOW!
i2c_start(); // this is actually a "restart"
i2c_write(SLAVE_ADDRESS + 1); // this sets "read" mode
data = i2c_read();
i2c_stop(); // send STOP sequence
} |
The above functions use CCS's i2c library in Master mode. On the slave side, I have most of my slave i2c code in the form of an ISR. #SSP interrupts are triggered when the Master issues an i2c_write() and i2c_read() (and a few other situations cause an SSP interupt, but is irrelevant to this discussion).
Okay, now suppose I have the slave running with an ICD-2 debugger, and the master is running by itself with a programmed PIC. I then set a breakpoint to totally "freeze" the slave at the point where the #ssp ISR determines that this it has received a "write()" from the Master and that this byte is actually an address byte (even number). So the breakpoint gets hit, and the PIC is physically frozen by the ICD. However, I find that the Master continues to run freely and will falsely read '1111111' (ie. 0xFF) because the SDA line remains pulled up by the inactive frozen slave.
Similiarly, even if i don't use a breakpoint, this first write() encountered by the slave's ISR will do some housekeeping (e.g. execute a loop to clear the receive buffer which is actually an array of chars). While the slave's isr sits in its loop clearing an the receive buffer array, then the Master will zoom right past it and attempt to do a successive write() despite the isr not having completed yet.
As a matter of fact, I can execute the Master running the above code, while holding the slave's MCLR low (using a pushbutton). Again, the master's start/write/write/restart/write/read/stop zoom right by.
So what i'm saying is that there is nothing inhibiting the master from overrunning the slave with i2c_write() calls. It seems the only choices are to sprinkle some time delays between successive i2c_writes to let the slave catch up, or force some clock stretching in places where things might take a bit longer, such as loops in the isr even though it is servicing a write by the master.
Then again, probably this would be a good place to use that i2c_poll(?) function.[/b] |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Feb 23, 2005 9:37 pm |
|
|
Writing an even number as the address will not cause the slave to stretch the clock. The odd address is where this should occur. Also, the i2c_write() calls are not infinite waits. There must be a timeout or error condition that occurs. You zooming by is do to the ignoring of these errors. I handle the receive in hardware but do the transmitting in software. I wrote my own routines so that I could have more control over these error conditions. I promised some code so I'll try to get something tomorrow. I been pretty busy at work and today spent most of the day installing wireless billing gateways. Man what an idea. Easy made money |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|