|
|
View previous topic :: View next topic |
Author |
Message |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 29, 2016 6:04 pm |
|
|
Quote: |
The Master appears to receive the information correctly but the
information received is just not what it should be receiving.
I don't know if the slave is not sending what it should, the master is not
reading as it should or what may be wrong. |
Make a test program for each PIC that only tests the i2c. Remove all
CAN bus code. Load the slave with dummy data. Example: 0x01, 0x23,
0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF. Then test your Master/Slave
code. See if it works. If it doesn't work, simplify the programs until
it does work. Then start adding complexity such as reading multiple bytes.
----------------------
How to make and test i2c Master/Slave programs that read one byte
from the slave:
Make the i2c slave using the CCS example file, Ex_slave.c.
Quote: | c:\program files\picc\examples\ex_slave.c |
Edit the #use i2c() line, and also the #include line for the PIC and
the #fuses and #use delay() to fit your project.
Then use the i2c bus scanner program to test if the slave is working.
If it's working, the scanner program will report the slave address.
http://www.ccsinfo.com/forum/viewtopic.php?t=49713
When the Ex_slave.c example is working, then use this Master code
to make your i2c master. Test it with the slave (made from Ex_slave.c).
It should work.
http://www.ccsinfo.com/forum/viewtopic.php?t=32368&start=3 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sat Jul 30, 2016 4:22 am |
|
|
His I2C code is fundamentally flawed. Pointed this out already.
Several important things won't be handled correctly. Result 'indeterminate'.... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Sat Jul 30, 2016 8:23 am |
|
|
This is one of those...
start over, start small, test each 'function' then proceed.
Jay |
|
|
murgui
Joined: 23 Dec 2015 Posts: 37
|
|
Posted: Sun Jul 31, 2016 5:44 am |
|
|
Hi. Thank you for all the information. I followed PCM Programmer's "guide". It worked fine. The 'raw' slave communicated with the 'raw' master. Then I implemented exactly the same code at my initial slave code. Everything worked fine. Now, I simply modified the information sent by the slave by another byte which is a real sensor data. It still sends me a B, how can it be possible?
My codes are right now like this:
Master
Code: |
#include <18F2685.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, BROWNOUT, PUT,NOMCLR,NOLVP
#use delay(int=16M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3,slow=150000)
void main()
{
int8 data;
while(1){
// Write the letter 'B' to the slave board. I tryed later with an A
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write('B'); //or A
i2c_stop();
// Read from the slave board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
data = i2c_read(0);
i2c_stop();
printf("read %c \n\r", data);
delay_ms(5000);
}
}
|
Slave
Code: |
#include <16F1826.h>
#fuses HS,NOWDT,NOMCLR,NOPROTECT,NOLVP
#use delay(int=16000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2)
#use i2c(SLAVE, SDA=PIN_B1, SCL=PIN_B4, address=0xa0,slow=150000)
BYTE address, buffer[0x10];
#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state <= 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming;
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}
void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {
printf("%c",buffer[address]);
delay_ms(500);
}
}
|
So the result of the communication is a B at any moment. What might be happening? Even if I change the sent character to an A, it still reads a B. It's ridiculous. I read the variable by serial port that the slave is suppoused to receive and return and it's an A, where is coming the B from?
Also, I don't undertand this part of the code:
Code: | incoming = i2c_read();
if(state == 1) //First received byte is address
address = incoming;
if(state == 2) //Second received byte is data
buffer[address] = incoming; |
state is a value let's say 1 the program only should assign 12c_read() to adress. When is buffer[adress] being assigned? Is the #INT_SSP run at every i2c_write from the master?
Is state automatically updated every time a i2c movement exists or it has to pass though state = i2c_isr_state(); every time? I guess it has to pass but then, when the master sends the B why is it going to save it in buffer[adress] if state=1?
Thank you for all the support.
Murgui |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Aug 01, 2016 7:35 am |
|
|
Murgui wrote: | if I change the sent character to an A, it still reads a B. |
I put together some hardware to test your problem, and I got the same
result as you got. I'll work on finding the reason for it later today. |
|
|
murgui
Joined: 23 Dec 2015 Posts: 37
|
|
Posted: Mon Aug 01, 2016 7:52 am |
|
|
Thank you very much. This weekend I read many many(really, several) examples and sundry information from ccs and outside the web without good results. I think that it's necessary some kind of magic. I hope you can do your magic.
Regards. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Mon Aug 01, 2016 9:02 am |
|
|
Code: |
#include <16F1826.h>
#fuses HS,NOWDT,NOMCLR,NOPROTECT,NOLVP
#use delay(int=16000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2)
#use i2c(SLAVE, SDA=PIN_B1, SCL=PIN_B4, address=0xa0)
//A slave does not have a speed.....
BYTE address, tx_buffer[0x10], rx_buffer[0x10];
#bit CKP=getenv("BIT:CKP") //see why below
#INT_SSP
void ssp_interupt (void)
{
BYTE incoming, state;
state = i2c_isr_state();
//State 80, is 'unique'. It requires a read, without releasing
//the clock hold, followed by a write, and the hold released
if(state == 0x80) //Master is sending data with reply
{
incoming = i2c_read(2); //read the byte without releasing clock
}
else if (state<0x80)
{
incoming=i2c_read(); //normal read
if(state == 1) //First received byte is address
address = incoming;
if(state >= 2) //later received bytes are data
rx_buffer[address++] = incoming;
//allows sequential writes
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(tx_buffer[address++]);
//and sequential reads
//Clock should release, but some compiler versions don't
//so explicitly release it.
CKP=TRUE;
}
if (address>=0x10)
address=0x0F; //ensure cannot write/read beyond buffer
}
void main ()
{
int8 ctr;
for (ctr=0;ctr<0x10;ctr++)
tx_buffer[ctr]=ctr+'0'; //data to be read back
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {
printf("%c",rx_buffer[address]);
delay_ms(500);
}
}
|
This has a separate TX and RX buffer, and data from the master goes into the rx_buffer, while data to the master is sent from the tx_buffer.
Getting I2C, to really work 'right', is poorly documented, with the need to hold the clock till after the reply byte is loaded, and then a lot of compiler versions failing to release it once it is loaded....
Delay the master between operations. Particularly stop, and a subsequent start, and sequential reads. The slave has to get into the slave routine, and load the byte for reply. This takes typically about 40 instruction cycles, so this much time needs to exist between these operations in the master. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Aug 01, 2016 2:35 pm |
|
|
In another thread, murqui said his compiler vs. is 4.114:
Quote: | I'm using the PIC 18f2685 and my compiler version is 4.114 |
I don't think his compiler version supports an i2c_read() parameter of 2.
vs. 4.114 - produces identical ASM code:
Code: | ........ incoming = i2c_read(2); //read the byte without releasing clock
0032: MOVLB 04
0033: BCF SSP1CON1.SSPOV
0034: MOVLB 00
0035: BTFSS PIR1.SSP1IF
0036: GOTO 035
0037: MOVLB 04
0038: MOVF SSP1BUF,W
0039: BSF SSP1CON1.CKP
003A: MOVLB 00
003B: MOVWF incoming
.................... incoming = i2c_read();
003C: MOVLB 04
003D: BCF SSP1CON1.SSPOV
003E: MOVLB 00
003F: BTFSS PIR1.SSP1IF
0040: GOTO 03F
0041: MOVLB 04
0042: MOVF SSP1BUF,W
0043: BSF SSP1CON1.CKP
0044: MOVLB 00
0045: MOVWF incoming |
vs. 5.061 - produces different ASM code:
Code: | ........ incoming = i2c_read(2); //read the byte without releasing clock
0032: MOVLB 04
0033: MOVF SSP1BUF,W
0034: MOVLB 00
0035: MOVWF incoming
.................... incoming = i2c_read();
0036: MOVLB 04
0037: BCF SSP1CON1.SSPOV
0038: MOVLB 00
0039: BTFSS PIR1.SSP1IF
003A: GOTO 039
003B: MOVLB 04
003C: MOVF SSP1BUF,W
003D: BSF SSP1CON1.CKP
003E: MOVLB 00
003F: MOVWF incoming |
|
|
|
murgui
Joined: 23 Dec 2015 Posts: 37
|
|
Posted: Mon Aug 01, 2016 3:44 pm |
|
|
Thank you for all the information and resources. I did a quick test and the result was still bad but tomorrow (IT'S late here). I will put all my effort on understanding all. About the compiler version, I am still using v4. 114, should I update to a newer version?
Thank you very much for all the time.
Murgui. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Aug 02, 2016 12:07 am |
|
|
OK. Thought that the 2 parameter had appeared by then. Guess it was 'late 4.130/140'.
It's OK without it, but makes adding time delays between the transactions essential. Add a delay equal to about 40 machine cycles after every USB transaction at the master.
What happens, is that with '2' the hardware holds the USB port as 'busy' for the period between reading the first byte and loading the reply. Without this, the hardware releases as soon as the first byte is read. If the master tries to start another transaction in this gap, things go wrong....
Delays are still needed, but this one is a 'killer' for reliable USB. |
|
|
murgui
Joined: 23 Dec 2015 Posts: 37
|
|
Posted: Tue Aug 02, 2016 1:56 am |
|
|
Well the protocol is I2C but I suppose it still applies(not USB) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Aug 02, 2016 2:09 am |
|
|
No, I meant I2C....
USB can't do this. Problem is I'm sitting having 'back answers', in 26500 lines of USB code, so have got 'USB on the brain!...).
What you need, is:
Code: |
while(1)
{
// Write the letter 'B' to the slave board. I tryed later with an A
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write('B'); //or A
i2c_stop();
//sequential 'writes' are perfectly OK.
// Read from the slave board and display the data.
delay_cycles(60); //ensure the slave has had time to complete
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
delay_cycles(60); //ensure the slave has time to load the reply
data = i2c_read(0);
i2c_stop();
printf("read %c \n\r", data);
delay_ms(5000);
}
|
Sequential writes are OK. The bus releases when the slave reads the byte, so the master can start sending it before the slave has dealt with the last value (bus will hold till the slave read occurs). Problem comes with reads, where the slave _must_ have loaded the reply byte, _before_ the master starts trying to clock it. The i2c_read(2) capability, reads the byte, but leaves the clock line held, so you can then release it after the new byte is loaded. Without this, you have to ensure there is enough time for the slave to have loaded the byte, before you start receiving at the master. Takes typically 30 instructions to get into an interrupt handler, then a few to handle decoding the state, half a dozen to load the byte, then perhaps a dozen to read the byte to send, and load this. Probably about 55 to 60 instructions. Delay_cycles(60), should just be enough (that is assuming both chips are clocked at the same rate - otherwise may need longer). |
|
|
murgui
Joined: 23 Dec 2015 Posts: 37
|
|
Posted: Tue Aug 02, 2016 1:20 pm |
|
|
Hi! All those examples and explanations are just wonderful! I've been trying to make them work but the only thing the master returns are 0. No matter what variable I send. I've managed to work with a newer compiler (v5.015), I tried with the 'delay_cycles()' but concluded that it might be unreliable and bet for a newer version. I'm working with the slave and master code Ttelmah posted but the results are not satisfactory. I don't know where should I focus. Could you point me what code lines could be conflictive? The code seems pretty simple with your help but I simply don't know what to take special care of.
Regards, Murgui. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Aug 02, 2016 1:25 pm |
|
|
Start with what resistors you are using for the pull-ups?.
How long is the bus?.
What wire is used?.
Good ground connections?. |
|
|
murgui
Joined: 23 Dec 2015 Posts: 37
|
|
Posted: Tue Aug 02, 2016 1:39 pm |
|
|
Hi, about the hardware:
I'm using 4k7 resistors, the bus is like 20 cm(almost 10 inches) long. The ground connections seem fine. In the first test, which concluded with no having the option of changing the 'B' I think, I'm not sure, that this B went from the master to the slave and back.
EDIT: Hi, finally the communication happened. Thank you very much to all of you guys, especially to Ttelmah. |
|
|
|
|
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
|