I built a circuit around a PIC16 MCU (PIC16F15244) that is connected to two devices over I2C - a 16x2 LCD and a temperature/humidity sensor. Everything worked just fine until I decided to add a header for the PICKIT4 programmer directly to the circuit. Since then I2C no longer works:
PIR1bits.SSP1IF = 0;
SSP1CON2 |= 0x1;
while (PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;
SSP1IF is stuck at 0.
Things that I have already tried/verified:
- The SDA and SCL pins on the MCU are connected to the I2C slave devices (tested with a multimeter)
- The same chip, when moved to a prototype board, can communicate with the same devices
- The chip’s clocks seem to work: I added an LED to blink a pattern if the while loop above does not terminate after a few rounds, and the pattern sequence is fine.
I’m sure I messed up something, just don’t know where to look. Any thoughts?
Welcome to the forum.
My first step in a situation like this is to remove the added circuitry and make sure the system still operates as before.
If the circuit does not operate as before then you wired something wrong and burned out some existing components. In this case you need to get the original circuit working again before trying to add the programming header again.
A schematic diagram of your circuit will help enormously, without it we’re guessing how this system is designed and so won’t spot design errors.
A couple of general tips about in-circuit serial programming (ICSP) of PIC micros.
- Read the ICSP section of the data sheet for your particular model of PIC very carefully and follow Microchip’s recommendations like they are laws not recommendations.
- Pay particular attention to how you handle the reset pin (MCLR) connection.
- Have the reset and programming clock/data pins as dedicated to those tasks, don’t use them for any other function, that’s an advanced experts only thing to do.
Here is the schematic for the controller board. It’s the first one I’ve ever drawn (software guy here), so it may be of questionable quality.
I did follow the datasheet for the MCLR pin. It is connected to 5V via a pull-up 10K resistor, and to ground via a 10pF capacitor with a jumper to be removed when programming.
A couple of other notes:
- An oscilloscope shows that the SCL leg (RB4) remains high, which I believe suggests the MCU is trying to send the start condition.
- I built a second copy of this circuit, including the programming header, and it works fine.
Excellent work for a first-time schematic!
Glad you how have a working design.
As a follow-up, please allow me to share this video - point #8 regarding zero-ohm jumpers will be especially helpful as you design the PCB.
P.S. you may be able to eliminate the 10 kΩ resistor associated with the switch. The PIC features weak pull-up resistors. Note that the switch must be repositioned to ground RC0 to use this feature.
Check the datasheet for your regulator. Does it require input capacitance.
Consider adding polarity protection to the DC power input. This could be a series connected diode. You could also add a fuse and then use a reverse connected diode such that improper polarity will cause the diode to conduct and open the fuse.
Thanks for the pointers! I will definitely take a look at the information.
Someone suggested that the I2C lines need pull ups, and that for the most part you can get away without because of weak pull ups in the MCU. I found this in the data sheet:
Both the SCL and SDA connections are bidirectional open-drain lines, each requiring pull-up resistors for the supply voltage. Pulling the line to ground is considered a logical zero and letting the line float is considered a logical one.
If this is indeed true, then I certainly can get a lot of mileage on I2C without the pull up resistors… Strange.
Funny, I was just going to send you a follow up note about the comms pull-up resistors.
Yes, you can use the internal weak pull-ups for this application BUT the clock must be slowed down considerably. If you were to view the signal on an oscilloscope you would see the classic RC charge curve.
Perhaps it’s best to add a place for the external resistors on the PCB and then populate as necessary.
P.S. Slow is a good way to save energy.
Your schematic does not show the isolating jumper.
The schematic predates the addition of the programming header, which started this problem. When I added the header I also added a jumper to isolate the 10pF capacitor from the MCLR pin.
Page 139 of the datasheet shows the register RxyI2C, which gives the options for configuring internal pull-ups specifically for I2C communication, including setting slew rate limiting control, the I2C pull-up selection for different current ratings (higher current will mean lower value pull-ups and generally more reliable communication, at expense of higher current consumption), and Threshold selection for I2C or SMBus.
If you are using internal pull-ups, you want to make sure you get these set right. My experience over the years is that most people have better success using external pull-ups, but this part does give more options than many of the older PICs, so if you configure this register optimally, you may still have good luck. Also, in general, the slower your I2C clock, the easier it is to get a working link.
Thanks. I tried that to no avail. This is how I initialize I2C (at this point B6 and B4 have already been set as digital inputs):
// Configure I2C for 100KHz (assuming a 4MHz oscillator).
SSP1CON1bits.SSPM = 0x08;
SSP1CON2 = 0;
SSP1ADD = 0x9;
SSP1STAT = 0;
And now I added
// Weak pull-up on SDA (B6) and SCL (B4).
RB6I2C = 0;
RB4I2C = 0;
WPUB6 = 1;
WPUB4 = 1;
INLVLB6 = 1;
INLVLB4 = 1;
And just to make sure these points were not lost: (1) this code used to work just fine for a couple of months before I fidgeted with the board to add the programming header, and (2) the same code works just fine on a new copy of the same circuit.
If these are both true, that’s a pretty good indication that the hardware is not in fact “the same” between both examples. I’d suggest a careful visual inspection for rogue solder blobs, dry joints, errant connections, or other such maladies. Failing that, damage to some portion of a circuit from ESD or such is not unheard of.
Sigh, that was it. The only thing I checked so far was that the I2C lines were connected from the MCU to the device (by probing with a multimeter and checking for 0 resistance). What seems to have happened is that these small wires (30AWG) have probably had some of the insulation stripped and touched a ground rail. Lifting these up makes everything work again.
Appreciate all the help, and I have certainly learned a few things.
We have all been there, Elad.
Sometimes I think persistence is the defining trait for those who work in this profession.
Luckily for me it’s just a hobby.
I write operating system kernels for a living, so I’m quite confident about my software development skills. Soldering skills, well, not so much