View previous topic :: View next topic |
Author |
Message |
karun211
Joined: 06 Feb 2006 Posts: 8
|
i2c and port b in 16f78 |
Posted: Mon Feb 06, 2006 8:34 pm |
|
|
Hi
It has been a wonderful experience using the CCSC compiler for my PIC projects . Thanks for the amazing compiler . Of late I have sort of run into a problem where in when the I2C communication is enabled and used in PIC16F87 , I am unable to use Port B pins for input . I have also disabled the interrupt on change and all other interrupts but for I2C . When the program reads an input from the Port B , the I2C communication gets killed in the board . I have not been able to figure out any solution to this . I am just wondering if there is a known bug in using I2C and Port B for inputs ( even when trying to read each pin at a time ) on the 16F87 .Any kind of advice on this would be very helpful .
Thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 06, 2006 9:40 pm |
|
|
1. Do you have a debugger (ICD2) connected to the PIC ?
2. Do you have NOLVP in your #fuses statement ?
If not, then add it. |
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
thanks |
Posted: Mon Feb 06, 2006 11:06 pm |
|
|
[quote="PCM programmer"]1. Do you have a debugger (ICD2) connected to the PIC ?
2. Do you have NOLVP in your #fuses statement ?
If not, then add it.[/quote]
i dont have a debugger connected and i never tried NOLVP in #fuses , i will give it a shot ASAP tomm morning and let you know the results..
thanks for the support |
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
Re: thanks |
Posted: Tue Feb 07, 2006 2:12 pm |
|
|
[quote="karun211"][quote="PCM programmer"]1. Do you have a debugger (ICD2) connected to the PIC ?
2. Do you have NOLVP in your #fuses statement ?
If not, then add it.[/quote]
I tried it using NOLVP in #fuses , it didnot work. do you have any other thoughts? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 07, 2006 2:26 pm |
|
|
1. Post a short but complete program that demonstrates the problem.
Show all #include, #device, #fuses, and #use statements.
2. Post your compiler version. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Tue Feb 07, 2006 2:55 pm |
|
|
Two comments:
1) PIC16F87 share some portB pins with ANALOGS inputs, if one of those pins are not assigned
properly as DIGITAL inputs in your header, by default they wake up as analog inputs.
2) You are using I2C. What about the pull ups resistors ?
Humberto |
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
|
Posted: Tue Feb 07, 2006 3:52 pm |
|
|
Iam attaching what you asked for,
1)
#include <16F87.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP,NOMCLR
#use delay(clock = 20000000)
#use i2c(slave, sda=PIN_B1, scl=PIN_B4)
2) iam using PCM version 3.174
thanks |
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
|
Posted: Tue Feb 07, 2006 4:07 pm |
|
|
[quote="Humberto"]Two comments:
1) PIC16F87 share some portB pins with ANALOGS inputs, if one of those pins are not assigned
properly as DIGITAL inputs in your header, by default they wake up as analog inputs.
2) You are using I2C. What about the pull ups resistors ?
Humberto[/quote]
1)thanks for the pointer, even some of port A pins take ANALOG inputs.
2)i2c bus is working fine when i use Port A pins as inputs, and it only hangs if i use any of the port B pins as inputs ( obviously iam not using I2C rb4 and rb1 pins) so i came to a conclusion that my i2c bus is pure and nothing wrong with the pullup registers. I think i am leaving out a simple obvious point and i need to figure it out soon.
thanks for the support |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 07, 2006 4:15 pm |
|
|
I didn't mean post only the pre-processor statements. I meant
post a small program, and don't forget to also show pre-processor
statements. Post the entire test program. (But keep it short). |
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
|
Posted: Tue Feb 07, 2006 4:28 pm |
|
|
ooops, sorry about that.
here comes the program. This is the shortest i can give you, cause you need to know the i2c routine interrupts and anything shorter than this will not be much useful i guess. thanks
[code]
#include <16F87.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP,NOMCLR
#use delay(clock = 20000000)
#use i2c(slave, sda=PIN_B1, scl=PIN_B4)
unsigned char read_i2c(void);
void i2c_interrupt_handler(void);
void i2c_initialize(void);
void i2c_error(void);
void write_i2c(unsigned char transmit_byte);
#INT_SSP
void ssp_interupt ()
{
i2c_interrupt_handler();
}
/* 16f87X bytes */
/* Change it per chip */
#byte PIC_SSPBUF=0x13
#byte PIC_SSPADD=0x93
#byte PIC_SSPSTAT=0x94
#byte PIC_SSPCON1=0x14
/* Bit defines */
#define PIC_SSPSTAT_BIT_SMP 0x80
#define PIC_SSPSTAT_BIT_CKE 0x40
#define PIC_SSPSTAT_BIT_DA 0x20
#define PIC_SSPSTAT_BIT_P 0x10
#define PIC_SSPSTAT_BIT_S 0x08
#define PIC_SSPSTAT_BIT_RW 0x04
#define PIC_SSPSTAT_BIT_UA 0x02
#define PIC_SSPSTAT_BIT_BF 0x01
#define PIC_SSPCON1_BIT_WCOL 0x80
#define PIC_SSPCON1_BIT_SSPOV 0x40
#define PIC_SSPCON1_BIT_SSPEN 0x20
#define PIC_SSPCON1_BIT_CKP 0x10
#define PIC_SSPCON1_BIT_SSPM3 0x08
#define PIC_SSPCON1_BIT_SSPM2 0x04
#define PIC_SSPCON1_BIT_SSPM1 0x02
#define PIC_SSPCON1_BIT_SSPM0 0x01
//#define RX_BUF_LEN 32
#define RX_BUF_LEN 3
#define NODE_ADDR 0x44 /* I2C address of the slave node */
#define S1 PIN_A0
#define S2 PIN_A1
#define S3 PIN_A2
#define S4 PIN_A3
#define S5 PIN_A4
#define S6 PIN_B2
#define S7 PIN_B6
#define S8 PIN_B7
unsigned char slave_buffer[RX_BUF_LEN];
int buffer_index;
int comms_error;
int debug_state;
void i2c_initialize(void)
{
/* Set up SSP module for 7-bit */
PIC_SSPCON1 = 0x36; /* 0011 0101 */
PIC_SSPADD = NODE_ADDR; /* Set the slave's address */
PIC_SSPSTAT = 0x00; /* Clear the SSPSTAT register. */
enable_interrupts(INT_SSP); /* Enable MSSP interrupts. */
// printf("initializing i2c/n");
}
void i2c_interrupt_handler(void)
{
unsigned char i2c_mask = 0x2D; /* 0010 1101 */
unsigned char temp_sspstat;
unsigned char this_byte;
unsigned char tx_byte;
int x;
/* Mask out the unnecessary bits */
temp_sspstat = PIC_SSPSTAT & i2c_mask;
switch (temp_sspstat)
{
/* Write operation, last byte was an address, buffer is full */
case 0x09: /* 0000 1001 */
/* Clear the receive buffer */
for (x=0; x<RX_BUF_LEN; x++)
{
slave_buffer[x] = 0x00;
}
buffer_index = 0; /* Clear the buffer index */
this_byte = read_i2c(); /* Do a dummy read of PIC_SSPBUF */
debug_state = 1;
break;
/* Write operation, last byte was data, buffer is full */
case 0x29: /* 0010 1001 */
/* Point to the buffer */
this_byte = read_i2c(); /* Get the byte from the SSP */
slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */
buffer_index++; /* Increment the buffer pointer */
/* Get the current buffer index */
/* Subtract the buffer length */
/* Has the index exceeded the buffer length? */
if (buffer_index >= RX_BUF_LEN)
{
buffer_index = 0; /* Yes, clear the buffer index. */
}
debug_state = 2;
break;
/* Read operation; last byte was an address, buffer is empty */
case 0x0C: /* 0000 1100 */
buffer_index = 0; /* Clear the buffer index */
/* Point to the buffer */
tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
write_i2c(tx_byte); /* Write the byte to PIC_SSPBUF */
buffer_index++; /* increment the buffer index */
debug_state = 3;
break;
/* Read operation; last byte was data, buffer is empty */
case 0x2C: /* 0010 1100 */
/* Get the current buffer index */
/* Subtract the buffer length */
/* Has the index exceeded the buffer length? */
if (buffer_index >= RX_BUF_LEN)
{
buffer_index = 0; /* Yes, clear the buffer index */
}
/* Point to the buffer */
/* Get the byte */
tx_byte = slave_buffer[buffer_index];
write_i2c(tx_byte); /* Write to PIC_SSPBUF */
buffer_index++; /* increment the buffer index */
debug_state = 4;
break;
/* A NACK was received when transmitting data back from the master. */
/* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */
/* If we don't stop in this state, then something is wrong!! */
case 0x28: /* 0010 1000 */
debug_state = 5;
break;
/* Something went wrong!! */
default:
i2c_error();
break;
}
}
void i2c_error(void)
{
comms_error = 1;
// printf ("Iam stupid I2C ERROR!\r\n");
}
void write_i2c(unsigned char transmit_byte)
{
unsigned char write_collision = 1;
while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */
{
/* If yes, then keep waiting */
}
while (write_collision)
{
/* If not, then do the i2c_write. */
PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL; /* Clear the WCOL flag */
PIC_SSPBUF = transmit_byte;
/* Was there a write collision? */
if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL)
{
/* Yes there was a write collision. */
write_collision = 1;
}
else
{
/* NO, there was no write collision. */
/* The transmission was successful */
write_collision = 0;
}
}
PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP; /* Release the clock. */
}
/* This function returns the byte in SSPBUF */
unsigned char read_i2c(void)
{
return PIC_SSPBUF;
}
void main(void)
{ int j,temp,t;
debug_state = 0;
i2c_initialize();
enable_interrupts(GLOBAL);
disable_interrupts(INT_RB);
slave_buffer[0]=0x62;
output_low_all();
while (1)
{
if (INPUT(S8)==0)slave_buffer[2]=88;
if (debug_state==2)
{
j=read_i2c();
slave_buffer[0]=j;
debug_state = 0;
}
}
}
[/code] |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Tue Feb 07, 2006 9:26 pm |
|
|
In your code you didn't post the function definition of:
output_low_all();
This statement is wrong:
Code: |
if (INPUT(S8)==0) slave_buffer[2]=88;
|
Surelly you wanted to write:
Code: |
if (!INPUT(S8)) slave_buffer[2]=88;
|
Just to see the difference it is a good practice to see the compiler .lst output file.
Your way generate this code:
Code: |
.................... if (INPUT(S8)==0)
00D5: MOVLW 00
00D6: BTFSC PORTB.7
00D7: MOVLW 01
00D8: XORLW 00
00D9: BTFSS STATUS.2
00DA: GOTO 0DD
.................... slave_buffer[2]=88;
00DB: MOVLW 58
00DC: MOVWF slave_buffer+2
|
Right way generate this code:
Code: |
.................... if (!input(S8))
00DD: BTFSC PORTB.7
00DE: GOTO 0E1
.................... slave_buffer[2]=88;
00DF: MOVLW 58
00E0: MOVWF slave_buffer+2
....................
|
Humberto |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 07, 2006 10:49 pm |
|
|
I have a question about that same line of code.
I assume that's the line you are referring to, when you say
doing an input from Port B causes i2c to stop working.
There are two possibilities:
1. It could be some low-level problem with TRIS or a Read-Modify-Write
problem, that affects the hardware i2c port.
2. It could be a design error in your program.
Your post implied that #1 is the problem, but it really could be #2.
Can you test this theory by inserting a line of code into your program
that just reads pin RB7, and doesn't control anything else ?
See if the i2c still stops working. Example:
Quote: |
while (1)
{
// if (INPUT(S8)==0)slave_buffer[2]=88; // Comment this line.
temp = input(S8); // Add this line.
if (debug_state==2)
{
j=read_i2c();
slave_buffer[0]=j;
debug_state = 0;
}
}
|
|
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
|
Posted: Wed Feb 08, 2006 9:57 am |
|
|
[quote="Humberto"]In your code you didn't post the function definition of:
[b]output_low_all();[/b]
i thought its not imp, this funcion pulls all the pins low. anyways iam posting it here.
void output_low_all(void)
{
output_low(S1);
output_low(S2);
output_low(S3);
output_low(S4);
output_low(S5);
output_low(S6);
output_low(S7);
output_low(S8);
}
This statement is wrong:
[code]
if (INPUT(S8)==0) slave_buffer[2]=88;
[/code]
Surelly you wanted to write:
[code]
if (!INPUT(S8)) slave_buffer[2]=88;
[/code]
thanks for correcting me, but it works if i read inputs from port A. it hangs only when i use port B pins for inputs.
Humberto[/quote] |
|
|
karun211
Joined: 06 Feb 2006 Posts: 8
|
|
Posted: Wed Feb 08, 2006 10:05 am |
|
|
There are two possibilities:
1. It could be some low-level problem with TRIS or a Read-Modify-Write
problem, that affects the hardware i2c port.
2. It could be a design error in your program.
Your post implied that #1 is the problem, but it really could be #2.
1) I tried the above code before and came to conclusion that there is some problem with i2c and port b, as it worked fine when i used port A as inputs. I burned the code again to double check and its the same old story, i2c didnt work.
2)I still strongly belive there is some low level tris B operation which is killing my i2c when i use port B as input. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Feb 08, 2006 1:31 pm |
|
|
Quote: | it hangs only when i use port B pins for inputs. |
In the line above, you refer to "pins". But in the code you posted,
you are only reading one pin, PIN_B7 (S8).
1. If you are reading other pins on Port B, which ones are they ?
I'm concerned that the code you posted does not show everything
you are doing. So it might be difficult for us to solve the problem.
2. Do you guarantee that there is no ICD2 or ICD or anything similar
plugged into your board ? I ask that question because Pin B7
is used by those units to communicate with the PIC. (Also pin B6). |
|
|
|