I purchased a IV-18 VFD tube driver module, which came with some example code for an ESP32 board. The driver module has a 20 output MAX6921 serial chip to drive the vacuum tube. I want to use this driver module with an Arduino Uno and then eventually a Raspberry Pi.

I think I have a very rough understanding of the electronics and demo code, but cannot seem to get my SPI calls to work. Rather than trying to translate the demo code in its entirety, my first goal is to just get one segment to light up.

Quick background

The IV18 tube has 9 grids. The first grid has only a dot and a dash, but the remaining 8 grid have 7 segments and a decimal point.

IV-18 Tube

To light a segment, you provide power to the segment pins / decimal point and to the grid for that segment. To display several numbers, you have to quickly cycle through lighting each of the grid positions and the relevant segments for that position. If you cycle through this fast enough, the human eye sees the whole grid with numbers (persistence of vision).

What I have tried

So far, I have made the connections from the Arduino Uno to the driver board

Driver GND   - Uno GND
Driver 5V    - Uno +5V
Driver Din   - Uno digital pin 11 / MOSI
Driver CLK   - Uno digital pin 13 / SCK
Driver LOAD  - Uno digital pin 2
Driver BLANK - Uno digital pin 3
Driver Dout  - Not connected

The example code has hex codes which I believe are then translated to a 24 bit buffer (although only 17 bits are required) to send via SPI to set the MAX6921 outputs HIGH or LOW.

I think the bits required are as follows:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

So to light the number 8 in the righthand most grid, I assumed I'd need the 8th bit high (grid) and bits 9,10,11,12,13,14 and 15 for the 7 semens for the "8".

In my setup function, I call SPI.begin and then SPI.transfer with what I assumed was the matching binary data (from right to left, I think because of the bit order LSB/MSB?):


This lights the first grid (the one after the degree and minus sign) but not what I want - I see some segments in the leftmost grid (the full grid, not the grid with the dot and minus) but these light in a different pattern each time (varies each time I reset or re-upload which I think is to be expected as I'm pushing data to the MAX6921 each time).

This is my code so far

#include "SPI.h"

#define DISP_CLK 13   // White - SPI SCK
#define DISP_DATA 11  // Yellow - SPI MOSI
#define DISP_LOAD 2   // Blue
#define DISP_BLANK 3  // Green

void setup() {
  Serial.println("IV18 Test");


  digitalWrite(DISP_BLANK, LOW);
  digitalWrite(DISP_LOAD, HIGH);


void loop() {


I'm pretty sure the two fundamental things I have wrong here are the bits of data to send and then the correct use of the SPI.

Can someone please help me to understand the ESP32 code properly, and ideally help me get the correct data to send via SPI so that I can light up the segments & grid positions that I expect to.

  • SPI.transfer() does only serve the clock and write/read MOSI/MISO. It does not bring the CS low to select the SPI slave. – Sim Son May 2 at 19:50

So it turns out that I got a few things wrong.

UPDATE: Working code is now on my GitHub if anyone is interested.

Firstly, I misunderstood the example code and made a mess of the bits to send to the MAX6921. To work out the correct mapping, I went and probed each pin of the IV-18 and noted the connection to the pins / outputs of the MAX6921 which gave me this table:

BIT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
IV-18 G9 G8 G7 G6 G5 G4 G3 G2 G1 A B C D E F G DP
MAX6921 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Note that the MAX6921 value is the OUTPUT number and not the PIN number

This then gave me the correct order for each bit to send, as noted in the top row of the table.

The next mistake was trying to send all 24 bits in one go. Instead, I broke each byte into a separate SPI.transfer() call which finally let me display the segments in the grid position that I expected.

For example, to display "HELLO", my loop function has this:

void loop() {
  //             XXXXXXXDP                 GFEDCBA1                  23456789
  SPI.transfer(0b00000000); SPI.transfer(0b11101100); SPI.transfer(0b10000000); delay(1);
  SPI.transfer(0b00000000); SPI.transfer(0b11110010); SPI.transfer(0b01000000); delay(1);
  SPI.transfer(0b00000000); SPI.transfer(0b01110000); SPI.transfer(0b00100000); delay(1);
  SPI.transfer(0b00000000); SPI.transfer(0b01110000); SPI.transfer(0b00010000); delay(1);
  SPI.transfer(0b00000001); SPI.transfer(0b01111110); SPI.transfer(0b00001000); delay(1);

IV-18 with hello message

I have setup TIMER1 to use instead of the loop/delay code, so hopefully I can finish converting the rest of the example code to Arduino.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.