|
|
View previous topic :: View next topic |
Author |
Message |
Imaginos
Joined: 26 Aug 2009 Posts: 6
|
I2C stops working after xmitting less than 50 bytes |
Posted: Sun Aug 30, 2009 11:35 am |
|
|
I'm building an I2C bus between an 18F24J11 and an 16F690. The 18F24J11's MSSP1 module is configured as the master, the 16F690's HW SSP is configured as the slave.
I can move multiple bytes from the master to the slave as per the examples/[however many other threads]. After a seeming random (but small) number of bytes, no more data is received. Neither chip is locked up on any one statement and continue to respond to input and internal interrupts normally (confirmed through various LEDs, encoders, and LCDs). LED toggled within the I2C calls on both chips continue to blink normally.
Reading out the results of i2c_irs_state() onto an LCD. When operating normally moving two byes from the 18F to the 16F, the state is 2 after a complete transfer. Over time and the bus crash begins, the state will initially drop to 1, then start counting upwards as the bus appears to freeze. Infrequently, the I2C communications will not begin after either a hard/soft reset.
I am completely baffled by this behavior. I suspect the problem is in my slave code and probably related to how ACK's are being handled, maybe SSPBUF, BF, and/or SSPOV, however, I don't understand CCS's I2C routines well enough to see where the problem is originating.
Any input would be greatly appreciated. Getting it working is the goal, but I really want to understand what's going on here.
MASTER (18F24J11):
Code: |
#include <18F24J11.h>
#fuses INTRC_IO, WDT, NOPROTECT, NOFCMEN, NODEBUG
#include "common.h" // Contains i2c addresses, some other shared globals
#use delay(clock=4000000)
// Configure I2C as HW master
#use i2c(MASTER, SCL=PIN_C3, SDA=PIN_C4, FORCE_HW, RESTART_WDT, SLOW)
volatile int1 update_i2c=0;
#define OPLIGHT PIN_B0
void main(void)
{
delay_ms(100); // power up delay
// Get to a roughly 1 second timer (with the irs counter)
setup_timer_2(T2_DIV_BY_4,0xF9,8);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
// Initialize data
humid_act=0xff;
temp_act=1;
while(1)
{
if(update_i2c) // Wait for Timer2 to trigger the i2c event
{
i2c_start();
i2c_write(FRONTEND_ADDR);
i2c_write(temp_act);
i2c_write(humid_act);
i2c_stop();
temp_act++; // Increment some debug/dummy data
humid_act--; // These will be populated in production
update_i2c=0; // Clear the timer flag
output_toggle(OPLIGHT); //Toggle an LED
delay_ms(10); // Maybe it's a timing thing?
}
}
}
#INT_TIMER2
void interupt_timer2(void)
{
static int8 Timer2Ticks=0;
Timer2Ticks++;
if(Timer2Ticks%128==1) update_i2c=1;
}
|
SLAVE (16F690): Asside from the config stuff (included for context), most attention is needed in the IRS at the very bottom.
Code: |
#include <16F690.h>
#device PASS_STRINGS=IN_RAM
#fuses INTRC_IO, NOPROTECT, NOFCMEN, NOBROWNOUT, NOMCLR, NOWDT, NOFCMEN
#include "common.h" // Contains the I2C addresses (0xA2 and 0xA4)
#use i2c(SLAVE, SCL=PIN_B6, SDA=PIN_B4, FORCE_HW, ADDRESS=FRONTEND_ADDR, SLOW, RESTART_WDT)
#use delay(clock=4000000)
#define EADOGM163 1
#define EADOGM_SPI_CS PIN_C1
#define EADOGM_SPI_RS PIN_C0
#define EADOGM_SPI_BB 1
#define EADOGM_SCLK_BB PIN_C6 // C3 default for Bit Bang
#define EADOGM_MOSI_BB PIN_C3 // C5 default for Bit Bang
#define OPLIGHT PIN_C2
#define ALARM_LIGHT PIN_C5
#define ALARM_PEIZO PIN_C4
#define I2C_SCL PIN_B6
#define I2C_SDA PIN_B4
#define TEMP_ENC_CHAN_A PIN_A2
#define TEMP_ENC_CHAN_B PIN_A3
#define TEMP_ENC_SPST PIN_A0
#include "EA-DOGM_SPI.c"
#include "encoders.c"
volatile int1 update_display=1;
volatile int1 update_setpoints=1;
volatile int1 update_actuals=0;
volatile int1 alarm_active=0;
volatile int1 alarm_cleared=0;
volatile int8 alarm_last=0;
#BIT SSPOV = 0xFC7.6 //Indicates overflow
#BIT BF = 0xFC6.0 //Buffer Full
BYTE state=0,address=0, trash=0; // some debug globals
void main(void)
{
setup_oscillator(OSC_4MHZ);
delay_ms(100); // power up delay
set_tris_a(0b00111111);
port_a_pullups(0b001111111);
temp_set=read_eeprom(0x00);
temp_set=min(temp_set,TEMP_MAX); temp_set=max(temp_set,TEMP_MIN);
humid_set=read_eeprom(0x01);
humid_set=min(humid_set,HUMID_MAX); humid_set=max(humid_set,HUMID_MIN);
eaDogM_Initialize();
eaDogM_DisplayOn();
eaDogM_SetPos(1,0);
eaDogM_WriteString("??\xDF( ) ??%( )");
setup_timer_2(T2_DIV_BY_1,0xFA,16);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
system_mode=ALARM_TEMP;
while(1)
{
if(update_display)
{ // Data formatting display, to do...
update_display=0;
}
if(update_actuals)
{// This is mostly for debug at present, won't look like this in production
eaDogM_SetPos(0,0); // Write out the debug state
eaDogM_WriteChr(state/10+'0');
eaDogM_WriteChr(state%10+'0');
eaDogM_SetPos(0,3);// Write out the debug counter
eaDogM_WriteChr(trash/10+'0');
eaDogM_WriteChr(trash%10+'0');
eaDogM_SetPos(1,0); // Print temp_act
eaDogM_WriteChr(temp_act/10+'0');
eaDogM_WriteChr(temp_act%10+'0');
eaDogM_SetPos(1,9); // Print humid_act
eaDogM_WriteChr(humid_act/10+'0');
eaDogM_WriteChr(humid_act%10+'0');
update_actuals=0;
}
}
}
#INT_TIMER2
void interupt_timer2(void)
{
static int8 Timer2Ticks=0;
Timer2Ticks++;
if(Timer2Ticks==125) //This number is arbitrary for debugging. Tuned up later...
{
update_display=1;
}
}
#INT_SSP
void ssp_interupt ()
{
BYTE incoming;
BYTE old_act1=0, old_act2=0; // Debug assistance for the counter
state = i2c_isr_state();
old_act1=temp_act; // Debug assistance for the counter
old_act2=humid_act; // Debug assistance for the counter
if(state <= 0x80)
{
incoming= i2c_read(); //how should read(0) and read(1) be correctly implemented in this situation?
if(state == 1) temp_act = incoming;
else if(state == 2) humid_act = incoming;
}
if(state == 0x80)
{
i2c_write(temp_set);
i2c_write(humid_set);
}
if(temp_act!=old_act1 || humid_act!=old_act2) trash++; // Update on change only (meaning I2C send data)
update_actuals=1; // Trigger the main loop to update the LCD
output_toggle(OPLIGHT); // visual evidence of IRS operating
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Aug 30, 2009 11:57 am |
|
|
Do some experiments.
Slave:
1. Disable the Timer interrupt in the Slave, so only the #INT_SSP
interrupt is operating.
2. Increase the oscillator frequency in the Slave to 8 MHz, so that
the slave is running faster than the master.
Master:
1. Disable the Timer interrupt in the Master.
2. Change the #use i2c() statement so the Master uses software i2c
instead of hardware. |
|
|
Imaginos
Joined: 26 Aug 2009 Posts: 6
|
|
Posted: Sun Aug 30, 2009 7:23 pm |
|
|
Speeding up the slave to 8MHZ appears to have solved it (so did disabling the slave timer for that fact). I'm going to let it run overnight (and then maybe for a few days) to see if any other problems crop up.
Thanks for the help. |
|
|
|
|
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
|