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

I2C problem: SDA and SCL Lines goes low
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
RVR



Joined: 04 Jan 2012
Posts: 18

View user's profile Send private message

I2C problem: SDA and SCL Lines goes low
PostPosted: Thu Oct 18, 2012 9:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 1:37 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 2:09 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 2:26 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 2:32 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 2:48 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 3:12 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 18, 2012 3:53 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 19, 2012 12:56 am     Reply with quote

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. Smile
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

View user's profile Send private message

Re: I2C problem: SDA and SCL Lines goes low
PostPosted: Fri Oct 19, 2012 7:11 am     Reply with quote

the question still open
Ttelmah



Joined: 11 Mar 2010
Posts: 19559

View user's profile Send private message

PostPosted: Fri Oct 19, 2012 8:20 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 20, 2012 6:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Oct 21, 2012 2:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Oct 21, 2012 3:44 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 22, 2012 12:54 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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