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

16F882 used as slave i2c
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
temtronic



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

View user's profile Send private message

PostPosted: Mon Sep 17, 2018 12:28 pm     Reply with quote

I'd add the speed option to FORCE the compiler to put the same speed in both master and slave. Relying on the 'default' is never a good idea. After all MY default won't be the same as what YOU want as a default....
Same holds true for the force_hw option. Look at the listing, maybe the compiler is doing a SW I2C and not HW. SW relies upn bitbanging and timing could be off just a tad..

just ideas to ponder...
Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Sep 17, 2018 12:35 pm     Reply with quote

No. Don't do this..

Setting a speed in slave mode, on some chips can result in invalid bit patterns in the I2C configuration register.

Caveat.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Sep 17, 2018 12:44 pm     Reply with quote

With NO_STRETCH selected the master device must clock the I2C slower than the slave can handle. So (for instance), the slave needs to be able to get into it's IRQ handler, and have read the registers, before the next byte arrives. It'll fail if this is not the case.

STRETCH is normally used. NO_STRETCH is only needed on a couple of particular PIC's that have I2C hardware issues. If your PIC doesn't list a stretch issue in it's data sheet, then the stretch resulting in hanging, means your IRQ handler is not correctly reading the registers. Remember when the bus is reversed, the IRQ, must first read the address byte and then write the first byte of the reply, in the single routine.

Your problem is that on state 0x80, you must first read then write. Your code is not reading in this state.

Leave stretch enabled, and fix this.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Mon Sep 17, 2018 12:49 pm     Reply with quote

The NO_STRETCH solved the bus hanging in the test program but not in my full program. The CCS manual says I'm using software unless I FORCE_HW.
As soon as I let the slave try a single read it hangs. I'm suspecting I have not set up something properly like cpu speed, or there is a problem in the compiler (my last resort). The errata does not show problems for this chip (revision 3 showing in my programmer if 0000011 means that).

I will check what you suggested. Remember it all works with a 16F722.
If I comment out the last if lines it still hangs, besides it reads first does it not?

Errata shows OSTS bit remains clear (Oscillator start up timer), and MSSP SPI Master Mode buffer full bit of MSSP interrupt flag bit becomes set half SCK cycle too early. I don't think these would be a problem.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Sep 18, 2018 11:57 am     Reply with quote

I was not forgetting it works on another chip.
PIC's differ. Some will absolutely require the read before write or the I2C will go to an indeterminate state. Many of the older chips though will accept a write only.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Tue Sep 18, 2018 1:07 pm     Reply with quote

Thanks Ttelmah,
I think I understand now. Do you mean adding "incoming = i2c_read ();" as shown below fourth line from bottom? I will try that.

Code:
// Interrupt on I2C
 #INT_SSP
 void ssp_interrupt ()                        // have an interrupt
   {
    int incoming, state;                     // variables
    state = i2c_isr_state ();                // get state
     if (state < 0x80)                       // master is sending data
      {
       incoming = i2c_read ();               // throw away device address if state = 0
       if (state == 1)                       // first data received is port speed
         p_speed = incoming;
       if (state == 2)                       // second data received is stbd speed
         s_speed = incoming;
       if (state == 3)                       // third data received is status reset
       status_reset = incoming;
       }
     if (state >= 0x80)                      // master is requesting data from slave
      {
 incoming = i2c_read ();
       i2c_write (side_thr_status);          // send side thruster status
      }
   }


Edit: No that did not work. Surely the ISR had to have read before getting this far?
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Wed Sep 19, 2018 12:15 am     Reply with quote

No. You are omitting states....

Think about it. You only read if the state is <0x80. So it'll get here without having already read.
Problem is though, you only want the extra read in state 0x80. In state 0x81, this is _not_ required/wanted.

State 0x0. Read. Byte is address. Ignore.
State 0x1..0x79. Read. Bytes are data
State 0x80. Read using i2c_read(2), then preload first byte of reply.
State 0x81. Just write.

Getting the sequencing right is important. Look at the slave example:
Code:

{
   unsigned int8 state, incoming;

   state = i2c_isr_state();
   //Note <= here
   if(state <= 0x80)                      //Master is sending data
   {
      if(state == 0x80) //Now note == here
         incoming = i2c_read(2);          //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
      else
         incoming = i2c_read();

      if(state == 1)                      //First received byte is address
         address = incoming;
      else if(state >= 2 && state != 0x80)   //Received byte is data
         buffer[address++] = incoming;
   }

   if(state >= 0x80)                      //Master is requesting data
   {
      i2c_write(buffer[address++]);
   }
}

Note that the read routine is being called here on state==0x80 with i2c_read(2)...
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
Page 2 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