  | 
	  | 
		 
	 
	
		| 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: 19967
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 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: 9589 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: 19967
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 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: 19967
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 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: 19967
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 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: 19967
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 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
  
		 |