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

Problems with I2C Slave Mode

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



Joined: 28 Jan 2004
Posts: 0
Location: Brasil

View user's profile Send private message Send e-mail

Problems with I2C Slave Mode
PostPosted: Wed Jan 28, 2004 5:39 am     Reply with quote

Very Happy Hi all I´m trying to use the I2C Slave Mode of the CCS Compiler but I´m having problems with the builtin functions, reading this forum I found a message that tryes to use I2C Slave Mode like AN734 and I did exactly what was doing but the case state 2 does never occurs.
As the master I´m using the PIC16876A (20Mhz) and as Slave I´m using the PIC16F877A (20Mhz) and I´m simulating all of them in Proteus. Could anyone see what´s wrong in it? And why cant I use the Build in Functions

Here is the Master Code
Code:

#include "D:\Eletronica\Codigos Fonte Telemetria\I2cMaster\i2cmaster.h"


void main()
{

   int leo1,leo2;
   BYTE cont = 0;
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);

  // while (TRUE)
   {
      i2c_start();
      i2c_write(0x2E);//Se for a0 manda o endereco mas diz que vai mandar msg
      i2c_write(0XAA);
      i2c_write(0X55);
      i2c_stop();

      delay_ms(70);
      i2c_start();
      i2c_write(0x2F);//Se for a0 manda o endereco mas diz que vai mandar msg
      leo1 = i2c_read();
      leo2 = i2c_read(0);

      printf("(%x %x)",leo1,leo2);


   }

}

here is his Header
Code:

#include <16F876A.h>
#device adc=8
#use delay(clock=20000000)
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3)
#use rs232(baud=1200,parity=N,xmit=PIN_B7,rcv=PIN_B6,bits=8)


And the Slave Code (Thanks for the guy (Kenny) who wrote this)
Code:

#include "D:\Eletronica\Codigos Fonte Telemetria\I2cSlave\i2cslave.h"
/*Como vimos a melhor forma de se implementar um slave I2c é na mao... ou seja
baseado no hardware do pic e o datasheet AN734*/

//Registradores associados ao I2C
#byte SSPADD  =0x93  //Endereco deste modulo Slave
#byte SSPCON1 =0x14  //Reg de Controle 1
#byte SSPCON2 =0x91  //Reg de Controle 2
#byte SSPBUF  =0x13  //Buffer dos dados mandados/recebidos
#byte SSPSTAT =0x94  //Diversos Status

//Bits do Reg de Status
#bit BF    = SSPSTAT.0  /*Em modo de transmissao indica se o recebimento foi
                        completado, em modo de recepcao indica se se a transmi
                        ssao foi completada*/
#bit UA     = SSPSTAT.1  //So e usado em modo de endereco de 10 bits
#bit R_W    = SSPSTAT.2  //Indica se o master mandou uma transacao read ou write
#bit START  = SSPSTAT.3  //Indica que uma condicao Start foi detectada
#bit STOP   = SSPSTAT.4  //Indica que uma condicao Stop foi detectada
#bit D_A    = SSPSTAT.5  /*Indica que o ultimo byte recebido foi um endereco ou
                        dado*/
#bit CKE    = SSPSTAT.6  //Configuracao I2c Specifica
#bit SMP    = SSPSTAT.7  //Configuracao do Slew Rate (para 100khz = 1)

//Bits do Reg de Controle 1
#bit SMPM0  = SSPCON1.0  //Bit 0 a 3 e usado para configurar o modo SSP
#bit SMPM1  = SSPCON1.1
#bit SMPM2  = SSPCON1.2
#bit SMPM3  = SSPCON1.3
#bit CKP    = SSPCON1.4  //Segura ou libera o Clock gerado pelo Master
#bit SSPEN  = SSPCON1.5  //Bit de Enable do modo SSP
#bit SSPOV  = SSPCON1.6  /*Bit de Overflow quando sum byte e recebido e o buffer
                         (SSPBUF) ainda nao foi apagado*/
#bit WCOL   = SSPCON1.7  //Bit de indicador de colisao MultiMaster (Nao usado)

//Bits do Reg de Controle 2
#bit SEN    = SSPCON2.0  /*No modo Slave indica Clock Streching em transmissao
                        ou recepcao em modo Slave e o (Start)*/
#bit RSEN   = SSPCON2.1  //So tem sentido em modo Master (Repeat Start)
#bit PEN    = SSPCON2.2  //So tem sentido em modo Master (Stop)
#bit RCEN   = SSPCON2.3  //Habilita Receive Mode (So tem sentido no Master)
#bit ACKSEN = SSPCON2.4  //Comeca Sequencia de ACK no Master
#bit ACKDT  = SSPCON2.5  //ACK de Bit de Dados
#bit ACKSTAT= SSPCON2.6  //ACK de Status Bit
#bit GCEN   = SSPCON2.7  //Chamada Geral (Usada para chamar todos os CI da BUS)

//Define os Estados possiveis ao Modo I2C Slave (Pegos no Datasheet AN734)

/*Estado 1 O Master comecou uma transacao Write apos um Start ou Restart com
o endereco deste modulo, neste momento SSPBUF esta cheio e contem o endereco
deste modulo passado pelo master SSPBUF deve ser lido para zerar BF mesmo que
o endereco seja descartado*/
#define estado_1 0x09   // D/A=0, S=1, R/W=0, BF=1

/*Estado 2 Depois do endereco tiver sido mandado pela operacao write do master
o master deve mandar um ou mais bytes para o slave. Se SSPBUF nao estiver cheio
devido ao write o Slave vai mandar um ACK no 9º tick do clock se nao vai ser
gerado um NACK devido ao flag SSPOV tiver sido setado*/
#define estado_2 0x29   // D/A=1, S=1, R/W=0, BF=1

/*Estado 3 O master iniciou uma transaco read apos um Start ou Restart depois
de ter mandado o endereco deste modulo. Neste momento o buffer esta esperando
para ser carregado para ser enviado para o master. O bit CKP e zerado para por
o clock do master em espera para dar tempo do slave preparar o byte. O byte
so sera mandado quando o slave soltar o CKP*/
#define estado_3 0x0C   // D/A=0, S=1, R/W=1, BF=0

/*Estado 4 Este estado acontece quando o master leu um byte e quer ler mais um*/
#define estado_4 0x2C   // D/A=1, S=1, R/W=1, BF=0

/*Estado 5 Este estado indica que o master mandou um NACk apos uma leitura
indicando que ele nao quer mais nenhum byte. Este estado reseta entao a logica
I2C Slave*/
#define estado_5 0x28   // D/A=1, S=1, R/W=0, BF=0

//Endereco deste modulo
#define ENDERECO_SLAVE 0x2E
#define TAM_BUFF 4
int8 buff[TAM_BUFF];//Cuidado para nao acabar com a memoria do PIC
int8 indice_buff;

//Finalmente vamos agora para o handler de interrupcao I2C
#int_SSP
interrupcao_i2c()
{
   if (SSPSTAT != 0x30)
   {
      //0x2d(101101) Mascara os bits deixando aparecer somente D/a, S, R/W, BF
      switch (SSPSTAT & 0x2D)
      {
         case (estado_1):
         /*Operacao Write do Master, o endereco fica em SSPBUF, temos que
         ler SSPBUF para apagar BF, O master tem que dar um tempo para*/
         CKP = 0; //Poe o Master em Espera
         printf("Estado 1");
         for (indice_buff = 0;indice_buff < TAM_BUFF;indice_buff++)
         {
            buff[indice_buff]=0;
         }
         SSPOV=0; //Zera Bit de Overflow pois pode ter sido setado anteriormente
         indice_buff = 0;
         buff[indice_buff]=SSPBUF; //Le SSPBUF apagando BF
         CKP = 1; //Deixa o Master continuar
         break;

         case (estado_2):
         /*Agora que o master mandou o endereco ao comecar a transacao write
         ele deve mandar agora bytes de informacao*/
         CKP = 0; //Poe o Master em Espera
         printf("Estado 2");
         SSPOV=0; //Zera Bit de Overflow pois pode ter sido setado anteriormente
         buff[indice_buff] = SSPBUF; //Le SSPBUF apagando BF
         /*No Clock Streching nos podemos depurar, pois depois que soltar o CKP
         o Master vai continuar mandando ...*/
         indice_buff++; //Incrementa buffer
         //Nao deixa rolar Buffer Overflow (Caralho tem falha de seguranca)
         if (indice_buff >TAM_BUFF) indice_buff = 0;
         CKP = 1; //Deixa o Master continuar
         break;

         case (estado_3):
         /*O master vai comecar uma operacao de read iniciando com Start ou
         Restart depois mandando o endereco em SSPBUF*/
         CKP=0; //Poe o Master em Espera
         printf("Estado 3");
         indice_buff = 0;
         SSPBUF = buff[indice_buff]; //Manda primeiro byte do buffer
         indice_buff++; //Incrementa para o proximo estado ... (estado 4)
         CKP=1; //Deixa o Master Shiftar SSPBUF fora do Slave liberando clock
         break;

         case (estado_4):
         /*Master quer ler mais bytes novamente*/
         CKP = 0; //Poe Master em Espera
         printf("Estado 4");
         SSPBUF = buff[indice_buff]; //Manda Proximo Byte do buffer pro Master
         indice_buff++; //Incrementa buffer
         //Nao deixa rolar Buffer Overflow (Caralho tem falha de seguranca)
         if (indice_buff >TAM_BUFF) indice_buff = 0;
         CKP=1; //Deixa o Master Shiftar SSPBUF fora do Slave liberando clock

         case (estado_5):
         /*Master nao quer mais saber de receber dados do slave, a logica i2c
         deve ser resetada e esperar por uma nova operacao do Master*/
         printf("Estado 5");
         break;

         default:
         /*Aconteceu um estado inesperado e nao conhecido devemos resetar o pic
         porem agora vou so indicar que algo fudeu..*/
         output_high(PIN_A0);
         printf("Estado nao encontrado");
         while (1);
         break;
      }
   }
}

void inicia_i2c()
{
   set_tris_c(0b11111111);
   SSPCON1 = 0b00110110; //Modo Slave 7 bits enderecamento
   SSPADD = ENDERECO_SLAVE;
   SSPSTAT = 0;
   WCOL = 0;
   SSPOV = 0;
}

void main()
{
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   inicia_i2c();

   while (TRUE)
   {
      output_high(PIN_A1);
      delay_ms(500);
      output_low(PIN_A1);
      delay_ms(500);
   }
}

and His Header
Code:

#include <16F877A.h>
#device adc=8
#use delay(clock=20000000)
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use rs232(baud=1200,parity=N,xmit=PIN_B7,rcv=PIN_B6,bits=8)


Please sorry anyway about my English and the bunch of code that I posted
neil



Joined: 08 Sep 2003
Posts: 128

View user's profile Send private message

PostPosted: Wed Jan 28, 2004 8:51 am     Reply with quote

Hello Leonardo,
that slave code was written by me in the earlier message. We found that the slave code does not like having a stop, then start sent to it. If you remove i2c_stop(); from your master code, you will probably find this works as it is, but also look at a post by Kyle (in the same post I started). This explains that the stop condition can cause an interrupt and this needs to be serviced otherwise the PIC can crash!
This stop condition corresponds to a value of 0x30 in SSPSTAT, so if you put the switch() from Kenny's code inside this:
Code:
if(SSPSTAT != 0x30){ switch() here...
}
Your slave should not crash.

I hope this helps
Neil.
kda406



Joined: 17 Sep 2003
Posts: 97
Location: Atlanta, GA, USA

View user's profile Send private message

PostPosted: Wed Jan 28, 2004 8:57 am     Reply with quote

Leonardo,

I don't know if this will fix your problem, but it is worth a try. Take the code you posted and move the clock stretching code out of the individual cases to the beginning and end of the ISR. Please reply back if this helped or not.

-Kyle

Sort of like this:
Code:

// I2C Slave Interrupt Handler
#int_SSP
SSP_isr() {
   CKP = 0;   // Make Master wait by holding SCL low
<overhead and switch/case code here>
   CKP = 1;       // Allow master to continue by re-enabling SCL
}
neil



Joined: 08 Sep 2003
Posts: 128

View user's profile Send private message

oops!
PostPosted: Wed Jan 28, 2004 9:06 am     Reply with quote

Sorry, I was writing the above post while your reply to mine arrived! Like I said, I'm not the best person to be asking! Confused
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Wed Jan 28, 2004 9:07 am     Reply with quote

Not sure why you are having to stretch the clock. My code does not do this and everything works great. We use I2C and the main bus to communicate in a multi-master enviroment. Some of the devices are 4MHz mixed with 20MHz as well as an embedded 586 PC104 card using one of Phillips I2C chips. Now I am using the slower speed to transmit mainly due to wire capacitance (the pics are actually bt banging around 47KHz). What speed are you transmitting?
neil



Joined: 08 Sep 2003
Posts: 128

View user's profile Send private message

PostPosted: Wed Jan 28, 2004 9:08 am     Reply with quote

Using hardware master @ 100KHz.
Thomas Blake



Joined: 18 Jan 2004
Posts: 22
Location: Burbank CA

View user's profile Send private message

I2C Slave
PostPosted: Wed Feb 04, 2004 6:23 pm     Reply with quote

There is an erratum out that may be relevant: http://www.microchip.com/download/lit/suppdoc/errata/80131c.pdf
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