|
|
View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
16F882 used as slave i2c |
Posted: Mon Sep 10, 2018 10:17 am |
|
|
I have a program that works with a 16F722.
When I replaced the PIC with a 16F882 and changed only the one line to #include<16F882.H> the program still runs OK but the I2C does not communicate. I get no compile errors.
I assume the problem lies in this line which works with the 16F722
Code: | #use i2c (SLAVE, SCL=PIN_C3, SDA=PIN_C4, address=0x14) |
and I tried variations, after reading the 16F882.h file, such as below
Code: | #use i2c (SLAVE, SCL=PIN_C3, SDA=PIN_C4)
#use i2c_slaveaddr(0x14) |
I get a compile error: Library not found "I2C_SLAVEADDR"
Any suggestions on how to correctly specify this as a slave i2c including its address? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Sep 10, 2018 10:41 am |
|
|
hmm..
this..
#use i2c_slaveaddr(0x14)
I've never seen before, must be a much newer version of the compiler than I have.
The error indicates that the library (file) that is called i2c_slaveaddr has not been found.
Without seeing your working code and what changes you made, it's hard to say exactly what's not correct. I don't use those PICs. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 10, 2018 11:12 am |
|
|
Quote: |
I assume the problem lies in this line which works with the 16F722:
#use i2c (SLAVE, SCL=PIN_C3, SDA=PIN_C4, address=0x14)
|
1. Ideally, you would post the complete slave program that fails.
2. What PIC you are using for the master ?
3. What are the pullup resistor values and the pullup's voltage ?
4. What are the Vdd voltages of the two PICs ?
5. What is the oscillator frequency of the master PIC ?
6. What's the distance between the two PICs (i2c bus length).
7. And what compiler version ? |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 10, 2018 12:01 pm |
|
|
Complete program below. As I said the only change is the #include<16F882.h>
The master is a 16F886. It works with a 16F722 as slave in this program
Nothing wrong with the hardware and pullups. The 16F722 works fine.
I repeat; the only change was #include <16F882.H> from #include <16F722.H>
The two PICs are on a common +5v
Both PICs at 8MHz
About 2" apart
MPLAB IDE v8.92, PCM 5.064
#use i2c_slaveaddr(0x14) that I tried came directly from the 16F882.h file which I have trouble understanding hence my question, and where I think the problem is. How do I correctly specify a slave PIC and its address?
Code: | /* Pre-processor directives */
#include <16F882.H>
#fuses INTRC, NOWDT, PUT, NOPROTECT
#use delay (clock=8MHZ) // osc defaults to 8 MHz
#use fast_io (B)
#use i2c (SLAVE, SCL=PIN_C3, SDA=PIN_C4)
#use i2c (SLAVE, SCL=PIN_C3, SDA=PIN_C4, address=0x14)
// Function Prototypes
void p_fwd (void);
void p_rev (void);
void p_stop (void);
void s_fwd (void);
void s_rev (void);
void s_stop (void);
// global variables
short p_dir, s_dir = true; // direction flags, true=fwd
int p_speed, s_speed; // port & stbd speeds, speed offset
int side_thr_status = 0x00; // initialize to no trips
int status_reset = 0xff; // initialize to no resets
int p_count = 0; // port jam count
int s_count = 0; // stbd jam count
// INTERRUPT ROUTINES
// Interrupt on I2C
#INT_SSP
void ssp_interrupt () // have an interrupt
{
int incoming, state; // variables
state = i2c_isr_state (); // get state
if (state < 0x80) // master is sending data
{
incoming = i2c_read (); // throw away device address if state = 0
if (state == 1) // first data received is port speed
p_speed = incoming;
if (state == 2) // second data received is stbd speed
s_speed = incoming;
if (state == 3) // third data received is status reset
status_reset = incoming;
}
if (state >= 0x80) // master is requesting data from slave
{
i2c_write (side_thr_status); // send side thruster status
}
}
/* The main function */
void main(void)
{
// declare variables
int speed;
int leak = 255; // voltage on leak pins
// initialize port directions
set_tris_a (0xF7); // set Port RA3 output, the rest inputs
set_tris_b (0xC9); // set Port B7, B6, B3, B0 inputs, B5, B4, B2, B1 outputs
set_tris_c (0xB9); // set Port C3 & C4 inputs, the rest outputs
output_low (PIN_A3); // initialize LED off
// setup for PWM
setup_CCP1 (CCP_PWM); // PORT SPEED & DIRECTION
setup_CCP2 (CCP_PWM); // STBD SPEED & DIRECTION
setup_timer_2 (T2_DIV_BY_16, 255, 2); // freq of 488 Hz
// setup ADCs
setup_adc (ADC_CLOCK_DIV_32); // configures ADC, 2-6 us reqd in .h
setup_adc_ports (sAN0|sAN1|sAN9|sAN12); // stbd leak, port leak, port current, stbd current
// initialize motors
p_stop(); // initialize thruster stop
s_stop();
p_speed = s_speed = 128; // both thrusters min fwd
// setup interrupts
enable_interrupts (INT_SSP); // enable I2C interrupt
enable_interrupts (GLOBAL);
// main loop ********************************************
while (1) // endless loop
{
// set port thruster speed & direction
if (!bit_test(side_thr_status, 3)) // set speed if no jam
{
if (p_speed <= 127) // below halfway set reverse
{
p_rev ();
speed = (127 - p_speed) * 2; // stop at 2.5v, max at 0v, make 8 bits
}
else // >127, set forward
{
p_fwd ();
speed = (p_speed - 128) * 2; // stop at 2.5, max at 5v
}
set_pwm1_duty (speed); // set port speed
}
// set stbd thruster speed & direction
if (!bit_test (side_thr_status, 2)) // set speed if no jam
{
// s_speed = 170; // test PWM
if (s_speed <= 127) // below halfway set reverse
{
s_rev ();
speed = (127 - s_speed) * 2; // stop at 2.5v, max at 0v, make 8 bits
}
else // >127, set forward
{
s_fwd ();
speed = (s_speed - 128) * 2; // stop at 2.5, max at 5v
}
set_pwm2_duty (speed); // set stbd speed
}
// apply any status resets, a 0 to reset, a 1 to remain unchanged ***********************
side_thr_status = (side_thr_status & status_reset); // AND with 0 to selectively reset
if (status_reset == 0)
p_count = s_count = 0; // reset jam counts
output_toggle (PIN_A3);
} // end of endless while loop
} // end of main function
// functions ***********************************************************************
void p_fwd (void)
{
if (!p_dir) // if dir = 0 (rev)
p_stop(); // stop first
output_high (PIN_B4); // then
output_low (PIN_B5); // Set direction forward
p_dir = true; // dir true for fwd
}
void p_rev (void)
{
if (p_dir) // if dir = 1 (fwd)
p_stop(); // stop first
output_low (PIN_B4); // then
output_high (PIN_B5); // Set direction reverse
p_dir = false; // dir false for reverse
}
void p_stop (void)
{
output_low (PIN_B4);
output_low (PIN_B5); // stop port motor
delay_ms(10); // wait for stop
}
void s_fwd (void)
{
if (!s_dir) // if dir = 0 (rev)
s_stop(); // stop first
output_high (PIN_B2); // then
output_low (PIN_B1); // Set direction forward
s_dir = true; // dir true for fwd
}
void s_rev (void)
{
if (s_dir) // if dir = 1 (fwd)
s_stop(); // stop first
output_low (PIN_B2); // then
output_high (PIN_B1); // Set direction reverse
s_dir = false; // dir false for reverse
}
void s_stop (void)
{
output_low (PIN_B2);
output_low (PIN_B1); // stop stbd motor
delay_ms(10); // wait for stop
}
// end |
If I uncomment the last line below (from the last block in main()) the motor turns showing there is nothing wrong with the PWM code. The I2C is not communicating.
Code: | // set stbd thruster speed & direction
if (!bit_test (side_thr_status, 2)) // set speed if no jam
{
// s_speed = 170; // test PWM |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Sep 10, 2018 12:15 pm |
|
|
hmm, any chance there's an internal peripheral in the new PIC that's not in the old one? If so, you should disable anything attached to the I/O pins used for I2C.
HMMMM ! Perhaps it's created a software I2C and not using the Hardware I2C ?? Looking at the listing will confirm/deny this. If those pins are HW I2C, you may need to add 'force_hw' or whatever the option is to tell the compiler to use the hardware peripheral.
Jay |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 10, 2018 1:07 pm |
|
|
There is a problem mentioned in the Silicon Errata about i2c slave mode for the 16F882.
I sort of understand it but the workaround is a PITA so it is easier to just go back to the 16F722.
Like windows everything seems to be getting "improved" until totally useless and burning up valuable time. I have been looking at C++ in 21 days and it is the same with all sorts of features like nameplaces:: and returning zero from main(). It sure lessens my interest in using a Raspberry Pi which seems to run on C++.
Getting old and grumpy.
There is also a problem with the 16F886 as a master i2c which is also in my circuit so perhaps I should go back to an older chip for that one that works as it should. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Sep 10, 2018 2:37 pm |
|
|
'new' is NOT always better, so WHY change ? Sounds like you had a good,working product so it begs the question WHY did you decide to change PICs? If the new ones are cheaper, well, you've blown a big pile of cash on R&D wasted on the new PICs. It's one of my many mantras NEVER,ever 'upgrade' unless you absolutely have to. HArdware or software, if it ain't broke, does the job, do NOT upgrade.
Maybe cause I'm now getting the 'old age ' pension, I'm crankier (sp) ?? |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 10, 2018 3:21 pm |
|
|
The 16F722 cannot be used as a master. The ancient 16C74A that I started with needed a UV erase and did not have EEPROM so as things evolved I had to change and am now using the 16F886 to replace the 16F874A. I try to stick to as few chips as possible and the 16F882 seemed a good replacement after a re-design that replaced many obsolete parts (digital compass, clinometers, depth gauge). Apparently my latest choices are not good so I will contact Microchip to see if they have versions that work. One nice thing is that the pinouts of this family of chips has not changed even though new features are added so minor harware additions can be incorporated with simple software changes. I use i2c between chips so some can be working on time consuming chores while the main PIC can run fast receiving and sending data between the ROV and surface. A few seconds time delay while trying to control a robotic arm remotely while watching a video display would be very frustrating I imagine, so I avoid designing in such a feature. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Fri Sep 14, 2018 8:29 am |
|
|
Microchip support was not much help:
"Regarding the PIC16F88x, the errata item #6 states that the clock stretching is not working as expected. The workaround is to slow down the I2C communication speed to match the speed of the slave. It means that the developer must consider the amount of time the slave needs to fetch the data needed by the master and that process must fall under 1 BRG period to avoid clock stretching.
For example, the PIC16F88x is talking to a slave MCU, the time to parse the data from the master, fetch it, write and shift the data out to the SDA should take less than 10us(100KHz baud rate, 1 BRG Period). If the slave MCU is running at 8MHz, an instruction would take 0.5us, the slave process must not take more than 20 instructions(at Disassembly)." That sounds like asking for problems with six slaves on the I2C lines.
Microchip Forum was helpful and suggested the 16F1938 that I have, but I believe is 2011 vintage (from the 2011-2013 date on the bottom of the data sheet).
Another suggestion was the 16F15356 which is not listed in my two year old version of PCM compiler.
Could someone check if it is listed in the newer compiler, then I will buy it and switch to these newer chips. |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 17, 2018 10:11 am |
|
|
I decided to use the 16F1938 for now but ran into problems.
My program works with 16F886 as Master and 16F722 as slave.
Does not work with 16F886 as Master and 16F882 as slave.
Does not work with 16F886 as Master and a 16F1938 as slave. The I2C bus is hung and the Master freezes in the loop.
Works with 16F1938 as Master and 16F722 as Slave.
Does not work with 16F1938 as Master and a 16F1938 as slave. The I2C bus is hung with SDA high and SCL low (should be high most of the time).
Here is the relevant part of my Master PIC software, it has worked reliably for years and is unchanged except for the type of PIC and changing INTRC to INTRC_IO in the #fuses.
Code: | /* Pre-processor directives */
#include <16F1938.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT
#use delay (clock=8000000)
#use rs232 (baud=9600, parity=N, bits=8, enable = pin_C5, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use I2C (master, SCL=PIN_C3, SDA=PIN_C4)
#byte porta = getenv ("SFR:PORTA")
#byte portb = getenv ("SFR:PORTB")
#byte portc = getenv ("SFR:PORTC")
// define I2C addresses
#define SERVO_WRT_ADDR 0X12 // Rud & Elev servo PIC
#define SERVO_READ_ADDR 0x13
#define SIDE_WRT_ADDR 0X14 // Side thrusters PIC
#define SIDE_READ_ADDR 0x15
#define ROTATE_WRT_ADDR 0X16 // Rotate PIC
#define ROTATE_READ_ADDR 0x17
// send p_speed and s_speed to SIDE THRUSTERS
I2C_START (); // start I2C
I2C_WRITE (SIDE_WRT_ADDR); // addr of side thrusters PIC
I2C_WRITE (p_motor); // send port speed
I2C_WRITE (s_motor); // send stbd speed
I2C_WRITE (side_thr_reset); // send any resets
I2C_STOP (); // stop I2C
// read side thruster status
I2C_START (); // start I2C
I2C_WRITE (SIDE_READ_ADDR); // addr of side thrusters
side_thr_status = I2C_READ (0); // get status (no ack)
I2C_STOP (); // stop I2C |
Here is the full code for the Slave PIC (stripped to bare minimum).
Code: | /// SIDE THRUSTERS TEST 16F1938 Last modified: 10 Sept 2018 ///
/* Pre-processor directives */
#include <16F1938.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT
#use delay (clock=8MHZ)
#use fast_io (B)
#use i2c (SLAVE, SCL=PIN_C3, SDA=PIN_C4, address=0x14)
// global variables
int p_speed, s_speed; // port & stbd speeds, speed offset
int side_thr_status = 0x00; // initialize to no trips
int status_reset = 0xff; // initialize to no resets
// Interrupt on I2C
#INT_SSP
void ssp_interrupt () // have an interrupt
{
int incoming, state; // variables
state = i2c_isr_state (); // get state
if (state < 0x80) // master is sending data
{
incoming = i2c_read (); // throw away device address if state = 0
if (state == 1) // first data received is port speed
p_speed = incoming;
if (state == 2) // second data received is stbd speed
s_speed = incoming;
if (state == 3) // third data received is status reset
status_reset = incoming;
}
if (state >= 0x80) // master is requesting data from slave
{
i2c_write (side_thr_status); // send side thruster status
}
}
/* The main function */
void main(void)
{
// declare variables
// initialize port directions
set_tris_a (0xF7); // set Port RA3 output, the rest inputs
set_tris_b (0xC9); // set Port B7, B6, B3, B0 inputs, B5, B4, B2, B1 outputs
set_tris_c (0xff); // set Port C3 & C4 inputs, the rest outputs
output_low (PIN_A3); // initialize LED off
// main loop
while (1) // endless loop
{
} // end of endless while loop
} // end of main function |
Is there something I'm not seeing? Any suggestions?
If I pull the I2C connector the Master is freed and my indicator LED blinks each loop. Remember the same software works with 16F722 as slave.
I tried editing out the #use fast_IO (B) which did not help. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Sep 17, 2018 10:29 am |
|
|
what value are the I2C pullups?
what speed is the I2C running ?
Is the clock a real xtal and 2 caps ?
OK, I see you're using the internal RC OSC. That might be a problem. If the 2 PICs are not running at the same speed...could mess up communications.
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 17, 2018 11:06 am |
|
|
rovtech wrote: | I decided to use the 16F1938 for now but ran into problems.
Is there something I'm not seeing? Any suggestions?
|
I'm not at my regular desk so I can't do my usual hardware tests.
But assuming everything else is correct, the first thing I'd do is run the
slave at 32 MHz while running the master at 8 MHz or less. See what
happens. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 17, 2018 11:19 am |
|
|
The pullups are 2k (one board only)
I have never defined the I2c speed which may be the probelm. I always assumed (from examples) that the compiler used a default.
Both Master and slave are 8MHz if I have defined them properly. I was not sure about the 16F1938 as the .h file is not clear what is being selected with INTRC_IO. This has always been a bit of a mystery and I have depended on #use delay (clock=xxx) for setting the clock. Where can I get info on what the compiler needs? The data sheet and .h do not help. I just looked at my CCS manual but not much help there either, it's too brief.
My compiler is PCM Ver 5.064 and I was wondering if it could be too old for the 16F1938 but I'm reluctant to make too many major changes at once.
Remember the software works fine with a 16F722 as slave.
I just ran with the slave at 32 MHz and master at 8 MHz but still hangs the master.
I added
Code: | enable_interrupts (INT_SSP);
enable_interrupts (GLOBAL); |
in main, no change.
If I comment out only the ISR then the Master runs so it seems the ISR is holding SCL low at some point.
If I change the ISR as below it still hangs the Master
Code: | // Interrupt on I2C
#INT_SSP
void ssp_interrupt () // have an interrupt
{
// int incoming, state; // variables
// state = i2c_isr_state (); // get state
// if (state < 0x80) // master is sending data
// {
// incoming = i2c_read (); // throw away device address if state = 0
// if (state == 1) // first data received is port speed
// p_speed = incoming;
// if (state == 2) // second data received is stbd speed
// s_speed = incoming;
// if (state == 3) // third data received is status reset
// status_reset = incoming;
// }
// if (state >= 0x80) // master is requesting data from slave
// {
// i2c_write (side_thr_status); // send side thruster status
// }
} |
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Sep 17, 2018 11:52 am |
|
|
When I use
Code: | #use i2c (SLAVE, FORCE_HW, NO_STRETCH, SCL=PIN_C3, SDA=PIN_C4, address=0x14) |
the master now works. It seems the slave is stretching indefinitely. The force is not needed but probably safer.
However since I really don't now what I'm doing can someone help?
Edit: BUT THERE IS NO i2c COMMUNICATIONS if I go back to my full program. |
|
|
|
|
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
|