RSS

Archive for March, 2012

STM32F4 Discovery – First Impressions

Monday, March 19th, 2012

I recently came across the STM32F4 Discovery board. This board is an ARM processor on a board with 1MB flash and 192KB RAM, ADC, Audio processing, motion detection USB for both debugging and HID support – not bad for less than £10. Given the price and a bit of research and I thought I’d risk it.

So the board arrived and now it’s time to set up the tool chain. There are several toolchains available but the one which was attractive was the Atollic toolchain. The LITE version 2.3 IDE had no code limitations and instead it limited the features available through the IDE. Note that since buying the board and downloading the software Atollic have gone down the route of removing the restrictions on the IDE and placing a code size restriction on the environment. This fits in with the approach taken by several of their competitors.

Installing the Software and the Board

Installation of the software and the board seemed to go OK. Connecting the board found a few problems. The first problem came from the samples. I imported the directory containing the samples and this seemed to pull in the samples for the Atollic system and also the samples for other development environments. This resulted in multiple projects with the same name and this (understandably) upset the Atollic environment. So a quick play with explorer deleting the extra projects and the remaining projects imported with now issues.

The second project came when I tried to compile, deploy and debug one of the samples. The debugger kept complaining that it could not find the board. Hello Google. The problem was simple to solve and all it required was to reinstall the driver for the board. All this required was to open control panel, selecting the board and then update the driver.

So far, so good. I have the board installed along with the software and I can deploy the sample projects.

Can I write my own software?

My First Application

For my first application I wanted to do a bit more than just flash the onboard LEDs, not much more but I wanted some indication of the speed of the board. So I decided to simply toggle one of the ports and look at this through a logic analyser.

So the first thing to do is to create a new project. So off to the file menu and I selected new project. The restricted version of the development environment does not allow C++ projects so I went for a C project and selected Embedded C Project:

Next I selected the board and hardware settings for the build:

And the final step is to configure the debugger settings:

Next thing to do was to modify the default sample code. I opened the main.c file and replaced the main program loop with the following:

GPIO_InitTypeDef  GPIO_InitStructure;

STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
STM_EVAL_LEDInit(LED5);
STM_EVAL_LEDInit(LED6);

/* Turn on LEDs */
STM_EVAL_LEDOn(LED3);
STM_EVAL_LEDOn(LED4);
STM_EVAL_LEDOn(LED5);
STM_EVAL_LEDOn(LED6);

int flag = 0;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure);
while (1)
{
    if (flag)
    {
        GPIO_SetBits(GPIOD, GPIO_Pin_0);
        flag = 0;
    }
    else
    {
        GPIO_ResetBits(GPIOD, GPIO_Pin_0);
        flag = 1;
    }
}

Hooking up the logic analyser to Port D, pin 0 gave a square wave with a frequency of about 2.25 MHz.

Success!

Back to the samples and lets see where it takes us.

Software for the LED Cube

Sunday, March 18th, 2012

So you’ve built is and now we need some software to run it. To do this we are going to need to perform two tasks at the same time:

  • Calculate what we are going to display in the cube
  • Run the display

Multithreading is used in order to achieve this. The program has one thread which does nothing but cycle through each layer one by one shifting the data for the layer into the shift registers and then turning the layer on.

The second thread prepares the next item to be displayed and then passes this on to the cube to display.

LEDCube Class

This is a relatively simple class having a single constructor and two methods. The constructor sets the scene for us and makes sure everything is ready to use:

public LEDCube()
{
    config = new SPI.Configuration(SPI_mod: SPI.SPI_module.SPI1,
                                   ChipSelect_Port: Pins.GPIO_PIN_20,
                                   ChipSelect_ActiveState: false,
                                   ChipSelect_SetupTime: 0,
                                   ChipSelect_HoldTime: 0,
                                   Clock_IdleState: true,
                                   Clock_Edge: true,
                                   Clock_RateKHz: 100);

    spi = new SPI(config);
    buffer = new byte[64];
    for (int index = 0; index < buffer.Length; index++)
    {
        buffer[index] = 0;
    }
}

The buffer contains the data we are going to be showing in the cube.

The next two methods perform the work or updating and displaying the buffer. We need to be careful that the buffer is not updated whilst we are trying to update the display.

public void UpdateBuffer(byte[] newValues)
{
    lock (buffer)
    {
        for (int index = 0; index < buffer.Length; index++)
        {
            buffer[index] = newValues[index];
        }
    }
}

The lock statement helps us to achieve this by locking the buffer so we can copy data into it and also stop the display method from trying to read the buffer and show the data.

The display method is a little longer:

public void DisplayBuffer()
{
    while (true)
    {
        lock (buffer)
        {
            byte[] displayData = new byte[8];

            for (int row = 0; row < 8; row++)
            {
                int offset = row * 8;
                for (int index = 0; index < 8; index++)
                {
                    displayData[index] = buffer[offset + index];
                }
                enable.Write(true);
                bit0.Write((row & 1) != 0);
                bit1.Write((row & 2) != 0);
                bit2.Write((row & 4) != 0);
                spi.Write(displayData);
                enable.Write(false);
            }
        }
    }
}

This method again uses the lock statement to lock the buffer. This means we cannot update the buffer until a full cube of data has been displayed. The method takes a block of 8 bytes representing a layer and then writes this to the shift registers using SPI. Note that the spi.Write is embedded in the writes to the enable line. This ensures that all of the layers are turned off whilst we are updating the shift registers.

Wrapping all of this in the LEDCube class means that we now have a very simple class where we can spawn the DislpayBuffer method into it’s own thread. So off to out Main program. We are going to need an instance of the cube and a buffer to hold the next “frame” we wish to display.

private static LEDCube cube = new LEDCube();
private static byte[] nv = new byte[64];

The first thing we do when entering the main program is to set all of the values in the buffer (set them to zero) and to start the display thread going:

ClearCube();
Thread display = new Thread(new ThreadStart(cube.DisplayBuffer));
display.Start();

ClearCube does just that, sets the values to zero and then calls the cube Update method to copy this zeroed buffer into the cube buffer.

The next line spawns a new thread which runs the DisplayBuffer method and the following line starts it.

At this point we have two threads, the main program loop and the display thread. We can now perform calculations in the main program loop and call cube.UpdateBuffer when we have new data to display.

So how about something to display, a little rain perhaps:

private static void AddDrops(int count, int plane = -1)
{
    for (int drops = 0; drops < count; drops++)
    {
        bool findingSpace = true;
        while (findingSpace)
        {
            int x = rand.Next() % 8;
            int y = rand.Next() % 8;
            int z;

            if (plane == -1)
            {
                z = rand.Next() % 8;
            }
            else
            {
                z = plane;
            }

            int position = ( z * 8 ) + y;
            byte value = (byte) ((1 << x) & 0xff);
            if ((nv[position] & value) == 0)
            {
                nv[position] |= value;
                findingSpace = false;
            }
        }
    }
}

private static void Rain(int noDrops, int cycles)
{
    ClearCube();
    AddDrops(noDrops);
    cube.UpdateBuffer(nv);
    for (int currentCycle = 0; currentCycle < cycles; currentCycle++)
    {
        int bitCount = 0;
        for (int plane = 0; plane < 8; plane++)
        {
            byte value = 1;
            for (int bit = 0; bit < 8; bit++)
            {
                if ((nv[56 + plane] & value) > 0)
                {
                    bitCount++;
                }
                value <<= 1;
            }
        }
        for (int plane = 7; plane > 0; plane--)
        {
            for (int currentByte = 0; currentByte < 8; currentByte++)
            {
                nv[(plane * 8) + currentByte] = nv[( (plane - 1) * 8 ) + currentByte];
            }
        }
        for (int b = 0; b < 8; b++)
        {
            nv[b] = 0;
        }
        AddDrops(bitCount, 0);
        cube.UpdateBuffer(nv);
        Thread.Sleep(75);
    }
}

AddDrops simply adds a specified number of rain drops to the buffer. It also makes sure that if asked for 10 it will always add 10 by checking to see if one exists in the location it wanted to use.

Rain adds the specified number of drops to the buffer, shows the drops and then moved them all down by one plane. Before doing this it counts how many drops are going to fall out of the cube. After all the drops have moved down one plane it adds the drops which have disappeared out of the bottom of the cube back in at the top in random positions.

We can display this by adding this to the main program:

while (true)
{
	Rain(10, 60000);
}

The full source code to this project is current hosted on Codeplex.

Conclusion

Hope that you enjoy trying out this project but be aware that it takes time. This consumed a lot of my spare time for about three weeks. There are still some tasks to complete

  • Power supply
  • A case
But the main stuff is working.

I have not covered the power regulation but you should make sure that you have a regulated 5V DC power supply capable of about 2A – but more would be better. I did actually add my own regulator to this project but it got very hot when the cube was fully lit. Beware – make sure you have a stable supply capable of supplying enough juice.

The Controller Board

Sunday, March 18th, 2012

Having a cube of LEDs is of little use without a controller board. As previously mentioned, all 512 LEDs can be controlled from just 7 lines from the Netduino Mini. As you will have seen during the testing, we can turn on any LED by connecting the anode to a positive supply and the entire layer in which it sits to ground.

The positive supply is a relatively simple thing to achieve and our good friend the 74HC595 shift register will help us there. Connecting to ground requires a little more work but this is achieved using the 74HC238 and a bank of transistors. At the end of this process I had the following board:

Annotated Controller Board

So, a quick walk around the board. Box one contains the Netduino Mini. The two connectors to the bottom left of the board allow the Mini to be connected to the computer – they are the Mini’s COM1 connections. The two connectors at the top right are for the ground and the 5V from my USB – FTDI connector. Only ground is connected, the other connector allows me to stop the 5V lead from flying around and touching something it shouldn’t.

Box 2 contains the bank of 8 x 74HC595s, current limiting resistors and a connector to allow a ribbon cable to be connected the cube to the controller. These will determine which of the LEDs received power. Each of the shift registers will control one row of LEDs, 8 rows need 8 registers. So the shift registers can control 64 LEDs at once.

The remainder of the electronics on the board determine which layer will be connected to ground. The 74HC238 takes four lines from the Mini. Three of the lines represent a binary number 0-7, the fourth line is an output enable line. The decoder takes the number and switches on one of one of the output lines. This is in turn connected to the base of a TIP122 transistor. Applying power to the base allows the layer the transistor is connected to connect to ground.

So all is in place to use persistence of vision to be used to give the appearance that the cube is permanently switched on. Starting with the cube switched off we load the shift registers with the data for layer 0. We then load the 74HC238 with 0 and enable the output. This will turn on the transistor for layer 0 which will allow current to flow through the LEDs in layer 0. We then turn the cube off by disabling the output of the 74HC238 and repeat for layer 1 and so on.

Shift Registers

A little more repetition – don’t you just love it. The eight shift registers are wired together in a cascade with the shifted output of one register forming the input of the next. By connecting eight together we can control 64 outputs.

The basic connections for the shift registers is as follows:

Schematic for the Cascaded Shift Registers

This needs to be repeated until all eight of the registers are connected as in the above diagram. In the controller board diagram the serial data in wires are blue, the clock wires are white and the enable wires are yellow.

Note that a 100nF ceramic capacitor is connected between power and ground and one is placed by each IC as close to the IC as possible.

The current limiting resistors for this project were selected to keep the current per LED at 25mA per LED. The nearest value actually puts this at 26mA per LED. Multiplying this up means that a layer when all of the LEDs are switched on will draw 1.6A. The maximum output current rating per pin on the 74HC494 is 35mA so we are getting close to the limit per pin.

Layer Switching

Layer switching is achieved by connecting a layer to ground through a TIP122 transistor. This should be capable of sinking 2A which is greater than the 1.6A which we could theoretically need to sink if all of the LEDs on a layer are switched on. The 74HC238 selects which layer is connected to ground – or in fact none of them may be connected if the output from the 74HC238 is disabled. The circuit diagram for this part of the controller looks as follows:

Layer Selection Schematic

Again, a 100nF capacitor is placed across power and ground for this IC.

Connecting the Controller to the Cube

The collector for each of the TIP122’s should be connected to a different layer. I connected mine with layer zero being the top layer.

Each of the shift registers should be connected to one row of LEDs. I connected mine with bit zero at the right of the cube. This was done with one of the female connectors (to fit the male connector on the controller board) and some ribbon cable.

The result of these two wiring decisions was a rather odd co-ordinate system. You may decide to use something more conventional.

Adding the Netduino Mini

The Netduino Mini connections have already been noted on the above schematics.

Making the Cube

Sunday, March 18th, 2012

For the majority of June I was working on making the LED cube featured in my previous post. The next few posts will cover making the cube and writing the software which controls it.

The initial post of the cube working first appeared on the Netduino forums in early July. As you can see, it received some good responses.

This project will require the following materials:

Description Quantity
LEDs (use which ever colour floats your boat – I went for blue) 512
74HC595 Shift Registers 8
74HC238 3 to 8 line decoder 1
Netduino Mini 1
16 Pin DIL Socket 9
24 Pin DIL Socket (0.6″) 1
TIP122 NPN Transistor 8
100nF Ceramic Capacitor 10
2.2K Resistor 8
68 Ohm 0.25W Resistor (you may need to change these depending upon the LED you choose) 64
8 Way Single Row Socket 8
36 Way Header Strip (Straight) 2
2 Way Single Row Socket 2
2 Way PCB Mount Terminal Connector 1
8 Way Ribbon Cable 2.5 metres
Wire and connectors Miscellaneous
Pad board 160 x 115 Hole 1
Hex PCB spaces, M3 threaded and M3 screw 4

As well as the above you will need the following items:

  • 5V Power capable of delivering 2A;
  • Solder – I used about 15 metres over the life of this project;
  • Wood to make a template.

As well as the physical items you will need a fair amount of patience and good attention to detail. There are a lot of repetitive tasks in this project. The method is detailed in the three articles listed at the head of this article.

Making a Cube of LEDs

Sunday, March 18th, 2012

This is probably the most time consuming part of the project requiring a lot of patience, testing and a 30cm x 30cm piece of wood. Seriously, you’ll need a piece of wood. Here we are going to convert this:

Into this:

Working out the Dimensions of the Cube

The exact dimensions of the cube will depend upon the length of the legs on the LEDs. The legs will be soldered together with the cathodes of the LEDs forming a horizontal plane and the anodes connecting the layers vertically.

Take one of the LEDs and bend the cathode at a point as close to the body of the LED as possible. The cathode should be at 90 degrees to the anode and parallel to the flat base of the LED. Now bend the top 3mm of the leg of the anode through 90 degrees. You are aiming for something which looks like this:

In the final cube we want all of our LEDs to be above each other. If we don’t then each layer will be slightly offset from the on beneath it. We won’t have a cube more of a leaning tower. So the final act of manipulation for the LED is to bend the anode of the LED slightly out from the body of the LED and then to straighten the anode again. The effect should be that the 3mm at the end of the anode should be enough to place the LEDS above each other. When they are connected in the cube they should look like this:

Layer Template

Measure the distance from the centre of the now horizontal cathode to the end of the leg and subtract about 2mm. This will tell you how far apart the LEDs are in the horizontal plane. The 2mm will be used to overlap with the neighbouring LED and will be used to connect the cathodes. Now this is where the wood comes in. You need to drill a grid of holes 8 x 8 which are each this measured distance apart. You will end up with a template in which you can place the LEDs in each layer making soldering easier.

The holes in the template must be small enough to hold the LED firmly but not too firm. The LEDs will need to be removed later without placing too much strain on the soldered joints.

Building the Layers

So now let’s get the soldering iron warmed up and on with the first layer. Take 8 of the LEDs and place them along the top row with the cathodes all pointing to the right (or left if you prefer). The cathodes of the 7 LEDs to the left will overlap slightly with the LED to the right. The rightmost cathode will go off into space. Solder the cathodes together. Congratulations, you now have a line of LEDs.

Now let’s add the remaining LEDs in the layer. I started on the left as I hold the soldering iron in my right hand. Take another 7 LEDs and place these under the top row down the far left column. Again the cathodes should be overlapping. Solder these together. Repeat with the remaining columns. At this point you should have a horizontal row of LEDs connected together with 8 strings of 7 LEDs hanging from it. Eventually you should have something looking like this:

Now test the layer. Simple enough, you just need a power supply and a current limiting resistor. For the LEDs I had chosen a 5V supply fed through a 68 Ohm resistor is adequate. Connect ground to the cathode of the LED which is flying off into space (remember, it’s on the top row, to the right). Now touch each leg of the LEDs in turn with the positive output of the supply (through the current limiting resistor of course). The LEDs should light up and as you touch the anode.

One final bit of soldering is to add a stiffening wire to the layer. Cut and strip a piece of wire. The wire should be long enough to cross the entire layer. Now solder the stiffening wire to the cathodes along the bottom of the layer. See the image above. One thing to note here is that although one piece of wire is sufficient, adding one or two more would not harm.

At this point you will have one complete layer. Time to remove it from the template. This should be done carefully so that you do not put too much stress on the joints. Lifting it up gently with a screwdriver should help. Do not be in a hurry, gently freeing the LEDs first may help. Put this layer to one side and repeat another 7 times.

Connecting the Layers

Now that we have all of the layers built I suggest that they are tested once again. This repeated test may save you pain later. Just imagine how difficult it will be to fix a bad joint in the middle of the cube. We are just checking that the LEDs are still connected and none of the joints have been broken removing the layers from the template.

Now drop one of the layers back into the template. What we now need to do is to place a second layer on top of this one so that the anodes of the layer in the template touch the anodes of the LEDs in this layer. Once in place we need to solder the anodes together – good game, good game. I had the advantage of having a few clamps which could be adjusted vertically as well as horizontally. I would imagine that cardboard (or wood) shaped to the correct height should help support the layers. Remember that whatever you use you will need to be able to remove it without damaging the cube.

Now you have the layer supported, solder the anode of the LEDs in the top layer to the anode of the LED in the layer directly beneath it. Once this has been done – test. Connect the cathode of the bottom layer to ground and touch each of the legs on the top layer in turn with the +ve supply (going through the current limiting resistor). The LED on the bottom layer should light. Move the cathode to the top layer and repeat the test, this time the LED on the top layer should light.

Repeat adding the remaining layers. Just for safety, I would test every layer in the cube as it is built up. This repeated testing sounds like a big overhead but trust me it’s worth it.

So at this point you should now have a cube and if you are like me, lost two days of your life in pursuit of happiness and all that is good in life.