Radio Control Panel – Tweeting Status


I made a few updates to the WiFi Radio Control Panel.  I fixed a few bugs in the display, and in the start and stop logic, but the biggest addition was the ability to tweet the currently playing song and station.  Whenever the radio detects a new song is playing, it tweets a message to @SchampsNetRadio.  You can probably tell I’ve been listening to a lot of Groove Salad lately…

Anyway, there  are no new photos, but here are some of the old ones, to remind you how cool it looks:

This is all part of an entry in the AdaFruit Make It Tweet Challenge on Instructables, though I readily admit it has limited usefulness.  A nifty future update would be to allow some kind of Twitter-based control interface.  You’d need some kind of crypto or authentication system to prevent random strangers from messing up your tunes, though.

The updated code is in my GitHub Repository.

Advertisements
Posted in Projects, Radio Control Panel | Leave a comment

Bus Pirate Breakout 3.2

There was some interest in making another run of these, so after I fixed some of the spacing issues with the 6-pin ISP/SPI header (it was too close to the 10-pin BP header to have cables hooked up to both at the same time), I made another run.

I updated the version to be 3.2, meaning it is compatible with Bus Pirate v3, version 2 of the breakout board.

Here’s the Bus Pirate Breakout topic on the Dangerous Prototypes Forum that I’m using to track updates to the project.  There is a possibility that Ian will add this to the Dangerous Prototypes free PCB drawer.  If there is enough interest, I can do another run, hopefully at the low, low price of $3.

The source, as always, is available in my github repository.


Posted in Bus Pirate Breakout, Projects | Leave a comment

Bus Pirate Breakout 0.1

My new Bus Pirate is great, but it’s kind of a pain to use the 10-pin cable and test clips to hook onto small components, and trying to find room for the Vpu pin alongside Vcc drove me to innovate.  So I made this breakout board, which connects to the Bus Pirate with a 5×2 to 5×2 cable.

Features:

  • breadboard breakout for all 10 pins
  • a power connector for providing VCC from an external source
  • a VCC select jumper so you can pick 5V or 3V3 from the Bus Pirate (or leave it open for external power)
  • a VPU-VCC select jumper, so you can tie Vpu to whatever you have selected for VCC
  • a 4-pin “standard” I2C header
  • a 3-pin “standard” 1-wire header
  • a 6-pin AVR ISP header (can also be used as an SPI breakout)

I got the boards from the DorkbotPDX PCB order, the same place I got the Bus Pirate v3b FTDI boards.  Once again, they are this totally awesome shade of purple.

You might be interested in the original forum post discussing it.

Download:

The Eagle design files are available from my Github repository.  I’ll probably be breaking everything out into separate repositories soon.

Photos:

The front.  It’s kind of crowded, because I wanted to keep it under 1 sq. in.  I did, but the 10-pin cable connector gets a little tight with the 6-pin SPI connector.  The “Vcc Select” header allows you to tie either the 3V3 or 5V pin from the Bus Pirate to “Vcc”  If you don’t choose, you can provide something else for Vcc at the “Power” header.  The “Vpu-Vcc” header allows you to connect whatever you have on Vcc to the Vpu pullup pin.  This is super handy for I2C stuff (my primary use for the BP at the moment).

Another angle of the front.  Those little tabs on the edges break off quite easily.  You can see the staggered header pins, which I got from the “Sneaky Footprints” Sparkfun Tutorial.  They help the headers stay in place and lined up better during assembly, which is great when you have things in the way that keeps you from just sticking it in a breadboard.

The back side.  I would have made this myself, but there just wasn’t room to make it one-sided without some jumpers, and I wanted a nice clean design.  The PCB order is cheap enough that it’s worth it (although the wait can get old).

Here it is, assembled.  You can tell it took me enough time to put together that the light got much worse, and I really had to drive up the exposure on these images of the assembled version.

Another shot of the front, kind of blurry.  I should try harder not to focus on the tips of the header pins…

This one’s a little better.  Longer header pins for the breadboard make it easier to get in.

The back, assembled.

Posted in Bus Pirate Breakout, Photo Gallery, Projects | 3 Comments

Bus Pirate Enclosure

My original Bus Pirate v3b FTDI had a vertical 6-pin FTDI cable header, but I found that the weight of the cable sticking up pulled the tiny board over.  I wanted to fit it into this matchbox enclosure anyway, so I replaced the header.

Here you can see a 6-pin right-angle header where the vertical header used to be.

The box was a little too big, so I used a 6-pin pass-thru header as an extender.  I cut a slit in the box, and the extender fit snugly.

This foam double-sided tape works well for holding things in place.  If I had thought this through, I would have skipped putting the LEDs on the bottom…oh well.

Here’s the Bus Pirate taped in place, and hooked up to the header extender.

There’s still plenty of room for the test pin cable.

And also plenty of room for the box lid when I’m not using it.

Posted in Bus Pirate v3b FTDI, Photo Gallery, Projects | Leave a comment

BusPirate-v3b-FTDI-0.3

I have released BusPirate-v3b-FTDI-0.3, which has:

  • room for a shrouded I/O header
  • Sparkfun’s locking header rows (see http://www.sparkfun.com/tutorials/114)
  • more clearance around voltage regulators, for easier assembly
  • improved label size and positioning

I don’t intend to produce any more boards, unless someone wants me to put together a kit for them, but I felt like these updates were worth making anyway.

You can find the zip distribution here: https://github.com/schamp/Schazamp/downloads
Or check here for the source:
https://github.com/schamp/Schazamp/tree/master/BusPirate-v3b-FTDI

This one comes in at 1.425″ x 1.110″, which is ~1.58 sq. in., which would be about $7.90 for three at Laen’s DorkboxPDX service.

Posted in Bus Pirate v3b FTDI, Projects | Leave a comment

BusPirate-v3-FTDI-0.2 Photos

Here’s the front of the board, courtesy of the DorkbotPDX PCB service.  Nice purple solder mask!  Note a few issues with tenting the vias, and the silkscreen being too close.  Also, VR4 is awfully close both to VR3 and the PIC, so I’m going to try and give it a bit more clearance.  Note also the incorrect version number.  This board is for version 0.2, not 0.1, as it says.  Finally, though the I/O headers are fine for normal double-row, I was hoping to use a shrouded header, but since I forgot to allow for it, there was way too much overlap with the CD4066 and the LED.

On the back, I screwed up the placement of the labels.  These were supposed to help with the ICSP header, but are totally in the wrong place.  Plenty of things to fix for version 0.3.

Here it is, all populated.  It’s quite crowded, but with some careful planning for doing things in the right order, it was not difficult at all.  Thank goodness for solder wick.  I found SparkFun’s SMD soldering tutorials very helpful.  It looks like there’s kind of a claw sticking up out of the leftmost LED, which needs to be fixed.

Here’s the back, populated.  Not much to say about it, but I thought I’d include it for completeness.  Having the proper LED labels on both sides sure would be nice.

Here’s the front from another angle.  If you look carefully at R14 (right in the center, to the right of the big yellow-ish 10uF tantalum cap), you can see that it’s standing off a bit from the board on one side, and there’s no connection.  This caused the self-test for Vpu to fail, which is how I found it.  Thank goodness for self tests!  Once I fixed it, the test passed with flying colors.

Here it is in its intended enclosure.  I need to cut some holes for the LEDs and headers, and tape it into place.

Here’s a view of my hacked-together ICSP programming adapter.  I won the ICD3 in the first round of the Make It Last contest, but the only cable it came with required the 6-pin RJ11 adapter, not the more common 5-pin ICSP header.  So, I cut the 6-wire cable, soldered on a header, and used my extension cable to hook it up to the target board, which worked like a charm.  This was actually my first PIC programming project (apart from some demo board stuff) and I found it far easier than I expected.

Here it is powered by the FTDI cable.  After programming the bootloader, I was able to update the firmware using the normal updater, and everything seems to be working perfectly.  Woo!

Posted in Bus Pirate v3b FTDI, Photo Gallery, Projects | Leave a comment

Radio Control Panel – LCD Text Scroller

To meet the deadline for the Instructables Microcontroller contest, I had to write up and submit the Instructable before I could put up my detailed write-up here.  There’s still a lot of write-up to do, but I wanted to spend some time discussing the scrolling mechanism I used for the LCD text.

Quick Introduction

The project in question is a standalone control panel for the WiFi internet radio I built (based on MightyOhm’s WiFi Radio project).  It is a modified wireless router that has a USB sound card, runs OpenWRT, and can play shoutcast stations, like my favorites at SomaFM (currently, Groove Salad).  I have also used Tinkernut’s instructions (also based on MightyOhm’s), which suggest a software-based control panel (in this case, Ario).  I wanted to avoid using my computer (as Tinkernut did), and also to avoid opening up my router and soldering on a serial port header (as MightyOhm did).

So, I built and Arduino-based ethernet-capable embedded system with a station selector knob, which uses the MPD (Music Player Daemon, the jukebox software running on the router) network protocol API to command it.  Part of the project is a character LCD that displays the current station, artist, and song.  However, the LCD is only 16×2 characters, so most song names and artists don’t fit.  So, I needed some way of scrolling the text so that it would all be displayed in an easy-to-read, appealing way.

For the display, the controller will store the station name in the first line, and an “Artist – Title” string in the second line.  The lines will scroll from right to left, with blank space on either side, with the line being completely blank for exactly one step in the scrolling sequence.  The lines will scroll independently, so that short station names won’t bit hidden while long song titles scroll by.

LCD Display Model

To control what I display on the LCD, I model the screen as an internal buffer, named scrollBuf, of N lines (in this case, 2, mapping directly to the lines on the display) and M characters (where M > 16, the maximum display on the buffer itself).  We also maintain an array of integers, named startPos, which maintains the start position into the scrollBuf string that we are printing to the LCD (for example, if we had scrolled the first 4 characters of a line off the screen, startPos would keep track of this).  This start position is offset by SCREEN_COLUMNS, because it includes the blank spaces that exist between the scrolled messages.  That will be explained in better detail later.

#define SCREEN_LINES 2
#define SCREEN_COLUMNS 16
#define SCROLL_BUF_LEN 64
char scrollBuf[SCREEN_LINES][SCROLL_BUF_LEN} = { 0 };
static uint8_t startPos[SCREEN_LINES] = { 0 };

In this case, I selected a maximum width of 64 characters (which, with the null terminator, of course, only holds 63 actual characters), trying to strike a balance between what most artist and song names were limited to, and how much RAM would be taken up by the scroll buffer (the ATmega328P on my Boarduino only has 2KB).

Scrolling Algorithm

When the station changes, the station name is put into scrollBuf[0] (naturally, length-checked and null terminated).  The controller periodically requests the current status of the radio, and parses out the current artist and song title.  The controller then periodically updates the LCD display, scrolling each line one character to the left, and wrapping as necessary.  Here’s how it works:

We loop through each of the lines on the screen buffer (any of which may have been populated with text elsewhere by the controller), and declare a variable to contain the “print buffer”, which will contain the string to be printed to the current line of the LCD.  The pBuf variable is SCREEN_COLUMNS wide, plus one character for the null terminator (since the LCD can display a full 16 characters).  We initialize pBuf to all blank spaces, and add a null terminator at the end.

for (uint8_t i = 0; i < SCREEN_LINES; i++) {
  char pBuf[SCREEN_COLUMNS+1] = { 0 };
  memset(pBuf, ' ', SCREEN_COLUMNS);
  pBuf[SCREEN_COLUMNS] = '';

Now is the good part.  Our aim is to figure out which part of the current line to put into the print buffer, and to figure out where in the print buffer to put it.  If the line is scrolling in from the left, there will be blank spaces at the front of it.  If it has filled the line and is scrolling across, there will be no blank spaces.  If the end has scrolled into view and is moving to the left, there will be spaces at the end.  Finally, once the entire line of the display has shown blank spaces for exactly one scrolling step, the line should start scrolling in from the right again.  To figure this out, we compute three values.

The first is the offset into the print buffer where the start of the displayed line is to be copied, in other words, how many blank spaces before the first character in the string.  It is found by the taking the greater of the number of columns (offset by the start position of the current line) and 0:

  uint8_t pBufOffset = max(SCREEN_COLUMNS - startPos[i], 0);

For example, if the start position is 3 (i.e., three blank spaces have been scrolled off the screen, 13 blank spaces remain, followed by the first three characters of the string), then pBufOffset will be 13.  If the start position is 20 (i.e., all 16 blank spaces, and four characters of the string have been scrolled off to the left), then pBufOffset will be 0.  We never want pBufOffset to be less than 0, that would be really bad when we use it as the index to copy into the buffer.

The next value we need to compute is the offset into the scroll buffer that we will be copying from, in other words, how many characters into the display string have been scrolled off the screen already.  It is found by taking the greater of the start position (offset by the number of columns on the screen) and 0:

  uint8_t scrollBufOffset = max(startPos[i] - SCREEN_COLUMNS, 0);

For example, if the start position is 3 (as above), then scrollBufOffset will be 0, since we want to copy the first characters of the display screen into the print buffer, after the 13 spaces.  Likewise, if the start position is 20 (also see above), then scrollBufOffset will be 4, since we want to skip over the 4 characters that have been scrolled off the screen to the left.

Finally, we need to compute the length of the string to copy into the print buffer.  This is found by taking the lesser of the number of screen columns (offset by the place we will be starting the string in the print buffer) and the length of the string to be scrolled.

  uint8_t len = min(SCREEN_COLUMNS - pBufOffset, strlen(scrollBuf[i]) - scrollBufOffset);

For example, if the start position is 3, then pBufOffset will be 13, and so at most 3 characters of the string can be copied in to the print buffer.  If the length of the string is (somehow) fewer than 3 characters, that will be used instead.  Likewise, if the start position is 20, then pBufOffset will be 0, and so at most 16 characters of the string can be copied in to the print buffer.  If the string is fewer than 16 characters left to display, then the entire remainder of the string will be copied in, followed by blank spaces.

Now we copy from the scroll buffer, at the specified offset, into the print buffer, at the specified offset, copying at most the computed number of characters, and add a null terminator.

  strncpy(pBuf + pBufOffset, scrollBuf[i] + scrollBufOffset, len);
  pBuf[pBufOffset + len] = '';

Finally, we must fill in any remaining, trailing spaces, so that the string sent to the display is exactly SCREEN_COLUMNS wide.

  if (strlen(pBuf) < SCREEN_COLUMNS) {
    memset(pBuf + strlen(pBuf), ' ', SCREEN_COLUMNS - strlen(pBuf));
  }
  pBuf[SCREEN_COLUMNS] = '';

Now we can send the print buffer to the display, and increment the start position counter (wrapping it as necessary).  We cycle startPos[i] up to the full length of the string plus the number of columns to account for the blank spaces between the scrolled text.

  if (startPos[i] < strlen(scrollBuf[i]) + SCREEN_COLUMNS) {
    startPos[i]++;
  } else {
    startPos[i] = 0;
  }

And that’s pretty much it.  It seems to work well.  Here you can see the entire code block in all its contextual glory, or you can find it in my github repository.


// how many lines are there on the screen?
#define SCREEN_LINES   2
// how many columns, i.e., how many characters can be displayed?
#define SCREEN_COLUMNS 16
// how many characters should I reserve for the scroll buffers?
// (note that null terminator limits the actual string length 
// to one less than this number)
#define SCROLL_BUF_LEN 64

// scrollBuf contains a buffer of text for each line,
// which will be scrolled from right to left
char scrollBuf[SCREEN_LINES][SCROLL_BUF_LEN] = { 0 };

// in milliseconds, how long to wait before scrolling display
// one character to the left.
#define SCROLL_DELAY 100

// render display maintains 
void renderDisplay(bool force = false) {
  // startPos maintains, for each line of the display, 
  // how many characters the display string has been scrolled.
  // it includes the blank spaces (SCREEN_COLUMNS of them, to be exact)
  // that exist between the scrolled messaged, so it must be offset
  // by SCREEN_COLUMNS to find the actual position in the display string
  // that is the first to be displayed (if the beginning of the string 
  // itself has been scrolled off the screen to the left)
  static uint8_t startPos[SCREEN_LINES] = { 0 };

  static uint32_t nextUpdate = 0;
  if ( (millis() > nextUpdate) || force) {
    nextUpdate = millis() + SCROLL_DELAY;

    // for each line of the display
    for (uint8_t i = 0; i < SCREEN_LINES; i++) {

      // declare a print buffer that will hold the line
      // as it is built up, to replace line i on the display
      // the size is the number of columns + 1, to allow room
      // for the null terminator
      char pBuf[SCREEN_COLUMNS+1] = { 0 }; // initialize array to null
      memset(pBuf, ' ', SCREEN_COLUMNS);   // set full line to blank spaces
      pBuf[SCREEN_COLUMNS] = '';         // sanity check for null terminator, could probably remove.

      // pBufOffset is the offset into the print buffer to begin the display string,
      uint8_t pBufOffset      = max(SCREEN_COLUMNS - startPos[i], 0);
      uint8_t scrollBufOffset = max(startPos[i] - SCREEN_COLUMNS, 0);
      uint8_t len = min((SCREEN_COLUMNS - pBufOffset), strlen(scrollBuf[i]) - scrollBufOffset);

      // we copy into the pBufOffset'th character into the pBuf string,
      // from the scrollBufOffset'th character in the scrollbuffer string,
      strncpy(pBuf + pBufOffset, scrollBuf[i] + scrollBufOffset, len);
      // add a null terminator (may not be necessary)
      pBuf[pBufOffset + len] = '';      

      // fill any remaining space after the contents pBuffer with spaces
      if (strlen(pBuf) < SCREEN_COLUMNS) {
        memset(pBuf + strlen(pBuf), ' ', SCREEN_COLUMNS - strlen(pBuf));
      }
      // add a null terminator
      pBuf[SCREEN_COLUMNS] = '';

      // set the cursor to the beginning of the appropriate line
      // and send the display buffer to be printed
      lcd.setCursor(0, i);
      lcd.print(pBuf);      

      // increment (or reset) the start position
      if (startPos[i] < strlen(scrollBuf[i]) + SCREEN_COLUMNS) {
        startPos[i]++; 
      } else {
        startPos[i] = 0;
      }
    }
  }
}

Downloads

Here is the original Instructable for the Standalone WiFi Radio Control Panel.

You can find the latest version of the source, along with the schematic and some photos, in my github repository.

Posted in Projects, Radio Control Panel | Leave a comment