-
-
Save powerswitch/79e91f8f2d5f311f0734438726b63486 to your computer and use it in GitHub Desktop.
// Connect your ET6202 pins and adapt constants below accordingly | |
const int kPinStb = 4; // Serial interface command mode port | |
const int kPinClk = 3; // Clock input port | |
const int kPinData = 2; // Data input and output port | |
/** | |
* Command (aka Order) to send to the chip. | |
*/ | |
enum Order { | |
eOrderSetDisplayMode = B00000000, // Display mode command set [B00....aa], aa = DisplayMode | |
eOrderSetData = B01000000, // Set the order data [B01..abc.], a = TestMode, b = AutoIncrementAddress, c = ReadKey | |
eOrderSetAddress = B11000000, // Address set up a command [B11..aaaa], aaaa = Address | |
eOrderSetDisplayControl = B10000000, // Display control order [B10..abbb], a = EnableDisplay, bbb = DimmingLevel | |
}; | |
/** | |
* Display mode to set via Order 1 command. | |
*/ | |
enum DisplayMode { | |
eDisplayMode13char4bit = B00000000, // 13 paragraph x 4 bits | |
eDisplayMode12char5bit = B00000001, // 12 paragraph x 5 bits | |
eDisplayMode11char6bit = B00000010, // 11 paragraph x 6 bits | |
eDisplayMode10char7bit = B00000011, // 10 paragraph x 7 bits | |
}; | |
const byte imageLen = 14; | |
byte image[imageLen]; // stores the current state of the display | |
/** | |
* Send a byte via SPI interface. | |
* | |
* @param data: byte to send. | |
*/ | |
void send_data(byte data) | |
{ | |
shiftOut(kPinData, kPinClk, LSBFIRST, data); | |
} | |
/** | |
* Set display mode (Order 1). | |
* | |
* @param mode: DisplayMode to set | |
*/ | |
void set_display_mode(DisplayMode mode) | |
{ | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetDisplayMode | mode); | |
digitalWrite(kPinStb, HIGH); | |
} | |
/** | |
* Set data flags (Order 2). | |
* | |
* @param testmode: enable test mode | |
* @param autoincrement: enable auto address increment | |
* @param readmode: enable reading the key scan data | |
*/ | |
void set_data_flags(bool testmode, bool autoincrement, bool readmode) | |
{ | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetData | (B00001000 * testmode) | (B00000100 * autoincrement) | (B00000010 * readmode)); | |
digitalWrite(kPinStb, HIGH); | |
} | |
/** | |
* Set address (Order 3). | |
* | |
* @param address: address to set (0x00 .. 0x0D, default 0x00). | |
* | |
* @hint: address will change automatically when autoincrement was set in set_data_order command. | |
*/ | |
void set_address(byte address) | |
{ | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetAddress | (B00001111 & address)); | |
digitalWrite(kPinStb, HIGH); | |
} | |
/** | |
* Send byte at address. | |
* | |
* @param address: address to set (0x00 .. 0x0D, default 0x00). | |
* @param data: byte to send. | |
*/ | |
void send_at_address(byte address, byte data) | |
{ | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetAddress | (B00001111 & address)); | |
send_data(data); | |
digitalWrite(kPinStb, HIGH); | |
} | |
/** | |
* Send byte array at address. | |
* | |
* @param address: address to set (0x00 .. 0x0D, default 0x00). | |
* @param data: array of bytes to send. | |
* @param len: length of array. | |
*/ | |
void send_array_at_address(byte address, byte *data, byte len) | |
{ | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetAddress | (B00001111 & address)); | |
for (byte i = 0; i < len; i++) | |
{ | |
send_data(data[i]); | |
} | |
digitalWrite(kPinStb, HIGH); | |
} | |
/** | |
* Set display control flags (Order 4). | |
* | |
* @param enable: enable display | |
* @param brightness: set dimmer brightness (0x00 .. 0x07) | |
*/ | |
void set_display_control(bool enable, byte brightness) | |
{ | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetDisplayControl | (B00001000 * enable) | (B00001111 & brightness)); | |
digitalWrite(kPinStb, HIGH); | |
} | |
/** | |
* Refresh display of image array. | |
*/ | |
void refresh_display() | |
{ | |
set_display_mode(eDisplayMode10char7bit); | |
set_data_flags(false, false, false); | |
send_array_at_address(0, image, imageLen); | |
set_display_control(true, 7); | |
} | |
/** | |
* Poll key/button memory from chip. | |
*/ | |
byte poll_keys() | |
{ | |
set_display_control(false, 7); | |
digitalWrite(kPinStb, LOW); | |
send_data(eOrderSetData | B00000010); | |
pinMode(kPinData, INPUT); | |
const byte keys = shiftIn(kPinData, kPinClk, LSBFIRST); | |
digitalWrite(kPinStb, HIGH); | |
pinMode(kPinData, OUTPUT); | |
set_display_control(true, 7); | |
return keys; | |
} | |
// the following functions depend on the display configuration and might not match all types | |
/** | |
* Select segments of a seven segment digit. | |
* | |
* @param pos: position of digit | |
* @param a: segment a | |
* @param b: segment b | |
* @param c: segment c | |
* @param d: segment d | |
* @param e: segment e | |
* @param f: segment f | |
* @param g: segment g | |
*/ | |
void show_digit(byte pos, bool a, bool b, bool c, bool d, bool e, bool f, bool g) | |
{ | |
byte add = 0; | |
byte shift = 0; | |
switch (pos) | |
{ | |
case 0: | |
shift = 1; | |
break; | |
case 1: | |
shift = 0; | |
break; | |
case 2: | |
shift = 2; | |
break; | |
case 3: | |
shift = 7; | |
break; | |
case 4: | |
shift = 0; | |
add = 1; | |
break; | |
} | |
if (a) image[12+add] |= 1 << shift; else image[12+add] &= ~(1 << shift); | |
if (b) image[2+add] |= 1 << shift; else image[2+add] &= ~(1 << shift); | |
if (c) image[4+add] |= 1 << shift; else image[4+add] &= ~(1 << shift); | |
if (d) image[6+add] |= 1 << shift; else image[6+add] &= ~(1 << shift); | |
if (e) image[8+add] |= 1 << shift; else image[8+add] &= ~(1 << shift); | |
if (f) image[10+add] |= 1 << shift; else image[10+add] &= ~(1 << shift); | |
if (g) image[add] |= 1 << shift; else image[add] &= ~(1 << shift); | |
} | |
/** | |
* Print a character as a seven segment display image. | |
* | |
* @param c: character to print | |
* @param pos: position to display character on | |
*/ | |
void print_char(char c, byte pos) | |
{ | |
switch (c) | |
{ | |
case '0': | |
case 'D': | |
case 'O': | |
show_digit(pos, true, true, true, true, true, true, false); | |
break; | |
case '1': | |
show_digit(pos, false, false, false, false, true, true, false); | |
break; | |
case '2': | |
show_digit(pos, true, false, true, true, false, true, true); | |
break; | |
case '3': | |
show_digit(pos, true, false, false, true, true, true, true); | |
break; | |
case '4': | |
show_digit(pos, false, true, false, false, true, true, true); | |
break; | |
case '5': | |
show_digit(pos, true, true, false, true, true, false, true); | |
break; | |
case '6': | |
show_digit(pos, true, true, true, true, true, false, true); | |
break; | |
case '7': | |
show_digit(pos, true, false, false, false, true, true, false); | |
break; | |
case '8': | |
case 'B': | |
show_digit(pos, true, true, true, true, true, true, true); | |
break; | |
case '9': | |
case 'g': | |
show_digit(pos, true, true, false, true, true, true, true); | |
break; | |
case 'A': | |
case 'a': | |
show_digit(pos, true, true, true, false, true, true, true); | |
break; | |
case 'b': | |
show_digit(pos, false, true, true, true, true, false, true); | |
break; | |
case 'c': | |
show_digit(pos, false, false, true, true, false, false, true); | |
break; | |
case 'd': | |
show_digit(pos, false, false, true, true, true, true, true); | |
break; | |
case 'e': | |
case 'E': | |
show_digit(pos, true, true, true, true, false, false, true); | |
break; | |
case 'f': | |
case 'F': | |
show_digit(pos, true, true, true, false, false, false, true); | |
break; | |
case 'h': | |
show_digit(pos, false, true, true, false, true, false, true); | |
break; | |
case 'i': | |
show_digit(pos, false, false, true, false, false, false, false); | |
break; | |
case 'j': | |
case 'J': | |
show_digit(pos, false, false, true, true, true, true, false); | |
break; | |
case 'k': | |
show_digit(pos, false, true, true, true, false, false, true); | |
break; | |
case 'l': | |
case 'L': | |
show_digit(pos, false, true, true, true, false, false, false); | |
break; | |
case 'M': | |
case 'N': | |
show_digit(pos, true, true, true, false, true, true, false); | |
break; | |
case 'm': | |
case 'n': | |
show_digit(pos, false, false, true, false, true, false, true); | |
break; | |
case 'o': | |
show_digit(pos, false, false, true, true, true, false, true); | |
break; | |
case 'p': | |
case 'P': | |
show_digit(pos, true, true, true, false, false, true, true); | |
break; | |
case '-': | |
show_digit(pos, false, false, false, false, false, false, true); | |
break; | |
} | |
} | |
/** | |
* Display an integer. | |
*/ | |
void print_int(int number) | |
{ | |
if (number < 0) | |
{ | |
print_char('-', 0); | |
number = -number; | |
} | |
else | |
{ | |
print_char('0'+((number / 10000) % 10), 0); | |
} | |
print_char('0'+((number / 1000) % 10), 1); | |
print_char('0'+((number / 100) % 10), 2); | |
print_char('0'+((number / 10) % 10), 3); | |
print_char('0'+(number % 10), 4); | |
} | |
/** | |
* Display a clock. | |
*/ | |
void print_time(unsigned long t) | |
{ | |
const byte minutes = t % 60; | |
const byte hours = t / 60 % 24; | |
print_char('0'+(minutes % 10), 4); | |
print_char('0'+(minutes / 10), 3); | |
print_char('0'+(hours % 10), 2); | |
print_char('0'+(hours / 10), 1); | |
} | |
void partition(byte pos, bool on) | |
{ | |
byte prefix; | |
switch (pos) | |
{ | |
case 0: | |
prefix = 10; | |
break; | |
case 1: | |
prefix = 2; | |
break; | |
case 2: | |
prefix = 0; | |
break; | |
case 3: | |
prefix = 6; | |
break; | |
case 4: | |
prefix = 4; | |
break; | |
case 5: | |
prefix = 12; | |
break; | |
} | |
if (on) | |
{ | |
image[prefix] |= B00010000; | |
} else { | |
image[prefix] &= B11101111; | |
} | |
} | |
void print_seconds(byte sec) | |
{ | |
partition(0, sec < 30); | |
partition(1, sec > 5 && sec < 35); | |
partition(2, sec > 10 && sec < 40); | |
partition(3, sec > 15 && sec < 45); | |
partition(4, sec > 20 && sec < 50); | |
partition(5, sec > 25 && sec < 55); | |
} | |
/** | |
* Setup routine | |
*/ | |
void setup() { | |
pinMode(kPinStb, OUTPUT); | |
pinMode(kPinClk, OUTPUT); | |
pinMode(kPinData, OUTPUT); | |
digitalWrite(kPinStb, HIGH); | |
digitalWrite(kPinClk, LOW); | |
digitalWrite(kPinData, LOW); | |
delay(200); // Delay 200 ms according to ET6202 manual | |
set_data_flags(false, false, false); | |
set_address(0); | |
set_display_mode(eDisplayMode10char7bit); | |
set_display_control(true, 7); | |
} | |
unsigned long startTime = millis(); | |
unsigned long offset = 0; | |
void loop() { | |
refresh_display(); | |
const byte key = poll_keys(); | |
if (key) | |
{ | |
bool modifier = false; | |
if (key & 0x08) | |
{ | |
modifier = true; | |
// Serial.write("Key 4"); | |
} | |
if (key & 0x01) | |
{ | |
// Serial.write("Key 5"); | |
offset += 1 + modifier * 59; | |
} | |
if (key & 0x02) | |
{ | |
// Serial.write("Key 3"); | |
offset -= 1 + modifier * 59; | |
} | |
if (key & 0x10) | |
{ | |
// Serial.write("Key 2"); | |
startTime = millis(); | |
} | |
delay(200); | |
} | |
unsigned long myTime = ((millis() - startTime) / 1000) / 60; | |
print_time(myTime + offset); | |
print_seconds(((millis() - startTime) / 1000) % 60); | |
} |
Sending a byte could have been easier with shiftOut() right?
Indeed.
I guess I should review this patch, as it seems to gain public interest
Hi @jenom1957, I've used the code above to hack my old DVD player display. It had six 7-segment display (three pairs, separated by a colon) and a spinning-disc symbol (kind of like six pizza pieces). Without any input on the serial port, it should display a digital stop watch. However, as far as I know, the LEDs on my display had a very strange order, so the order on your display might be completely different. I do have the display somewhere down in my basement, but I need some time to dig into that project once again.
Here you can see a video of the code above in action on my board: https://cloud.netzente.de/index.php/s/fEWYRr92zCrPPKk
The code above was not polished, and in retrospective I would change quite a lot. If you want to test around, try:
void loop() { for (byte a = 0; a < 14; a++) { disp[a] = 0; } }
All LEDs should now be off. If you then set them all to
disp[a] = 255
, all LEDs should be turned on. Then you can play around and find what LED is what bit in this array. Have fun!
Hi, is it possible to upload the video again. I am also working on the DVD player 7 segment Dsiplay and would like to see it in more detail on the video, so I can understand it better.
Found the old board again, will tweak the gist a bit and then upload it again :)
Sending a byte could have been easier with shiftOut() right?