Purpose & Scope
Provide information about Arduino Micro as we attempt to use such a board to interface with a Noritake GU256x64D-3900 VFD module from a Windows PC over a USB HID connection.Software engineering skills and basic electronics knowledge are assumed.
Motives
After attempting to interface our VFD module from a PC over parallel port we came to the conclusion that it would be faster and cheaper to use a GPIO solution such as the one offered by Arduino Micro.Prerequesites
In the following article we make use an Arduino Micro board and a Noritake GU256x64D-3900B VFD module. On top of that we will be needing a breadboard, jumper wires and an assortments of LEDs and resistors to be able to carry out our experiments.Getting started
- Download the latest Arduino IDE from Arduino Software page.
- Plug your Arduino Micro to one of your computer USB port.
- Open Arduino IDE:
- Go to menu Tools > Board and select Arduino/Genuino Micro.
- From that same Tools menu select the Port you board is connected to.
- Go to menu File > Examples > 01.Basics > Blink
Go do some reading about that Blink example you are looking at or just Upload it to your board and see what happens.
Arduino development is done using AVR language.
See also that neat getting started guide.
Digital I/O
From the above Blink example you should be able to set your pins high and low as you wish and visualise the results using LEDs on your breadboard.Here are the Arduino functions involved with controlling Digital I/O on Arduino:
- pinMode()
- digitalWrite()
- digitalRead()
However for our VFD application we will need our micro-controller to pass on significant amount of data from the USB host to the Noritake hardware.
Doing that communication one bit at a time would be rather inefficient so we will need a solution to upload our data one byte at a time as both our hardware are 8-bit.
Luckily Arduino provides means to do port manipulations and tap directly into our ATmega32U4 8-bit registers.
Port manipulation
Looking at the ATmega32U4 to Arduino Micro pin mapping you'll notice that only two ports offer full byte control: port B and port D.We decided to use port B for our data byte. Here is how the port B pins are laid out on the Arduino Micro PCB.
Here is our breadboard test circuit using 560 Ohm resistors:
We modified the Blink example as follow to validate our cabling:
C:
byte offset=0;
int blinkPeriodInMs = 250;
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
// Set port B pins as output
DDRB = B11111111;
}
// the loop function runs over and over again forever
void loop() {
// Set the one bit corresponding to current offset in our port register
PORTB = B00000001 << offset;
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(blinkPeriodInMs); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(blinkPeriodInMs); // wait for a second
offset++; // Increase our offset making sure we light up the next LED
offset%=8; // Keep it between 0 and 7
}
- An output pin, called /WR, to signal data has been written and is ready for the display module to read.
- An input pin, called RDY. The VFD module will use it to notify when it's ready, high or busy, low.
We decided to use port C for that purpose since it has only two lines available anyway.
PC6 controls Digital Pin 5 and will be used for /WR.
PC7 controls Digital Pin 13 and will be used for RDY.
Arduino to VFD communication
We upgraded our circuit to connect the /WR and RDY pins and we hooked in our VFD module.We implemented an AVR Sketch to exercise and debug our communication protocol between our micro-controller and our VFD module.
Without the call to delayMicroseconds() we would lose characters in the traffic and get the following result:
Once we solved our timing issue our output remains aligned:
C:
/*
* Noritake GU256x64D-3900B
* Character writting test
* By Stéphane Lenclud
*/
const byte KRdyOffset = 7;
const byte KWrOffset = 6;
/*
* Send a single byte to our VFD module
*/
void sendByte(byte aByte)
{
// Write data
PORTB = aByte;
// Bring /WR down to tell our display data is ready
PORTC &= B10111111;
// Make sure we wait long enough for our display to kick in
// This very is important otherwise some characters will be lost
// 108us was not long enough, characters would get lost.
// 109us seems very reliable
delayMicroseconds(109);
// Set /WR high up again
PORTC |= 1 << KWrOffset;
}
/*
* Clear VFD module screen
*/
void clearScreen()
{
sendByte(0x0C);
}
/*
* The setup function runs once when you press reset or power the board
*/
void setup()
{
// Set port B pins as output
DDRB = B11111111;
// Set /WR pins as output
DDRC = DDRC | B01000000;
// Set RDY as input
DDRC = DDRC & B01111111;
// Clear our screen and wait a bit for it to be noticeable as we come online
clearScreen();
delay(1000);
}
/*
* The loop function runs over and over again forever
*/
void loop()
{
sendByte('O');
sendByte('K');
sendByte('-');
}
Those timing issues could also have been caused by our usage of Serial port logs as we found out later Serial usage would corrupt our HID traffic it seems.
PC to Arduino communication using HID over USB
For high speed communication from PC to Arduino we need to use generic HID also known as raw HID.HID is basically the protocol that enables your mice, keyboards and joysticks.
Raw HID is a subset of that same protocol typically used for application specific devices such as our display module for instance.
For Arduino to use raw HID you need to setup that HID-Project library in your IDE.
Go to Sketch > Include Library > Manage Libraries then search and install HID-Project library.
It comes with examples that should get you started.
We were not able to send HID reports larger than 64 bytes. So we need to send multiple reports to push a whole frame to our display.
This 64 bytes limitation was detailed in a GitHub issue.
Other than that the implementation was rather straight forward. You can find details in our GitHub repository, look for .ino files if you are interested in the Arduino source code.
Graphic DMA mode
The above testing were done using the VFD module normal command mode. However for better performance we had to switch to Graphic DMA command mode.DMA mode allows you to tap directly into the display RAM thus gaining access to its frame buffers, on-screen and off-screen ones.
To enable DMA mode you need to toggle the switch number 6 on the DIP of the PCB. That DIP features below in the bottom left corner of that picture.
Conclusion
We were able to squeeze a stable 30 FPS driving that Noritake GU256x64D-3900 from our PC over an Arduino Micro.It's two to three times as fast as devices like the Futaba GP1212A0x and their built-in USB interface.
We are confident performance could be improved further. Given enough time and resources it would be interesting to see how the Arduino raw HID stack could be improved.
Alternatively the Arduino Micro could be replaced by a Teensy 3.2 to see if that boosts performance.
One issue remains, when running sustained high frame rate, we noticed rare occurrence single pixel noise similar to what was caused by using Arduino Serial.write() as explained above.
We are pretty sure this is caused by some Arduino core library somehow. It would be nice to fix but is not a show stopper.
We will most certainly deploy that solution in a production environment at some point to see how stable it is.
References
- Proper HID library for Arduino.
- Article about Arduino ports registers.
- Optimise Arduino power usage.
- Arduino Port Manipulation.
- Noritake Dot Matrix Graphic Displays.
Last edited: