Jump to content

LED Panel 30x7

From base48
Revision as of 00:21, 29 October 2026 by Buger (talk | contribs)


What is this about

This project is about to make these LED panels working. We got them for free including power supplies and some cables, however the communication protocol is unknown.

To be able to use them we need to find out the protocol, or make our own firmware.

Hack the protocol!

The device is equipped with pair of XLR connectors connected in parallel suggesting use of DMX or RS485 protocol with daisy-chaining in mind, also the vendor (https://www.srs-group.com) is making a lot of DMX stuff, however I tried to send it DMX data on all 512 channels but no luck. I also tried to send it RS485 data in various formats, baudrates, etc - nothing worked.

I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).

So I deciced to go "my firmware" way...

Make our own firmware

To be able to make our own firmware we need to know how this works - so I spent couple of hours reverse engineering the control board so we have the schematic

LED & driver layout
LED & driver layout

Then I used money of the US tax payers (free chatgpt AI) to make the firmware for atmega16 in arduino with the MightyCore atmega16 support. I told him where and how are the shift registers and row decoders connected, his first task was just to display "base48" text... He did it... Then I asked him to add very simple serial protocol that whill wait for device address and then starts to receive graphics data column by column... And that worked too.

After some polishing here is the firmware that:

  • on power up it reads device address from EEPROM address 0
  • shows the device address for 3 seconds on the screen
  • then screen is cleared and it waits for serial data (115200, 8N1)
  • it ignores all data until device address is received
  • after it receives its address, it starts to receive graphics data and resets the column counter
  • because each colum of display consists of 7 LEDs, I decided that all bytes with 0 in the most significant bit (0x0-0x7F) will represent graphics data (simply each bit corresponds to LED in the column) and all with 1 in this bit (0x80-0xFF) will represent device address
  • therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus
  • after each received graphics byte column counter is incremented
  • therefore if the device address its for example 0x80, you need to send 0x80, 0x7F, 0x7F, ... and 28 more 0x7Fs to make all LEDs on the panel lid up
  • the device ignores all bytes >=0x80 if they are not its device address
  • the device ignores all graphics data if end of display was reached (means all 30 columns received)
#include <SPI.h>
#include <EEPROM.h>

// device address is stored in eeprom on address 0 and should be >=0x80
// to change it run "avrdude -c usbasp -p m16 -U eeprom:w:0x80:m" and replace 0x80 with your address

// graphics data = all bytes from serial < 0x80 (as we have only 7 LEDs)
// when device address is received on serial = start receiving graphics data to display buffer

// =====================================================
// Konfigurace pinů – ATmega16, MightyCore std pipnout
// =====================================================

const uint8_t PIN_LATCH = 21;  // PC5
const uint8_t PIN_OE    = 20;  // PC4
const uint8_t PIN_S0    = 16;  // PC0
const uint8_t PIN_S1    = 17;  // PC1
const uint8_t PIN_S2    = 18;  // PC2
const uint8_t PIN_EN    = 19;  // PC3

const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz

// =====================================================
// Parametry displeje
// =====================================================

const uint8_t WIDTH  = 30;
const uint8_t HEIGHT = 7;

const uint32_t ROW_TIME_US = 1000;

const uint8_t DECODER_ENABLED  = LOW;
const uint8_t DECODER_DISABLED = HIGH;
const uint8_t OUTPUTS_ENABLED  = LOW;
const uint8_t OUTPUTS_DISABLED = HIGH;

// =====================================================
// Sériová komunikace
// =====================================================

const uint32_t SERIAL_BAUD = 115200;

// =====================================================
// Obrazová paměť
//
// buffer[row][column]
// =====================================================

bool buffer[HEIGHT][WIDTH];

// Index následujícího zapisovaného sloupce.
// WIDTH znamená, že je buffer plný.

uint8_t writeColumn = 0;

uint8_t devAddr = 80;
uint32_t startupDisplayTime = 0;
bool startupDisplayActive = true;

// =====================================================
// Font 3x5 pro úvodní zobrazení adresy
// =====================================================

// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.
// Bit 0 = horní pixel.

const uint8_t font3x5[][3] = {
  {0x1F, 0x11, 0x1F}, // 0
  {0x00, 0x1F, 0x00}, // 1
  {0x1D, 0x15, 0x17}, // 2
  {0x15, 0x15, 0x1F}, // 3
  {0x07, 0x04, 0x1F}, // 4
  {0x17, 0x15, 0x1D}, // 5
  {0x1F, 0x15, 0x1D}, // 6
  {0x01, 0x01, 0x1F}, // 7
  {0x1F, 0x15, 0x1F}, // 8
  {0x17, 0x15, 0x1F}, // 9
  {0x1E, 0x05, 0x1E}, // A
  {0x1F, 0x15, 0x0A}, // B
  {0x0E, 0x11, 0x11}, // C
  {0x1F, 0x11, 0x0E}, // D
  {0x1F, 0x15, 0x11}, // E
  {0x1F, 0x05, 0x01}, // F
  {0x14, 0x08, 0x14}  // x
};

// Vymazání obrazového bufferu.
void clearBuffer() {
  memset(buffer, 0, sizeof(buffer));
}

// Vykreslení jednoho znaku 3x5.
void drawChar(uint8_t index, uint8_t x, uint8_t y) {
  for (uint8_t col = 0; col < 3; col++) {
    uint8_t bits = font3x5[index][col];

    for (uint8_t row = 0; row < 5; row++) {
      if (x + col < WIDTH && y + row < HEIGHT) {
        buffer[y + row][x + col] = (bits >> row) & 1;
      }
    }
  }
}

// Zobrazení adresy, například 0x83.
void showDeviceAddress() {
  clearBuffer();

  char text[5];
  snprintf(text, sizeof(text), "%02X", devAddr);

  // Text tvoří 0, x a dvě hexadecimální číslice.
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.
  // Začátek je vypočítán pro vodorovné vycentrování.
  uint8_t x = (WIDTH - 15) / 2;
  uint8_t y = (HEIGHT - 5) / 2;

  drawChar(0, x, y);  // 0
  x += 4;

  drawChar(16, x, y);  // x
  x += 4;

  for (uint8_t i = 0; i < 2; i++) {
    char c = text[i];

    uint8_t index;
    if (c >= '0' && c <= '9') {
      index = c - '0';
    } else {
      index = c - 'A' + 10;
    }

    drawChar(index, x, y);
    x += 4;
  }
}

// =====================================================
// Příjem dat ze sériového portu
// =====================================================

void processSerial() {

  while (Serial.available() > 0) {

    uint8_t data = Serial.read();

    // Bajty s nejvyšším bitem 1 jsou příkazy.
    if (data & 0x80) {

      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.
      if (data == devAddr) {
        writeColumn = 0;
      }

      // Ostatní ignorovat
      continue;
    }

    // Pokud je buffer plný, další data ignorovat.
    if (writeColumn >= WIDTH) {
      continue;
    }

    // Zapsat všech 7 bitů do aktuálního sloupce.
    for (uint8_t row = 0; row < HEIGHT; row++) {

      buffer[row][writeColumn] = (data >> row) & 1;
    }

    // Připravit následující sloupec.
    writeColumn++;
  }
}

// =====================================================
// Výběr řádku přes 74LS138
// =====================================================

void selectRow(uint8_t row) {

  digitalWrite(PIN_S0, (row & 0x01) ? HIGH : LOW);
  digitalWrite(PIN_S1, (row & 0x02) ? HIGH : LOW);
  digitalWrite(PIN_S2, (row & 0x04) ? HIGH : LOW);
}

// =====================================================
// Zápis sloupců do dvou A6276E
// =====================================================

void writeColumns(uint8_t row) {

  uint32_t word = 0;

  for (uint8_t col = 0; col < WIDTH; col++) {

    if (buffer[row][col]) {
      word |= (1UL << col);
    }
  }

  digitalWrite(PIN_LATCH, LOW);

  SPI.transfer((word >> 24) & 0xFF);
  SPI.transfer((word >> 16) & 0xFF);
  SPI.transfer((word >> 8)  & 0xFF);
  SPI.transfer(word & 0xFF);

  digitalWrite(PIN_LATCH, HIGH);
}

// =====================================================
// Multiplexní obsluha displeje
// =====================================================

uint8_t currentRow = 0;
uint32_t lastRowChange = 0;

void refreshDisplay() {

  uint32_t now = micros();

  if ((uint32_t)(now - lastRowChange) < ROW_TIME_US) {
    return;
  }

  lastRowChange = now;

  // 1. Zhasnout výstupy během změny řádku.
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);

  // 2. Zakázat dekodér.
  digitalWrite(PIN_EN, DECODER_DISABLED);

  // 3. Zapsat data pro aktuální řádek.
  writeColumns(currentRow);

  // 4. Vybrat řádek.
  selectRow(currentRow);

  // 5. Povolit řádek.
  digitalWrite(PIN_EN, DECODER_ENABLED);

  // 6. Povolit výstupy LED driverů.
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);

  // 7. Připravit následující řádek.
  currentRow++;

  if (currentRow >= HEIGHT) {
    currentRow = 0;
  }
}

// =====================================================
// Inicializace
// =====================================================

void setup() {
  // Sériová komunikace 115200 baud.
  Serial.begin(SERIAL_BAUD);

  // SPI pro LED drivery.
  SPI.begin();

  SPI.beginTransaction(
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)
  );

  // Konfigurace pinů.
  pinMode(PIN_LATCH, OUTPUT);
  pinMode(PIN_OE, OUTPUT);
  pinMode(PIN_S0, OUTPUT);
  pinMode(PIN_S1, OUTPUT);
  pinMode(PIN_S2, OUTPUT);
  pinMode(PIN_EN, OUTPUT);

  // Displej při inicializaci zhasnout.
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);
  digitalWrite(PIN_EN, DECODER_DISABLED);
  digitalWrite(PIN_LATCH, HIGH);
  digitalWrite(PIN_S0, LOW);
  digitalWrite(PIN_S1, LOW);
  digitalWrite(PIN_S2, LOW);

  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr
  writeColumn = WIDTH;

  // Okamžitá první obnova displeje.
  currentRow = 0;
  lastRowChange = micros() - ROW_TIME_US;

  // Adresa zarizeni z EEPROM z adresy 0
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude >=0x80

  showDeviceAddress();

  startupDisplayTime = millis();
  startupDisplayActive = true;
}

// =====================================================
// Hlavní smyčka
// =====================================================

void loop() {

  if (!startupDisplayActive) {
    processSerial();
  } else if ((uint32_t)(millis() - startupDisplayTime) >= 3000) {
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data
    startupDisplayActive = false;
    clearBuffer();    
  }

  // obnovovat displej
  refreshDisplay();
}

You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration

Also here is the compiled firmware in .hex (sorry wiki does not let me to upload is as file...

100000000C9465000C948D000C948D000C948D0064
100010000C948D000C948D000C948D000C948D002C
100020000C948D000C94A9020C948D000C94770212
100030000C9451020C948D000C948D000C948D0046
100040000C948D000C948D000C948D000C948D00FC
100050000C948D0000000002000000000000000071
100060000504000700000000000000000000000080
100070000000000000003B003800350032000000A6
100080003A0037003400310002020202020202028A
100090000404040404040404030303030303030328
1000A0000101010101010101010204081020408049
1000B0000102040810204080010204081020408042
1000C0000102040810204080FB0411241FBECFE56C
1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3
1000E00002C005900D92AC3AB107D9F722E0ACEA14
1000F000B0E001C01D92AF32B207E1F710E0C5E6F3
10010000D0E004C02197FE010E94E307C436D10766
10011000C9F70E94F3020C9419080C940000CF93C5
10012000DF9323E0829FC001112430E020E070E0E3
10013000635A7E4FF901E80FF91FEC58FF4FC08159
10014000FB01E20FF31F50E040E0D0E0DE01042E9F
1001500002C0B595A7950A94E2F7A170A68F4F5FEC
100160005F4F7E964530510589F72F5F3F4F233013
10017000310501F7DF91CF91089590E0FC01E8553A
10018000FF4F249188579F4FFC018491882399F059
1001900090E0880F991FFC01E258FF4FA591B491A0
1001A000FC01EC58FF4F859194918FB7F894EC9136
1001B000E22BEC938FBF0895AF92BF92CF92DF9264
1001C000EF92FF920F931F93CF93DF936C017B010C
1001D0008B01040F151FEB015E01AE18BF08C0179D
1001E000D10759F06991D601ED91FC910190F08110
1001F000E02DC6010995892B79F7C501DF91CF91D3
100200001F910F91FF90EF90DF90CF90BF90AF9034
100210000895FC01538D448D252F30E0842F90E00C
10022000821B930B541710F0CF96089501970895F1
10023000FC01918D828D981761F0A28DAE0FBF2FBA
10024000B11D5D968C91928D9F5F9F73928F90E010
1002500008958FEF9FEF0895FC01918D828D98177F
1002600031F0828DE80FF11D858D90E008958FEFBC
100270009FEF0895FC01918D228D892F90E0805C85
100280009F4F821B91098F739927089583EB90E00C
100290000E943A0121E0892B09F420E0822F089581
1002A00080E090E0892B29F00E94460181110C9496
1002B00000000895FC01A48DA80FB92FB11DA35A09
1002C000BF4F2C91848D90E001968F739927848F76
1002D000A689B7892C93A089B1898C9182748C935B
1002E000938D848D981306C00288F389E02D808158
1002F0008F7D80830895EF92FF920F931F93CF938A
10030000DF93EC0181E0888F9B8D8C8D981319C051
10031000E889F989808185FF14C09FB7F894EE8938
10032000FF896083E889F9898081827480839FBF17
1003300081E090E0DF91CF911F910F91FF90EF90BE
100340000895F62E0B8D10E00F5F1F4F0F731127CE
10035000E02E8C8D8E110CC00FB607FCFACFE88909
10036000F989808185FFF5CFCE010E945A01F1CF36
10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D
10038000F8940B8FEA89FB8980818062CFCFCF936D
10039000DF93EC01888D8823B9F0AA89BB89E889AD
1003A000F9898C9185FD03C0808186FD0DC00FB653
1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1
1003C000CE010E945A01E9CFDF91CF91089590E0CC
1003D000FC01EC5AFF4F2491FC01E855FF4F34918A
1003E000FC01E857FF4FE491EE23C9F0222339F0D6
1003F0002430F1F0A8F4213011F1223001F1F0E0C5
10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2
10041000EC91611118C030953E233C938FBF089535
10042000253051F0273059F785B58F7D85BDE7CF51
100430008FB58F778FBDE3CF8FB58F7DFBCF83B720
100440008F7D83BFDCCF3E2BE8CF3FB7F894809100
10045000AD009091AE00A091AF00B091B00022B776
1004600008B600FE05C02F3F19F00196A11DB11D71
100470003FBFBA2FA92F982F8827BC01CD01620F4B
10048000711D811D911D42E0660F771F881F991F06
100490004A95D1F708958FB90000779BFECF8FB1B1
1004A00008951F920F920FB60F9211242F933F932E
1004B0004F935F936F937F938F939F93AF93BF936C
1004C000EF93FF9383EB90E00E945A01FF91EF912D
1004D000BF91AF919F918F917F916F915F914F915C
1004E0003F912F910F900FBE0F901F9018951F9264
1004F0000F920FB60F9211242F938F939F93EF9328
10050000FF93E091C300F091C4008081E091C900A5
10051000F091CA0082FD1BC090818091CC008F5F5A
100520008F732091CD00821741F0E091CC00F0E074
10053000ED54FF4F958F8093CC00FF91EF919F91E9
100540008F912F910F900FBE0F901F901895808163
10055000F4CF1F920F920FB60F9211242F933F9357
100560008F939F93AF93BF938091500190915101CE
10057000A0915201B09153013091AC0023E0230FC0
100580002D3768F126E8230F0296A11DB11D209397
10059000AC008093500190935101A0935201B0930D
1005A00053018091AD009091AE00A091AF00B09149
1005B000B0000196A11DB11D8093AD009093AE00D7
1005C000A093AF00B093B000BF91AF919F918F9176
1005D0003F912F910F900FBE0F901F90189501968D
1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F
1005F0000FB6F894DEBF0FBECDBF789483B783608B
1006000083BF83B7886483BF89B7816089BF92E065
100610009EBD8EB581608EBD8FB581608FBD85B565
10062000846085BD85B5806485BD87E886B91AB8C4
10063000E091C300F091C4009083E091BF00F0917D
10064000C0001082E091C100F091C20080E180837F
100650001092CB00E091C700F091C80086E880833B
10066000E091C500F091C600808188698083E091A7
10067000C500F091C60080818F7D80831FB7F894FC
100680008091B100811120C0ECE8F0E08491ECEAA7
10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB
1006A000A591B491EC91E92321F461E084E00E94EA
1006B000E70184E00E94BD006C9A6E9A87E00E9478
1006C000BD0085E00E94BD008091B1008F5F8093E6
1006D000B1001FBF80E58DB981E08EB985E10E9430
1006E000BD0084E10E94BD0080E10E94BD0081E167
1006F0000E94BD0082E10E94BD0083E10E94BD0016
1007000061E084E10E94E70161E083E10E94E7018A
1007100061E085E10E94E70160E080E10E94E7017D
1007200060E081E10E94E70160E082E10E94E70170
100730008EE18093B200109254010E942502685EFF
10074000734081099109609355017093560180931C
1007500057019093580190E080E00E94A4078068C0
1007600080936000EDE5F1E092EDDF011D929A9536
10077000E9F71F928F9387EA90E09F938F931F92E0
1007800085E08F93CE0101969F938F930E94E90796
1007900067E080E00E948F006BE080E10E948F00A4
1007A000998180ED890F0FB6F894DEBF0FBECDBFE3
1007B0008A3010F089EC890F6FE00E948F009A81D7
1007C00080ED890F8A3010F089EC890F63E10E9477
1007D0008F002FB7F8948091500190915101A09112
1007E0005201B09153012FBF8093590190935A0148
1007F000A0935B01B0935C0181E0809361002DE5E3
10080000822E21E0922E3EE1232E412C512C3201EA
10081000439450E0A52E50E0B52E809161008111E7
1008200033C083EB90E00E943A01181619060CF0D1
100830004EC083EB90E00E94180187FF07C09091A3
1008400060009813EECF1092B200EBCF6091B2002F
100850006E3138F7E62FF0E0E35AFE4F30E020E04B
100860009927AC01022E02C0559547950A94E2F7EC
10087000417040832F5F3F4F7E962730310589F7C7
100880006F5F6093B200CDCF2FB7F8948091500185
1008900090915101A0915201B09153012FBF40910D
1008A000590150915A0160915B0170915C01841B68
1008B000950BA60BB70B883B9B40A105B10538F003
1008C00010926100D401E2ED1D92EA95E9F70E94D1
1008D0002502009155011091560120915701309148
1008E00058016B017C01C01AD10AE20AF30A970190
1008F0008601083E13402105310508F46DC0609360
10090000550170935601809357019093580161E00F
1009100084E10E94E70161E083E10E94E7013090F9
100920005401329C9001112490E080E0C12CD12C24
100930007601032D10E0F901E80FF91FE35AFE4F8D
100940005081552371F0B301A201082E04C0440F59
10095000551F661F771F0A94D2F7C42AD52AE62AA4
10096000F72A01968E31910531F760E085E10E940A
10097000E7018F2D0E944B028E2D0E944B028D2D80
100980000E944B028C2D0E944B0261E085E10E9487
10099000E701632D617080E10E94E701B801759560
1009A0006795617081E10E94E7011595079515959E
1009B0000795602F617082E10E94E70160E083E1AA
1009C0000E94E70160E084E10E94E70181E0830D7D
1009D000873070F480935401A114B10409F41DCF41
1009E0000E944601882309F418CF0E94000015CF09
1009F00010925401F1CFE3EBF0E01382128288EE03
100A000093E0A0E0B0E084839583A683B78386E675
100A100090E09183808380E490E09587848729E249
100A200030E0378726872BE230E0318B208B2AE2BB
100A300030E0338B228B958B848B8CE290E0978B0C
100A4000868B118E128E138E148E0895ABE0B0E05B
100A5000ECE2F5E00C94AC077C013B018A01FC015F
100A600017821682838181FFC8C1CE0101965C0185
100A7000F7019381F30193FD859193FF81913F01EC
100A8000882309F453C1853239F493FD859193FF8E
100A900081913F01853229F4B70190E00E94160749
100AA000E7CF912C212C312CFFE1F31538F08B325C
100AB00011F190F4803209F1833229F137FC3CC006
100AC00020ED280F2A3050F536FE20C08AE0989E8F
100AD000200D1124922E06C08D3291F0803371F7D3
100AE000689430F8F30193FD859193FF81913F0164
100AF0008111DACF21C0689431F8689432F8F2CFCE
100B0000689433F8EFCF689434F8ECCFEAE02E9E87
100B1000200D1124222E689435F8E4CF8E3229F46A
100B200036FC04C1689436F8DDCF8C3619F468942D
100B300037F8D8CF8836B1F2982F9F7D95549330EF
100B4000E0F08336A1F18337C1F1833509F063C04A
100B50002801F2E04F0E511CF801C080D180692DB0
100B600070E036FC02C06FEF7FEFC6010E94000705
100B70004C01689437F882010AC00C5F1F4FFFE3F5
100B8000F98388248394912C6501E89437F833FE27
100B90002DC0522C8114910471F5552009F468CFB1
100BA000B70180E290E00E9416075A94F6CFF80150
100BB000808189830E5F1F4FE4CF2801F2E04F0E42
100BC000511CF801C080D180692D70E036FC02C054
100BD0006FEF7FEFC6010E940B074C018201D5CF5A
100BE000B70180E290E00E9416072A9428141904A5
100BF00009F0B0F7CECFF60137FC859137FE819131
100C00006F01B70190E00E94160751105A94F1E06D
100C10008F1A9108BFCF843619F0893609F077C052
100C2000F80137FE6BC060817181828193810C5F16
100C30001F4FF32DFF763F2E97FF09C090958095AB
100C4000709561957F4F8F4F9F4F689437F82AE0DA
100C500030E0A5010E944607C82ECA188C2C432CF0
100C600036FE0CC0E89440F8C91440F434FE05C0C8
100C700032FC03C0F32DFE7E4F2E892C44FE95C01E
100C8000FE01EC0DF11D8081803309F087C0242D19
100C9000297E422E842D8870582E43FC95C040FE3C
100CA0008FC09C2C821418F42C0C922C981844FEA3
100CB00091C0B70180E390E00E94160742FE09C090
100CC00088E790E041FE02C088E590E0B7010E940D
100CD0001607C91408F48AC0CA94D12C9FEFC91A08
100CE000D90ACA0CDB1CF60182916F01B70190E0B2
100CF0000E941607AC14BD04B1F74FCF608171811B
100D0000072E000C880B990B0E5F1F4F92CFD32C30
100D1000E894D4F82AE030E0853739F1232D297F93
100D2000D22E8F3601F148F48835A9F0F70186817B
100D300097812B96E2E10C94C807803749F08837F9
100D4000A9F7D4FE02C06894D2F820E130E00DC0CB
100D50006894D4F8F6CF34FE03C0822F8660D82E74
100D600020E132E002C028E030E0F801D7FE0FC0F9
100D700060817181828193810C5F1F4FA5010E9468
100D80004607C82ECA183D2CE89437F867CF608113
100D9000718190E080E00E5F1F4FF0CF42FC02C0F7
100DA000839478CF8394839475CF842D867809F4C7
100DB00071CFF6CFB70180E290E00E9416078394CE
100DC0008214C0F3512C73CF522C5818821408F49B
100DD0006ECFF8CF842D867809F47BCF8BE241FE6D
100DE00080E247FC8DE2B70190E071CFB70180E36C
100DF00090E00E9416079A946CCF8FEF9FEF99CFE7
100E0000FC010590615070400110D8F780959095D5
100E10008E0F9F1F0895FC016150704001900110DA
100E2000D8F7809590958E0F9F1F08950F931F936D
100E3000CF93DF93182F092FEB018B8181FD09C020
100E40001FEF0FEF812F902FDF91CF911F910F9107
100E5000089582FF14C02E813F818C819D812817C7
100E600039073CF4E881F981CF01019699838883A1
100E700010838E819F8101969F838E83E3CFE885C7
100E8000F985812F0995892BA1F3DACFFA01AA27D9
100E9000283051F1203181F1E8946F936E7F6E5FBD
100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B
100EB000670F781F891F9A1FA11D680F791F8A1F4E
100EC000911DA11D6A0F711D811D911DA11D20D0B5
100ED00009F468943F912AE0269F11243019305D6F
100EE0003193DEF6CF010895462F4770405D419360
100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD
100F000018F0495D31FD4052419302D0A9F7EACF74
100F1000B4E0A6959795879577956795BA95C9F7A3
100F200000976105710508959B01AC010A2E069496
100F30005795479537952795BA95C9F7620F731F4F
100F4000841F951FA01D0895E199FECF9FBB8EBB06
100F5000E09A99278DB308952F923F924F925F9216
100F60006F927F928F929F92AF92BF92CF92DF92B9
100F7000EF92FF920F931F93CF93DF93CDB7DEB71E
100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2
100F90002A88398848885F846E847D848C849B8409
100FA000AA84B984C884DF80EE80FD800C811B8117
100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46
100FC000CDBFED010895EE0FFF1F0590F491E02DC8
100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB
100FE0001E898F89988D26E02C831A83098397FFA9
100FF00002C080E090E801979E838D83AE01455E3C
101000005F4F698D7A8DCE0101960E9426054D8134
101010005E8157FD0AC02F813885421753070CF4B3
101020009A01020F131FF80110822E96E4E00C942F
06103000D607F894FFCF83
101036005001000000007B01DC000901C7013A01F4
1010460018012C011F111F001F001D151715151F54
1010560007041F17151D1F151D01011F1F151F173B
10106600151F1E051E1F150A0E11111F110E1F1525
0C107600111F0501140814253032580029
00000001FF


Flash the FW into the panel

You need programmer able to program atmega16 MCUs in DIP40 packages, luckily there is ISP header on the control borad, so I used cheap USBasp to do that.

!!! THE ISP HEADER USE NON-STANDARD PINOUT - DO NOT PLUG STANDARD USBASP CABLE, YOU NEED TO PIN THESE ACCORDING TO SCHEMATIC OTHERWISE USBASP POWER WILL BE SHORTED !!!

  • install avrdude
  • connect USBasp and panel power supply
  • verify that you can communicate with the atmega over USBasp avrdude -c usbasp -p m16 that should say "device signature = 0x1e9403 (probably m16)"
  • erase the locked atmega16 using avrdude -c usbasp -p m16 -e
  • set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m
  • set the device address (needs to be in range 0x80-0xFF) using avrdude -c usbasp -p m16 -U eeprom:w:0x80:m replace 0x80 with desired address
  • write and verify the firmware using avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i
  • done