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 CCS Technical Support

Master and slave I2C implemented on one PIC

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
jallum



Joined: 05 Mar 2008
Posts: 9

View user's profile Send private message

Master and slave I2C implemented on one PIC
PostPosted: Thu Mar 06, 2008 1:33 pm     Reply with quote

If you are trying to set up your PIC as master of an I2C bus using SW implementation, and slave of an altogether different bus (or even the same bus I suppose) using the HW SSP module, here is some code for you:

Code:

#include <16F877A.h>
#device adc=10

#FUSES NOWDT                     //No Watch Dog Timer
#FUSES HS                        //High speed Osc (> 4mhz)
#FUSES PUT                       //Power Up Timer
#FUSES PROTECT                   //Code protected from reads
#FUSES NODEBUG                   //No Debug mode for ICD
#FUSES BROWNOUT                  //Brownout reset
#FUSES NOLVP                     //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                     //No EE protection
#FUSES NOWRT                     //Program memory not write protected

#use delay(clock=20M)

//NOTE: Must declare MASTER before SLAVE, i2c_isr_state() returns 0
//      when MASTER is the most recent #use i2c
#use i2c(MASTER, sda=PIN_C1, scl=PIN_C0, stream=I2CM)
#use i2c(SLAVE, sda=PIN_C4, scl=PIN_C3, address=0x60, force_hw, stream=I2CS)
#use rs232(baud=57600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, stream=COM1)

#use fast_io(D)

int rcv_buf[0x10];       
int wrt_buf[0x10];       
int cmd=0xFF;           

#int_SSP // interrupt on i2c activity
void  i2c_isr(void)
{
    int state, incoming;
    state = i2c_isr_state();
   
    if(state < 0x80)
    {
        incoming = i2c_read(I2CS);
        if (state == 1)
        {
            cmd = incoming;
        }
       
        else if (state > 1)
        {
            rcv_buf[state-2]=incoming;
        }
    }
    else
    {
        i2c_write(I2CS,wrt_buf[state-0x80]);
    }
}

void main()
{
   
    enable_interrupts(INT_SSP);
    enable_interrupts(GLOBAL);
   
    printf("\n\rbegin");
   
    while (TRUE)
    {
        if (cmd<0xFF)
            printf("\n\rcmd: %x", cmd);
        i2c_start(I2CM);
        i2c_write(I2CM,0xa0);      //i2c address of a slave device
        i2c_write(I2CM,0x2e);      //1st byte to slave
        i2c_write(I2CM,0xa0);      //2nd byte to slave
        i2c_stop(I2CM);
    }
}




It is VERY important to declare the SLAVE after the MASTER. It appears that i2c_isr_state() will return 0 if the MASTER declaration is the most recently encountered #use statement, although i2c_isr_state() should only read the state of the SLAVE SSP hardware.
XyVy



Joined: 10 Sep 2008
Posts: 2

View user's profile Send private message

PostPosted: Wed Sep 10, 2008 3:16 am     Reply with quote

Hello Jallum, I need to do work i2c master and slave in the same PIC, but when I introduce the #use i2c(master...) the slave side does not work, but if I delete the #use i2c(master...) line, the slave side works okey again.

What is wrong?

My code is:
Code:

#include <16F876A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=4000000)

#byte port_b=0x06

#use i2c(MASTER, FAST, sda=PIN_A0, scl=PIN_A1, address=0xB0, force_sw, stream=i2cM)
#use i2c(SLAVE, FAST, sda=PIN_C4, scl=PIN_C3, address = 0x08, force_hw, stream = i2cS)

// Comandos soportados por el PIC 16F876 en nuestro software
#define INIT            0x01
#define CONSULTA_MOTOR1 0x02
#define CONSULTA_MOTOR2 0x03
#define MUEVE_MOTOR1    0x04
#define MUEVE_MOTOR2    0x05
#define INTERRUPTOR1    0x06
#define INTERRUPTOR2    0x07
#define INTERRUPTOR3    0x08
#define INTERRUPTOR4    0x09
#define STOP_MOTOR1     0x0A
#define STOP_MOTOR2     0x0B

// definimos los datos para usar i2c
char data;
char cuenta;
BYTE state;
BYTE comando;
BYTE dato;


void inicializa()
{
   output_high(PIN_B2);
   i2c_start(i2cM);
   i2c_write(i2cM, 0xB0);   // Dirección del dispositivo
   i2c_write(i2cM, 0x00);   // Registro de Modo
   i2c_write(i2cM, 0x01);   // Motor1 detenido
   i2c_stop(i2cM);     
   output_low(PIN_B2);     
}

void MueveMotor1(char dato)
{
   output_high(PIN_B2);
   i2c_start(i2cM);
   i2c_write(i2cM, 0xB0);  // Dirección del dispositivo
   i2c_write(i2cM, 0x01);  // Registro de modo
   i2c_write(i2cM, dato);   // Registro Velocidad motor 1
   i2c_stop(i2cM);     
   output_low(PIN_B2);   
}

void MueveMotor2(char dato)
{
   output_high(PIN_B2);
   i2c_start(i2cM);
   i2c_write(i2cM, 0xB0);   // Dirección del dispositivo
   i2c_write(i2cM, 0x02);   // Velocidad de los motores
   i2c_write(i2cM, dato);   // Velocidad del motor2
   i2c_stop(i2cM);
   output_low(PIN_B2);       
}

void StopMotor1()
{
   output_high(PIN_B2);
   i2c_start(i2cM);
   i2c_write(i2cM, 0xB0);   // Dirección del dispositivo
   i2c_write(i2cM, 0x01);   // Registro de Modo
   i2c_write(i2cM, 128);
   i2c_stop(i2cM);
   output_low(PIN_B2);       
}

void StopMotor2()
{
   output_high(PIN_B2);
   i2c_start(i2cM);
   i2c_write(i2cM, 0xB0);   // Dirección del dispositivo
   i2c_write(i2cM, 0x02);   // Velocidad de los motores
   i2c_write(i2cM, 128);   // velocidad del motor1
   i2c_stop(i2cM);
   output_low(PIN_B2);       
}


#INT_SSP
void ssp_interupt ()
{
   state = i2c_isr_state();
 
   if(state<0x80)                 //master is sending data
   {
      if(state == 0)
      {
     
      } else if (state == 1)                   //first received byte
      {
         output_high(PIN_B2);
         comando = i2c_read(i2cS);
      } if (state==2) {   // 2º byte recibido
         dato=i2c_read(i2cS);
      }
   }else if (state == 0x80) {               //master is requesting data
      output_high(PIN_B1);
      if (input(PIN_B4)) {
         i2c_write(i2cS, 1);
      } else {
         i2c_write(i2cS, 0);
      }
      i2c_write(i2cS, cuenta);  //send requested data
      cuenta++;
   }
}


void main()
{
   char data;
   int pulsado=0;
   char sw=0;
   int activo;
   cuenta=0;
   port_b=0;
 
   enable_interrupts(GLOBAL);   
   enable_interrupts(INT_SSP);   
         
   sw=0;
   pulsado=0;
   while (1) {     
      activo=input(PIN_B4);
      if (activo && (sw==0) && (!pulsado)) {
         output_low(PIN_B2);
         MueveMotor1(255);
         StopMotor2();
         pulsado=1;
         sw=1;
      } else if (activo && (sw==1) && (!pulsado)) {
         output_high(PIN_B2);
         MueveMotor2(255);         
         StopMotor1();
         pulsado=1;
         sw=0;
      }
     
      delay_ms(50);
      if (!input(PIN_B4)) {
         output_low(PIN_B2);
         pulsado=0;
      }
      delay_ms(50);       
   }
   
}



Thanks in advance!
XyVy



Joined: 10 Sep 2008
Posts: 2

View user's profile Send private message

PostPosted: Thu Sep 11, 2008 2:40 am     Reply with quote

Good news guys!

I have solved my problem.

I put the uses like:

#use i2c(MASTER, sda=PIN_A0, scl=PIN_A1, address=0xB0, stream=i2cM)
#use i2c(SLAVE, sda=PIN_C4, scl=PIN_C3, address = 0x08, force_hw, stream = i2cS)

But, I believe the problem was in the following function:

Code:

#INT_SSP
void ssp_interupt ()
{
   state = i2c_isr_state(i2cS);
 
   if(state<0x80)                 //master is sending data
   {
      if(state == 0)
      {
     
      } else if (state == 1)                   //first received byte
      {
         output_high(PIN_B2);
         comando = i2c_read(i2cS);
      } if (state==2) {   // 2º byte recibido
         dato=i2c_read(i2cS);
      }
   }else if (state == 0x80) {               //master is requesting data
      output_high(PIN_B1);
      if (input(PIN_B4)) {
         i2c_write(i2cS, 1);
      } else {
         i2c_write(i2cS, 0);
      }
      i2c_write(i2cS, cuenta);  //send requested data
      cuenta++;
   }
}



I forgot put the "i2cS" stream in the i2c_isr_state.

The PIC works okey!!

Thanks!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library 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