|
|
View previous topic :: View next topic |
Author |
Message |
leonardo.araujo
Joined: 28 Jan 2004 Posts: 0 Location: Brasil
|
Problems with I2C Slave Mode |
Posted: Wed Jan 28, 2004 5:39 am |
|
|
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
|
|
Posted: Wed Jan 28, 2004 8:51 am |
|
|
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
|
|
Posted: Wed Jan 28, 2004 8:57 am |
|
|
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
|
oops! |
Posted: Wed Jan 28, 2004 9:06 am |
|
|
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! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Jan 28, 2004 9:07 am |
|
|
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
|
|
Posted: Wed Jan 28, 2004 9:08 am |
|
|
Using hardware master @ 100KHz. |
|
|
Thomas Blake
Joined: 18 Jan 2004 Posts: 22 Location: Burbank CA
|
|
|
|
|
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
|