Today I earned the dot flipper badge, and a milestone in this project has been reached. Those few weeks of hard work, figuring all out, selecting components, designing a PCB and coding a simple firmware finally paid off !
Below is my very first dot flipped, and you cannot imagine how excited I was when I heard the clicking sound after plugging in the power supply. More tests shown below.
I kept the code as simple as possible :
- Define the outputs (setup)
- Load coordinates of the dot to flip into the rows and columns shift registers (load_single_dot function)
- Send the pulse (flip function)
- Toggle modes between SET and RESET
- Repeat every 2 seconds
#include <Arduino.h>
#include <SPI.h> // Using SPI is faster than bit-banging in that case
// SPI pins for sending data into shift registers
#define SPI_SPEED 8000000 // 8 Mhz
#define PIN_CS_ROW 22
#define PIN_CS_COL 21
#define PIN_RST_ROW 2
#define PIN_RST_COL 0
// Pins used for flipping dots
#define PIN_SET_RESET 4
#define PIN_PULSE 15
// Fixed parameters
#define PULSE_LENGTH_US 200 // May be adjusted according to voltage used
#define SET 1 // HIGH
#define RESET 0 // LOW
void clear_registers() {
// Resets shift registers
digitalWrite(PIN_RST_ROW, LOW);
digitalWrite(PIN_RST_COL, LOW);
delayMicroseconds(1);
digitalWrite(PIN_RST_ROW, HIGH);
digitalWrite(PIN_RST_COL, HIGH);
}
void load_single_dot(uint8_t x, uint8_t y){
// Clear shift register data
clear_registers();
// Initialise SPI communication
SPI.beginTransaction(SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0));
// Transmit coordinate x and y coordinates to shift registers :
// Slave Select Columns shift registers
digitalWrite (PIN_CS_COL, LOW);
SPI.transfer(1 << (x%8));
for(int i=0; i<(x/8); i++){
// Insert 8 blank bits 'spacers' if x>=8
SPI.transfer(0x00);
}
digitalWrite (PIN_CS_COL, HIGH);
// Slave Select Rows shift registers
digitalWrite (PIN_CS_ROW, LOW);
// 16 rows, so let's send all 16 bits at once, it's overall faster.
SPI.transfer16(1 << y);
digitalWrite (PIN_CS_ROW, HIGH);
// End SPI
SPI.endTransaction();
}
void flip(bool dir) {
// SET or RESET mode
digitalWrite(PIN_SET_RESET, dir);
delayMicroseconds(1);
// Send pulse
digitalWrite(PIN_PULSE, HIGH);
delayMicroseconds(PULSE_LENGTH_US);
digitalWrite(PIN_PULSE, LOW);
}
void setup() {
// Defining outputs
pinMode(PIN_CS_ROW, OUTPUT);
pinMode(PIN_CS_COL, OUTPUT);
pinMode(PIN_RST_ROW, OUTPUT);
pinMode(PIN_RST_COL, OUTPUT);
pinMode(PIN_SET_RESET, OUTPUT);
pinMode(PIN_PULSE, OUTPUT);
// Initial outputs state
digitalWrite(PIN_SET_RESET, LOW);
digitalWrite(PIN_PULSE, LOW);
// Clear Shift Registers
clear_registers();
SPI.begin();
}
void loop() {
// Load (x,y) coordinates of dot to flip
load_single_dot(0, 0);
flip(SET); // YELLOW
delay(2000);
flip(RESET); // BLACK
delay(2000);
}
I eyeballed the pulse length to 200us for a start, thinking I would have to increase it to a higher value, but it seems to work perfectly and I might even be able to reduce it a touch. It would increase the overall frame rate, as waiting for the pulses to complete is the most time consuming task of the process (loading the shift registers takes on average 20us per dot).
Anyway, here is what I got flipping each dot every 200ms, and finally at full speed without any delay.
I’m quite impressed, knowing this is only the very first tests and a lot of optimisation is possible ! Stay tuned, while I hypnotise myself looking at it.
BONUS VIDEOS :
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
WoW... great work Fred!
Great to see what you have achieved with the Annax flip-dot modules....
Are you sure? yes | no
That's so awesome !!!
Congrats !!!
Are you sure? yes | no