Thursday, June 20, 2013

Arduino-compatible VFD modular clock from Akafugu

There aren't many VFD clock kits out there that are software-compatible with Arduino (and by that I mean the "Arduino sketch" being compilable in Arduino IDE and uploadable through USB-FTDI).
Most of these kits come with the microcontroller pre-programmed, so they can be built quickly and easily, with minimal effort (totally understandable instant gratification; nobody wants to end up with an expensive dud). Upgrading the software usually requires familiarity with the microcontroller toolchain (compile-build-flash), plus an ISP programmer. (Note: The only processor I am familiar with is AVR/Atmega.)

I was going to build myself an Arduino-based VFD clock, one that can take a sketch through the FTDI cable. Instead of starting from scratch (choosing a schematic, making the board etc), I decided to try one of the only 2 open-source VFD clock kits I found that are based on Atmega processor and :

I settled for the VFD modular clock because the Akafugu people offered me the pair of PCBs in their kit (for a very reasonable $19, shipping included) and also because I already had most of the parts, including the two SMDs (that come pre-soldered in the kit: ATmega328 and HV5812) and the IV-17 VFD tubes.



















I built the clock following their great assembling instructions, but, as you will see, not without hitting a few stumbling blocks on the way.

I should clarify that this post is not a review of the VFD modular clock kit (since I did not have the kit), but just a record of my observations. It was my choice to not use the kit, thus forcing myself to try to understand the schematic and the software.

Since my goal was to make the VFD modular clock Arduino-compatible, I was aware of the challenges awaiting me:
- burning the bootloader for ATmega328 with internal 8MHz oscillator;
- connecting a makeshift FTDI header;
- adapting the software to work in Arduino IDE;

Once I figured out the fuses, burning the bootloader was straightforward. For this purpose I created this section in boards.txt:

intclock328.name= ATmega328 Internal clock 8MHz
intclock328.upload.protocol=stk500
intclock328.upload.maximum_size=30720
intclock328.upload.speed=57600
intclock328.bootloader.low_fuses=0xE2
intclock328.bootloader.high_fuses=0xDA
intclock328.bootloader.extended_fuses=0x05
intclock328.bootloader.path=atmega
intclock328.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex
intclock328.bootloader.unlock_bits=0x3F
intclock328.bootloader.lock_bits=0x0F
intclock328.build.mcu=atmega328p
intclock328.build.f_cpu=8000000L
intclock328.build.core=arduino

Then I checked that the bootloader works, by uploading a simple sketch that outputs on D9 (which is connected to the buzzer). Before doing this, I had to connect the FTDI breakout to the board. Luckily (more probably intentionally), all of the required pins (Rx, Tx, Vcc, Gnd, Rst) are broken out on the female header, so just using wires worked, as shown in the next photo. This is not a nice solution though, since the top board (with the VFDs) needs to be removed before every sketch upload. (Hopefully the Akafugu team will also include an FTDI header in the next revision.)



















After I soldered all the parts on the base board, I realized the biggest problem of them all: some parts (sourced by me, and obviously of different size than those in the kit) stuck well above the two lateral headers, so the display shield (upper board) could not be plugged in the base board. Almost a showstopper at this point. The solution was to replace the tall 330uF/16V capacitor, bend both 47uF capacitors sideways, replace the 330uF/50V with a pair of thinner 100uF, push both inductors as much into the PCB as possible, then cut the top plastic wrapping on one of them. These, combined with the male headers not being flush to the display board when I soldered them, did the trick. I managed to have the clock looking as intended by its creators (if you don't look too closely), as shown in the next photo.



















The Akafugu designers tried to minimize the size of the clock, leaving little room for flexibility (that is, ability to use a broader range of components, of different sizes eventually). The sizes for the chosen components (especially the capacitors and the inductors) are really unique, any deviation would lead to the boards not fitting together.
Using (smaller) SMD components would not be a good solution, since these would also need to be pre-soldered (or otherwise potential non-SMD-soldering clients would be excluded). The only compromise I can think of is enlarging the base board a little bit, keeping in mind that this 4-tube version is the smallest of the display boards, all others extending laterally beyond both sides of the base board.

And finally, the last challenge: the software. I started from the original C code published here. This was written for the avr-gcc compiler and produces a hex file, which is then flashed onto the processor (no bootloader needed, nor provided) using an ISP programmer.

I changed the code (available here), mostly cosmetically, to compile with Arduino 1.0. It does not require any other external libraries and it includes its own I2C/Wire functions (does not use Arduino's Wire library).

In the end, I have an Arduino-compatible Akafugu VFD modular clock that looks just like the original one (I need to add the spacers though).



Saturday, June 1, 2013

Unifont on Wise Clock 3/4

This was a quick experiment inspired by WyoLum's EReader library: displaying Unicode characters on the 3216 display from Sure Electronics (as used in Wise Clock 3/4).

The fonts (developed by Roman Czyborra a very long time ago (1998!) and documented here) are defined in the file unifont.wff on the SD card. Before a character is displayed, its 32-byte definition is loaded from the file, starting from the calculated address.



The simple sketch used in the above video can be found here. It was tested with Arduino 1.0.4 and does not require the EReader library (but requires the unifont.wff file on the SD card).

PS  For the non-Chinese speakers/readers, the displayed symbol is "nihao" ("hello"), Unicode 0x6829.

Wednesday, May 15, 2013

Play WAV files from SD card with Wise Clock 3/4 board

The video below shows another hack for Wise Clock 3/4, playing a WAV file directly (not using extra hardware) from SD card, with the help of the TMRpcm library.



The TMRpcm software uses the standard SD library (coming with Arduino IDE 1.0 and later) to read WAV files from SD card. To output the audio while buffering the content of the SD file, TMRpcm uses ISR triggered by internal timer. The buzzer/speaker can be connected only to certain pins of the processor. For ATmega1284/ATmega644 (used in Wise Clock 3/4), these pins are D3, D4, D12, D13, D14 and D15, as shown in the definition below (from sanguino core file pins_arduino.c).





















From the perspective of TMRpcm library, the buzzer in Wise Clock 4 is connected to the "wrong" pins, D22 and D23, which are not eligible for this trick. I chose to connect another speaker to pin D13, but that's already taken by the display (CS, pin 1). So I had to cut the trace from D13 to the display, and connect pin 1 of the display to D18 (another choice was D19, the only other available I/O left).

From now on it's only software.
  • modify this line in HT1632.cpp:
    #define HT1632_CS 18 //  Chip Select (pin 1 of display connector)
  • add line
     #define SPEAKER_PIN1  13


Then follow from step 4 of this previous post.

Unfortunately, this will not work with Wise Clock 4 software as is, and the main reason is the timer interrupts used by TMRpcm library, which disrupt the "SPI-like" commands for the display.

The video above may seem like another Wise Clock "app", but it is just a "cheating" sketch running standalone, shown below.


#include "Arduino.h"
#include "Wire.h"
#include "DS3231.h"
#include "HT1632.h"
#include "AlarmClock.h"
#include "WiseClock.h"
#include "SD.h"
#include "TMRpcm.h"
#define SD_ChipSelectPin   4
#define AudioPin          13  // must be PWM pin

TMRpcm tmrpcm;

//**********************
void setup()
{
  Serial.begin(9600);

  // disable JTAG (to use pin D18);
  uint8_t tmp = 1<
  MCUCR = tmp;
  MCUCR = tmp;

  ht1632_setup();

  SD.begin(SD_ChipSelectPin);
  tmrpcm.speakerPin = AudioPin;
}

//*********************
void loop()
{
  alarmClock.isAlarmEnabled = true;
  alarmClock.getTimeFromRTC();

  Serial.print("Time is: ");
  Serial.print(alarmClock.hour, DEC);
  Serial.print(":");
  Serial.print(alarmClock.minute, DEC);
  Serial.print(":");
  Serial.println(alarmClock.second, DEC);
  
  if (!tmrpcm.isPlaying())
  {
    ht1632_putTinyString(0, 0, "Playing", RED);
    wiseClock.displayTime(8, false);
    tmrpcm.play("dancing.wav");
  }
  delay(2000);
}

The display is statically updated once, before the WAV file starts playing.

It would probably be possible to update the display between playing short WAV files (with interrupts disabled right after each file is played). But that may open a door to other set of problems, since the display is practically frozen for the duration of the file playing. On the other hand, the I2C (through Wire library) works just fine (that's because I2C is hardware driven), so getting the current time from RTC while playing music is not an issue.

Conclusion
Although in theory would be possible to integrate TMRpcm library in the Wise Clock software (to play WAV files from SD card while the clock functionality is not affected), in practice that would take a lot of programming effort. A much easier and cheaper way to include audio into Wise Clock 4 (hardware and software) would be through the use of serially controlled audio-playback specialized modules, like this one (or maybe even the radio/MP3 module I reviewed here, if I ever find it in my pile of stuff).

Friday, May 10, 2013

Miscellaneous

1. Some time ago I did some (unpaid and unaccredited) work for a kickstarter project that ultimately failed to raise the required funds. My task was to develop a prototype board that can read data from a sensor and post it over WiFi to a web site (cosm.com-like). The board I designed was based on readiymate, piggybacking on its capability to update the software "over the air" (through WiFi), which at the time seemed to be the only board offering this feature. Although a readiymate-based system is not cheap nor sophisticated enough (design and feature-wise) to become a commercial success (like the Nest thermostat, for instance), it relies on easy-to-find off-the-shelf components, it is open source and Arduino-compatible. So, it is easy to modify, adapt, hack and support.

Here are some photos of my readiymate-derivative board, for the record, and also with the hope that someone may find it interesting enough to pick up the pieces and develop it further.















Please contact me if you have a need for this PCB or you want to buy one.















The board (which was not even given a name), has just 2 major components: the ATmega1280 microcontroller (also found in the first generation Arduino Mega) and the WiFly RN171 module.
The sensor module gets plugged in the pair of 6-pin female headers (compatible with the JeeLab's JeeNode, apparently). The button is normally used for switching to setup mode (allowing user-configuration of the board, so it can get the name of the WiFi network and the password), as described in this post.















At some point we considered replacing the ATmega1280 with the cheaper, but as powerful, ATmega1284 (as used in Wise Clock 4), thus saving about $4 per board. Although the bootloader could be easily adapted, due to time constraints we preferred to go with the tested and proven solution (ATmega1280) instead.

A project that comes close (it is actually way ahead of the one shown here) in terms of requirements (size, cost, power etc.) and functionality ("over the air" software updates etc.) is the SparkCore: Wi-Fi for Everything (Arduino compatible).


2. Posterous.com blog site (which hosted some quite interesting microcontroller projects authored by "rossum", as far as I remember) just closed its doors. Could this happen to blogger.com /blogspot.com? I honestly thought that the internet can only grow, and every piece of contribution is recorded forever. Well, I was obviously wrong, if the internet is ever to become a "living" thing, some parts of it must die off occasionally, like branches of a tree, I imagine.


3. I recently discovered some interesting open source clocks that use the same 3216 display as Wise Clock 4:
Both clocks look like well-designed finished products, with elaborate enclosures and lots of features, including playing audio files from SD card (using the Wave Shield).

Saturday, May 4, 2013

Hacking Wise Clock 3/4 - Graphical Audio Spectrum Analyzer

For those who asked how to add hardware and software to their Wise Clock 3 or 4, here is a step-by-step recipe, using the example of a digital vu-meter. The hardware itself is nothing new, based on the MSGEQ7 "graphic equalizer display filter" chip. The minor challenge is adding the multi-band vu-meter application to the existing Wise Clock 3/4 software.

Step 1.
First make sure that the new hardware works on its own. Connect it to an Arduino and test it with a sketch that performs the desired functionality. This sketch will be the base code for your new Wise Clock 4 "app".

In my example, I assembled the circuit shown below, where the MSGEQ7 and the 3216 display are connected to an old seeeduino. The 3216 display is connected to the same digital pins used in Wise Clock 4 (D12, D13, D14, D15). The MSGEQ7 chip uses analog pin A2 and digital pins D2 and D3 (these will  need to be later adapted for Wise Clock 4).















The little green "appendix" connected to the MSGEQ7 board is the IN-ZX-Sound microphone amplifier, which could be replaced with the cheaper and probably better version from Adafruit.

The working vu-meter sketch (compiled and tested in Arduino 1.0) can be found here.


Step 2.
Re-wire the hardware to the Wise Clock 3/4 board, using digital and/or analog pins that are not already taken, like D18, D19 and A0-A7 (check schematic here).

Note: Some "already taken" pins could be re-assigned, but the original functionality that they provide will be lost. For example, you could re-use D20 and D21, which are currently involved in serial communication with the BT module (through SoftwareSerial library, look for USE_SOFTWARE_SERIAL macro in WiseClock.cpp), but then communication with the module will be disabled.

In the example, since the 3216 display is already connected (D12-D15), I only had to find two available digital pins (the only choice being D18 and D19) and one analog pin (A0) to connect the MSGEQ7 chip to the ATmega644/1284.

After soldering the 5 wires (3 signal, Vcc and GND), the hacked WC4 board looks like this. (Note that the yellow wire in the photo is left unconnected.)















Step 3.
Make sure that the code that worked with Arduino (in Step 1) still works with the Wise Clock 4 board (target board "Sanguino" or "Sanguino with Atmega1284/16MHz" in Arduino IDE), after the hardware and software changes.
In my example, because I am using D18 and D19 (also used by JTAG), I had to disable JTAG in the code, using these lines:

uint8_t tmp = 1<<JTD;
MCUCR = tmp;
MCUCR = tmp;

This is the Wise Clock 4 with the display and the attached VU-meter board:















Step 4.
Now we focus completely on the software. To add a new app to the existing Wise Clock sketch, start with creating 2 new files (.h and .cpp) for the new app class. One easy way, for example, is to copy the files AppLife.h and AppLife.cpp and rename those copies AppVu.h and AppVu.cpp, then delete the implementations of the 2 functions (init() and run()) . After updating their content, the 2 new files should look like the ones below.


// file AppVu.h
#ifndef _APP_VU_H_
#define _APP_VU_H_

#include "Arduino.h"

class CAppVu
{
public:
  void init();
  int16_t run();
};

extern CAppVu appVu;

#endif  // _APP_VU_H_




// file AppVu.cpp
#include "AppVu.h"
#include "HT1632.h"

void CAppVu::init()
{
  // todo:
}

int16_t CAppVu::run()
{
  // todo:
}

CAppVu appVu;



Step 5.
Modify WiseClock.cpp to include the new header, add new menu item ("VU"), reference the global single instance of this class (named appVu in this case) etc. Basically, add the following lines (in the appropriate places):


#include "AppVu.h"
...
// add to enum of menu item indexes
#ifdef _APP_VU_H_
MENU_VU,
#endif
...
// add the menu item display string
#ifdef _APP_VU_H_
const char menu_str_vu[] PROGMEM = "VU";
#endif
...
// add to const char * menu[] PROGMEM = {...
#ifdef _APP_VU_H_
menu_str_vu,
#endif
...
// in WiseClock::processButtonSet()
#ifdef _APP_VU_H_
case MENU_VU:
crtApp = APP_VU;
appVu.init();
--item;
isMenuActive = false;
break;
#endif
...
// in WiseClock::runCrtApp()
#ifdef _APP_VU_H_
case APP_VU:
ms = appVu.run();
break;
#endif


In file WiseClock.h add the name of the new app (APP_VU) at the end of the enum:

// names of the possible "applications";
enum { APP_QUOTE, APP_UTC, APP_BIG, APP_LIFE, APP_DEMO, APP_PONG,  APP_PACMAN, APP_LIVED, APP_SCORE, APP_STOPW, APP_CNT_DOWN, APP_WORDS, APP_MSG, APP_STATS, APP_TCLOK, APP_TIX, APP_LINES, APP_SUN, APP_ANIM, APP_LOG_CLEAR, APP_TMP, APP_NEWSD, APP_VU };

After all these changes are done, make sure that the Wise Clock sketch still compiles (even without the functions CAppVu::init() and CAppVu::run() implemented).


Step 6.
Implement the functions init() and run() of the new class (CAppVu::init() and CAppVu::run() in my example). The code for init() should be copied from the function setup() of the prototype sketch (in Step 1).

void CAppVu::init()
{
  // disable JTAG;
  uint8_t tmp = 1<<JTD;
   MCUCR = tmp;
  MCUCR = tmp;

  // MSGEQ7;
  pinMode(analogPin, INPUT);
  pinMode(strobePin, OUTPUT);
  pinMode(resetPin, OUTPUT);
  analogReference(DEFAULT);

  digitalWrite(resetPin, LOW);
  digitalWrite(strobePin, HIGH);

  clearDisplay();
}

The code for run() comes from the loop() function in the prototype sketch of Step 1.

// show 2-columns bars for each of the 7 channels;
int16_t CAppVu::run()
{
clearDisplay();

digitalWrite(resetPin, HIGH);
digitalWrite(resetPin, LOW);

for (int i = 0; i < 7; i++)
{
digitalWrite(strobePin, LOW);
delayMicroseconds(30); // allow output to settle;
spectrumValue[i] = analogRead(analogPin);
digitalWrite(strobePin, HIGH);

  // try to eliminate some noise;
if (spectrumValue[i] < 100)
      spectrumValue[i] = 0;

int x = i*5;
int vu = spectrumValue[i]/64;
  if (vu <= 8)
  {
    ht1632_line(x, 15, x, 15-vu, GREEN);
    ht1632_line(x+1, 15, x+1, 15-vu, GREEN);
  }
  else if (vu <= 12)
  {
    ht1632_line(x, 15, x, 8, GREEN);
    ht1632_line(x+1, 15, x+1, 8, GREEN);
    ht1632_line(x, 7, x, 15-vu, ORANGE);
    ht1632_line(x+1, 7, x+1, 15-vu, ORANGE);
  }
  else
  {
    ht1632_line(x, 15, x, 8, GREEN);
    ht1632_line(x+1, 15, x+1, 8, GREEN);
    ht1632_line(x,  7, x, 4, ORANGE);
    ht1632_line(x+1,7, x+1, 4, ORANGE);
    ht1632_line(x,  3, x, 16-vu, RED);
    ht1632_line(x+1,3, x+1, 16-vu, RED);
  }
}
}

Note that the CAppVu::run() uses a new display function ht1632_line(...), which needs to be added to HT1632.h and cpp.


Step 7.
Compile, upload and test. Then improve, extend, publish and brag about it :)



Homework
Add graphic effects (e.g. display like a 6-inflection point graph), selectable from menu (follow example of the UTC app).