View previous topic :: View next topic |
Author |
Message |
temtronic
Joined: 01 Jul 2010 Posts: 9081 Location: Greensville,Ontario
|
|
Posted: Mon Sep 17, 2018 12:28 pm |
|
|
I'd add the speed option to FORCE the compiler to put the same speed in both master and slave. Relying on the 'default' is never a good idea. After all MY default won't be the same as what YOU want as a default....
Same holds true for the force_hw option. Look at the listing, maybe the compiler is doing a SW I2C and not HW. SW relies upn bitbanging and timing could be off just a tad..
just ideas to ponder...
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19195
|
|
Posted: Mon Sep 17, 2018 12:35 pm |
|
|
No. Don't do this..
Setting a speed in slave mode, on some chips can result in invalid bit patterns in the I2C configuration register.
Caveat. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19195
|
|
Posted: Mon Sep 17, 2018 12:44 pm |
|
|
With NO_STRETCH selected the master device must clock the I2C slower than the slave can handle. So (for instance), the slave needs to be able to get into it's IRQ handler, and have read the registers, before the next byte arrives. It'll fail if this is not the case.
STRETCH is normally used. NO_STRETCH is only needed on a couple of particular PIC's that have I2C hardware issues. If your PIC doesn't list a stretch issue in it's data sheet, then the stretch resulting in hanging, means your IRQ handler is not correctly reading the registers. Remember when the bus is reversed, the IRQ, must first read the address byte and then write the first byte of the reply, in the single routine.
Your problem is that on state 0x80, you must first read then write. Your code is not reading in this state.
Leave stretch enabled, and fix this. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 17, 2018 12:49 pm |
|
|
The NO_STRETCH solved the bus hanging in the test program but not in my full program. The CCS manual says I'm using software unless I FORCE_HW.
As soon as I let the slave try a single read it hangs. I'm suspecting I have not set up something properly like cpu speed, or there is a problem in the compiler (my last resort). The errata does not show problems for this chip (revision 3 showing in my programmer if 0000011 means that).
I will check what you suggested. Remember it all works with a 16F722.
If I comment out the last if lines it still hangs, besides it reads first does it not?
Errata shows OSTS bit remains clear (Oscillator start up timer), and MSSP SPI Master Mode buffer full bit of MSSP interrupt flag bit becomes set half SCK cycle too early. I don't think these would be a problem. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19195
|
|
Posted: Tue Sep 18, 2018 11:57 am |
|
|
I was not forgetting it works on another chip.
PIC's differ. Some will absolutely require the read before write or the I2C will go to an indeterminate state. Many of the older chips though will accept a write only. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Tue Sep 18, 2018 1:07 pm |
|
|
Thanks Ttelmah,
I think I understand now. Do you mean adding "incoming = i2c_read ();" as shown below fourth line from bottom? I will try that.
Code: | // Interrupt on I2C
#INT_SSP
void ssp_interrupt () // have an interrupt
{
int incoming, state; // variables
state = i2c_isr_state (); // get state
if (state < 0x80) // master is sending data
{
incoming = i2c_read (); // throw away device address if state = 0
if (state == 1) // first data received is port speed
p_speed = incoming;
if (state == 2) // second data received is stbd speed
s_speed = incoming;
if (state == 3) // third data received is status reset
status_reset = incoming;
}
if (state >= 0x80) // master is requesting data from slave
{
incoming = i2c_read ();
i2c_write (side_thr_status); // send side thruster status
}
} |
Edit: No that did not work. Surely the ISR had to have read before getting this far? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19195
|
|
Posted: Wed Sep 19, 2018 12:15 am |
|
|
No. You are omitting states....
Think about it. You only read if the state is <0x80. So it'll get here without having already read.
Problem is though, you only want the extra read in state 0x80. In state 0x81, this is _not_ required/wanted.
State 0x0. Read. Byte is address. Ignore.
State 0x1..0x79. Read. Bytes are data
State 0x80. Read using i2c_read(2), then preload first byte of reply.
State 0x81. Just write.
Getting the sequencing right is important. Look at the slave example:
Code: |
{
unsigned int8 state, incoming;
state = i2c_isr_state();
//Note <= here
if(state <= 0x80) //Master is sending data
{
if(state == 0x80) //Now note == here
incoming = i2c_read(2); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
else
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
else if(state >= 2 && state != 0x80) //Received byte is data
buffer[address++] = incoming;
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(buffer[address++]);
}
}
|
Note that the read routine is being called here on state==0x80 with i2c_read(2)... |
|
|
|