Skip to content

Instantly share code, notes, and snippets.

@powerswitch
Last active May 2, 2024 22:50
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save powerswitch/79e91f8f2d5f311f0734438726b63486 to your computer and use it in GitHub Desktop.
Save powerswitch/79e91f8f2d5f311f0734438726b63486 to your computer and use it in GitHub Desktop.
Arduino code for ET6202 LED driver chip
// 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);
}
@jenom1957
Copy link

I have a 5 digit , common anode 7 segment display and the Arduino Uno board
to be able to compile , I needed to disable line 18, because it gave me an error

sketch_may16a.ino: In function 'void setup()':
sketch_may16a.ino:18:11: error: 'led' was not declared in this scope
'led' was not declared in this scope

//pinMode(led, OUTPUT); // sets the digital pin as output

now the sketch runs, showing some-kind-of counter, with random character outputs on display

Question 1: Is this made for a common anode or common cathode display ?
Question 2: If made for common cathode display, how I can modify it for common anode ?
Question 3: Is this just an example or it supposed to do something else? (display analog input?)

Thanks!

@powerswitch
Copy link
Author

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!

@jenom1957
Copy link

Thanks for the info, The published data sheet for the chineese ETEK ET6202 chip shows wrong pinout, either by mistake or by purpose.
The correct pin out on the chip for the segments are: #13 A, #12 B, #11 C, #10 D, #9 E, #8 F, #20 G
(Display segment "A" is on top, and going clockwise)
I removed the original DVD display from board, and wired to a common cathode, 4 digit, 7 segment display.
Since this is an old & uncommon driver chip, google search found only 2 sketches, unfortunately both are above my understanding.
Would you be able to put more comments into your script as an explanation or perhaps make something new with simpler code.
Thanks!

@sidtronics
Copy link

Sending a byte could have been easier with shiftOut() right?

@powerswitch
Copy link
Author

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

Copy link

ghost commented Aug 31, 2021

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.

@powerswitch
Copy link
Author

Found the old board again, will tweak the gist a bit and then upload it again :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment