CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

ADC erratic readings
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21370

View user's profile Send private message

PostPosted: Fri Jul 29, 2016 6:04 pm     Reply with quote

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: 16941

View user's profile Send private message

PostPosted: Sat Jul 30, 2016 4:22 am     Reply with quote

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: 7987
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Jul 30, 2016 8:23 am     Reply with quote

This is one of those...
start over, start small, test each 'function' then proceed.

Jay
murgui



Joined: 23 Dec 2015
Posts: 37

View user's profile Send private message

PostPosted: Sun Jul 31, 2016 5:44 am     Reply with quote

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: 21370

View user's profile Send private message

PostPosted: Mon Aug 01, 2016 7:35 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Aug 01, 2016 7:52 am     Reply with quote

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: 16941

View user's profile Send private message

PostPosted: Mon Aug 01, 2016 9:02 am     Reply with quote

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: 21370

View user's profile Send private message

PostPosted: Mon Aug 01, 2016 2:35 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Aug 01, 2016 3:44 pm     Reply with quote

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: 16941

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 12:07 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 1:56 am     Reply with quote

Well the protocol is I2C but I suppose it still applies(not USB)
Ttelmah



Joined: 11 Mar 2010
Posts: 16941

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 2:09 am     Reply with quote

No, I meant I2C.... Very Happy

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

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 1:20 pm     Reply with quote

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: 16941

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 1:25 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Aug 02, 2016 1:39 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
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