View previous topic :: View next topic |
Author |
Message |
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
I2C slave again and again and again and ... |
Posted: Mon Apr 07, 2008 1:49 pm |
|
|
Hi to all,
This time it's a PIC18F2431 (slave). The interrupt is not working and the master is NOT stalling at all (writing and reading)
Master code: (working for sure, captured on scope)
Code: |
//test
i2c_start();
i2c_write(0xE0); //slave address
i2c_write(0x00);
i2c_write(0xAA);
i2c_write(0x55);
i2c_write(0xA5);
i2c_write(0x5A);
i2c_stop();
delay_ms(100);
i2c_start();
i2c_write(0xE0); //slave address
i2c_write(0x00);
i2c_start();
i2c_write(0xE1); //read
dummy1 = i2c_read();
dummy2 = i2c_read();
dummy3 = i2c_read();
dummy3 = i2c_read();
i2c_stop();
|
slave code:
Code: |
#include <18F2431.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT //Code NOT protected from reads
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOBROWNOUT //NO Reset when brownout detected
#FUSES BORV27 //Brownout reset at 2.7V
#FUSES PUT //Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES NOSTVREN //Stack full/underflow will not cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOWINEN //WDT Timer Window Disabled
#FUSES T1LOWPOWER //Timer1 low power operation when in sleep
#FUSES HPOL_HIGH //High-Side Transistors Polarity is Active-High (PWM 1,3,5 and 7)
//PWM module high side output pins have active high output polarity
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES LPOL_HIGH //Low-Side Transistors Polarity is Active-High (PWM 0,2,4 and 6)
//PWM module low side output pins have active high output polar
#FUSES PWMPIN //PWM outputs disabled upon Reset
#FUSES MCLR //Master Clear pin enabled
#use delay(clock=8000000)
#use rs232(baud=38400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, BRGH1OK)
#use i2c(Slave,Slow,sda=PIN_C4,scl=PIN_C3,address=0xE0, FORCE_HW)
#use spi(Master, MSB_FIRST, DI=PIN_A2, DO=PIN_A3, CLK=PIN_A4, BITS=8, BAUD = 100000, MODE=0)
#byte PORTA = 0xF80
#byte PORTB = 0xF81
#byte PORTC = 0xF82
#byte TRISB =0xF83
#byte TRISC =0xF84
#byte SSPADD = 0xFC8
#byte SSPCON = 0xFC6
#byte SSPSTAT = 0xFC7
#bit SSPOV = SSPCON.6
#bit DA = SSPSTAT.5
#bit P = SSPSTAT.4
#bit S = SSPSTAT.3
#bit RW = SSPSTAT.2
#bit BF = SSPSTAT.0
#bit CKP = SSPCON.4
#define SSPSTATMASK 0B00101101
///////////////////////////////////////////////////////////////////////////////
BYTE Page[256] = {0x01, 0x02, 0x03, 0x04};
BYTE InternalAddressCounter = 0;
int1 InternalAddress = TRUE;
///////////////////////////////////////////////////////////////////////////////
#int_SSP
void SSP_isr(void)
{
BYTE incoming, state;
state = SSPSTAT & SSPSTATMASK;
RX_LOS_SFP = 0; //LED indicator
switch (state)
{
case 0B00001001: // i2c write operation, last byte was address
incoming = i2c_read(); // dummy read!
InternalAddress = TRUE;
break;
case 0B00101001: // i2c write operation, last byte was data
incoming = i2c_read(); // data read
if (InternalAddress)
{
InternalAddressCounter = incoming;
InternalAddress = FALSE;
}
else
Page[InternalAddressCounter++] = incoming;
break;
case 0B00001100: // i2c read operation, last byte was address
i2c_write(Page[InternalAddressCounter++]); // data write
break;
case 0B00101100: // i2c read operation, last byte was data
i2c_write(Page[InternalAddressCounter++]); // data write
break;
case 0B00101000: // slave i2c logic reset by NACK from master
break;
default:
break;
}
SSPOV = 0; // process errata
}
///////////////////////////////////////////////////////////////////////////////
#bit CDR_SHDN = PORTC.1
#bit OSC_SHDN = PORTC.2
#bit RX_CDR_LOS = PORTB.2
#bit LOLN = PORTB.3
#bit RX_LOS_SFP = PORTA.1
#bit TX_FAULT_SFP= PORTA.0
////////////////////////////////////////////////////////////////////////////////
void main()
{
int8 Length;
setup_oscillator(OSC_8MHZ|OSC_TIMER1);
PORTA = 0x80;
set_tris_a(0x04);
PORTB = 0x00;
set_tris_b(0xFF);
PORTC = 0x00;
set_tris_c(0xB8);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0|ADC_WHEN_INT0|ADC_INT_EVERY_OTHER);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_INTERNAL);
setup_timer_2(T2_DISABLED,0,1);
//enable_interrupts(INT_RDA);
enable_interrupts(INT_SSP);
SSPCON |= 0x0E;
SSPOV = 0;
BF = 0;
clear_interrupt(INT_SSP);
enable_interrupts(GLOBAL);
RX_LOS_SFP = 1;
TX_FAULT_SFP = 1;
while(1);
}
|
Once the interrupt occurs the LED should turn off:
Code: |
RX_LOS_SFP = 0; //LED indicator
|
But it's always on, no interrupt!!
Any thoughts?
10x |
|
|
Matro Guest
|
|
Posted: Mon Apr 07, 2008 2:36 pm |
|
|
Use output_low() and output_high() instead of assigning directly the register to change output levels.
We already wrote in a previous post that the last read of a master shall return a NACK :
i2c_read(0);
Last thing is that you have to ensure that the tris of port C is not changes during I²C operations, i.e. that no pin level is changed since you don't use fast_io or fixed_io.
Matro |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Apr 07, 2008 2:38 pm |
|
|
I didn't look at your whole program, but I noticed this immediately:
Quote: |
i2c_start();
i2c_write(0xE0); //slave address
i2c_write(0x00);
i2c_start();
i2c_write(0xE1); //read
dummy1 = i2c_read();
dummy2 = i2c_read();
dummy3 = i2c_read();
dummy3 = i2c_read();
i2c_stop();
|
The last i2c_read operation in the Master must do a NACK. In CCS this
is done by giving it the 0x00 parameter as shown in bold below:
Quote: | dummy3 = i2c_read(0); |
|
|
|
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
|
Posted: Tue Apr 08, 2008 12:52 am |
|
|
You're right PCM programmer, but it has nothing to do with issuing an interrupt on the slave side since the master has written first (no interrupt occured)
Matro, i've always used the direct pin assignment and it works perfect. I'll double check the TRISC issue.
One thing to mention is SDA & SCL on PIC18LF2431 can also be configued as INT1 & INT2
Could it be that the micro is looking at those pins as INT1 & INT2 instead of SDA & SCL!?!? (That's why no interrupt is occuring on SSP). PIC18LF2431 is one of the micros that has no silicon errata regarding SSP!
Note: compiler version: 4.066
Thank you, |
|
|
Matro Guest
|
|
Posted: Tue Apr 08, 2008 2:44 am |
|
|
Could you try with the following lines removed from your code :
Code: |
PORTA = 0x80;
set_tris_a(0x04);
PORTB = 0x00;
set_tris_b(0xFF);
PORTC = 0x00;
set_tris_c(0xB8);
|
Have this test and tell us about results.
Matro. |
|
|
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
|
Posted: Tue Apr 08, 2008 3:46 am |
|
|
Matro,
i cannot remove these lines but i re-initialized i2c instead, right after
Code: |
...
// Call
InitI2CSlave();
...
// Implementation
void InitI2CSlave(void)
{
set_tris_c(0xB8);
SSPSTAT = 0x00;
SSPADD = 0xE0;
SSPCON = 0x36;
}
|
The interrupt works only one time and BF stays 1
I even tried the SSP_ISR provided by CCS, same problem
Thanks |
|
|
Matro Guest
|
|
Posted: Tue Apr 08, 2008 4:19 am |
|
|
PICoHolic wrote: | Matro,
i cannot remove these lines but i re-initialized i2c instead, right after
Code: |
...
// Call
InitI2CSlave();
...
// Implementation
void InitI2CSlave(void)
{
set_tris_c(0xB8);
SSPSTAT = 0x00;
SSPADD = 0xE0;
SSPCON = 0x36;
}
|
The interrupt works only one time and BF stays 1
I even tried the SSP_ISR provided by CCS, same problem
Thanks |
Just remove these lines for a test purpose. I don't think it's really a problem.
Remove (comment) all lines that are setting/changing tris or port and have a test without these lines.
It's just to have information. ;-)
Matro. |
|
|
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
|
Posted: Tue Apr 08, 2008 5:11 am |
|
|
OK, Done
The interrupt is still not occuring :(
Using the it was better.
Thanks |
|
|
Matro Guest
|
|
Posted: Tue Apr 08, 2008 5:39 am |
|
|
You can remove the InitI2CSlave() too.
All you are doing in this function is already done because of the #use i2c directive.
Really try without any line modifying any tris or port, and if possible modify your isr to use the i2c_isr_state instead of your SSPSTATMASK.
It should be a good starting point to debug.
Try with this simple isr:
Code: |
#INT_SSP
void i2c_isr()
{
unsigned int8 state;
state = i2c_isr_state();
if(state >= 0x80)
{
i2c_write(state);
//you can add here a serial trace or a LED toggle (not on port C)
}
else
{
state = i2c_read();
//you can add here a serial trace or a LED toggle (not on port C)
}
}
|
AND do not set or change tris in your code. Ensure too that no tris or port change could appear during the main endless loop (your code doesn't need to stay as it later but that is for test purpose).
Tell me about the result.
Matro. |
|
|
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
|
Posted: Tue Apr 08, 2008 6:20 am |
|
|
Thanks Matro,
I have tried it. i swear
Same problem No interrupt!
10x |
|
|
Matro Guest
|
|
Posted: Tue Apr 08, 2008 6:31 am |
|
|
No interrupt at all, or 1 interrupt and after no more?
or some interrupts and after no more?
Could you try it?
- add in the initialization of your slave main()
Code: |
dummy = i2c_read(); //dummy can be any byte variable
SSPOV = 0;
|
- compile and program your slave
- reset the master and keep it in reset
- reset the slave and let it run some seconds
- only now release the master reset and let it run.
What are the results of this test?
Matro. |
|
|
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
|
Posted: Tue Apr 08, 2008 7:22 am |
|
|
here's my new isr:
Code: |
#INT_SSP
void SSP_isr(void)
{
BYTE incoming, state;
state = SSPSTAT & SSPSTATMASK;
RX_LOS_SFP = 0; //LED indicator
// test
if (BF)
incoming = i2c_read();
SSPOV = 0;
BF = 0;
RX_LOS_SFP = 1; //LED indicator
}
|
RX_LOS_SFP (monitored on scope) stays off given that it was ON initially. that means that the interrupt is occuring only once!
The micro is stalling on [incoming = i2c_read();] even if BF is H
Thanks |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Apr 08, 2008 8:17 am |
|
|
Quote: | #use spi(Master, MSB_FIRST, DI=PIN_A2, DO=PIN_A3, CLK=PIN_A4, BITS=8, BAUD = 100000, MODE=0)
|
I'm not sure if this might be your problem but you might not be able to have both I2C & SPI declared. Try commenting out the above line and see if that will enable your I2C routine.
Ronald |
|
|
PICoHolic
Joined: 04 Jan 2005 Posts: 224
|
|
Posted: Tue Apr 08, 2008 8:24 am |
|
|
This is software SPI. It has nothing to do with hardware I2C |
|
|
Matro Guest
|
|
Posted: Tue Apr 08, 2008 8:38 am |
|
|
What is the #use i2c used for the master?
If "force_hw" is present at master level, it can lock the system so you can try to remove it if present.
But I don't think it can be the problem root here.
In your isr try to replace
Code: |
incoming = i2c_read();
|
by
Code: |
#ASM
MOVF SSPBUF,W
#ENDASM
|
Of SSPBUF shall be declared with a #BYTE but I let you do that by yourself.
Did you already try to test your program with several chips or is it always the same?
Matro |
|
|
|