BMOW title
Floppy Emu banner

Spot The Design Error

A prototype for the latest Star Ring. Q1, Q2, and Q3 use this N-channel MOSFET. The circuit runs from a 3V battery. When one of the transistors is turned on, the six red/green LEDs in the associated row can be turned on or off using six microcontroller outputs. At least that’s the theory. I built this, and it works – barely. The LEDs are extremely dim. Why?

Hint: what gate voltage is needed to turn on the transistors?

I’m not sure if there’s any way I can patch this, without having to redesign a new board.

Read 7 comments and join the conversation 

Atmel ICE Wiring Horror

The Atmel ICE programmer/debugger has its SWD connector pins reversed from the standard ARM Cortex debug connector. Arghh… why? It’s the same physical connector (5×2 0.05 inch polarized male), but the pins are rotated 180 degrees from the standard, as if the cable were plugged in backwards. Incredibly, it also ships with a 180-degree reversing cable, so it works – as long as you use their cable. It’s not a mistake: the product is actually designed around a reversed connector with an un-reversing cable.

WHO BUILDS A PRODUCT THIS WAY?? I shake my fist at you, Atmel hardware designer. This is like designing an electric outlet where 110V and ground are swapped from their normal locations, but bundling it with an appliance cord that unswaps them.

The problem began when I grew tired of Atmel’s tiny 4-inch cable, and decided to get a replacement cable. Naturally I used a standard 10-pin ribbon cable with 5×2 0.05 inch connectors on each end: Adafruit’s purpose-made SWD cable for ARM development. I couldn’t understand why it didn’t work, and why strange things happened when it was plugged in.

After scratching my head for a while, I noticed something odd. The title photo shows both the original cable and the Adafruit cable connected to the Atmel ICE. Notice how one has the red stripe on the right, and the other on the left? Ouch!

From looking at the original Atmel cable, it’s not at all obvious that the pins are reversed. It looks like a straight-through cable, because each connector is crimped straight on to the 10-pin ribbon, with no crossing wires. But a more careful inspection reveals that one of the connectors is crimped on so it’s facing the opposite direction of the other, resulting in a 180-degree rotation of the pin assignments. It violates the rule of the cable’s red wire indicating the location of pin 1. (Ignore the extra 6-pin header, which is used for other devices)

The good news is that there’s no permanent damage to my ARM board. The bad news is that I still need a replacement cable, but now I need to build a reversing one.

Read 5 comments and join the conversation 

Where Did All The Watts Go?

How efficient is a typical 5V AC-to-DC power supply? I’m digging through my box of assorted power supplies from past projects, looking for something appropriate for a large LED matrix, and noticed the one pictured above. 110V 0.8A input – that’s 88 watts. 5V 4A output – that’s 20 watts. Is the power supply really only 22.7% efficient, or is my reasoning flawed somehow? I would have expected a switching power supply like this one to have much better efficiency than that. A quick search for information on “level IV power supplies” suggests they must be 85%+ efficient, so something doesn’t add up.

Read 10 comments and join the conversation 

Limiting SD Card Inrush Current

I’m experimenting with methods to limit the inrush current when an SD card is inserted, and beginning to wonder whether my solutions are worse than nothing.

When an SD card is inserted into a board that’s already powered on, a large amount of current will flow briefly, as the card’s internal capacitors are charged through its 3.3V supply pin. This is called inrush current. If the inrush current is too large, it can overtax the main board’s voltage regulator and capacitors, causing the board’s supply voltage to drop temporarily. If the voltage drops far enough, it may cause the board’s microcontroller to do a brownout reset. That’s what happened with early versions of the Floppy Emu. It wasn’t really a problem, because you’ll almost always want to perform a reset anyway after inserting a new card, but it was slightly annoying.

In later versions of the Floppy Emu, I added a 1 uH inductor and 10 uF capacitor for the SD card, as shown in the circuit schematic above. Later the capacitor was changed to a 33 uF tantalum. The purpose of the inductor was to limit the inrush current, preventing the main board’s supply voltage from sagging and causing a brownout. And it worked, mostly, as confirmed by observing the main supply and SD card supply voltages on a scope during card insertion. The exact behavior depended on the brand and type of SD card and the card’s internal circuitry. Some types of cards still caused a brownout reset when hot-inserted, but it was rare.

Revisiting this question again recently, I noticed that the inductor created a new issue that may be worse than the one I was trying to solve. When the SD card is inserted, its 3.3V supply pin doesn’t go cleanly from disconnected to connected. Instead it bounces and wiggles over a period of microseconds to milliseconds, just like the contacts of a mechanical switch. As a result, the inrush current isn’t one single burst, but a series of short on/off current pulses. Because of the presence of the inductor in the circuit, these pulses create voltage spikes on the SD card’s 3.3V supply pin. They’re brief – lasting about 100 ns – but some of the spikes go above 4V. Despite their brevity, I’m wondering if they’re high enough to damage the SD card.

Using an inductor seems to be a pretty standard solution for SD card inrush current, but I’ve never seen any discussion of the voltage oscillation and spikes this can cause for the card’s supply. An alternative is a power management IC with “soft start” behavior, but I’m not interested in adding extra chips in this case. I’m starting to think it may be best to remove the inductor, and connect the card’s 3.3V supply directly to the board’s 3.3V supply. Better to cause a nuisance brownout due to high inrush current, than to risk damaging the card with voltage spikes – and still have brownouts sometimes anyway. Have you ever dealt with this topic? How did you address it?

Read 12 comments and join the conversation 

LED PWM Without Resistors

I’ve been working on version 3 of Star Ring, my fun but useless circular LED blinker, and I had an idea. Do I really need current-limiting resistors for the LEDs? Or can I effectively control the LED current using PWM?

Normally a resistor is always needed in series with an LED. Without the resistor, a very high current would flow, destroying the LED. The max DC forward current is specified in the LED datasheet, and is typically something like 30 mA. Often the datasheet will also specify a peak forward current, higher than the DC max, for applications where the LED is rapidly switched on and off with PWM. But how can I calculate what the current will be, if there’s no resistor? As usual, the answer is in the datasheet.

Star Ring is an ATTINY84A microcontroller powered by a 3V CR2032 watch battery. For the sake of this analysis, we’ll assume I’m using this Lite-On dual-color LED with independent red and green elements. The datasheets for the microcontroller and the LED both include graphs of voltage vs current:

The more current that’s drawn from an ATTINY I/O pin, the more the voltage will sag below the 3V supply. And the more current that’s passed through the LED, the more the voltage across it will rise. At some point these two graphs will intersect. You have to exchange the X and Y axes of the LED graph, and extrapolate the ATTINY graph a little, but for the green LED the crossing point is about 2.0V at 25 mA. In the absence of any current-limiting resistor, that’s what you’ll get – theoretically.

25 mA is below the LED’s 30 mA max current rating, so that’s fine. It’s also below the ATTINY’s 40 mA max current per I/O pin, so that’s fine too (although it’s curious why the ATTINY IV graph only goes up to 20 mA). So for this combination of hardware, it looks like current-limiting resistors aren’t needed at all. If 25 mA is more current than is desired, PWM can be used to reduce the average current to something lower.

In reality, the DC current without a resistor will be lower than 25 mA, because of the internal resistance of the CR2032 battery, which I’ve estimated is something like 13 ohms. At 25 mA, even with a fresh 3V battery, the supply voltage to the ATTINY will only be 2.675V due to the battery internal resistance. The I/O pin output voltage will sag further below 2.675V, and those two IV curves will cross at a different point with a current lower than 25 mA. A simple experiment could find the exact number.

 
Ignoring My Own Advice

Despite this conclusion, I’m probably going to keep the current-limiting resistors, for a few reasons. The graph for the red LED is different than the green, and the no-resistor current will be higher, potentially at an unsafe level. I’m also uncertain whether 25 mA is really OK for the ATTINY – it’s below the 40 mA absolute max rating, but the rest of the datasheet implies 20 mA is the recommended maximum, and there’s no max continuous vs peak current distinction I can see for the I/O pin. I’m also concerned about what happens during debugging or a software crash when my PWM code unexpectedly stops running, and the LED is left constantly on until I can manage to do a reset or kill the power. The resistors will provide some valuable insurance, even if they’re not absolutely required.

Be the first to comment! 

Raspberry Pi GPIO Programming in C

The Raspberry Pi’s 40-pin GPIO connector often gets overlooked. Typical Pi projects use the hardware as a very small desktop PC (RetroPie, Pi-hole, media center, print server, etc), and don’t make any use of general-purpose IO pins. That’s too bad, because with a little bit of work, the Raspberry Pi can make a powerful physical computing device for many applications.

 
Raspberry Pi vs Arduino (and other microcontrollers)

Why would you want to use a Raspberry Pi instead of an Arduino or other microcontroller (STM32, ATSAM, PIC, Propeller)? There are loads of “Raspberry Pi vs Arduino” articles on the web, and in my view almost all of them miss the mark. The Pi is not a better, more powerful Arduino. It’s a completely different type of device, better at some tasks, but markedly worse at others.

The Pi is vastly more powerful than something like an Arduino Uno. The latest Pi 3 Model B+ has an 88x faster CPU clock and 500,000x more RAM than the Uno. It also runs a full-fledged Linux operating system, so it’s much easier to create projects involving high-level functions like networking or video processing. And you can connect a standard keyboard, mouse, and monitor, and use it as a normal computer.

But the Pi operating system is also a huge weakness in many applications. There’s no “instant on”, because it takes nearly a minute for the device to boot up. There’s no appliance-like shutoff either – the Pi must be cleanly shutdown before power is turned off, or else the operating system files may get corrupted. And real-time bit twiddling of GPIO is mostly impossible, because the kernel may swap out your process at any moment, making precise timing unpredictable.

In theory it’s possible to do bare-metal programming on the Raspberry Pi, eliminating Linux and its related drawbacks for real-time applications. Unfortunately this doesn’t seem to be a common practice, and there’s not much information available about how to do it. So the Pi is probably best for those applications where you need some major CPU horsepower and some kind of GPIO connection to other sensors or equipment, but don’t need precise real-time behavior or microsecond-level accuracy.

 
GPIO and Python?

If you start Googling for “Raspberry Pi GPIO programming”, you’ll quickly discover that most of the examples use the Python language. In fact, this seems to be the most popular way by far to use GPIO on the Pi.

I have nothing against Python, but I’m a C programmer through and through, and the idea of using a high-level language for low-level digital interfaces is unappealing. By one measure, Python is over 300x slower at Raspberry Pi GPIO manipulation than plain C. I’m sure there are applications where it’s OK to throw away 99.7% of potential performance, but I’ll be sticking with C, thank you very much.

I spent a little time researching four different methods of Raspberry Pi GPIO manipulation in C. This involved reading documentation and data sheets, and examining the source code of various libraries. I haven’t yet tried writing any code using these methods, so take my impressions accordingly.

If any of the authors of these C libraries happen to read this – thank you for your work, and please don’t be offended by any criticisms I may make. I understand that creating an IO library necessarily involves many tradeoffs between simplicity, speed, flexibility, and ease of use, and not everyone will agree on the best path.

 
Direct Register Control – No Library

The GPIO pins on the Raspberry Pi can be directly accessed from C code, similarly to how it’s done on the ATMEGA or other microcontrollers. A few different memory-mapped control registers are used to configure the pins, and to read input and set output values. The only big difference is that the code must first call mmap() on /dev/mem or /dev/gpiomem, to ask the kernel to map the appropriate region of physical memory into the process’s virtual address space. If that means nothing to you, don’t worry about it. Just copy a couple of dozen lines of code into your program’s startup routine to do the mmap, and the rest is fairly easy.

Here’s an example of reading the current value of GPIO 7:

if (gpio_lev & (1<<7))
  // pin is high
else
  // pin is low

Just test a bit at a particular memory address - that's it. This looks more-or-less exactly like reading GPIO values on any other microcontroller. gpio_lev is a memory-mapped register whose address was previously determined using the mmap() call during program initialization. See section 6 of the BCM2835 Peripherals Datasheet for details about the GPIO control registers.

Setting the output value of GPIO 7 is similarly easy:

gpio_set |= (1<<7); // sets pin high

gpio_clr |= (1<<7); // sets pin low

Using other control registers, it's possible to enable pull-up and pull-down resistors, turn on special pin functions like SPI, and change the output drive strength.

Watch out for out-of-order memory accesses! The datasheet warns that the system doesn't always return data in order. This requires special precautions and the use of memory barrier instructions. For example:

a_status = *pointer_to_peripheral_a; 
b_status = *pointer_to_peripheral_b;

Without precautions, the values ending up in the variables a_status and b_status can be swapped. If I've understood the datasheet correctly, a similar risk exists for GPIO writes. Although data always arrives in order at a single destination, two different updates to two different peripherals may not be performed in the same order as the code. These out-of-order concerns were enough to discourage me from trying direct register IO with my programs.

 
Wiring Pi

WiringPi wraps the Raspberry Pi GPIO registers with an API that will look very familiar to Arduino users: digitalRead(pin), digitalWrite(pin, value). It's a C library, but third parties have added wrappers for Python and other high-level languages. From a casual search of the web, it looks like the most popular way to do Raspberry Pi GPIO programming in C.

WiringPi appears to be designed with flexibility in mind, at the expense of raw performance. Here's the implementation of digitalRead():

int digitalRead (int pin)
{
  char c ;
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  if ((pin & PI_GPIO_MASK) == 0)		// On-Board Pin
  {
    /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS)	// Sys mode
    {
      if (sysFds [pin] == -1)
	return LOW ;

      lseek  (sysFds [pin], 0L, SEEK_SET) ;
      read   (sysFds [pin], &c, 1) ;
      return (c == '0') ? LOW : HIGH ;
    }
    else if (wiringPiMode == WPI_MODE_PINS)
      pin = pinToGpio [pin] ;
    else if (wiringPiMode == WPI_MODE_PHYS)
      pin = physToGpio [pin] ;
    else if (wiringPiMode != WPI_MODE_GPIO)
      return LOW ;

    if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0)
      return HIGH ;
    else
      return LOW ;
  }
  else
  {
    if ((node = wiringPiFindNode (pin)) == NULL)
      return LOW ;
    return node->digitalRead (node, pin) ;
  }
}

That's a lot of code to accomplish what could be done by testing a bit at an address. To be fair, this code does a lot more, such as an option to access GPIO using sysfs (doesn't require root?) instead of memory-mapped registers, and pin number remapping. It also adds a concept of on-board and off-board pins, so that pins connected to external GPIO expanders can be controlled identically to pins on the Raspberry Pi board itself.

From a brief glance through the source code, I couldn't find any use of memory barriers. I'm not sure if the author determined that they're not necessary somehow, or if out-of-order read/writes are a risk.

WiringPi also includes a command line program called gpio that can be used from scripts (or interactively). It won't be high-performance, but it looks like a great tool for testing, or for when you just need to switch on an LED or something else simple.

 
pigpio

pigpio is another GPIO library, and appears more geared towards simplicity and speed. And yes, it was quite a while before I recognized the name was Pi GPIO, and not Pig Pio. 🙂

Here's pigpio's implementation of gpioRead():

#define BANK (gpio>>5)
#define BIT  (1<<(gpio&0x1F))

int gpioRead(unsigned gpio)
{
   DBG(DBG_USER, "gpio=%d", gpio);

   CHECK_INITED;

   if (gpio > PI_MAX_GPIO)
      SOFT_ERROR(PI_BAD_GPIO, "bad gpio (%d)", gpio);

   if ((*(gpioReg + GPLEV0 + BANK) & BIT) != 0) return PI_ON;
   else                                         return PI_OFF;
}

Here there's no pin number remapping or other options. The function does some error checking to ensure the library is initialized and the pin number is valid, but otherwise it's just a direct test of the underlying register.

As with WiringPi, I did not see any use of memory barriers in the source code of pigpio.

 
bcm2835

bcm2835 is a third option for C programmers looking for a Raspberry Pi GPIO library. It appears to have the most thorough and well-written documentation, but also seems to be the least commonly used library of the three that I examined. This may be a result of its name, which is the name of the SoC used on the Raspberry Pi. It's somewhat difficult to find web discussion about this library, as opposed to the chip with the same name.

Like pigpio, bcm2835 appears more focused on providing a thin and fast interface to the Pi GPIO, without any extra options. Here's the implementation of bcm2835_gpio_lev(), the oddly-named read function:

uint32_t bcm2835_peri_read(volatile uint32_t* paddr)
{
    uint32_t ret;
    if (debug)
    {
		printf("bcm2835_peri_read  paddr %p\n", (void *) paddr);
		return 0;
    }
    else
    {
       __sync_synchronize();
       ret = *paddr;
       __sync_synchronize();
       return ret;
    }
}

uint8_t bcm2835_gpio_lev(uint8_t pin)
{
    volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32;
    uint8_t shift = pin % 32;
    uint32_t value = bcm2835_peri_read(paddr);
    return (value & (1 << shift)) ? HIGH : LOW;
}

The pin number is constrained to the range 0-31, but otherwise there's no error checking. The actual read of the GPIO register is performed by a helper function that includes memory barriers before and after the read.

 
Impressions

For my purposes, I would probably choose pigpio or bcm2835, since I prefer a thin API over one with extra features I don't use. Of those two options, I'd tentatively choose bcm2835 due to the format of its documentation and its use of memory barriers. I wish I understood the out-of-order risk better, so I could evaluate whether the apparent absence of memory barriers in the other libraries is a bug or a feature.

Any analysis that looks at just a single API function is clearly incomplete - if you're planning to do Rasbperry Pi GPIO programming, it's certainly worth a deeper look at the many other capabilities of these three libraries. For example, they differ in their support for handling interrupts, or byte-wide reads and writes, or special functions like SPI and hardware PWM.

Did I miss any other C programming options for Raspberry Pi GPIO, or overlooked something else obvious? Leave a note in the comments.

Read 10 comments and join the conversation 

Older Posts »