热度 19
2016-1-21 18:18
1491 次阅读|
0 个评论
I have a feeling that I'm starting to lose track of the plot. Let me expound, explicate, and elucidate (don’t worry; I'm a professional). The Inter-Integrated Circuit (I 2 C, I2C, or IIC) bus is a multi-master, multi-slave, single-ended, serial bus that is typically used for attaching lower-speed peripheral integrated circuits (ICs) to processors and microcontrollers. The great thing about this bus is that it allows you to control a bunch of I2C-enabled shields using a single pair of pins on your microcontroller. It's no secret that pullup resistors are required somewhere on the I2C bus (one for each of the two signal lines). This is because the pins on any of the devices connected to the bus are of a type known as open collector. However, I fear that I've been lulled into a sense of complacency, because all of my recent projects have included one of Adafruit's RGB LCD I2C shields , and these little scamps already have pullup resistors on their I2C signals. Thus, I've not been obliged to add any pullup resistors of my own. (Source: Max Maxfield/EETimes.com) In my spare time (ha!), I'm currently hard at work on my Capaciously Cunning Chronograph project as illustrated in the photo above. Having said this, although I've spent a lot of time on this little rascal's music mode, I've only recently begun to turn my attention to its time-keeping functions. As part of this, I'm using one of Adafruit's ChronoDot Real-Time Clock (RTC) breakout boards. This board doesn’t have any pullup resistors on its I2C pins, but I know I'll be adding other sensors in the future that will include pullup resistors. I wasn't too sure what to do in this case, so I emailed my chum Duane Benson to noodle the situation over with him, and Duane responded as follows: Ideally, these pullup resistors should be 4.7kΩ in value, and there should be only one pair for the whole bus. In practice, however, some shields come equipped with pullup resistors pre-installed. In this case, it's common for these resistors to be 10kOmega in value, thereby ensuring that if two such shields are connected to the bus, the shared (parallel) resistance will end up being 5kΩ. "Fair enough," I thought to myself, so I took my ChronoDot RTC breakout board, soldered it onto an Arduino prototyping shield, added a couple of 10kΩ resistors, and connected the power, ground, and signal wires. Next, I plugged the shield into an Arduino Uno and ran the example sketch that comes with the ChronoDot RTC. Absolutely nothing happened (sad face). I mean nothing at all (really sad face). Part of the sketch says: if (! rtc.isrunning()) { Serial.println("RTC is NOT running!"); } I scattered additional Serial.println() function calls throughout the code like confetti and determined that the system was locking up in the rtc.isrunning() function call, but why? I've used a ChronoDot RTC before when I was performing early algorithm development for my Inamorata Prognostication Engine. Do you remember when I was trying to calculate how many days there were until the next Full Moon, and I confused the sidereal month (with a value of 27.321661 days) with the synodic month (with a value of 29.530588 days)? How we all laughed (I'm still smiling through the tears). The point is that I know these things do work, and last time I played with one everything was easy-peasy, so what could possibly have gone wrong? First of all I performed a Google for "I2C Pullup Resistors," which led me to a rather useful I2C at the Hardware Level tutorial on SparkFun's website. Google also introduced me to a really interesting article on The effects of varying I2C pullup resistors . This article shows the waveforms associated with a range of pullup resistor values, starting at 68kΩ, followed by 47kΩ, 33kΩ, 10kΩ, 6.8kΩ, 4.7kΩ, 3.3kΩ, 2.2kΩ, and ending at 1.5kOmega;. A few snippets that jumped out at me were as follows: "...notice how the measured frequency approaches our desired clock frequency between 33k and 10k ohms As you can see, 4.7k yields a good looking signal with a rise time around 1 microsecond A simple formula for calculating the smallest pull-up resistor is which for a 5V system comes out to be about 1.5k ohms. The formula for calculating the largest resistor is which yields a high side value of 50k ohms The point that really caught my eye was when the author says "...4.7k yields a good looking signal..." "Hmmm," I thought to myself, "even though he says we could go as high as 50kΩ, is there any chance that my 10KΩ resistors are messing things up?" So I strapped an additional 10kΩ resistor in parallel with each of my existing resistors. I took a deep breath, powered-up the board, and... once again... nothing happened. Now I was really wearing my frowny face. I was seriously contemplating dispatching the butler to fetch my angry trousers. I had been looking forward to a happy time programming my time display functions, but instead I was stumped by the hardware, which is a bit embarrassing when we remind ourselves that all we're talking about here is a small breakout board and two resistors. "How complicated can this be?" I thought to myself. Thus it was that I returned to the all-knowing Google and searched for "Problems with I2C pullup resistors." This led me to a morass of forum postings that, initially, helped me not at all. As part of this, however, I did run across a posting from a newbie who said something like: "I'm not sure what you mean by pullup. Do I connect one end of the resistor to the signal and the other end to 5V?" "Bless his little cotton socks," I thought (with a wry smile). "Just a minute," I thought (with a bemused look). "OMG," I screamed (inside my head -- I can still hear the echoes bouncing off my skull). Give me strength! Since the task of wiring the board was so trivial, I'd let my mind wander while I was attaching the parts and wires, pondering all the cool things I was going to do with my code. As a result, I'd connected my two 10kOmega; resistors in series with the I2C signals instead of wiring them as pullups. There was much gnashing of teeth and rending of garb at that time, let me tell you. So I quickly pulled out the existing resistors and cobbled together the correct circuit as illustrated below (this time I used 4.7kΩ resistors, just to make sure): (Source: Max Maxfield/EETimes.com) As you can imagine, I was feeling pretty confident when I powered-up this new configuration. I fully anticipated that the little scamp would now work as planned. Would you believe it -- NOTHING HAPPENED! The board still hung up at the same place! Now I was miffed, verging on peeved. If fact, one might even go so far as to say that I was approaching a state of disgruntlement. Fortunately, when I rooted around in my "bits and pieces" box, I found another ChronoDot RTC still in its package (I've got to the stage these days where I always buy two or three of everything, "just in case"). So I quickly replicated the circuit on a breadboard as illustrated below: Ignore the LED and resistor on the right-hand side of the breadboard; they're from a separate experiment (Source: Max Maxfield/EETimes.com) When I was poised to powered-up this time, I would have bet money that everything would be tickety-boo. I would have lost my money. On the bright side, the system didn’t simply lock up this time; instead, I was presented with the "RTC is NOT running!" message. I was seriously beginning to think that the fates were against me. When I looked closely at my breadboard, however, I realized that I'd plugged the SCL flying lead into the wrong column. As soon as I tweaked this, everything started to function as expected, so maybe my original ChronoDot is fried (but that's a problem for another day). I must admit that my nerves were a bit frazzled by this time. The next day, when I was chatting with Duane on the phone, I mentioned that the ChronoDot was a bit of an awkward shape, and that working with it on a standard Arduino Uno prototyping was a pain in the tuchus, as it were. The problem is only going to be compounded when I start adding other sensors, because I also want a 9DOF sensor (nine degrees of freedom boasting a triple-axis accelerometer, a triple axis gyroscope, and a triple axis magnetometer) along with a temperature barometric pressure sensor. Duane is also interested in having a multi-sensor shield for some of his projects, so we spent a happy few minutes rooting around on the Internet. In the end, we decided that -- in addition to the ChronoDot -- we also want to use one of Adafruit's BNO055 9-DOF Absolute Orientation IMU Fusion breakout boards and one of their BMP180 Barometric Pressure + Temperature boards. All of these boards are accessed using the I2C bus. The reason we've opted for the BNO055 flavor of 9-DOF is that its MEMs sensor package is accompanying by a Cortex-M0 microcontroller that number-crunches all of the complicated, CPU-intensive algorithms and squeezes out the "informational juice," thereby off-loading the Arduino and -- at the same time -- making our lives so much easier. The quick-and-dirty (let's say "cheap-and-cheerful") solution is to create a simple custom shield onto which we will attach these three breakout boards. We'll also have places for two I2C pullup resistors if required. A longer term solution might be to fabricate a more sophisticated custom shield onto which the components are mounted directly, and that will work with both 3.3V and 5V microcontroller boards, but we will leave that as a project for another day. In the meantime, do you agree with our choice of sensor breakout boards, or would you recommend other versions? Also, would you add additional sensor types? Duane will be laying out the shield this coming weekend, so we'd appreciate your feedback sooner rather than later.