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

i2c Slave and RS232 printf
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

i2c Slave and RS232 printf
PostPosted: Sat Aug 08, 2015 2:48 am     Reply with quote

Hi,
Quick one, (18F4620)
Could someone explain what is happening on the hardware when I printf something and in the same time I get i2c call from Master.

Is this affecting printf routine? Is i2c able to work in parallel when processor is printing to serial port in the same time?

I do have a board with 2 processors, one is master and second one is slave. I do print out to the LCD screen from the slave processor.

So here is the scenario: master is ordering slave to print out string to LCD, slave takes it and starts printing out the data, in the middle of this process we receive another call from master cpu sending some other instruction to slave. I just try to understand if this will affect the printf routine once it is underway in the middle of execution.

thnx 4 help
_________________
Help "d" others and then you shell receive some help from "d" others.
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Sat Aug 08, 2015 3:03 am     Reply with quote

That is totally down to your software.

There is no magic. The serial has just a couple of characters of buffering in each direction (the actual output shift register being 'sent', and the next byte waiting to send. The I2C, again has a buffer register and in the slave, this has to be read when the master sends a byte.
The serial driver always 'loads ahead', so the buffer register is kept full.
If you stopped and didn't listen to the I2C, then it'd be held till the byte is read. However if you are using interrupt driven I2C, as in the example, then the interrupt will be called, the data read, and meanwhile the byte in the shift register will be sending. If this finishes, then the next byte that is waiting, will be loaded. So you have a 'minimum' of a complete character time, that the serial will keep sending even if not 'serviced'. Given that typically serial rate may be something like 9600bps, and I2C, 100Kbps, the time needed to handle the byte is easily covered.

So it is possible to hang either the serial, or the I2C, if your software doesn't always handle things, but the hardware contains enough buffering to give time for this, provided you use interrupt driven comms.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Mon Aug 10, 2015 2:00 am     Reply with quote

thnx, that is what I was after. I run 40MHz 18F4620 and could not catch why I miss on some transmission on i2c. In the end it looks like it was too fast, had to slow it down to 100000 and it did fix the issue.
_________________
Help "d" others and then you shell receive some help from "d" others.
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Mon Aug 10, 2015 2:27 am     Reply with quote

The rate shouldn't matter.
Are you sure your bus capacitance is low enough, and the pull up's good enough to handle 400K?.
What does matter is the delay after sending a byte, before the next. Lowering the rate will give the slave a little more time here.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Mon Aug 10, 2015 2:32 am     Reply with quote

1.8K the bus is fairly good, 6 chips on it.
I have two different boards, different design, the same thing happening.

It seem to lose every second, third message. I was able to pin it to lost byte in between. I post my routines later on after I clean it. On 100 it is more stable but still playing up occasionally. Thnx
_________________
Help "d" others and then you shell receive some help from "d" others.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Mon Aug 10, 2015 3:07 am     Reply with quote

Quote:
Master code


Code:
#use i2c(master, sda=I2CSDA, scl=I2CSCL, FORCE_HW, SMBUS, FAST=100000) 


Code:
void send_to_i2c_worker(BYTE destinationi2c_, BYTE command_, BYTE data1_, BYTE data2_, BYTE data3_, BYTE data4_, BYTE data5_, BYTE data6_, BYTE data7_, BYTE data8_)

   i2c_start ();     //begin transmission
   i2c_write (destinationi2c_);  //select address of device to communicate with
   i2c_write (command_);  //send actual command                                       
   i2c_write (data1_);    //send actual data
   i2c_write (data2_);    //send actual data                                       
   i2c_write (data3_);    //send actual data                     
   i2c_write (data4_);    //send actual data
   i2c_write (data5_);    //send actual data
   i2c_write (data6_);    //send actual data       
   i2c_write (data7_);    //send actual data
   i2c_write (data8_);    //send actual data
   i2c_stop ();           //terminate communication
   delayms (5);


Code:
void read_i2c(BYTE destinationi2c, BYTE rcommand, BYTE rdata)               

   int a = 0;                                         
   
   i2c_start () ;
   i2c_write (destinationi2c) ;
   i2c_write (rcommand);
   i2c_write (rdata);
   i2c_start () ;
   i2c_write (destinationi2c + 1);
   i2creadbuff = i2c_read (0);
   i2c_stop ();
   delayms (5);
}


Quote:
Slave code:


Code:
#use i2c(slave, sda=I2CSDA, scl=I2CSCL, address=0xA0, FORCE_HW, SMBUS)


Code:
#INT_SSP                       
       
void ssp_interupt(VOID)
{                 
   byte c;
   state = i2c_isr_state ();
 
   IF (state <= 0x80) // send data here                   
   {                           
      //master is sending data
                                       
      IF (state == 0)                   
      {                                         
         //address
         c = i2c_read ();                                                       
         i2cbuffer[0] = c;     
         
         IF (c == 0xA0) 
         {                                                       
            process_i2c = 1;     
         } //IF 
      } //IF
                                 
      IF (state == 1)
      {                     
         //command
         c = i2c_read ();
         i2cbuffer[1] = c;
      } //IF                             
                                   
      IF (state == 2)
      {
         //data1
         c = i2c_read ();
         i2cbuffer[2] = c;
      } //IF

      IF (state == 3)
      {
         //data1
         c = i2c_read ();
         i2cbuffer[3] = c;
      } //IF

      IF (state == 4)
      {
         //data1
         c = i2c_read ();
         i2cbuffer[4] = c;
      } //IF

      IF (state == 5)
      {
         //data1
         c = i2c_read ();
         i2cbuffer[5] = c;
      } //IF

      IF (state == 6)
      {
         //data1
         c = i2c_read ();
         i2cbuffer[6] = c;
      } //IF

      IF (state == 7)
      {
         //data1
         c = i2c_read ();                               
         i2cbuffer[7] = c;
      } //IF

      IF (state == 8)
      {
         //data1
         c = i2c_read ();
         i2cbuffer[8] = c;
      } //IF                                                       
                                         
      IF (state == 9)
      {                                                         
         //data1                             
         c = i2c_read ();
         i2cbuffer[9] = c;                                 
      } //IF 
     
      IF (state > 9)         
      {
                               
       }                                                                                                       
   } //IF                             
                                                     
   IF (state >= 0x80) // read data from here
   {                             
      //master is requesting data
     
      IF (i2cbuffer[0] == 0xA0)                       
      {
         check_data_to_i2c (); //switch selecting data from VARs
                               
         i2cdata = read_back;
         
         i2c_write (i2cdata); //send requested data

         SSP_locked = 0;   
      } //IF                 
   } //IF                       

} //VOID             

_________________
Help "d" others and then you shell receive some help from "d" others.
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Mon Aug 10, 2015 4:10 am     Reply with quote

Seriously, with six devices, you are probably straining at 1.8KR.

For 5v Operation (assumed since you have a 5v PIC), with standard bus transition points and 400K operation, your maximum bus capacitance allowed would be about 190pF. Now depending on the wire you have joining the devices, and the specs of the devices themselves, I can see a six device bus, straining this.....
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Mon Aug 10, 2015 4:12 am     Reply with quote

Thnx, I put a scope on it later on and let you know where I sit on the transmission. Last time I have tested it it was ok but you right it was on prototype Smile in 2009, many things are changed since.
_________________
Help "d" others and then you shell receive some help from "d" others.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 4:07 am     Reply with quote

Hey,
1.8K - 2.2K are fairly spot on on the scope. Rising and fall times are in norm.
So circuit is OK.

I think my problem is in the data being overrun by incoming. Slave is not fast enough to process commands and new ones do override the old data in the middle of processing. So I need to slow the master chip down or do a ring buffer on i2c.

thnx for help.
_________________
Help "d" others and then you shell receive some help from "d" others.
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 4:52 am     Reply with quote

There is one thing 'wrong' that might be causing problems:

On the I2C_read, in state 0x80, the clock will normally release on the read, but in this one state, should not until the write. Hence on this particular read you should use i2c_read(stream_name,2); - this tells the chip _not_ to release the clock. It then gets released on the write.

You should also check that the SEN bit is being set high by the compiler in the slave.

The other thing you can do is simply pause for the slave latency time after each read/write on the master. Should not be necessary.
temtronic



Joined: 01 Jul 2010
Posts: 9163
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 4:59 am     Reply with quote

re: slave code.

this...
Code:

 IF (state == 1)
      {                     
         //command
         c = i2c_read ();
         i2cbuffer[1] = c;
      } //IF                             
 

seems to be 'kinda' repeated 9 times( if I'm reading it right..) perhaps just one 'c=i2c_read(); will be faster ? Also maybe using 'switch' will create better (faster) code ?
I know ISRs must be fast so might be worth cutting test code,compiling, dump the listing to see if it 'looks' better then real world test and check the performance.


Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Mon Aug 17, 2015 11:16 am     Reply with quote

Also you say the rise time looks OK. Spec is 300nSec max for fast mode. Is it less than this?.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Tue Aug 18, 2015 12:37 am     Reply with quote

Ttelmah wrote:
Also you say the rise time looks OK. Spec is 300nSec max for fast mode. Is it less than this?.


580ns/40ns at 100KHz
_________________
Help "d" others and then you shell receive some help from "d" others.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Tue Aug 18, 2015 1:53 am     Reply with quote

Ttelmah wrote:
There is one thing 'wrong' that might be causing problems:

On the I2C_read, in state 0x80, the clock will normally release on the read, but in this one state, should not until the write. Hence on this particular read you should use i2c_read(stream_name,2); - this tells the chip _not_ to release the clock. It then gets released on the write.

You should also check that the SEN bit is being set high by the compiler in the slave.

The other thing you can do is simply pause for the slave latency time after each read/write on the master. Should not be necessary.


...here you gave me a bit of Googling to do, anyway it is simple and not, will take me some time to figure this out how to do it properly.
_________________
Help "d" others and then you shell receive some help from "d" others.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Tue Aug 18, 2015 2:09 am     Reply with quote

temtronic wrote:
re: slave code.

this...
Code:

 IF (state == 1)
      {                     
         //command
         c = i2c_read ();
         i2cbuffer[1] = c;
      } //IF                             
 

seems to be 'kinda' repeated 9 times( if I'm reading it right..) perhaps just one 'c=i2c_read(); will be faster ? Also maybe using 'switch' will create better (faster) code ?
I know ISRs must be fast so might be worth cutting test code,compiling, dump the listing to see if it 'looks' better then real world test and check the performance.


Jay


Code:
 IF (state <= 0x80)     
      {             
         c = i2c_read ();
         
         IF (state == 0)
         {           
            i2cbuffer[0] = c;
            if (c == 0xA0)
            {
               process_i2c = 1;
            }
            else
            {
               process_i2c = 0;
            }
         }

         if (state <= 9)
         {
            i2cbuffer[state] = c;   
         }
      }


I had a bug, if my comms would be more than 9 (like reading time of RTC) then I was not clearing the buffer. This does fix the issue, however for some reason the code is unstable.
_________________
Help "d" others and then you shell receive some help from "d" others.
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 1, 2  Next
Page 1 of 2

 
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