|
|
View previous topic :: View next topic |
Author |
Message |
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
I2C slave sends 0x5555, master receives 0xab55 |
Posted: Thu Sep 17, 2020 7:38 am |
|
|
Why can't things be easy?
I am looking for some thoughts on this strange problem I am seeing with an I2C transaction.
The slave is a PIC16LF19156 that I developed, and the master is a PIC24FJ128GA308. Essentially, I am just testing it right now, and I am making it send 0x5555 to the master. However, the master picks up 0xab55. I am positive that it is the master side that is screwing up, because my logic analyzer picks up 0x5555, and my other dev board with a PIC24FJ128GA204 picks it up 0x5555.
Logic analyzer trace: https://sta.sh/01aa8jcoqntz
Both of my masters are running essentially the same code:
Code: | #include <24FJ128GA308.h>
#DEVICE ADC=12
#case
#FUSES ICSP1 // ICD uses PGC1/PGD1 pins
#FUSES NOJTAG // JTAG disabled
#FUSES NODEBUG // No Debug mode for ICD
#FUSES NOWRT // Program memory not write protected
#FUSES NOPROTECT // Code not protected from reading
#FUSES WPDIS // All Flash memory may be erased or written
#FUSES NOWPCFG // Configuration Words page is not erase/write-protected
#FUSES NOBROWNOUT // No brownout reset
#FUSES NODSBOR // BOR disabled in Deep Sleep
#FUSES NOVBATBOR // VBAT BOR Disabled
#FUSES NOLVR // Low Voltage Regulator Disabled
#FUSES NOIOL1WAY // Allows multiple reconfigurations of peripheral pins
#FUSES VREFNORM_CVREFNORM // VREF and CVREF are mapped to their default pins
#FUSES NOIESO // Internal External Switch Over mode disabled
#FUSES NOWDT // No Watch Dog Timer
#FUSES FRC_PLL // Internal Fast RC oscillator with PLL
#FUSES NOOSCIO // OSC2 is clock output
#FUSES SOSC_DIG // SOSC as digital input (using external clock module)
#use delay(clock=32MHz)
#define I2CSTREAM I2C_1
#USE I2C(MASTER, I2C1, STREAM=I2CSTREAM)
#pin_select U2TX=RS232_TX
#pin_select U2RX=RS232_RX
#define PC U2STREAM
#USE RS232(BAUD=115200, UART2, BITS=8, PARITY=N, STOP=1, STREAM=PC, ERRORS, RECEIVE_BUFFER=128)
int16_t conc_get_temperature(void)
{
uint8_t reslo;
uint8_t reshi;
i2c_start(I2CSTREAM);
i2c_write(I2CSTREAM, CONC_ADDR_W);
i2c_write(I2CSTREAM, CONC_REQ_TEMPERATURE);
i2c_start(I2CSTREAM, 1);
i2c_write(I2CSTREAM, CONC_ADDR_R);
reslo = i2c_read(1);
reshi = i2c_read(0);
i2c_stop(I2CSTREAM);
int16_t temp = make16(reshi, reslo);
return temp;
}
int main(void)
{
CLKDIVbits.RCDIV = 0;
delay_ms(500);
while(1)
{
uint16_t temp = conc_get_temperature();
fprintf(PC, "faketemp: %x\r\n", temp);
delay_ms(2000);
}
return 0;
}
|
I have tried swapping out the slave, swapping out the master, but the result is the same.
I also don't see anything in the errata about the I2C module...
EDIT: hrmmm... On the slave there's a 10k pullup and on the master there's a 4k7 pullup on the lines. Is that too strong? But if it really is then why do I receive the low byte properly, but not the high byte?
EDIT2: There is another device on the bus, but it's only reading 1 byte at a time rather than 2, and for that I can read properly.
EDIT3: If I tell it to send 0xAAAA, it sends and receives correctly...
EDIT4: So this appears to be the pattern: If the 64's bit of the lower byte (first value I send) is 1, then the second byte gets a 1-bit left shift + 1. I'm also sure it's not the make16 messing up the number. I printed the two numbers separately.
EDIT5: Solved...? Out of desperation, I put a delay_us(50) in between my two i2c_read() calls and now I am reading things correctly. What gives?
Last edited by dluu13 on Thu Sep 17, 2020 10:27 am; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 17, 2020 10:21 am |
|
|
Quote: |
int16_t conc_get_temperature(void)
{
uint8_t reslo;
uint8_t reshi;
i2c_start(I2CSTREAM);
i2c_write(I2CSTREAM, CONC_ADDR_W);
i2c_write(I2CSTREAM, CONC_REQ_TEMPERATURE);
i2c_start(I2CSTREAM, 1);
i2c_write(I2CSTREAM, CONC_ADDR_R);
reslo = i2c_read(1);
reshi = i2c_read(0);
i2c_stop(I2CSTREAM);
int16_t temp = make16(reshi, reslo);
return temp;
}
|
The CCS manual says:
Quote: |
i2c_start( )
Parameters:
stream - specify the stream defined in #USE I2C
restart:- 2 - new restart is forced instead of start
1 - normal start is performed
0 - (or not specified) – restart is done only if the compiler last encountered a
i2c_start() and no i2c_stop()
Function:
Issues a start condition when in the I2C master mode. After the start
condition the clock is held low until i2c_write() is called. If another
i2c_start() is called in the same function before an i2c_stop() is called,
then a special restart condition is issued.
Note that specific I2C protocol depends on the slave device.
The i2c_start() function will now accept an optional parameter.
If 1 the compiler assumes the bus is in the stopped state.
If 2 the compiler treats this i2c_start() as a restart.
If no parameter is passed a 2 is used only if the compiler
compiled a i2c_start() last with no i2c_stop() since. |
You have put in a '1' as the parameter, but your code shows the i2c bus
is not in a stopped state. Therefore, you should have used a '2' or left
it blank, per the manual. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Thu Sep 17, 2020 10:33 am |
|
|
Thanks PCMP
I did as you said, but it still comes out with the same result.
As per my edit above, it seems that this error depends on the 64's bit of the first byte sent. And I must have posted my edit the same time as you posted your answer... Actually I made it work by putting a 50 us delay between the two reads. Not sure why that makes it work. Puzzling, since the logic analyzer shows that the correct bits are being sent, so I'm very confident that the issue is confined to the master. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Sep 17, 2020 10:39 am |
|
|
Er. It is the last read from the master that needs NACK. You are nacking the
first read, and then sending ACK on the second. Wrong way round...
Code: |
i2c_start(I2CSTREAM);
i2c_write(I2CSTREAM, CONC_ADDR_W);
i2c_write(I2CSTREAM, CONC_REQ_TEMPERATURE);
i2c_start(I2CSTREAM,);
i2c_write(I2CSTREAM, CONC_ADDR_R);
reslo = i2c_read();
reshi = i2c_read(1);
i2c_stop(I2CSTREAM);
|
|
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Thu Sep 17, 2020 11:00 am |
|
|
Ttelmah wrote: | Er. It is the last read from the master that needs NACK. You are nacking the
first read, and then sending ACK on the second. Wrong way round...
Code: |
i2c_start(I2CSTREAM);
i2c_write(I2CSTREAM, CONC_ADDR_W);
i2c_write(I2CSTREAM, CONC_REQ_TEMPERATURE);
i2c_start(I2CSTREAM,);
i2c_write(I2CSTREAM, CONC_ADDR_R);
reslo = i2c_read();
reshi = i2c_read(1);
i2c_stop(I2CSTREAM);
|
|
Hmm? I am NACKing on the second time. From the CCS manual:
Quote: | 0 indicates do not ack
1 indicates to ack
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Sep 17, 2020 12:35 pm |
|
|
The '1' needs to be on the last byte and only on the last byte. The chip needs
to ACK all the earlier bytes, and NACK the last one only. These are both
actually acknowledges, just one is -ve logic. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Thu Sep 17, 2020 1:11 pm |
|
|
Yes, what I mean is that in the CCS manual, it says that 1 is ACK and 0 is NACK. So that's why I have 1 on the earlier byte to ACK, and 0 on the last byte to NACK. |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Thu Sep 17, 2020 3:43 pm |
|
|
As for example ; Code: | i2c_write(DS1338_READ_ADD);
ds1338_time_array[0]=BCDtoINT(i2c_read(1));
ds1338_time_array[1]=BCDtoINT(i2c_read(1));
ds1338_time_array[2]=BCDtoINT(i2c_read(0));
i2c_stop(); |
This works fine. you may wanna try nack last.
By the way, manual says Quote: | ack -Optional, defaults to 1
0 indicates do not ack
1 indicates to ack | so i2c_read(1) and i2c_read() are actually same. _________________ There is nothing you can't do if you try |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 17, 2020 6:12 pm |
|
|
dluu13,
You have a thread here from July 2020, in which find that the speed of
the slave vs. the master is very important.
http://www.ccsinfo.com/forum/viewtopic.php?t=58809
You didn't tell us your slave speed. I wonder if it's the same problem
as before. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Thu Sep 17, 2020 6:50 pm |
|
|
PCM programmer wrote: | dluu13,
You have a thread here from July 2020, in which find that the speed of
the slave vs. the master is very important.
http://www.ccsinfo.com/forum/viewtopic.php?t=58809
You didn't tell us your slave speed. I wonder if it's the same problem
as before. |
Right. I have that slave running with a clock of 32 MHz now. That problem happened because I decreased the clock from 32 MHz to 4 MHz. After we determined that the clock was the cause of the issue, I increased it back to 32 MHz.
My master runs at 32 MHz as well. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 17, 2020 7:23 pm |
|
|
Right, but the essence of that thread was that the slave must be running
faster than the master, to do it without a delay between reads.
Your master runs at 32 MHz, but it's a PIC24, so it takes only 2 clocks
per instruction cycle, compared to the PIC16.
So effectively, that PIC24 master is running at 64 MHz compared to the
PIC16 slave at 32 MHz. This violates the lesson of that previous thread.
If the clock speeds are important to you, then you must keep the delay
between reads. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Thu Sep 17, 2020 7:26 pm |
|
|
Ok that makes sense. But something that confuses me about this now is that the master I was using then was also a PIC24 running at 32 MHz. I suppose that it doesn't matter too much... I don't expect this device to be used anywhere besides in house. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Sep 18, 2020 1:16 am |
|
|
OK.
Let's apologise.
I'm trying to confuse with the NAC/ACK thing....
On standard PIC's the sequence is i2c_read().... i2c_read(0).
However I've had issues on PIC33's with this. For some reason, when I
used a pair of PIC33s, I had to reverse the ACK/NACK behaviour to
get it to work...
Suspect though that this was a coding issue in the I2C library on this
particular PIC :(
This has the I2C with IPMI support.
However lets also comment, that here it is the high byte that is being
corrupted. This suggests a timing problem could be happening.
Key thing is how the slave handles the clock stretch between the bytes.
The timing issues being referred to largely disappeared when CCS
added the I2C_read(2) option for the first byte on the slave after the
bus reversal. How is the slave handling this?.
One other comment. It is impossible to actually know which byte is being
received. Send different values to give a diagnostic on this. So perhaps
0xA55A.
My suspicion is that the clock hold is being released immediately, so you
receive 'one byte behind' all the time. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Fri Sep 18, 2020 7:37 am |
|
|
No worries.
I did end up trying your suggestion anyway, although it did not work.
Regarding the clock stretching: I do use i2c_read(2) on the slave.
Regarding the "other comment": I actually did mess around with the bytes. As I mentioned above, regardless of what I actually send, as long as the 64's bit of the first byte sent = 1, the second byte gets (byte << 1) + 1. That certainly does seem to indicate that the master just straight up misses one of the bits.
PCM Programmer thinks it might have to do with my clock rates, but the strange thing is that on my previous master, I ran the same clock rate as I am now with no issues. The difference is that the old master was a PIC24FJ128GA204 on the Curiosity board, and this one is a PIC24FJ128GA308 on my own board. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Sep 18, 2020 11:18 am |
|
|
OK. The +1 would be the bus floating high after the last bit.
The <<1 is odd though, since it suggests the slave is clocking the
first bit out before the clock from the master. There are no errate
on this chip for the I2C.
I'd suspect it is clocking the first bit, when the clock is released.
I would specify a baud rate on the I2C setup. The default may be
different between the chips, and the I2C rate being abnormally high
could cause problems, especially since this chip does have hardware
slew rate limitation. You might want to try ensuring this is disabled
(on both master and slave chips)
Code: |
#BIT DISSLW=getenv("BIT:DISSLW")
//Then in your initialisation code
DISSLW=TRUE; //disable slew rate limitation
|
|
|
|
|
|
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
|