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 10-bit Addressing

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Seaborgium



Joined: 23 Jul 2012
Posts: 14

View user's profile Send private message

I2C 10-bit Addressing
PostPosted: Wed Jul 25, 2012 6:02 pm     Reply with quote

Hi,

I'm trying to implement 10-bit I2C addressing with a PIC16LF1503 master and PIC16F886 slave, using CCS 4.133. I have a totally functional 7-bit addressing version. I've included the relevant parts here, for the working version:

Master.c:
Code:
#include <Master.h>
#define LED PIN_A5
#define LED2 PIN_A4
#define LED3 PIN_C5

#use i2c(Master, Slow, sda=PIN_C3, scl=PIN_C4, force_sw, stream=module)

void flash(int ledsToFlash) {
   if ((ledsToFlash&0b1)==0b1)
      output_high(LED);
   if ((ledsToFlash&0b10)==0b10)
      output_high(LED2);
   if ((ledsToFlash&0b100)==0b100)
      output_high(LED3);
   delay_ms(500);
   output_low(LED);
   output_low(LED2);
   output_low(LED3);
   delay_ms(200);
}

//Communicates with a certain slave address by delivering a certain
//data address, then returns the received data.
int16 requestData(int16 slaveAddress, unsigned int dataAddress) {
   int16 data;

   //Instruct slave that you wish to write
   i2c_start(module);
   flash(0b100|i2c_write(module, slaveAddress));
   
   //Give data address
   flash(0b100|i2c_write(module, dataAddress));
   
   //Restart; instruct slave that you wish to read
   i2c_start(module);
   flash(0b100|i2c_write(module, slaveAddress|1));
   
   //Receive data and finish
   data=i2c_read(module, 1)<<8; //Read high byte and ACK
   data+=i2c_read(module, 0); //Read low byte and end transmission
   i2c_stop(module);
   flash(0b111);
   
   return data;
}

void main() {
   setup_comparator(NC_NC_NC_NC); // This device COMP currently not supported by the PICWizard
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   
   delay_ms(3000);
   int i;
   i=0;
   while (TRUE) {
      flash(requestData(0xa0, i));
      i++;
      delay_ms(1000);
   }
}


Master.h:
Code:
#include <16LF1503.h>
#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES WDT_SW                   //No Watch Dog Timer, enabled in Software
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(int=16000000)


Slave.c:
Code:
#include <Slave.h>

//Reserve a 14-bit word for saving data address
#define ADDRESSLOC 0x500
#ORG 0x500, 0x500 {}

//Define output pins
#define LED PIN_A7
#define LED2 PIN_A6
#define LED0 PIN_C5

//Define states
#define READY 0 //Ready for next command (change address order, or sensor request)
#define CHANGEADDR 1 //Next byte received will be new assigned address
#define SENDLOW 2 //Sent high bit of data; next send low bit

//General call bit
#BYTE SSPCON2=0x91
#BIT GCEN=SSPCON2.7
//10-bit addressing bit
#BYTE SSPCON=0x14
#BIT SSPM0=SSPCON.0

//Change # of sensors per module to correct number in sensorVals

int writeBuffer [2]; //Holds one 10-bit integer to write through i2c
int16 sensorVals [16];
int orderState;

void flash(int ledsToFlash) {
   output_high(LED0);
   if ((ledsToFlash&0b1)==0b1)
      output_high(LED);
   if ((ledsToFlash&0b10)==0b10)
      output_high(LED2);
   delay_ms(400);
   output_low(LED);
   output_low(LED2);
   output_low(LED0);
   delay_ms(200);
}

#int_SSP
void i2c_interrupt() {
   int state;
   unsigned int message;
   state = i2c_isr_state();
   if (state==0||state==0x80) //Master has issued start command
      i2c_read(); //Clear address from read buffer.
   
   if (state>=0x80) //Master is waiting for data
      i2c_write(writeBuffer[state - 0x80]); //Write appropriate byte, based on how many have already been written
   
   else if(state>0) { //Master has sent data; read.
      message=i2c_read();
      if (orderState==READY) {
         if (message==0x20) { //Master wants to assign address.
            orderState=CHANGEADDR;
         }
         else { //Master requests sensor data.
            int16 toSend;
            toSend=sensorVals[message]; //Grab appropriate sensor value.
            writeBuffer[0] = toSend>>8;
            writeBuffer[1] = toSend&0xFF;
         }
      }
      else if (orderState==CHANGEADDR) { //Master has just sent new address
         i2c_slaveaddr(message); //Change address
         write_program_eeprom(ADDRESSLOC, message); //Set address in eeprom
         orderState=READY;
         GCEN=FALSE; //Disable general calls for remainder of runtime
      }
   }
}

void main() {
   setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
   enable_interrupts(INT_SSP); //Enable interrupts
   enable_interrupts(GLOBAL);
   
   GCEN=TRUE; //Allow general calls
   
   i2c_slaveAddr(0xa0);
   
   orderState=READY; //Ready for orders
   
   while (true) { //Constantly refresh sensor values
      sensorVals[0]=0b101;
      sensorVals[1]=0b011;
      sensorVals[2]=0b110;
      sensorVals[3]=0b100;
      sensorVals[4]=0b010;
   }
}


Slave.h:
Code:
#include <16F886.h>
#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOPROTECT                //No read protection
#FUSES NOWRT                    //No write protection

#use delay(int=8000000)

#use i2c(Slave, Slow, sda=PIN_C4, scl=PIN_C3, force_hw, address=0xa0)


In this code, the master asks the slave for "sensor values" (really just an array for testing purposes). The master has 3 LEDs, which it flashes to indicate certain states. It is supposed to flash LED 3 to indicate a successful write (0b100 is OR'ed with the return value of i2c_write, so if there was an unsuccessful write, it would flash LED 3 and LED 1 simultaneously). It does this three times. Then it flashes all three LEDs at the end of a successful i2c transaction; and then it flashes the value given to it by the slave.

In this version, it flashes: 3-3-3-123-13; 3-3-3-123-23; 3-3-3-123-12; and so on, with the last value matching up perfectly with the array values that the slave is supposed to send.

I made certain changes to implement 10-bit addressing. On the slave, I set SSPM0 to 1 (I also outputted SSPM to the LEDs and verified that it was 0111, I2C slave mode with 10-bit address). On the master, I made the appropriate calculations to transform the 7-bit address into a 10-bit address. This did not work, so I tried manually specifying the addresses bit-by-bit. I've included below the relevant changes.

Master.c
Code:
int16 requestData(int16 slaveAddress, unsigned int dataAddress) {
   int16 data;
   //int slaveHigh; //High byte of slave address
   //int slaveLow; //Low byte of slave address
   
   //Split slave address into low and high byte
   //slaveHigh = (slaveAddress>>8)&0xFE; //Shift over first 3 bits; clear R/W bit
   //slaveHigh = slaveHigh|0xF0; //"11110XXX" signifies 10-bit address; add this.
   //slaveLow = slaveAddress>>1; //Get lower 8 bits, without R/W bit
   
   //Instruct slave that you wish to write
   i2c_start(module);
   flash(0b100|i2c_write(module, 0b11110000)); //High byte
   flash(0b100|i2c_write(module, 0b00001111)); //Low byte


Slave.c
Code:

void i2c_interrupt() {
   int state;
   unsigned int message;
   state = i2c_isr_state();
   flash(0b11);

void main() {
   SSPM0=TRUE; //10-bit addressing

   i2c_slaveAddr(0b00011110);


The slave responds to general calls, but will not recognize its 10-bit address at all - no interrupt is even generated. I've looked through the CCS documentation and it seems that there is no support for 10-bit addresses (e.g. i2c_slaveAddr specifies an 8-bit address as input). However, since I'm using force_hw, I assume that the compiler uses the PIC16F886's internal hardware to check for address matches, and the PIC16F886 supports 10-bit addressing. How would I use 10-bit addresses? I've looked at the PIC16F866 data sheet and it's a little confusing - would I have to manually load the second byte of the address as described in section 13.4.1.1?
Ttelmah



Joined: 11 Mar 2010
Posts: 19369

View user's profile Send private message

PostPosted: Thu Jul 26, 2012 1:47 am     Reply with quote

The I2c address in the slave, needs to be set to look for the first address byte. So: 0b11110000
and bit 0 of CCPCON has to be set (I see you do this).

Then in the interrupt code, you need to test the UA bit (before _anything_ else), and if this is set, change the I2C address for the second byte, and immediately return.

The rest of the slave code remains the same, once this test has been passed, _except_ you must reset the address byte ready for the first value. So usually on the 'address match' code, you add a set address, back to look for the first byte.

Basically with 10bit, there are two address bytes, one after the other, with after the first, an interrupt, with the UA bit set to say 'second address needed'. The code behaves just as normal, except when you arrive in the ISR, if this bit is set, you just load the new address and get out again. Then when the second match is made, read the direction flag, and reset the address ready for the first match again.

Best Wishes
Seaborgium



Joined: 23 Jul 2012
Posts: 14

View user's profile Send private message

PostPosted: Thu Jul 26, 2012 2:06 pm     Reply with quote

Ah, I see. I managed to get it working. Thank you!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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