|
|
View previous topic :: View next topic |
Author |
Message |
henry
Joined: 05 Feb 2005 Posts: 10
|
HELP WITH I2C PIC16F690 |
Posted: Mon Aug 21, 2006 8:17 am |
|
|
HELLO,
I was looking for information in all topics about I2C and I still can't solve my problem.....
I'm trying to comunicate 2 PIC16F690 with I2C, 1 Master and 1 Slave, but i don't know what is the problem with my code......the 'ACK' bit sometimes is received and sometimes isn't.
START
1st byte - adress
2nd byte - data
3rd byte - data
STOP
Sometimes the master reveceives 3 'ACK', 1 per bit.....and doesn't receive the 'NACK'......othewise there are no any 'ACK'.
The 'ssp_handler' routine in the SLAVE is like Microchip's one.
Thanks
Henry
Last edited by henry on Tue Aug 22, 2006 2:37 am; edited 2 times in total |
|
|
Ttelmah Guest
|
|
Posted: Mon Aug 21, 2006 9:07 am |
|
|
Without looking too deeply, there are two big problems 'leaping out', which are connected.
You are using the 'INT_SSP' defintion, which inherently implies that the _compiler_ will have allready 'added' the interrupt register saves, before this code is called. You then save the registers inside your routine, which is both unnecessary (given that the compiler has already done this), and takes _time_. Now you send bytes immediately following one another. Given the time delays in the interrupt handling (worse in C, because of the number of registers involved), and especially given your code effectively 'saving' the registers twice, the slave just does not have time to actually handle it's 'end' of the transaction...
You need to make a decision, whether you are going to use the existing assembler SSP handler, and the assembler register saving (which should only be used together, and without _any_ C in the routines), in which case, your interrupt handler, needs to be defined as 'int_global', or use the C approach, in which case a lot of the routine can be thrown away, since the compiler has already done the necessary register saving. However the 'ssp_handler' routine you are using, needs a _lot_ of extra registers saved (it is using array accesses, and a switch statement in particular), so going to assembler, would involve a lot of work.
Look at the CCS example I2C slave routine, which shows how to handle this, and slow down the master transactions a little, and you may then have a chance.
Best Wishes |
|
|
henry
Joined: 05 Feb 2005 Posts: 10
|
|
Posted: Tue Aug 22, 2006 1:43 am |
|
|
Hello everybody,
Now, i changed my code and i can send and receive correctly the 3 bytes i want...
START
delay....
1st byte - Address
delay...
2nd byte - data
delay...
3rd byte - data
delay...
STOP
The problem is that i'm not receiving the NACK at the end of the last byte.
How the MASTER sends a NACK???
Thanks
Henry
Code: |
/////////////////////////////////////////////////////////////////////////////////
MASTER
/////////////////////////////////////////////////////////////////////////////////
#if defined(__PCM__)
#include <16F690.h>
#device ADC=10
#fuses HS, NOPROTECT, NOBROWNOUT, NOMCLR, NOCPD, NOWDT, PUT, NOIESO, NOFCMEN
#use delay(clock=20000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5, BITS = 8 )
#use i2c(MASTER, sda=PIN_B4, scl=PIN_B6, SLOW=100000 )
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////FUNCIONES//////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include "inicializacion.c" //Config. inicial de todos los registros
#include "puerto_serie.c" //On serial port, off serial port....
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////MAIN/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void main()
{
delay_cycles( 1 );
output_a(0b00000000); //Latch del puerto a 00
output_b(0b00000000); //Latch del puerto a 00
output_c(0b00000000); //Latch del puerto a 00
delay_cycles( 1 );
set_tris_a(0b11111111); //All I/O ports as inputs
set_tris_b(0b11111111);
set_tris_c(0b11111111);
delay_cycles( 1 );
puerto_serie_off(); //Serial port off
inicializacion(); //Inicializacion general de registros
delay_ms( 1000 );
do
{
i2c_start(); //start bit
delay_cycles( 50 );
i2c_write(0xa0); //Send slave address
delay_cycles( 50 );
i2c_write(1); //Send first data
delay_cycles( 50 );
i2c_write(40); //Send second data
delay_cycles( 50 );
i2c_stop(); //Stop bit
delay_ms( 1000 ); //delay
i2c_start(); //start bit
delay_cycles( 50 );
i2c_write(0xa0); //Send slave address
delay_cycles( 50 );
i2c_write(2); //Send first data
delay_cycles( 50 );
i2c_write(80); //Send second data
delay_cycles( 50 );
i2c_stop(); //Stop bit
delay_ms( 1000 ); //delay
i2c_start(); //start bit
delay_cycles( 50 );
i2c_write(0xa0); //Send slave address
delay_cycles( 50 );
i2c_write(3); //Send first data
delay_cycles( 50 );
i2c_write(120); //Send second data
delay_cycles( 50 );
i2c_stop(); //Stop bit
delay_ms( 1000 ); //delay
}while( TRUE );
}
/////////////////////////////////////////////////////////////////////////////////
SLAVE
/////////////////////////////////////////////////////////////////////////////////
#if defined(__PCM__)
#include <16F690.h>
#device ADC=10
#fuses HS, NOPROTECT, NOBROWNOUT, NOMCLR, NOCPD, NOWDT, PUT, NOIESO, NOFCMEN
#use delay(clock=20000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5, BITS = 8 )
#use i2c( SLAVE, SDA=PIN_B4, SCL=PIN_B6, address=0xa0, SLOW=100000 )
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////FUNCIONES//////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include "ssp_handler.c"
#include "inicializacion.c" //Config. inicial de todos los registros
#include "puerto_serie.c" //On serial port, off serial port....
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////INTERRUPCIONES//////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#INT_SSP NOCLEAR
void ssp_interupt ()
{
////////////////////////////////////////////////////////////////////////////////
ssp_handler();
////////////////////////////////////////////////////////////////////////////////
bit_clear( SSPSTAT_R, 0); //Clear flag buffer full
bit_clear( SSPCON_R, 6); //Clear flag Overflow
bit_clear( SSPSTAT_R,7 ); //Must be clear
}
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////MAIN/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void main()
{
delay_cycles( 1 );
output_a(0b00000000); //Latch del puerto a 00
output_b(0b10000000); //PIN TX puerto serie a alto
output_c(0b00000000); //Latches del puerto a 00
delay_cycles( 1 );
set_tris_a(0b00001111);
set_tris_b(0b01111111);
set_tris_c(0b11111111);
delay_cycles( 1 );
inicializacion(); //Inicializacion general de registros
delay_ms( 100 );
puerto_serie_tx();
printf("start");
bit_clear( SSPSTAT_R,7 ); //Must be clear
buffer_full = 0;
bit_clear( PIR1_R, 3 ); //Clean interrupt flag
bit_clear( SSPCON_R,5 ); //reset ssp module
delay_cycles( 5 );
bit_set( SSPCON_R,5 ); //reset ssp module
delay_cycles( 5 );
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
do
{
bit_clear( SSPSTAT_R,7 ); //Must be clear
if(buffer_full == 1)
{
buffer_full = 0;
printf("%u,%u\n\r",buffer_i2c[ 0 ], buffer_i2c[ 1 ]);
}
}while( TRUE );
}
/////////////////////////////////////////////////////////////////////////////////
SLAVE FUNCTIONS
/////////////////////////////////////////////////////////////////////////////////
//SSP_Handler
//---------------------------------------------------------------------
// The I2C code below checks for 5 states:
//---------------------------------------------------------------------
// State 1: I2C write operation, last byte was an address byte.
//
// SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
//
// State 2: I2C write operation, last byte was a data byte.
//
// SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
//
// State 3: I2C read operation, last byte was an address byte.
//
// SSPSTAT bits: S = 1, D_A = 0, R_W = 1, BF = 0
//
// State 4: I2C read operation, last byte was a data byte.
//
// SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
//
// State 5: Slave I2C logic reset by NACK from master.
//
// SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 0
//
// For convenience, WriteI2C and ReadI2C functions have been used.
//---------------------------------------------------------------------- ////
//////////////////////////////VARIABLES GLOBALES////////////////////////////////
int buffer_i2c[0x02]; //Data buffer
int address_i2c; //address i2c
int buffer_full;
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////ssp_handler.c/////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void ssp_handler()
{
int SSPSTAT_TEMP = 0; //Auxiliar register for SSPSTAT
int incoming = 0;
SSPSTAT_TEMP = SSPSTAT_R & 0b00101101; //Masking bits unuseful on SSPSTAT
switch ( SSPSTAT_TEMP )
{
//State 1
case 0x09: //Write operation,last byte was address,
{ //buffer is full
buffer_i2c[ 0 ] = 0; //clean data buffer
buffer_i2c[ 1 ] = 0;
address_i2c = 0; //Clean address i2c
incoming = i2c_read(); //Read byte received
bit_clear( PIR1_R, 3 ); //Clean Interrupt flag
}
break;
////////////////////////////////////////////////////////////////////////////////
//State 2
case 0x29: //Write operation, last byte was data,
{ //buffer is full
buffer_i2c[ address_i2c ] = i2c_read();//Received byte to buffer
bit_clear( PIR1_R, 3 ); //Clean interrupt flag
address_i2c++; //++ buffer address
if( address_i2c >= 2)
{
address_i2c = 0; //Clean address i2c
buffer_full = 1;
}
}
break;
////////////////////////////////////////////////////////////////////////////////
//State 3
case 0x0C: //Read operation, las byte was address,
{ //buffer empty
address_i2c = 0; //Clean address i2c
i2c_write(buffer_i2c[address_i2c]); //Write byte in SSPBUF
bit_clear( PIR1_R, 3 ); //Clean interrupt flag
address_i2c++; //++ buffer address
}
break;
////////////////////////////////////////////////////////////////////////////////
//State 4
case 0x2C: //Read operation, last byte was data,
{ //buffer empty
if( address_i2c >= 2)
{
address_i2c = 0; //Clean address i2c
}
i2c_write(buffer_i2c[address_i2c]); //Write byte in SSPBUF
bit_clear( PIR1_R, 3 ); //Clean interrupt flag
address_i2c++; //++ buffer address
}
break;
////////////////////////////////////////////////////////////////////////////////
//Estado 5
case 0x28: //NACK receive when transmiting data
{
bit_clear( PIR1_R, 3 ); //Clean interrupt flag
printf("todo ok\n\r");
}
break;
////////////////////////////////////////////////////////////////////////////////
default: //ERROR
{
bit_clear( PIR1_R, 3 ); //Clean interrupt flag
bit_clear( SSPCON_R,5 ); //reset ssp module
delay_cycles( 5 );
bit_set( SSPCON_R,5 ); //reset ssp module
printf("todo ko\n\r");
}
break;
}
}
|
|
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Aug 22, 2006 12:54 pm |
|
|
If the Master is writing to the slave then it's the slave that sends the ACK/NOACK back to let the master know if the information was received okay. The only time the master sends the ACK/NOACK to the slave is if the master is Reading from the slave. This tells the slave if the master is still going to want more data or if it's done reading from the slave. The NOACK is sent on the Last read that is sent from the master by sending the command:
variable = i2c_read(0);
The zero(0) sends the NOACK to the slave at the end of the read sequence.
Ronald |
|
|
Guest
|
|
Posted: Wed Aug 23, 2006 12:14 am |
|
|
Thanks,
Now i have a tested I2C for 2 PIC16f690 (MASTER - SLAVE) at 100kbps. anyone who needs the code just ask ..... |
|
|
henry
Joined: 05 Feb 2005 Posts: 10
|
|
Posted: Wed Aug 23, 2006 12:16 am |
|
|
Thanks,
Now i have a tested I2C for 2 PIC16f690 (MASTER - SLAVE) at 100kbps. anyone who needs the code just ask ..... |
|
|
Guest
|
|
Posted: Wed Jun 13, 2007 10:08 am |
|
|
henry wrote: | Thanks,
Now i have a tested I2C for 2 PIC16f690 (MASTER - SLAVE) at 100kbps. anyone who needs the code just ask ..... |
Yes, Thank-you, would you send me the code? I too am using the 690s.
Please send to
ebarnes@islandhideaway.net
Thanks in advance.
Ed. |
|
|
|
|
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
|