|
|
View previous topic :: View next topic |
Author |
Message |
technomation
Joined: 27 Oct 2012 Posts: 8 Location: united kingdom
|
16f1829 i2c master slave issue |
Posted: Sun Feb 02, 2014 2:39 pm |
|
|
hi guys
after a bit of help on a problem as it's now driving me nuts, (have also asked CCS the same question and awaiting some response) I am using a 16f1829 as an I2C slave (on I2C1) to a 18f46k22 on the same board (220R resistors in series on SCL and SDA with a 2k4 resistor on each as a pullup), the 16f1829 also acts as a i2c master to some other devices (on I2C2) , the problem I have is it locks up the master (18f46k22), (though the slave keeps running fine) now if I disable the master (on the 16f1829) it doesn't lock up the master (18f46k22) and it runs fine as a slave, (I also have another 16f1829 on the same network which also works fine once the lockup from the first slave is cleared) my i2c is setup as
Code: | #use i2c(Master,I2C2, fast=60000 ,stream = LocalI2C,force_hw) //sensor i2c
#use i2c(Slave,I2C1,fast,force_hw,address=0x56,STREAM=i2c_host) |
my main program however runs in the timer 4 interrupt as it needs to happen on time (though it makes no difference if I put this in the main while loop still locks it up)
the main bulk of the code is Code: | #INT_SSP
void ssp_interupt ()
{
unsigned int8 incoming, state;
state = i2c_isr_state(i2c_host);
if(state <= 0x80) //Master is sending data
{
if(state == 0x80)
incoming = i2c_read(i2c_host,2); //Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
else
incoming = i2c_read(i2c_host);
if(state == 1) //First received byte is address
{address = incoming;
i2c_watchdog =0;
}
if(state >= 2 && state != 0x80) //Received byte is data
{
scratchData[address++] = incoming;
}
}
if(state > 0x80) //Master is requesting data
{
i2c_write(i2c_host,scratchData[address++]);
}
}
/****************************************************************************/
#int_TIMER4
void TIMER4_isr(void)//
{ if (i2c_watchdog < 100)
i2c_watchdog ++;
else // if communications aren't seen for 600ms reset controller variables
{i2c_watchdog = 0;
scratchdata[4] = 0;
scratchdata[5] = 0;
scratchdata[6] = 0;
scratchdata[7] = 0;
scratchdata[8] = 0;
scratchdata[9] = 0;
}
sensor = read_tank_sensor(TANK_SENS_ID); // sensor
valve_switcher();
set_analog_output(MAKE16(scratchdata[4], scratchdata[5]),false,0);
if ( bit_test (scratchdata[10],2))
{
if ( bit_test (scratchdata[10],3))
output_high(Q_P1_DIR);
else
output_low(Q_P1_DIR);
set_analog_output_byte( scratchdata[6], scratchdata[7],false,1);
SensorRecirc = read_recirc_sensor(RECIRC_SENS_ID); or
}
//alive status LED and output (use for measuring sample rate)
if (sec_time < 200)
sec_time ++;
else
{sec_time = 0;
if(!input_state(Q_ALIVE))
output_high(Q_ALIVE);
else
output_low(Q_ALIVE);
}
}
/****************************************************************************/
void main()
{
delay_ms(1000);
setup_timer_2(T2_DIV_BY_4,99,1); //50.0 us overflow, 50.0 us interrupt
setup_timer_4(T4_DIV_BY_16,149,2); //600us interupt @32mhz
set_pwm1_duty((int16)0);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_B );
setup_ccp2(CCP_PWM|CCP_SHUTDOWN_AC_L|CCP_SHUTDOWN_BD_L);
set_pwm2_duty((int16)0);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
enable_interrupts(INT_SSP);
enable_interrupts(INT_TIMER4);
initAout_i2c();
enable_interrupts(GLOBAL);
set_analog_output(0,true,0);
set_analog_output(0,true,1);
set_analog_output(0,false,0);
set_analog_output(0,false,1);
//setup/initialise Communications
while(TRUE)
{
}
} |
I'm using version 5.018 of the compiler (though have tried this with 5.016,5.017 as well (the master is before the slave due to the issue with <5.017 (found that one out myself!)
I have a setup as well using 18f26k22 with a 16f1825 as the slave (exactly the same code except for the pin id's) this runs but also had lockup issues when I first wrote it which I fixed by taking all the complexity out of the interrupt so it was more stream lined
I have made sure all my device librarys are fully using the stream name as well so it's not that
so the question is any ideas? is this an school boy issue with my programming (i am more than willing to hold my hands up on that)? or am I battling a deeper CCS issue possible to do with library and their tracking of the stream names,? should I really be ditching the interrupt altogether and inlineing the slave reading as part of my main loop (though wouldn't know where to start on that as I guess I would have to track the bit registers)?
any help from anyone would be great
Thanks in advance
Graham
...the wheel might still be spinning but the hamsters long dead! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19553
|
|
Posted: Sun Feb 02, 2014 3:07 pm |
|
|
State 0x80, is 'unique'. On this state you have to read, and then write. You only read. This is the whole point about 'not releasing the clock', since it must not be released, till the write is done.
Then (minor) a slave I2C setup, does not have a 'speed'.
Best Wishes |
|
|
technomation
Joined: 27 Oct 2012 Posts: 8 Location: united kingdom
|
|
Posted: Sun Feb 02, 2014 3:29 pm |
|
|
hi Ttelmah
I'm going to sound an idiot but do just mean
Quote: | if(state > 0x80) //Master is requesting data
{
i2c_write(i2c_host,scratchData[address++]);
} |
should be
Quote: | if(state >= 0x80) //Master is requesting data
{
i2c_write(i2c_host,scratchData[address++]);
} |
if so your right that is what it's supposed to be (been trying everything and didn't change that back so well spotted) and that didn't work either
kind regards
graham |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19553
|
|
Posted: Mon Feb 03, 2014 4:01 am |
|
|
OK.
Now that is how it 'should be', but you still have the problem.
Some comments:
There is an erratum for this chip, that in one particular state (I2C mixed with SPI), the settings on one channel affect the other). Shouldn't apply in your case (meant to only be when you use slew rate limiting on one port as an SSP port....), but suggests there are some oddities about the interconnections between the channels. As such, it'd be worth trying swapping the two channels.
Then the SSP2 channel SDO2 line can be relocated. As such worth explicitly setting the affected bit in AFPCON, to ensure this is configured as you want.
Now, does your master (both the 46K22, and the 1829), correctly do the I2C_read(0) on the last transfer when reading data from the bus?. This is required by I2C, and some PIC I2C interfaces, won't recover, if this is not done before the I2C_stop.
You don't actually show us the master I2C code for the 1829. It is definately problematical to put this in the timer4 interrupt. Remember that a slave _must_ respond to things like write requests quite quickly, and if the code is inside the timer4 interrupt handling I2C transactions, it'll be stuck there for a long time (especially at 60000bps - why so slow?.).
Best Wishes |
|
|
|
|
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
|