Posts Tagged led

Blinky on the STM32L Discovery

My program seems to have locked-in syndrome, so now I’ll see if I can get it to flash an LED.

A good start would be to check the schematic for where the LED is connected.  There’s one connected to PB6 and PB7, and they’re actually marked with this on the PCB, next to the two push buttons.

Now how to interface them?  The programming manual has a whole section on GPIOs.  It mentions that there are registers for selecting the alternate function (which is how you activate SPI, the USARTs etc), selecting whether the pin is an output or input, whether there are pull-up or pull-down resistors activated, among other things.  One thing worth noting is section 6.3.1, which says “During and just after reset, the alternate functions are not active and the I/O ports are configured in input floating mode.”  What it doesn’t say though is how the registers map to the I/O pins.

The first page of the reference manual mentions one document I haven’t looked at yet: the datasheet.  And sure enough, the memory map in section 5 says that port B is at memory location 0x40020400.  There’s still no mention of how these map to the I/O registers, or how to access the registers from C code.

Figure 1 of the reference manual suggests the GPIO access is via the “AHB system bus”.  A search of the CPU reference manual says that AHB is the “Advanced High-performance Bus”, which doesn’t really mean anything for this.

Another look at the memory map shows that port B goes from 0x40020400 to 0x400207FF.  That’s 1kB of address space, so maybe all of the port registers live here?  If I assume that, I need to set a few bits in GPIOA_MODER at 0x40020400, and turn on the output pin in GPIOA_ODR at 0x40020414 (the reference manual shows the offset of this register as 0x14).  Like this:

    *((int*) 0x40020400) = 0x00005000;
    *((int*) 0x40020414) = 0x00000080;

No that doesn’t work… time to cheat.  I’ll look at “blinky.c”, which is included with the Keil IDE.  It mentions a GPIO clock, maybe I need to enable that.  This idea is a bit unusual to me, since AVRs don’t have a clock for the output pins, but maybe in an ARM you need one so DMA works or something.  Figure 12 contains a rather elaborate map of how the clocks work, but the important bit is on the right: HCLK goes to the AHB bus (which I saw earlier and dismissed!)  This is fed through a prescaler from SYSCLK.  Section 5.3.8 discusses the AHB peripheral clock enable register (RCC_AHBENR) which has a “GPIOB EN” bit at bit 1.  RCC is at 0x40023800, AHBENR is at offset 1C, so this register is at 0x4002381C.

So this gets the LED to light:

  *((uint32_t*) 0x4002381C) = 0x00000002; /* Enable GPIO clock */
  *((uint32_t*) 0x40020400) = 0x00005000; /* Output mode */
  *((uint32_t*) 0x40020408) = 0x00005000; /* 2MHz clock speed */
  *((uint32_t*) 0x40020418) = 0x00000080; /* LED on */

That’s pretty ugly and you wouldn’t want to write too much code like that, so I’ll look at libraries that contain these numbers instead.


Leave a Comment

Run a V-USB demo on an AVR stick (Easylogger)

This article describes how to run one of the V-USB demos on an AVR stick (which is an Easylogger clone).

V-USB is a firmware-only USB implementation for AVR 8-bit microcontrollers.  This means that it’s possible for most AVR chips to communicate via USB, even though they have no hardware support for that.

The AVR stick

The AVR stick is a tiny circuit board that contains the minimum components to get a somewhat useful USB device, based on an ATmega85.  It costs about $10, and is available in Australia from Little Bird Electronics and also from Sparkfun.

I’ll use the USB HID class, because it doesn’t require any fancy drivers to get running.

First, grab the V-USB code, (I’m using version 20100715), and extract the /examples/hid-custom-rq directory somewhere.

Let’s get the firmware working first.  The AVR stick works a bit differently to the circuit the demo is for, so we need a few changes.

The ATmega85 only has one port: port B.  The sample uses port D.  Edit these lines in /firmware/usbconfig.h:

#define USB_CFG_DMINUS_BIT      0

The LED is on PORTB1, not PORTB0, so change /firmware/main.c:

#define LED_BIT             1

Finally, we need to change the Makefile to match the ATmega85:

DEVICE  = attiny85
F_CPU   = 16500000

Where does 16500000 come from? The AVR stick uses the internal RC oscillator for its clock, which runs at about 8MHz.  The problem is, V-USB needs a clock speed of at least 12MHz to run.  ATmega5s have a fuse setting which doubles its clock speed (they call it the PLL clock or something like that).

While the internal RC clock is fairly stable, it’s not very accurate.  When V-USB starts, it uses the USB signal to calibrate the clock so it runs at the same speed as the USB bus.  Using this calibration, it’s possible to run the internal clock at 8.25MHz, which is doubled to 16.5MHz.  This is the speed the AVR stick must run at.

Since I was using the Bus Pirate to program the AVR stick, I had to change the AVRDUDE= line also.

That was it for the firmware – hopefully it compiles and uploads to the AVR stick.

Now for the software that runs on the computer.  When I compiled and ran ./set-led on, I got this message:

Could not find USB device "LEDCtlHID" with vid=0x16c0 pid=0x5df

but when I ran lsusb, I saw this line:

Bus 002 Device 023: ID 16c0:05df VOTI

“VOTI” doesn’t match “LEDCtlHID”, no wonder it couldn’t find it!  But when I ran sudo lsusb -v, I saw this instead:

iProduct                2 LEDCtlHID

OK, so “VOTI” is simply the string form of the USB vendor ID 0x16c0, and the name “LEDCtlHID” is correct after all.  What’s going on then?

I noticed that the usbOpenDevice function takes a few file descriptors, of which the final one is called warningsFp.  This is called from set-led.c; perhaps I’ll change this last parameter from NULL to stderr.

When I ran ./set-led on again, I got this:

Warning: cannot query manufacturer for VID=0x16c0 PID=0x05df: error sending control message: Operation not permitted

That’s a slightly more useful error message!  So the USB library doesn’t seem to be able to use the device.  I read that some USB devices appear under /dev/usb, so let’s have a look with ls -l /dev/usb:

crw------- 1 root root 180, 96 2011-12-14 22:50 hiddev0
crw------- 1 root root 180, 97 2011-12-16 21:33 hiddev1

Maybe that’s the problem – there’s no write permissions on the device.  To fix this, I’ll make this device writable by everyone.  Create the file /etc/udev/rules.d/90-avrstick.rules, and put this in it:

SUBSYSTEM=="usb", DEVTYPE="usb_device", SYSFS{idVendor}=="16c0", SYSFS{idProduct}=="05df", MODE="0666"

then sudo reload udev.  Remove the stick then put it back in, then look at /dev/usb again:

crw------- 1 root root 180, 96 2011-12-14 22:50 hiddev0
crw-rw-rw- 1 root root 180, 97 2011-12-16 21:42 hiddev1

That’s a bit better.  Now run ./set-led on – the white LED on the AVR stick should come on!

There’s one improvement I can think of – the C code is pretty ugly, so I had a go in Python.  I copied the USB calls from the C code.  The Python code follows:

import sys
import usb
import itertools

vid=0x16C0; pid=0x05DF;

devs = itertools.ifilter(
    lambda dev: dev.idVendor==vid and dev.idProduct==pid,
    (dev for bus in usb.busses() for dev in bus.devices)

if len(sys.argv) == 1:
    print 'Specify "on", "off" or "status"'
op = sys.argv[1]

for dev in devs:
    #print "Handling device %04x:%04x" % (dev.idVendor, dev.idProduct)
    handle =
    if op == "on" or op == "off":
            usb.TYPE_VENDOR | usb.RECIP_DEVICE | usb.ENDPOINT_OUT,
            1, # = CUSTOM_RQ_SET_STATUS
            [], # Empty payload - the data goes in the "wValue" field
            value = (op == "on" and 1 or 0 )
        data = handle.controlMsg(
            usb.TYPE_VENDOR | usb.RECIP_DEVICE | usb.ENDPOINT_IN,
            2, # = CUSTOM_RQ_GET_STATUS
            1, # How many bytes to read
        print "LED is " + (data[0] and "on" or "off")

That’s much shorter than the C code, and does the same thing (admittedly there’s much less error handling here).  I used the pyusb library version 0.4.2.  The documentation for this library is a bit thin, but I found the Python command “help(usb)” of some use, as well as the source code for the library.

Talking to the USB device is all using Control signals, which I think you need to do because it’s pretending to be an HID device.  I found it interesting that they never send data to the AVR stick – they send the desired LED status in the “wValue” field, which sounds like a 16-bit field that’s in every control message.  I don’t know much about USB, but conveniently copying the C code worked fine.

Leave a Comment