Tag Archives: gpio

GPIO ramp up/down

While testing the menu system yesterday I notice a strange problem. Sometimes pressing  a button triggers not only the GPIO associated with that line, but adjacent lines as well.

My first thought was ‘wiring problem’ as everything is crammed inside the RC with 30+ jumper wires, so I started shaking and moving wires around but it didn’t seem to change much.

Then I turned to code – I thought I might have a bug – and after close introspection the code seemed correct:

  • Set the column GPIO as output
  • Set the column GPIO high (+3.3v)
  • Read all 4 line GPIOs, see which button is pressed
  • Set the column GPIO as input to turn it off
  • Repeat

Everything seemed ok so I took out the oscilloscope and probed one of the columns.

Here’s what I got:


I probe 2 column GPIOs here and the trigger is on the green trace. The 2 problems become obvious – first of all the pin goes low too slow so by the time the next pin is high, the previous one still has ~2.3V, enough to register as high. And second – the code lops through this without any delay between pins.

On paper, the code works correctly but not so in real life where there is inductance and bandwidth limits for triggering GPIOs high/low.


The fix is trivial. I changed the loop like this:

  • Set the column GPIO as output
  • Set the column GPIO high
  • Wait 2 microseconds for the pin to settle
  • Read all 4 line GPIOs
  • Set the column GPIO low <— this causes the voltage to drop way quicker than just setting the gpio as input
  • Set the column GPIO as input
  • Wait 2 microseconds for the pin to settle
  • Repeat


Here’s the trace on the oscilloscope after the changes:



As you can see there is a clear, safe distance between triggering adjacent column GPIOs and (not visible in the trace) the lines are sampled right in the middle of the high interval.

This works perfectly now.

RC – First HW Test

After a few more failed attempts to print the RC case with ABS I finally gave PLA a chance. Ordered some black 1.75 filament from amazon and a few days later I printed the case successfully from the first try. PLA is great, it’s easy to print, it smells like sugar when printing – as opposed to the chemical smell of ABS – and the quality is really good. However it doesn’t like to be sanded. At all! It’s like trying to sand rubber – or more accurately – sugar.

I decided to stop worrying about the finish so much and ordered some plastic primer and white matte paint. In the meantime I finished the RC PCB and made all the connections and did the first real test.

Here it is:


  • 3 axis gimbal for yaw, pitch and roll. It’s a very high quality one with bearings and hall sensors instead of pots
  • Motorized linear pot for the throttle. I went for motorized because when changing flight modes I want to have the throttle in the correct position to avoid stopping the motors
  • 0.96″ OLED screen for status info, calibration and other things
  • 8 ADC channels – 4 for the sticks, 3 for the individual LiPo cells and another one for the Gimbal Pitch pot
  • a 4×4 button matrix implemented with pigpio for all the buttons and switches
  • 2 rotary encoders for live editing of parameters like PIDS, menu navigation, etc
  • 2x 2.4 GHZ wifi diversity for the video feed
  • 5.8 GHZ wifi for the phone connection – to send the video feed through
  • 433 Mhz 30 dBm link for the RC data
  • 2.2Ah 3S LiPo battery for ~5h of continuous use, with charger/balancer port

The screen is connected through i2c1 at 1Mhz together with 2 ADC sensors (ADS1115).
I’m using this library to talk to the screen but noticed that a full display update takes ~20-30ms during which I cannot talk to the ADC sensors. To fix this, I changed the library and implemented partial screen updates. Now I can call screen->displayIncremental(1000) and the class will send incremental lines to the screen for 1000 microseconds (1 millisecond). The overall FPS is the same as with full updates but I get to do other things while the display is being updated. To avoid tearing I also added double buffering to the class and an explicit swap method.

The end result is a 40-45 screen updates per second but each update is split in 12-13 partial uploads with ADC readings in the middle. So I can sample the ADC at ~600Hz which is more than enough for a RC system.

The RC has 13 buttons and 2 rotary encoders requiring a total of 17 GPIO. Since I didn’t have enough I ended up grouping the 13 buttons in a matrix of 4×4 following this tutorial. This allows me to reduce the number of GPIO to 12 (8 for the matrix and 4 for the rotary encoders). I implemented the matrix reading using PIGPIO and added some debounce code to avoid detecting ghost presses/releases. Seems to work great and it’s very fast.


Most of the HW is done and it’s a mess of wires. I’m working now on some videos of potting it together, making the connections and the calibration.

The next step is to work on the phone app to receive the video feed, although I think I will give the quad a test – line of sight.

I really want to fly soon.

Odroid W ADC Fail!

2 days and 5 forum posts later and the picture is clearer. Let’s start from the beginning. To simplify I’ll refer to the Raspberry pi rev. 2 board and ignore rev. 1 and the A+/B+ (** check the notes for details).

The Raspberry pi has the i2c-0 and i2c-1 busses. The former** is used by the GPU to talk to the camera while the latter can be used by the user however she/he wants. Each of the 2 busses can be redirected to several physical pins by changing the mode of these pins:

GPIO 0/1  – ALT0 mode
GPIO 28/29  – ALT0 mode
GPIO 44/45 – ALT1 mode

GPIO 2/3 – ALT0 mode
GPIO 44/45 – ALT2 mode

Only one of these pairs can be activated at any moment per bus.

The camera is physically connected to GPIO 0/1 **. These pins are setup as inputs by default and the GPU will change them to ALT0 whenever it needs to talk to the camera but _switches them back_ to INPUT immediately after. If you monitor the mode of GPIO 0/1 you’ll see that most of the time they are INPUT with random switching to ALT0 0-30 times per second. It seems that the more movement the camera sees the more it talks to the GPU. It seems to be related to AWB and shutter speed.

So far – no problem. It’s pretty clear from the design of the Raspberry pi that i2c-0 is off limits and there is no way to synchronize the GPU access with the CPU – so i2c-0 cannot be shared between the camera and any other device. If one attempted to use i2c-0 and started ‘raspivid -t 0’ he would see weird things ranging from i2c errors, the image freezing for seconds, random noise on the screen or even the board completely freezing.


The OdroidW has a nice PMC 5t619 chip that provides 2 free ADC pins that I intended to use to monitor voltage and current of silkopter. The PMC uses i2c-0 to talk to the CPU so care must be taken to synchronize somehow with the GPU. This is what I’ve been trying to achieve the whole weekend…

– 1st  try: After every use of mmal I switched GPIO 1/2 mode from IN back to ALT0 so I can talk to the PMC. Didn’t work as it seems the GPU uses the bus even between calls to mmal (in hindsight it makes sense as the camera has to inform the GPU about starting and finishing transfers and the GPU has to set awb, gains and shutter speeds).

– 2nd try: Use a semaphore to trigger the ADC measurement in the mmal callbacks – hoping that after the callback I get a period of silence from the GPU. No such luck

– 3rd try: Give up using the hw i2c-0 bus and try bitbanging on GPIO 0/1. This was such a nice idea – let the GPU use the hardware i2c-0 bus and I’ll use bitbanging… Didn’t work as both the GPU and the PMC are connected to GPIO 0/1 pins – so they share the same physical pins….

So basically it looks like the OdroidW is not capable of using both the camera and the PMC at the same time because they share the i2c-0 bus but _also the pins_!!!. This could have been easily avoided by putting the PMC on some other GPIO and bit banging, or at the very lease putting it on i2c-1.

So now I’m back to the drawing board and started considering an Arduino mini board as ADC + PWM generator. Connected through i2c-1 probably..



** Rev.1 boards have i2c-0 and i2c-1 reversed. So i2c-0 is free while i2c-1 is the camera one. ** A+ and B+ have the camera using GPIO 28/29 pins to access i2c-0.