|
|
View previous topic :: View next topic |
Author |
Message |
RVR
Joined: 04 Jan 2012 Posts: 18
|
I2C problem: SDA and SCL Lines goes low |
Posted: Thu Oct 18, 2012 9:22 am |
|
|
Hi,
CCS PCHW 4.130
Master 18f2550
Slave 18f2550
Pickit3 programmer
I have a old problem with the I2C bus. In the master - slave mode i need to the slave write data and the master read it. Very simple. But after the start, address+1, ack, both lines goes low rather than the slave start to write.
When measure the lines reallly are into low level, and when i reset slave
PIC, the master resumes the clock signal and the slave (obviously) response with a SDA high state.
any idea?
MASTER CODE
Code: |
//ARCHIVOS DE CABECERA y ARCHIVOS FUENTE//
#Include <18f2550.h>
#device adc=10;
//FUSES//
#Fuses HSPLL
#Fuses PLL5
#Fuses CPUDIV1
#Fuses NOFCMEN
#Fuses NOIESO
#Fuses PUT
#Fuses NOBROWNOUT
//#FUSES DEBUG
#Fuses VREGEN
#Fuses NOWDT
#Fuses NOPBADEN
#Fuses NOSTVREN
#Fuses NOPROTECT
#fuses MCLR
//DECLARACION DEL CLOCK PARA EL MICRO//
#use delay (clock=48000000)
#DEFINE USB_CON_SENSE_PIN Pin_B2
//librerias y variables para el protocolo usb//
#Include <pic18_usb.h>//capa de hardware de los micros 18f
#Include <tracker_descriptores.h>//configuracion Usb y los descriptores
#Include <Usb.c>
int8 buffer_usb_in[USB_EP1_RX_SIZE]; //64
int8 buffer_usb_out[USB_EP1_TX_SIZE];//64 Ver tracker_descriptores.h
//declaraciones y varaibels para la comunicacion I2C//
#Use I2C(MASTER,slow, SDA=PIN_B0,SCL=PIN_B1,force_hw)
int8 Slave_Dir=0xA0;//direccion slave
int8 Buffer_I2C_MASTER_IN[8];
int8 Buffer_I2C_MASTER_OUT[8];
int8 i=0;//indice para buffer entrada
int8 j=0;//indice para buffer salida
//flags globales de tareas principales//
int1 inicializacion=1;
int1 adc_active=0;
int1 tarea_usb_pendiente=0;
//Funciones de Interrupcion//
//Funciones//
void task_slave(int8 configuracion)
{
i2c_start();//restart para enviar direccion con bit READ
i2c_write(Slave_dir+1);//el bit0 corresponde al R/W, R=1 para lectura en el bus
Buffer_I2C_MASTER_IN[0]=i2c_read(1);
Buffer_I2C_MASTER_IN[1]=i2c_read(1);
Buffer_I2C_MASTER_IN[2]=i2c_read(0);
i2c_stop();
}
//MAIN//
void main (void)
{
set_tris_a(0x00);//A0 A1 A2 A3 - A5 A6 - ENTRADAS
set_tris_B(0x07);//B0 B1 B2 - - - - - ENTRADAS
set_tris_c(0x80);//- - - - - - - - ENTRADAS
while (true)
{
if (input(Pin_b2 ))//usb.h, es lo mismo que input(usb_con_sense_pin)
{
if (inicializacion)
{
usb_init();
usb_task();
inicializacion=0;
}
tarea_usb_pendiente=1;
output_high(led_ok);
while (tarea_usb_pendiente)
{
if (usb_enumerated())
{
if (usb_kbhit(1))
{
usb_get_packet(1,buffer_usb_in,64);
if (buffer_usb_in[3])
{
output_high(led_ok);
task_slave(0x01); buffer_usb_out[50]=buffer_I2C_MASTER_IN[0];
buffer_usb_out[51]=buffer_I2C_MASTER_IN[1];
buffer_usb_out[52]=buffer_I2C_MASTER_IN[2];
}
//send package//
usb_put_packet(1,buffer_usb_out,64,usb_dts_toggle);
tarea_usb_pendiente=0;
output_low(led_ok); //fin de tareas
}//kbhit
}
tarea_usb_pendiente=0;
}//while tarea pendiente
}//input
}//while
}//main
|
SLAVE CODE
Code: |
//same fuses
#Define Led_ok Pin_C6
//declaraciones y varaibles para la comunicacion I2C//
#Define Slave_Dir 0xA0
#Use I2C(SLAVE,slow, SDA=PIN_B0,SCL=PIN_B1,ADDRESS=Slave_Dir,force_hw)
int8 Buffer_I2C_SLAVE_IN[8];
int8 Buffer_I2C_SLAVE_OUT[8];
int8 i=0;//indice para buffer entrada
int8 j=0;//indice para buffer salida
//flags globales de tareas principales//
int1 tarea_I2C_pendiente=0;
//Funciones de Interrupcion//
#INT_SSP
void ssp_interrupt (void)
{
int8 estado;
tarea_I2C_pendiente=1;
estado = i2c_isr_state();//lee data desde el SSPBUF
if(estado==0x80)//lee la direccion y bit R/W
{i2c_read(2);
i2c_write(0x20);//SEE new info
}//add+1
if(estado==0x81)
{i2c_write(0x21);}
if(estado==0x82)
{i2c_write(0x22);}
if(estado==0x83)
{i2c_write(0x23);}
clear_interrupt(int_ssp);
}
//funciones
void enable_I2C(void)
{
enable_interrupts(int_ssp);//com serial
enable_interrupts(global);
}
//MAIN//
void main (void)
{
set_tris_a(0xF6);//A0 A1 A2 A3 - A5 A6 - ENTRADAS
set_tris_B(0x77);//B0 B1 B2 - B4 - - - ENTRADAS
set_tris_c(0x42);//- C1 - - - - C6 - ENTRADAS (los pines de USB los maneja el SIE)
buffer_I2C_SLAVE_IN[1]=0;
enable_I2C();//habilita las interrupciones del SSP
while (true)
{
if (tarea_I2C_pendiente)
{
output_toggle(led_OK);
}
tarea_I2C_pendiente=0;
}//while
}//main
|
SDA blue and shows start, 0xA0, ACK
SCL red with 9 clock pulses
after the last pictures and when reset the slave, the master clock
resumes
new info:
Deleting the USB protocol communication from the master, replaced by a single pulse into b2, and putting after i2c_read(2) an instruction i2c_write(0x20), the results was the same.
Last edited by RVR on Thu Oct 18, 2012 2:52 pm; edited 2 times in total |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Thu Oct 18, 2012 1:37 pm |
|
|
For starters you need to whittle those programs down to smaller working versions. remove all the USB stuff and just focus on I2C.
Somethings in the slave:
1. You are not correctly handling state==0x80. This needs to read and write (see the manual entry for this method).
2. Around the same location you call i2c_read(2). That function only takes 0 or 1 as inputs, so you may be having trouble there. For slave communications, you don't specify a parameter in i2c_read() as the hardware takes care of it. Only the master manages acks/nacks |
|
|
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Thu Oct 18, 2012 2:09 pm |
|
|
jeremiah wrote: | For starters you need to whittle those programs down to smaller working versions. remove all the USB stuff and just focus on I2C.
Somethings in the slave:
1. You are not correctly handling state==0x80. This needs to read and write (see the manual entry for this method).
2. Around the same location you call i2c_read(2). That function only takes 0 or 1 as inputs, so you may be having trouble there. For slave communications, you don't specify a parameter in i2c_read() as the hardware takes care of it. Only the master manages acks/nacks |
Thanks for your answer Jeremiah.
some observations:
1.-I agree with you, i made a mistake and delete the i2c_write in 0x80 because this it part to a large program.
2.- i2c_read(2) its a new parameter withe 4.130 upgrade (see ex_slave.c) that does not release the clock to later write. it is correct.
3.-about the USB protocol, this works ok.
The question still open. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Thu Oct 18, 2012 2:26 pm |
|
|
I don't disagree about the USB protocol working, it was more that it is difficult to help when you have to wade through a bunch of code not related to the problem. Getting a program down to the smallest part that is causing the issue sometimes helps immensely, especially for us other folk who aren't as intimately familiar with your code. It tends to hide issues from us that might be in plain sight.
Back onto the "2" parameter. Have you tried taking it out and running the program? The text description in ex_slave.c would indicate that it isn't releasing the clock, which would give you some of the issues you see. Granted, I am not familiar with using that parameter, so that is conjecture on my part based on how I interpreted the comment. Just something to try. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Thu Oct 18, 2012 2:32 pm |
|
|
No, you are missing the point about i2c_read(2).
It must be followed by an i2c_write.
state 0x80, is the only state that may use this. This reads the byte _without_ releasing the clock, which _must_ then be followed by a write, which then releases the clock. In your code you are using this, but not then writing on this state, which _will_ result in the clock being held low.....
Best Wishes |
|
|
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Thu Oct 18, 2012 2:48 pm |
|
|
Ttelmah wrote: | No, you are missing the point about i2c_read(2).
It must be followed by an i2c_write.
state 0x80, is the only state that may use this. This reads the byte _without_ releasing the clock, which _must_ then be followed by a write, which then releases the clock. In your code you are using this, but not then writing on this state, which _will_ result in the clock being held low.....
Best Wishes |
Thanks for your answer Ttelmah.
About the sense of i2c_read(2), in the last reply I wrote that I made a mistake, delete a sentence into 0x80 state with the i2c_write, so the i2c_read its now correct. So the i2c_read(2) its right applied. |
|
|
Battery David
Joined: 01 Feb 2010 Posts: 25
|
|
Posted: Thu Oct 18, 2012 3:12 pm |
|
|
I recently wrote I2C slave code and added the i2c_read(2) at the same place. I had to do a tech support request to CCS to get it worked out. It isn't in the manual yet, they said it would be in soon. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 18, 2012 3:53 pm |
|
|
That's interesting, about the i2c_read(2) being a new feature. I made a
test program and it definitely produces different code for that option.
With a parameter of '2', it only reads the SSPBUF. The normal version
clears the overflow flag, waits to receive a byte, then it reads SSPBUF and
then it sets SCL high when done. I tested this with vs. 4.130 and 4.137.
It's the same in both versions.
Code: |
.................... #int_ssp
.................... void ssp_isr(void)
.................... {
.................... int8 temp;
....................
.................... temp = i2c_read();
00AE: BCF SSPCON1.SSPOV
00B0: BTFSS PIR1.SSPIF
00B2: BRA 00B0
00B4: MOVF SSPBUF,W
00B6: BSF SSPCON1.CKP
00B8: MOVWF temp
.................... temp = i2c_read(0);
00BA: BCF SSPCON1.SSPOV
00BC: BTFSS PIR1.SSPIF
00BE: BRA 00BC
00C0: MOVF SSPBUF,W
00C2: BSF SSPCON1.CKP
00C4: MOVWF temp
.................... temp = i2c_read(1);
00C6: BCF SSPCON1.SSPOV
00C8: BTFSS PIR1.SSPIF
00CA: BRA 00C8
00CC: MOVF SSPBUF,W
00CE: BSF SSPCON1.CKP
00D0: MOVWF temp
....................
.................... //-----------------------
....................
.................... temp = i2c_read(2);
00D2: MOVFF SSPBUF,temp
....................
.................... //-----------------------
....................
.................... temp = i2c_read(3);
00D6: BCF SSPCON1.SSPOV
00D8: BTFSS PIR1.SSPIF
00DA: BRA 00D8
00DC: MOVF SSPBUF,W
00DE: BSF SSPCON1.CKP
00E0: MOVWF temp
.................... temp = i2c_read(4);
00E2: BCF SSPCON1.SSPOV
00E4: BTFSS PIR1.SSPIF
00E6: BRA 00E4
00E8: MOVF SSPBUF,W
00EA: BSF SSPCON1.CKP
00EC: MOVWF temp
....................
....................
.................... }
|
Test program:
Code: |
#include <18F2550.h>
#fuses HS, NOWDT, BROWNOUT, PUT, NOLVP, CPUDIV1
#use delay(clock=20M)
#use i2c(Slave, sda=PIN_B0, scl=PIN_B1, address=0xA0)
#int_ssp
void ssp_isr(void)
{
int8 temp;
temp = i2c_read();
temp = i2c_read(0);
temp = i2c_read(1);
//-----------------------
temp = i2c_read(2);
//-----------------------
temp = i2c_read(3);
temp = i2c_read(4);
}
//==================================
void main()
{
while(1);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Fri Oct 19, 2012 12:56 am |
|
|
Yes, it is an interesting new feature, offering potentially the possibility of using much slower clocks on the slave than previously. Historically if your clock on a slave device was very slow compared to the bus speed, the transactions tended to fail, and this was (of course), because on this particular transaction, the clock got released before the return byte was loaded, and with a fast master, this could cause problems. The new code should allow this to be avoided.
I had in the past used my own receive code for the I2C ISR, for exactly this reason.
Best Wishes |
|
|
RVR
Joined: 04 Jan 2012 Posts: 18
|
Re: I2C problem: SDA and SCL Lines goes low |
Posted: Fri Oct 19, 2012 7:11 am |
|
|
the question still open |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Fri Oct 19, 2012 8:20 am |
|
|
The big problem left is you are not reading for the states below 0x80.
You need to read, or the bus won't release. Remember state 0, is the slave address being received, so it is the very first thing that happens in the slave.....
Code: |
if(estado<0x80) i2c_read();
|
Also, as a comment you can get rid of your clear_interrupt line. Provided the hardware transactions have been properly done, the compiler automatically clears the interrupt for you (unless the handler is declared with 'NOCLEAR').
Best Wishes |
|
|
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Sat Oct 20, 2012 6:58 am |
|
|
Hi Ttelmah,
When I read the states below 0x80 this code works only when the master sends data, but in my code it never happens.
Another thing, I understand that the state 0x00 is the address when the R/W is clean (for master sends data) and the 0x80 is when the slave must to send data (add+1) so, the state 0x00 never take value when the slave sends data.
Another information, I ask in parallel to CCS support and the response was "I don't see anything wrong with your code, and when I tried your programs they worked perfectly fine for me" but when i compile the result its the same.
I know that is not important, but even in Proteus also works correctly.
any idea? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Sun Oct 21, 2012 2:30 am |
|
|
First, get rid of the speed setting in the slave. The slave does not have a 'speed', the bus speed is controlled by the master. This may well be giving an invalid setting for the slave. Common problem.
Second, have you tried using the old standard syntax for the read on state 80?. Though the basic idea of the new format sounds good, it'll only work if the i2c_write code is clearing the clock. I'd not put is past CCS to have missed this. With your slave running at 48MHz, it shouldn't make any difference, and might be the problem.
Best Wishes |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Sun Oct 21, 2012 3:44 pm |
|
|
Also, have you checked the errata for the part to make sure there are no I2C issues with that particular chip? I run into a few in the past. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19559
|
|
Posted: Mon Oct 22, 2012 12:54 am |
|
|
A very good point.
There are a _lot_ of errata for the MSSP part of this chip. I've run into one, where the port would not configure correctly as a master, but remember there were a lot more affecting slave operation, especially to do with the timings of reads/writes to the registers, and with problems regarding clock stretching....
There was at least one problem which required you to use clock stretching to get reliable operation, but another which suggested you didn't or it'd cause problems.....
Best Wishes |
|
|
|
|
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
|