Minimus usb and 64 LEDs

May 22, 2012 at 7:47 pm (computers) (, , )

This is the last post on this for a bit (it will probably be a while before I get my next chance to tinker).  Once I’d got my minimus wired up I wanted to flash some LEDs!  After all, that’s the whole point right?

I got hold of a 8×8 LED matrix.  Some some initial confusion about common-anode matrix vs common-cathode matrix then realising that for a single colour matrix, actually it doesn’t really matter, I got hold of one of these – a Kingbright – 8×8 LED Matrix (TC15-11EWA) (around £5 from Spiratronics on ebay)

Then I had to work out how to drive it!  Well finding the data sheet was a start, and then I found some application notes for arduinos to drive an 8×8 matrix:

Neither really explained what I wanted to know – the nuts and bolts of wiring one up to a minimus …

Then the following data sheet on oomlout give me more clues:

This described the scanning approach to getting a picture on the display.  So, to connect the matrix to my minimus, I’d use 8 IO pins for the rows and 8 for the columns, then set a value across the columns, then activate that row only.  Doing this quickly for all rows would give me a display.

The pinouts for the LED matrix are quite peculiar – no logical order, so I had a choice – wire it up in a more complex way to bring them out in a logical order or wire them simply and use software to map IO pins to LEDs.  I really couldn’t entertain having anything other than a simple port to LED mapping,  and I wanted my IED ribbon cable nicely soldered to the edge of my stripboard, so I put together a simple circuit to map the LED pins to tracks on the stripboard.

I also needed some current limiting resistors, so as I get all my electronics knowledge either from first principles physics or wikipedia – in this case I just followed the formula for LEDs on the wikipedia page and decided I needed ~120 Ohm resistors.  Well, I had 150 in an old electronics box, so that’s what I used.

Now shown on this circuit (I don’t have any real circuit drawing tools) – I added the resistors as bridges/links prior to the R (rows) connectors then connected it up to my IDE cable so that:

  • R1-R8 -> PB0-7
  • C1-C4 -> PC4-7
  • C5-C8 -> PD1-4

I didn’t use PD0-7 because of the aforementioned problem I had with pin PD0.

So to drive the matrix, I used the following code

// row = 0 to 7
// col = 0x00 to 0xff
void led (int row, int col)
{
  PORTB = 0;   // turn all rows off prior to this scan

  // Cols = must be set low to activate LED matrix,
  //        so will need to inverse logic
  // Bits 0-3 = PORT C4-7
  // Bits 4-7 = PORT D1-4
  int portc = (~(col & 0x0f))<<4;
  int portd = (~(col & 0xf0))>>3;

  PORTC &= ~ (0xf0);
  PORTC |= portc;
  PORTD &= ~ (0x1e);
  PORTD |= portd;

  // PORTB = bit per row
  // must be active to set the row
  PORTB = (1<<row);
}

Notice how I bit-shift and split the col value across ports C (4-7) and D (1-4). I just set a single bit to activate the row.  Also notice how for an LED to light up the row (port B) must be high and the col must be low (ports C and D).

To turn all rows off, I just send a 0 to PORTB.

Also, I need to initialise the ports appropriately for outputs:

PORTB = 0b00000000;
DDRB  = 0b11111111;   // all outputs
PORTB = 0b00000000;   // start low

PORTC = 0b00000000;
DDRC  = 0b11110000;   // 4-7 outputs
PORTC = 0b11110000;   // start high

PORTD = 0b00000000;
DDRD  = 0b01111110;   // 1-4 outputs for matrix, 5,6 for onboard LEDs
PORTD = 0b01111110;   // start high

At this point I can start playing.  By repeating the following in a loop, it will output the display in the picture below!

led (7, 0b00000000);
led (6, 0b00000000);
led (5, 0b01100110);
led (4, 0b01100110);
led (3, 0b00000000);
led (2, 0b10000001);
led (1, 0b01111110);
led (0, 0b00000000);

Its not perfect – for some reason the LEDs are brighter at the edges than in the centre.  And I’m sure what I thought was going to be a row has turned out to be column!  But its a pretty good start.

At the end of the day – I have 64 LEDs and a smiley face.  Could I want for more?

And with that, I think my minimus tinkering will take a short pause.

Kevin.

Permalink 1 Comment

Minimus usb – getting the solder out

May 21, 2012 at 10:31 pm (computers) (, , )

Ok, having spent some time programming the device as is (see my previous posts here and here) if I was to get any further I have to do some soldering!  The minimus has 22 IO pins sitting around the edge of the circuit board.

All 8 port B and port D IO pins are available, along with 5 of port C – bits 2 and 4-7.  Recall that bits 5 and 6 of port D are the onboard LEDs and bit 7 is the onboard switch, so niaively I wondered why only part of port C was exposed, when bits of port D that were already in use were exposed. It turns out that the other bits of port C are used for other things – PC1 is the reset (I think) for example.

So, I have lots of bits of old PCs kicking around, so I found some old IDE cables – with 40 pin connectors, and got a 40 pin IDC PCB mounted connector to plug into it. It is possible to plug the IDE cable to both sides of a connector, so it can effectively join two IDE cables together.

So, I’ve soldered 24 leads of the IDE cable to the minimus, giving me the following:

  • Vcc
  • PC2
  • PD0-7
  • PC4-7
  • PB7-0
  • RST
  • GND

While I was at it, I also reinforced the USB connector’s solder joints, as suggested here on the makestuff blog.

Now I needed some way to check that the minimus survived my heavy handed soldering (I’m much more at home with a keyboard than a screwdriver, let along a soldering iron), so I returned to my LUFA keyboard test code.

I wrote a function that could be called from the CALLBACK_HID_Device_CreateHIDReport function to “insert” keypresses depending on which IO pin was active.  It only needed to return the first one it detected – this would enable me to test each pin and therefore verify my soldering.

I had to initialise all IO pins for input, and enabled the pull-up resistors.  This meant that for me to trigger an IO pin, I had to connect it to ground.

  DDRB = 0;
  PORTB = 0xff;
  DDRC = 0;
  PORTC = 0xff;
  DDRD = 0;
  PORTD = 0xff;

Setting DDRx = 0 sets all bits to input, then writing 0xff to PORTx enables the internal pull-up resistors.  After this, the value can be read (leaving a pin unconnected at Vcc reading 0 and connecting it to GND reading 1) from the PINx registers.

Then I had a function to return a series of key presses to say B, C or D followed by a numeral for 0 through 7.

I ended up with the following:

uint8_t port2num (uint8_t portval)
{
  if (portval & 1)
  {
    return HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS;
  }
  else if (portval & 2)
  {
    return HID_KEYBOARD_SC_1_AND_EXCLAMATION;
  }
  else if (portval & 4)
  {
    return HID_KEYBOARD_SC_2_AND_AT;
  }
  else if (portval & 8)
  {
    return HID_KEYBOARD_SC_3_AND_HASHMARK;
  }
  else if (portval & 16)
  {
    return HID_KEYBOARD_SC_4_AND_DOLLAR;
  }
  else if (portval & 32)
  {
    return HID_KEYBOARD_SC_5_AND_PERCENTAGE;
  }
  else if (portval & 64)
  {
    return HID_KEYBOARD_SC_6_AND_CARET;
  }
  else if (portval & 128)
  {
    return HID_KEYBOARD_SC_7_AND_AND_AMPERSAND;
  }
  else
  {
    return HID_KEYBOARD_SC_X;
  }
}

// Can only add up to 4 more keys
uint8_t checkMinimusIO (USB_KeyboardReport_Data_t*KeyboardReport, uint8_t UsedKeyCodes)
{
  uint8_t usedkeys = UsedKeyCodes;
  if (usedkeys > 3)
  {
    // no room left...
    return 0;
  }

  // Check ports B, C then D
  uint8_t portval;

  // want to reverse the sense of the data (as "unconnected" will be 1)
  portval = ~PINB;
  if (portval)
  {
    KeyboardReport->KeyCode[usedkeys++] = HID_KEYBOARD_SC_B;
    KeyboardReport->KeyCode[usedkeys++] = port2num (portval);
  }
  else
  {
    // Must filter as can only see pins 2, 4-7
    portval = ~(PINC) & (0b11110100);
    if (portval)
    {
      KeyboardReport->KeyCode[usedkeys++] = HID_KEYBOARD_SC_C;
      KeyboardReport->KeyCode[usedkeys++] = port2num (portval);
    }
    else
    {
      // mask out the buttons and LEDS
      portval = ~(PIND) & (0b00011110);
      if (portval)
      {
        KeyboardReport->KeyCode[usedkeys++] = HID_KEYBOARD_SC_D;
        KeyboardReport->KeyCode[usedkeys++] = port2num (portval);
      }
      else
      {
        KeyboardReport->KeyCode[usedkeys++] = HID_KEYBOARD_SC_O;
      }
    }
  }

  return usedkeys;
}

It was quite irritating to find that the numbers weren’t a simple HID_KEYBOARD_SC_0 … through SC_9, but that they all had _AND_WHATEVER on the end. I was hoping for a simple, predictable constant to cut-and-paste in, but no such luck.

Anyway this gave me the checkMinimusIO() function I could call from CALLBACK_HID_Device_CreateHIDReport() as follows:

  if (ButtonStatus_LCL & BUTTONS_BUTTON1)
  {
    UsedKeyCodes = checkMinimusIO (KeyboardReport, UsedKeyCodes);
  }

Note that I only called if it the button was pressed, which just made testing easier for me.

I did have a problem though  when I  first ran it – for some reason, PD0 was always floating no matter what I set it to which meant that whenever I tried to test a pin from port D, I always got D0.  In the end I had to mask that pin out in my code (hence the 0b00011110 value in the test for PIND – masks out pins 5,6,7 – the LEDs and switches and pin 0).

I don’t know if this was as a result of my soldering or if it always did that – I never checked the pins prior to me soldering the cable on.  If I force D0 to GND or Vcc, it all seems to work fine.  They appears to be something wrong with setting the internal pull-up resistor.  Everything else works fine though.  Odd.

It was somewhere around this time that I realised the major flaw in my thinking … I had wired up the pins so that they aligned neatly with the IDE cable in the sequence described above – so 8 adjacent cables were PD0-7 and another 8 were PB7-0 and so on … but by using the PCB connector to join two IDE cables together, the pins are now reversed in the second cable, so when it comes to wiring something up at the other end, the sequence will be something like PC2, VCC, PD1, PD0, PD3, PD2, etc.  And it was such a good idea!  Oh well.

I do however have at least 17 IO pins I can use for other things, all available on the end of an IDE 40 pin connector. I just need to remember which pin goes where.

Kevin.

Permalink 1 Comment

Minimus usb and LUFA

May 21, 2012 at 7:20 pm (computers) (, , , )

Once I’d got the basics of programming the Minimus sorted out (see my last post), I was keen to see if I could get a USB stack compiled and running on it, so I could then actually think about talking to my code running on it from a PC.

Well it turns out that the LUFA stack “knows” about the minimus and it doesn’t take much to get the demo applications running.  LUFA is an excellent set of code, supporting both raw USB access and many common classes.

I downloaded and extracted the code base into my project area and sought out the sample keyboard class application (Demos/Device/ClassDriver/Keyboard).

There is a top-level project file (lufa.pnproj) for Programmers Notepad which gives you the full set of code – all demos, library, drivers, etc. Navigate to the demo application you wish to build and then you can “make all” in that directory and built the entire library and code.

Before that though, I had to configure the Makefile for the minimus. The documentation is very good once you know a little about what you are doing, but it took me a while to understand enough of the ‘getting started’ documentation to get the stage where I had running code.

The following had to be set to work for the minimus:

MCU = at90usb162
ARCH = AVR8
BOARD = MINIMUS
F_CPU = 16000000

Then I had to tailor the example a bit for the minimus.  Key things to do:

  • Keyboard.c: In SetupHardware() comment out Joystick_Init() – as there is no joystick on a minimus
  • Keyboard.c: Same in CALLBACK_HID_Device_CreateHIDReport() – comment out the line with the call to Joystick_GetStatus()
  • Keyboard.c: Then I commented out all the code examining JoyStatus_LCL in the same function and was left with a single test – the check for the switch
  • Keyboard.h: Comment out the #include <LUFA/Drivers/Board/Joystick.h> line

After some thought, I decided what I wanted was to generate a Windows-L key sequence (thinking it would be entertaining to force the ‘change user’ screen to show).  For what I had to lookup the USB modifier term for the Windows key, which had a peculiar name – it turns out it is the HID_KEYBOARD_MODIFIER_LEFTGUI modifier key …

My final CALLBACK_HID_Device_CreateHIDReport() function was thus as follows

  USB_KeyboardReport_Data_t* KeyboardReport =
         (USB_KeyboardReport_Data_t*)ReportData;

  uint8_t ButtonStatus_LCL = Buttons_GetStatus();
  uint8_t UsedKeyCodes = 0;

  if (ButtonStatus_LCL & BUTTONS_BUTTON1)
  {
    KeyboardReport->KeyCode[UsedKeyCodes++] = HID_KEYBOARD_SC_L;
    KeyboardReport->Modifier = HID_KEYBOARD_MODIFIER_LEFTGUI;
  }

  *ReportSize = sizeof(USB_KeyboardReport_Data_t);
  return false;

Note that the sample code allows for up to 6 keys to be returned in one go. I’m only using one for this test.

At this point I was ready to compile everything and give it a go.

Unfortunately when configuring the Makefile, I had got distracted before changing F_CPU (I couldn’t remember the clock speed and was about to look it up when kids happened).  So for my first build, after loading and running, nothing happened at all.  It just so happens that nothing works when F_CPU is the default of 8000000.

After quite a bit of head scratching, I returned to the Makefile and remembered that I hadn’t looked up the clock setting.  Thankfully setting it correctly and another build (after a ‘make clean’ to be sure) sorted it all out.

There was some benefit to this problem though – I got to navigate a fair bit of the LUFA code and standard AVR definitions trying to decode macros for watchdogs, definitions for LEDs and so on.  Some key bits of information I learned:

  • The standard AVR definitions I’d need were installed with WinAVR in c:\WinAvr-version\avr\include\avr directory. Key files being io.h and wdt.h
  • The definitions for the minimus from the LUFA libraries were installed in <LUFA Root>\LUFA\Drivers\Board\AVR8\MINIMUS with the main (well, only actually) files being Buttons.h and LEDs.h
  • The key bits of LUFA I was using were in <LUFA Root>\LUFA\Drivers\USB\Class\Device

So once it was running my code, Windows obligingly went through its “detecting new device” routine and recognised the minimus as a USB HID keyboard device and at that point, pressing the button triggered the Windows-L response I’d been looking for.

And that was it.  I now have a successfully running USB stack on the minimus.  My very many thanks to Dean Camera at http://www.fourwalledcubicle.com/.  The LUFA code is just great – so many possibilities!

Kevin.

 

Permalink 1 Comment

Minimus usb (or my quest to flash some LEDs)

May 20, 2012 at 9:36 pm (computers) (, , )

I was nicely surprised to hear from some of the Northackton chaps that there was a new, very cheap (around a fiver) board you can get that plugs directly into a PC with fully programmable I/O (input/output) connections and a free development kit.  That board turned out to be a Minimus USB and I got hold of one for a play straight away.

I won’t recount all the details of it here, its all one the websites, but you can buy them for around £5 and they are basically an ATMEL microcontroller (AT90USB162), 2 LEDs, 2 switches and a USB connector – and thats about it!  Here is a good article from MakeStuff introducing the board and what it can do.

This is the first in a series of posts about it and what I’ve been up to.

First a disclaimer – I am not an electronics person!  I am software and networks through and through, so I make no guarantees for technical accuracy in any of this.  It has been pulled together from all corners of the Internet and it all worked for me.  It hasn’t fried anything yet, but that is all the assurance you’ll get.

Now like many software engineers, when faced with a bit of hardware with LEDs on it, I wanted to make them flash!  Well to do that I needed a few things to get started – namely a development environment and a means to programme the device.

WinAVR gives an IDE (Programmers Notepad), ports of the GNU compilers for AVR devices and a full set of standard library definitions for AVR chips.  Atmel’s own FLIP software provides a means of sending compiled binaries to the device and the minimus includes its own bootloader software all ready to go.

Other useful information:

So I installed it all, following the instructions, and got started on my first programme to make the LEDs flash.  I started with the demo LED programme provided on the minimus USB website.  This compiled up and loaded ok, but I wanted to know more about how it all worked, so I looked up the basics of driving an AVR to make its input/output ports work.  I stumbled on this explanation, telling me about the main three registers and pull-up resistors and so on, which was very useful.

What I didn’t find easily was anything that say “poke this bit with a 1 or 0 to make X happen”.  The sample code tends to toggle the LEDs and things, but eventually from the schematic and some experimentation I realised that the switch reads 0 when pressed and 1 otherwise (PD7 is tied to 5v in the schematic and pulled low when you press the switch) and that similarly you write a 0 to PD5 or PD6 to light the LEDs (they are connected between 5v and the PORT D pins).

So I ended up with the following main functions:

int switch_on ()
{
  if (PIND & (1<<PD7))
  {
    return 0;
  }
  else
  {
    return 1;
  }
}

void red_on()
{
  PORTD = PORTD & ~(1<<PD6);
}

void red_off()
{
  PORTD = PORTD | (1<<PD6);
}

void blue_on()
{
  PORTD = PORTD & ~(1<<PD5);
}

void blue_off()
{
  PORTD = PORTD | (1<<PD5);
}

Which illustrates the basics. The only thing missing then is something to initialise the I/O registers:

PORTD = 0b00000000;
DDRD = 0b01100000;
PORTD = 0xb0110000; // Start with them off

Which sets bits 5 and 6 as outputs (the LEDs), leading bit 7 as an input (as this is the switch).

The only other thing from the sample code is that you have to disable the watchdog (otherwise I guess it will trigger and reset/interrupt/whatever it is configured to do by default!)

MCUSR &= ~(1 << WDRF);
wdt_disable();

These all use the standard definitions for AVR microcontrollers provided by WinAVR’s io.h and wdt.h headers.

At this point, the standard Makefile that came with the LED sample application was enough to build my source file (I’d just hacked the above into the provided C file) from within Programmers Notepad and I was off. I was then able to download the resulting hex file using FLIP and I had LEDs flashing in various sequences.  I also got quite a lot of practise rolling my thumb across the switches to get the device back into programming mode once I’d run my code on it.  (you can “roll” a thumb quite easily across the switches to get the right sequence: reset on – other on – reset off – other off).

I was building up a list of things to look at next – getting some kind of connector on the IO pins, tying up a range of LEDs to the IO pins and also taking at look at the LUFA USB stack to see if I could get that going.  But more on those next time.

Kevin.

Permalink 2 Comments