leonardo.araujo
Joined: 28 Jan 2004 Posts: 0 Location: Brasil
|
I2C Solutions and Problems on MultiSlave(Real) |
Posted: Tue Feb 17, 2004 7:56 am |
|
|
Hi people sorry about my last Message (I wasnīt succeding on sending this message)
Does someone knows why when I use I2C to comunicate with a slave PIC and then try to communicate to another the second slave donīt respond.
When I use
i2c_start
i2c_write (slave1)
i2c_stop
AND
i2c_start
i2c_write(slave2)
i2c_stop
The slave 2 does not respond (If I use just on slave the comunication is Ok)
In this message I will try to put the source code of them:
Master Code
Code: |
#include "C:\Documents and Settings\leonardo.araujo\Desktop\Projeto Telemetria\I2cMaster\i2cmaster.h"
/*Byte alto e baixo dos valores do ADC*/
BYTE v_alto,v_baixo;
BYTE v_adc_alto,v_adc_baixo;
void le_entrada(int entrada);
void le_atuador();
void atua_entrada(int8 n_bit,int1 b_val);
void inicia_lcd();
void escreve_controle_lcd();
void main()
{
BYTE 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);
inicia_lcd();
while (TRUE)
{
le_entrada(31);
cont++;
if (cont > 1)
break;
}
//To tendo que fazer um WorkArround neste Bug de Botar um bit de Sinal
//e para mandar um valor de 8 bits terei que mandar 2 vezes
printf("(%d %d)",v_adc_alto,v_adc_baixo);
while (TRUE)
{
le_entrada(10);
cont++;
if (cont > 1)
break;
}
printf("(%d %d)",v_adc_alto,v_adc_baixo);
while (TRUE)
{
le_entrada(17);
cont++;
if (cont > 1)
break;
}
printf("(%d %d)",v_adc_alto,v_adc_baixo);
/*Agora endereca o microcontrolador de atuacao*/
cont = 0;
while (TRUE)
{
le_atuador();
atua_entrada(7,1);
cont++;
if (cont > 10)
break;
}
printf("Vindo do Atuador os nibles %d %d",v_alto,v_baixo);
}
void le_entrada(int entrada)
{
//Procedure para fazer requisicao para o modulo ADC
i2c_start();
i2c_write(0x2E);//Manda um Request for Write
i2c_write('?');//Manda Byte de comando
i2c_write(entrada);//Complemento do comando
//Agora le do Modulo a ordem e primeiro alto depois baixo
i2c_start(); //Acho que vai ter que reescever o master tambem
i2c_write(0x2F);//Manda um Request for read
v_adc_alto = i2c_read();//Recebe sinalizando que quer mais
v_adc_baixo = i2c_read(0);//Recebe ultimo byte*/
//delay_us(50);
i2c_stop();//Porque o I2C_Stop nao esta funcionando?
}
void le_atuador()
{
i2c_start();
i2c_write(0x20);//Manda um Request for Write
i2c_write('?');//Manda Byte de comando
i2c_start(); //Acho que vai ter que reescever o master tambem
i2c_write(0x21);//Manda um Request for read
v_alto = i2c_read();//Recebe sinalizando que quer mais
v_baixo = i2c_read(0);//Recebe ultimo byte*/
i2c_stop();
}
void atua_entrada(int8 n_bit,int1 b_val)
{
//Mandando escrever em alguma pino do port B
i2c_start();
i2c_write(0x20);//Manda um Request for Write
i2c_write(n_bit);
i2c_write(b_val);
i2c_write('!');//Manda Byte de comando
i2c_stop();//Este Stop é opcional poder ser usado um Repeated Start
}
void inicia_lcd()
{
/*Rotina de Inicializacao do LCD*/
output_low(PIN_C7);//Poe E LOW
delay_ms(20);
escreve_controle_lcd();
}
void escreve_controle_lcd()
{
output_low(PIN_C5);
output_high(PIN_C7);//Poe E HIGH
delay_cycles(10);
output_low(PIN_C7);//Poe E LOW
}
|
And his header
Code: |
#include <16F876.h>
#device adc=8
#use delay(clock=4000000)
#fuses HS,NOWDT,PUT,NOLVP
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3,FORCE_HW)
#use rs232(baud=1200,parity=N,xmit=PIN_B7,rcv=PIN_B6,bits=8)
|
If I send 2 slave codes the server donīt receive my message then I will send just one (This code is fully working)
Code: |
#include "C:\atuador\Atuador.h"
/*Buffer de Recebimento do PIC*/
int8 buff[TAM_BUFF];//Cuidado para nao acabar com a memoria do PIC
int8 indice_buff;
BYTE v_alto = 0,v_baixo = 0;
int1 em_processo_i2c_wr = 0;
int1 em_processo_i2c_r = 0;
char comando = 0;
void processa_pergunta()
{
BYTE valor_b;
/*Este comando manda uma o byte referente a uma porta como so vai ser a linha
portb nos vamos mandar a parte alta e a parte baixa do byte de portb*/
valor_b = input_b();
//Agora antes de terminar a funcao vamos separa os bytes para mandar para I2C
swap(valor_b);
v_alto = valor_b&0b00001111;
swap(valor_b);
v_baixo = valor_b&0b00001111;
}
#int_SSP
interrupcao_i2c()
{
CKP = 0;
if (SSPSTAT != 0x30)
{
//0x2d(101101) Mascara os bits deixando aparecer somente D/a, S, R/W, BF
switch (SSPSTAT & 0x2D)
{
//O Modulo Leitor foi enderecadao para receber um comando
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*/
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;
//Agora o master esta mandando o comando (2 Vezes por comando)
case (estado_2):
SSPOV=0; //Zera Bit de Overflow pois pode ter sido setado anteriormente
buff[indice_buff] = SSPBUF; //Le SSPBUF apagando BF
if (buff[indice_buff] = '?') processa_pergunta();
/*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;
em_processo_i2c_wr = 1;
}
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*/
indice_buff = 0;
SSPBUF = v_alto;
em_processo_i2c_r = 1;
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*/
//SSPBUF = buff[indice_buff]; //Manda Proximo Byte do buffer pro Master
SSPBUF = v_baixo;
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*/
CKP = 1;
break;
default:
/*Aconteceu um estado inesperado e nao conhecido devemos resetar o pic
porem agora vou so indicar que algo fudeu..*/
while (1);
break;
}
}
}
void main()
{
set_tris_a(0b00000000);
set_tris_c(0b11111111);
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);
//Habilita interrupcoes para I2C
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
/*Inicia I2C em Modo Slave*/
SSPCON1 = 0b00110110; //Modo Slave 7 bits enderecamento
SSPADD = ENDERECO_SLAVE;
SSPSTAT = 0;
WCOL = 0;
SSPOV = 0;
while (TRUE)
{
output_high(PIN_A0);
//O comando ? Pergunta o estado de uma linha o ! Seta seu estado.
if ((buff[0] == '?') && (em_processo_i2c_wr == 1))
{
/*O CPU Master quer receber o status da linha portb, logo esta funcao
separa o portb em 2 nibbles referentes ao nible alto e o nible baixo
logo depois ele vai mandar 2 reads para receber estes valores*/
em_processo_i2c_wr = 0;
processa_pergunta();
comando = '?';
};
if ((buff[0] == '!') && (em_processo_i2c_wr == 1))
{
em_processo_i2c_wr = 0;
};
if (em_processo_i2c_r == 1)
{
/*Foi pedida uma leitura se o comando anterior foi um ? esta na hora
de mandar o nible alto e o nible baixo do comando*/
em_processo_i2c_r = 0;
}
output_low(PIN_A0);
}
}
|
And his header
Code: |
#include <16F876.h>
#device adc=8
#use delay(clock=20000000)
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use rs232(baud=1200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
/*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 0x20
#define TAM_BUFF 3 |
I read on microchip errata that this could hapen on repeated start but I tested on my code and does not work, if someone could help
Thanks anyway
Remember this code works fine if does not have two PIC slaves
Later I would put an Image of the schematic
Obs:
Sorry about my english (Iīm from Brazil) |
|