<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.base48.cz/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Buger</id>
	<title>base48 - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.base48.cz/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Buger"/>
	<link rel="alternate" type="text/html" href="https://wiki.base48.cz/wiki/Special:Contributions/Buger"/>
	<updated>2026-11-05T07:52:22Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.45.4</generator>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5730</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5730"/>
		<updated>2026-10-29T01:54:14Z</updated>

		<summary type="html">&lt;p&gt;Buger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display  was reached (means all 30 columns received) until it receives its address again&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore https://github.com/MCUdude/Mightycore in your arduino to be able to compile it, and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
* ... the address could be changed using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; in the future without the need of reflashing the main FW again&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
You need RS485 adapter to send data from computer to the module. Alternatively (for testing purposes with short cables) you can use cheap TTL USB-to-Serial adapter connected this way (do NOT use ordinary RS232, will not work):&lt;br /&gt;
* GND from USB-to-Serial to pin 1 on XLR&lt;br /&gt;
* TxD from USB-to-Serial to pin 3 on XLR&lt;br /&gt;
* put two same resistors (about 1k - 5K) in series, connect one end to Vcc+ (from USB-to-Serial), the other to GND, and the middle of them to pin 2 on XLR&lt;br /&gt;
* this way it will work with the differencial bus, but the range (lenght of the cable) and intereference immunity will be significantly reduced&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stay 420, have fun!&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5729</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5729"/>
		<updated>2026-10-29T01:52:09Z</updated>

		<summary type="html">&lt;p&gt;Buger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display  was reached (means all 30 columns received) until it receives its address again&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore https://github.com/MCUdude/Mightycore in your arduino to be able to compile it, and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
* ... the address could be changed using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; in the future without the need of reflashing the main FW again&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
You need RS485 adapter to send data from computer to the module. Alternatively (for testing purposes with short cables) you can use cheap USB-to-Serial adapter connected this way:&lt;br /&gt;
* GND from USB-to-Serial to pin 1 on XLR&lt;br /&gt;
* TxD from USB-to-Serial to pin 3 on XLR&lt;br /&gt;
* put two same resistors (about 1k - 5K) in series, connect one end to Vcc+ (from USB-to-Serial), the other to GND, and the middle of them to pin 2 on XLR&lt;br /&gt;
* this way it will work with the differencial bus, but the range (lenght of the cable) and intereference immunity will be significantly reduced&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stay 420, have fun!&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5728</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5728"/>
		<updated>2026-10-29T01:29:18Z</updated>

		<summary type="html">&lt;p&gt;Buger: added info how to connect serial adapter to be able to send data from computer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display  was reached (means all 30 columns received) until it receives its address again&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
* ... the address could be changed using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; in the future without the need of reflashing the main FW again&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
You need RS485 adapter to send data from computer to the module. Alternatively (for testing purposes with short cables) you can use cheap USB-to-Serial adapter connected this way:&lt;br /&gt;
* GND from USB-to-Serial to pin 1 on XLR&lt;br /&gt;
* TxD from USB-to-Serial to pin 3 on XLR&lt;br /&gt;
* put two same resistors (about 1k - 5K) in series, connect one end to Vcc+ (from USB-to-Serial), the other to GND, and the middle of them to pin 2 on XLR&lt;br /&gt;
* this way it will work with the differencial bus, but the range (lenght of the cable) and intereference immunity will be significantly reduced&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stay 420, have fun!&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5727</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5727"/>
		<updated>2026-10-29T00:55:56Z</updated>

		<summary type="html">&lt;p&gt;Buger: /* Flash the FW into the panel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display  was reached (means all 30 columns received) until it receives its address again&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
* ... the address could be changed using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; in the future without the need of reflashing the main FW again&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stay 420, have fun!&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5726</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5726"/>
		<updated>2026-10-29T00:53:28Z</updated>

		<summary type="html">&lt;p&gt;Buger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display  was reached (means all 30 columns received) until it receives its address again&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stay 420, have fun!&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5725</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5725"/>
		<updated>2026-10-29T00:52:09Z</updated>

		<summary type="html">&lt;p&gt;Buger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display  was reached (means all 30 columns received) until it receives its address again&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5724</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5724"/>
		<updated>2026-10-29T00:50:57Z</updated>

		<summary type="html">&lt;p&gt;Buger: ok, most info there&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display was reached (means all 30 columns received)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload it as file)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
=== This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7.jpg|center|frameless|600x600px|base48 rulezz]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== This example shows simple clock on screen with address 0x80 ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_clock.jpg|center|frameless|600x600px|LED panel 30x7 showing clock]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Here is a simple pong game for two players controlled with keys Q, A, P, L ===&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_pong.jpg|center|frameless|600x600px|pong game on LED panel 30x7]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_pong.jpg&amp;diff=5723</id>
		<title>File:LED panel 30x7 pong.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_pong.jpg&amp;diff=5723"/>
		<updated>2026-10-29T00:47:13Z</updated>

		<summary type="html">&lt;p&gt;Buger: pong on LED panel 30x7&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
pong on LED panel 30x7&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_clock.jpg&amp;diff=5722</id>
		<title>File:LED panel 30x7 clock.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_clock.jpg&amp;diff=5722"/>
		<updated>2026-10-29T00:44:28Z</updated>

		<summary type="html">&lt;p&gt;Buger: clock on 30x7 LED panel&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
clock on 30x7 LED panel&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5721</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5721"/>
		<updated>2026-10-29T00:37:16Z</updated>

		<summary type="html">&lt;p&gt;Buger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display was reached (means all 30 columns received)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload is as file...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example shows simple clock on screen with address 0x80&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is a simple pong game for two players controlled with keys Q, A, P, L...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5720</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5720"/>
		<updated>2026-10-29T00:35:44Z</updated>

		<summary type="html">&lt;p&gt;Buger: first usable version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display was reached (means all 30 columns received)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload is as file...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;hexdump&amp;quot;&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
You need programmer able to program atmega16 MCUs&amp;lt;code&amp;gt; in DIP40 packages, luckily there is ISP header on the control borad, so I used cheap USBasp to do that.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;br /&gt;
&lt;br /&gt;
== Show something on the screen ==&lt;br /&gt;
Here are some bash examples (to be easy to understand) how to display something on the screen.&lt;br /&gt;
&lt;br /&gt;
This example shows the &amp;quot;base48&amp;quot; text on screen with address 0x80:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu: 115200 baud, 8N1&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Odeslat příkaz 0x80 a grafická data.&lt;br /&gt;
# Každý znak má 4 sloupce, mezi znaky je jeden prázdný sloupec.&lt;br /&gt;
# Bit 0 = horní LED, bit 6 = spodní LED.&lt;br /&gt;
&lt;br /&gt;
printf &#039;\x80\x7F\x48\x48\x30\x00\x20\x54\x54\x78\x00\x48\x54\x54\x20\x00\x38\x54\x54\x18\x00\x18\x14\x12\x7F\x00\x36\x49\x49\x36\x00&#039; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example shows simple clock on screen with address 0x80&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Font číslic 3x5&lt;br /&gt;
declare -a FONT=(&lt;br /&gt;
    &amp;quot;111 101 101 101 111&amp;quot;  # 0&lt;br /&gt;
    &amp;quot;010 110 010 010 111&amp;quot;  # 1&lt;br /&gt;
    &amp;quot;111 001 111 100 111&amp;quot;  # 2&lt;br /&gt;
    &amp;quot;111 001 111 001 111&amp;quot;  # 3&lt;br /&gt;
    &amp;quot;101 101 111 001 001&amp;quot;  # 4&lt;br /&gt;
    &amp;quot;111 100 111 001 111&amp;quot;  # 5&lt;br /&gt;
    &amp;quot;111 100 111 101 111&amp;quot;  # 6&lt;br /&gt;
    &amp;quot;111 001 010 010 010&amp;quot;  # 7&lt;br /&gt;
    &amp;quot;111 101 111 101 111&amp;quot;  # 8&lt;br /&gt;
    &amp;quot;111 101 111 001 111&amp;quot;  # 9&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# Vykreslení číslice do sloupcového bufferu.&lt;br /&gt;
# Číslice má šířku 3 a výšku 5 LED.&lt;br /&gt;
# Začíná na řádku 1, takže je na displeji vystředěná.&lt;br /&gt;
&lt;br /&gt;
draw_digit() {&lt;br /&gt;
    local digit=$1&lt;br /&gt;
    local x=$2&lt;br /&gt;
    local row col bits&lt;br /&gt;
    local -a rows&lt;br /&gt;
&lt;br /&gt;
    read -ra rows &amp;lt;&amp;lt;&amp;lt; &amp;quot;${FONT[$digit]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for ((row = 0; row &amp;lt; 5; row++)); do&lt;br /&gt;
        for ((col = 0; col &amp;lt; 3; col++)); do&lt;br /&gt;
            if [[ ${rows[$row]:$col:1} == 1 ]]; then&lt;br /&gt;
                ((bits = 1 &amp;lt;&amp;lt; (row + 1)))&lt;br /&gt;
                ((columns[x + col] |= bits))&lt;br /&gt;
            fi&lt;br /&gt;
        done&lt;br /&gt;
    done&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Nekonečná smyčka hodin&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # Získat aktuální čas počítače&lt;br /&gt;
    time=$(date &#039;+%H%M%S&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Vymazat obrazový buffer&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        columns[i]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Rozložení HH:MM:SS&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:0:1}&amp;quot; 2&lt;br /&gt;
    draw_digit &amp;quot;${time:1:1}&amp;quot; 6&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[10] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:2:1}&amp;quot; 12&lt;br /&gt;
    draw_digit &amp;quot;${time:3:1}&amp;quot; 16&lt;br /&gt;
&lt;br /&gt;
    # Dvojtečka&lt;br /&gt;
    ((columns[20] |= 0x14))&lt;br /&gt;
&lt;br /&gt;
    draw_digit &amp;quot;${time:4:1}&amp;quot; 22&lt;br /&gt;
    draw_digit &amp;quot;${time:5:1}&amp;quot; 26&lt;br /&gt;
    # Sestavit příkaz 0x83 a všech 30 sloupců.&lt;br /&gt;
    # Data jsou zatím reprezentována jako escape sekvence,&lt;br /&gt;
    # aby fungovaly i bajty s hodnotou 0x00.&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((i = 0; i &amp;lt; 30; i++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[i]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Odeslat celý obraz jedním printf&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # Aktualizace přibližně jednou za sekundu&lt;br /&gt;
    sleep 1&lt;br /&gt;
&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is a simple pong game for two players controlled with keys Q, A, P, L...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
PORT=&amp;quot;/dev/ttyUSB0&amp;quot;&lt;br /&gt;
WIDTH=30&lt;br /&gt;
HEIGHT=7&lt;br /&gt;
DELAY=0.05&lt;br /&gt;
&lt;br /&gt;
# Nastavení sériového portu&lt;br /&gt;
stty -F &amp;quot;$PORT&amp;quot; 115200 cs8 -cstopb -parenb raw -echo&lt;br /&gt;
&lt;br /&gt;
# Uložení nastavení terminálu a povolení čtení kláves bez Enteru&lt;br /&gt;
OLD_STTY=$(stty -g) || exit 1&lt;br /&gt;
restore_terminal() {&lt;br /&gt;
    stty &amp;quot;$OLD_STTY&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
trap restore_terminal EXIT INT TERM&lt;br /&gt;
&lt;br /&gt;
stty -echo -icanon min 0 time 0&lt;br /&gt;
&lt;br /&gt;
# Počáteční pozice pálek&lt;br /&gt;
left_paddle=3&lt;br /&gt;
right_paddle=3&lt;br /&gt;
&lt;br /&gt;
# Inicializace hry&lt;br /&gt;
new_game() {&lt;br /&gt;
    ball_x=15&lt;br /&gt;
    ball_y=3&lt;br /&gt;
&lt;br /&gt;
    # Náhodný směr míčku&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vx=1&lt;br /&gt;
    else&lt;br /&gt;
        vx=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Náhodný vertikální směr&lt;br /&gt;
    if ((RANDOM % 2)); then&lt;br /&gt;
        vy=1&lt;br /&gt;
    else&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new_game&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Čtení kláves&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    while IFS= read -r -s -n 1 -t 0.001 key; do&lt;br /&gt;
        case &amp;quot;$key&amp;quot; in&lt;br /&gt;
            q|Q)&lt;br /&gt;
                ((left_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((left_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            a|A)&lt;br /&gt;
                ((left_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((left_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            p|P)&lt;br /&gt;
                ((right_paddle &amp;gt; 1)) &amp;amp;&amp;amp; ((right_paddle--))&lt;br /&gt;
                ;;&lt;br /&gt;
            l|L)&lt;br /&gt;
                ((right_paddle &amp;lt; HEIGHT - 2)) &amp;amp;&amp;amp; ((right_paddle++))&lt;br /&gt;
                ;;&lt;br /&gt;
            $&#039;\003&#039;)&lt;br /&gt;
                exit 0&lt;br /&gt;
                ;;&lt;br /&gt;
        esac&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Výpočet nové pozice míčku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    next_x=$((ball_x + vx))&lt;br /&gt;
    next_y=$((ball_y + vy))&lt;br /&gt;
&lt;br /&gt;
    # Odraz od horní a dolní hrany&lt;br /&gt;
    if ((next_y &amp;lt; 0)); then&lt;br /&gt;
        next_y=1&lt;br /&gt;
        vy=1&lt;br /&gt;
    elif ((next_y &amp;gt;= HEIGHT)); then&lt;br /&gt;
        next_y=$((HEIGHT - 2))&lt;br /&gt;
        vy=-1&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;lt; 0 &amp;amp;&amp;amp; next_x &amp;lt;= 0)); then&lt;br /&gt;
        if ((next_y &amp;gt;= left_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= left_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl levou pálku&lt;br /&gt;
            next_x=1&lt;br /&gt;
            vx=1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; left_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; left_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                # Zásah doprostřed: náhodný vertikální směr&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí levé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    if ((vx &amp;gt; 0 &amp;amp;&amp;amp; next_x &amp;gt;= WIDTH - 1)); then&lt;br /&gt;
        if ((next_y &amp;gt;= right_paddle - 1 &amp;amp;&amp;amp;&lt;br /&gt;
             next_y &amp;lt;= right_paddle + 1)); then&lt;br /&gt;
&lt;br /&gt;
            # Míček zasáhl pravou pálku&lt;br /&gt;
            next_x=$((WIDTH - 2))&lt;br /&gt;
            vx=-1&lt;br /&gt;
&lt;br /&gt;
            if ((next_y &amp;lt; right_paddle)); then&lt;br /&gt;
                vy=-1&lt;br /&gt;
            elif ((next_y &amp;gt; right_paddle)); then&lt;br /&gt;
                vy=1&lt;br /&gt;
            else&lt;br /&gt;
                if ((RANDOM % 2)); then&lt;br /&gt;
                    vy=1&lt;br /&gt;
                else&lt;br /&gt;
                    vy=-1&lt;br /&gt;
                fi&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            # Minutí pravé pálky: okamžitý restart&lt;br /&gt;
            new_game&lt;br /&gt;
            continue&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    # Uložení pozice míčku&lt;br /&gt;
    ball_x=$next_x&lt;br /&gt;
    ball_y=$next_y&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Vykreslení snímku&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        columns[x]=0&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Levá pálka&lt;br /&gt;
    for ((y = left_paddle - 1; y &amp;lt;= left_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[0] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Pravá pálka&lt;br /&gt;
    for ((y = right_paddle - 1; y &amp;lt;= right_paddle + 1; y++)); do&lt;br /&gt;
        ((columns[WIDTH - 1] |= 1 &amp;lt;&amp;lt; y))&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    # Míček&lt;br /&gt;
    ((columns[ball_x] |= 1 &amp;lt;&amp;lt; ball_y))&lt;br /&gt;
&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
    # Odeslání snímku displeji&lt;br /&gt;
    # ---------------------------------------&lt;br /&gt;
&lt;br /&gt;
    payload=&#039;\x80&#039;&lt;br /&gt;
&lt;br /&gt;
    for ((x = 0; x &amp;lt; WIDTH; x++)); do&lt;br /&gt;
        printf -v byte &#039;\\x%02X&#039; &amp;quot;${columns[x]}&amp;quot;&lt;br /&gt;
        payload+=&amp;quot;$byte&amp;quot;&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    printf &#039;%b&#039; &amp;quot;$payload&amp;quot; &amp;gt; &amp;quot;$PORT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    sleep &amp;quot;$DELAY&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5719</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5719"/>
		<updated>2026-10-29T00:21:57Z</updated>

		<summary type="html">&lt;p&gt;Buger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display was reached (means all 30 columns received)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You need MightyCore in your arduino https://github.com/MCUdude/Mightycore and here is the arduino configuration&lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_arduino_cfg.png]]&lt;br /&gt;
&lt;br /&gt;
Also here is the compiled firmware in .hex (sorry wiki does not let me to upload is as file...&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
:100000000C9465000C948D000C948D000C948D0064&lt;br /&gt;
:100010000C948D000C948D000C948D000C948D002C&lt;br /&gt;
:100020000C948D000C94A9020C948D000C94770212&lt;br /&gt;
:100030000C9451020C948D000C948D000C948D0046&lt;br /&gt;
:100040000C948D000C948D000C948D000C948D00FC&lt;br /&gt;
:100050000C948D0000000002000000000000000071&lt;br /&gt;
:100060000504000700000000000000000000000080&lt;br /&gt;
:100070000000000000003B003800350032000000A6&lt;br /&gt;
:100080003A0037003400310002020202020202028A&lt;br /&gt;
:100090000404040404040404030303030303030328&lt;br /&gt;
:1000A0000101010101010101010204081020408049&lt;br /&gt;
:1000B0000102040810204080010204081020408042&lt;br /&gt;
:1000C0000102040810204080FB0411241FBECFE56C&lt;br /&gt;
:1000D000D4E0DEBFCDBF10E0A0E6B0E0E6E3F0E1A3&lt;br /&gt;
:1000E00002C005900D92AC3AB107D9F722E0ACEA14&lt;br /&gt;
:1000F000B0E001C01D92AF32B207E1F710E0C5E6F3&lt;br /&gt;
:10010000D0E004C02197FE010E94E307C436D10766&lt;br /&gt;
:10011000C9F70E94F3020C9419080C940000CF93C5&lt;br /&gt;
:10012000DF9323E0829FC001112430E020E070E0E3&lt;br /&gt;
:10013000635A7E4FF901E80FF91FEC58FF4FC08159&lt;br /&gt;
:10014000FB01E20FF31F50E040E0D0E0DE01042E9F&lt;br /&gt;
:1001500002C0B595A7950A94E2F7A170A68F4F5FEC&lt;br /&gt;
:100160005F4F7E964530510589F72F5F3F4F233013&lt;br /&gt;
:10017000310501F7DF91CF91089590E0FC01E8553A&lt;br /&gt;
:10018000FF4F249188579F4FFC018491882399F059&lt;br /&gt;
:1001900090E0880F991FFC01E258FF4FA591B491A0&lt;br /&gt;
:1001A000FC01EC58FF4F859194918FB7F894EC9136&lt;br /&gt;
:1001B000E22BEC938FBF0895AF92BF92CF92DF9264&lt;br /&gt;
:1001C000EF92FF920F931F93CF93DF936C017B010C&lt;br /&gt;
:1001D0008B01040F151FEB015E01AE18BF08C0179D&lt;br /&gt;
:1001E000D10759F06991D601ED91FC910190F08110&lt;br /&gt;
:1001F000E02DC6010995892B79F7C501DF91CF91D3&lt;br /&gt;
:100200001F910F91FF90EF90DF90CF90BF90AF9034&lt;br /&gt;
:100210000895FC01538D448D252F30E0842F90E00C&lt;br /&gt;
:10022000821B930B541710F0CF96089501970895F1&lt;br /&gt;
:10023000FC01918D828D981761F0A28DAE0FBF2FBA&lt;br /&gt;
:10024000B11D5D968C91928D9F5F9F73928F90E010&lt;br /&gt;
:1002500008958FEF9FEF0895FC01918D828D98177F&lt;br /&gt;
:1002600031F0828DE80FF11D858D90E008958FEFBC&lt;br /&gt;
:100270009FEF0895FC01918D228D892F90E0805C85&lt;br /&gt;
:100280009F4F821B91098F739927089583EB90E00C&lt;br /&gt;
:100290000E943A0121E0892B09F420E0822F089581&lt;br /&gt;
:1002A00080E090E0892B29F00E94460181110C9496&lt;br /&gt;
:1002B00000000895FC01A48DA80FB92FB11DA35A09&lt;br /&gt;
:1002C000BF4F2C91848D90E001968F739927848F76&lt;br /&gt;
:1002D000A689B7892C93A089B1898C9182748C935B&lt;br /&gt;
:1002E000938D848D981306C00288F389E02D808158&lt;br /&gt;
:1002F0008F7D80830895EF92FF920F931F93CF938A&lt;br /&gt;
:10030000DF93EC0181E0888F9B8D8C8D981319C051&lt;br /&gt;
:10031000E889F989808185FF14C09FB7F894EE8938&lt;br /&gt;
:10032000FF896083E889F9898081827480839FBF17&lt;br /&gt;
:1003300081E090E0DF91CF911F910F91FF90EF90BE&lt;br /&gt;
:100340000895F62E0B8D10E00F5F1F4F0F731127CE&lt;br /&gt;
:10035000E02E8C8D8E110CC00FB607FCFACFE88909&lt;br /&gt;
:10036000F989808185FFF5CFCE010E945A01F1CF36&lt;br /&gt;
:10037000EB8DEC0FFD2FF11DE35AFF4FF0829FB77D&lt;br /&gt;
:10038000F8940B8FEA89FB8980818062CFCFCF936D&lt;br /&gt;
:10039000DF93EC01888D8823B9F0AA89BB89E889AD&lt;br /&gt;
:1003A000F9898C9185FD03C0808186FD0DC00FB653&lt;br /&gt;
:1003B00007FCF7CF8C9185FFF2CF808185FFEDCFD1&lt;br /&gt;
:1003C000CE010E945A01E9CFDF91CF91089590E0CC&lt;br /&gt;
:1003D000FC01EC5AFF4F2491FC01E855FF4F34918A&lt;br /&gt;
:1003E000FC01E857FF4FE491EE23C9F0222339F0D6&lt;br /&gt;
:1003F0002430F1F0A8F4213011F1223001F1F0E0C5&lt;br /&gt;
:10040000EE0FFF1FEC58FF4FA591B4918FB7F894F2&lt;br /&gt;
:10041000EC91611118C030953E233C938FBF089535&lt;br /&gt;
:10042000253051F0273059F785B58F7D85BDE7CF51&lt;br /&gt;
:100430008FB58F778FBDE3CF8FB58F7DFBCF83B720&lt;br /&gt;
:100440008F7D83BFDCCF3E2BE8CF3FB7F894809100&lt;br /&gt;
:10045000AD009091AE00A091AF00B091B00022B776&lt;br /&gt;
:1004600008B600FE05C02F3F19F00196A11DB11D71&lt;br /&gt;
:100470003FBFBA2FA92F982F8827BC01CD01620F4B&lt;br /&gt;
:10048000711D811D911D42E0660F771F881F991F06&lt;br /&gt;
:100490004A95D1F708958FB90000779BFECF8FB1B1&lt;br /&gt;
:1004A00008951F920F920FB60F9211242F933F932E&lt;br /&gt;
:1004B0004F935F936F937F938F939F93AF93BF936C&lt;br /&gt;
:1004C000EF93FF9383EB90E00E945A01FF91EF912D&lt;br /&gt;
:1004D000BF91AF919F918F917F916F915F914F915C&lt;br /&gt;
:1004E0003F912F910F900FBE0F901F9018951F9264&lt;br /&gt;
:1004F0000F920FB60F9211242F938F939F93EF9328&lt;br /&gt;
:10050000FF93E091C300F091C4008081E091C900A5&lt;br /&gt;
:10051000F091CA0082FD1BC090818091CC008F5F5A&lt;br /&gt;
:100520008F732091CD00821741F0E091CC00F0E074&lt;br /&gt;
:10053000ED54FF4F958F8093CC00FF91EF919F91E9&lt;br /&gt;
:100540008F912F910F900FBE0F901F901895808163&lt;br /&gt;
:10055000F4CF1F920F920FB60F9211242F933F9357&lt;br /&gt;
:100560008F939F93AF93BF938091500190915101CE&lt;br /&gt;
:10057000A0915201B09153013091AC0023E0230FC0&lt;br /&gt;
:100580002D3768F126E8230F0296A11DB11D209397&lt;br /&gt;
:10059000AC008093500190935101A0935201B0930D&lt;br /&gt;
:1005A00053018091AD009091AE00A091AF00B09149&lt;br /&gt;
:1005B000B0000196A11DB11D8093AD009093AE00D7&lt;br /&gt;
:1005C000A093AF00B093B000BF91AF919F918F9176&lt;br /&gt;
:1005D0003F912F910F900FBE0F901F90189501968D&lt;br /&gt;
:1005E000A11DB11DD4CFCF93DF93CDB7DEB729972F&lt;br /&gt;
:1005F0000FB6F894DEBF0FBECDBF789483B783608B&lt;br /&gt;
:1006000083BF83B7886483BF89B7816089BF92E065&lt;br /&gt;
:100610009EBD8EB581608EBD8FB581608FBD85B565&lt;br /&gt;
:10062000846085BD85B5806485BD87E886B91AB8C4&lt;br /&gt;
:10063000E091C300F091C4009083E091BF00F0917D&lt;br /&gt;
:10064000C0001082E091C100F091C20080E180837F&lt;br /&gt;
:100650001092CB00E091C700F091C80086E880833B&lt;br /&gt;
:10066000E091C500F091C600808188698083E091A7&lt;br /&gt;
:10067000C500F091C60080818F7D80831FB7F894FC&lt;br /&gt;
:100680008091B100811120C0ECE8F0E08491ECEAA7&lt;br /&gt;
:10069000F0E09491E82FF0E0EE0FFF1FE258FF4FDB&lt;br /&gt;
:1006A000A591B491EC91E92321F461E084E00E94EA&lt;br /&gt;
:1006B000E70184E00E94BD006C9A6E9A87E00E9478&lt;br /&gt;
:1006C000BD0085E00E94BD008091B1008F5F8093E6&lt;br /&gt;
:1006D000B1001FBF80E58DB981E08EB985E10E9430&lt;br /&gt;
:1006E000BD0084E10E94BD0080E10E94BD0081E167&lt;br /&gt;
:1006F0000E94BD0082E10E94BD0083E10E94BD0016&lt;br /&gt;
:1007000061E084E10E94E70161E083E10E94E7018A&lt;br /&gt;
:1007100061E085E10E94E70160E080E10E94E7017D&lt;br /&gt;
:1007200060E081E10E94E70160E082E10E94E70170&lt;br /&gt;
:100730008EE18093B200109254010E942502685EFF&lt;br /&gt;
:10074000734081099109609355017093560180931C&lt;br /&gt;
:1007500057019093580190E080E00E94A4078068C0&lt;br /&gt;
:1007600080936000EDE5F1E092EDDF011D929A9536&lt;br /&gt;
:10077000E9F71F928F9387EA90E09F938F931F92E0&lt;br /&gt;
:1007800085E08F93CE0101969F938F930E94E90796&lt;br /&gt;
:1007900067E080E00E948F006BE080E10E948F00A4&lt;br /&gt;
:1007A000998180ED890F0FB6F894DEBF0FBECDBFE3&lt;br /&gt;
:1007B0008A3010F089EC890F6FE00E948F009A81D7&lt;br /&gt;
:1007C00080ED890F8A3010F089EC890F63E10E9477&lt;br /&gt;
:1007D0008F002FB7F8948091500190915101A09112&lt;br /&gt;
:1007E0005201B09153012FBF8093590190935A0148&lt;br /&gt;
:1007F000A0935B01B0935C0181E0809361002DE5E3&lt;br /&gt;
:10080000822E21E0922E3EE1232E412C512C3201EA&lt;br /&gt;
:10081000439450E0A52E50E0B52E809161008111E7&lt;br /&gt;
:1008200033C083EB90E00E943A01181619060CF0D1&lt;br /&gt;
:100830004EC083EB90E00E94180187FF07C09091A3&lt;br /&gt;
:1008400060009813EECF1092B200EBCF6091B2002F&lt;br /&gt;
:100850006E3138F7E62FF0E0E35AFE4F30E020E04B&lt;br /&gt;
:100860009927AC01022E02C0559547950A94E2F7EC&lt;br /&gt;
:10087000417040832F5F3F4F7E962730310589F7C7&lt;br /&gt;
:100880006F5F6093B200CDCF2FB7F8948091500185&lt;br /&gt;
:1008900090915101A0915201B09153012FBF40910D&lt;br /&gt;
:1008A000590150915A0160915B0170915C01841B68&lt;br /&gt;
:1008B000950BA60BB70B883B9B40A105B10538F003&lt;br /&gt;
:1008C00010926100D401E2ED1D92EA95E9F70E94D1&lt;br /&gt;
:1008D0002502009155011091560120915701309148&lt;br /&gt;
:1008E00058016B017C01C01AD10AE20AF30A970190&lt;br /&gt;
:1008F0008601083E13402105310508F46DC0609360&lt;br /&gt;
:10090000550170935601809357019093580161E00F&lt;br /&gt;
:1009100084E10E94E70161E083E10E94E7013090F9&lt;br /&gt;
:100920005401329C9001112490E080E0C12CD12C24&lt;br /&gt;
:100930007601032D10E0F901E80FF91FE35AFE4F8D&lt;br /&gt;
:100940005081552371F0B301A201082E04C0440F59&lt;br /&gt;
:10095000551F661F771F0A94D2F7C42AD52AE62AA4&lt;br /&gt;
:10096000F72A01968E31910531F760E085E10E940A&lt;br /&gt;
:10097000E7018F2D0E944B028E2D0E944B028D2D80&lt;br /&gt;
:100980000E944B028C2D0E944B0261E085E10E9487&lt;br /&gt;
:10099000E701632D617080E10E94E701B801759560&lt;br /&gt;
:1009A0006795617081E10E94E7011595079515959E&lt;br /&gt;
:1009B0000795602F617082E10E94E70160E083E1AA&lt;br /&gt;
:1009C0000E94E70160E084E10E94E70181E0830D7D&lt;br /&gt;
:1009D000873070F480935401A114B10409F41DCF41&lt;br /&gt;
:1009E0000E944601882309F418CF0E94000015CF09&lt;br /&gt;
:1009F00010925401F1CFE3EBF0E01382128288EE03&lt;br /&gt;
:100A000093E0A0E0B0E084839583A683B78386E675&lt;br /&gt;
:100A100090E09183808380E490E09587848729E249&lt;br /&gt;
:100A200030E0378726872BE230E0318B208B2AE2BB&lt;br /&gt;
:100A300030E0338B228B958B848B8CE290E0978B0C&lt;br /&gt;
:100A4000868B118E128E138E148E0895ABE0B0E05B&lt;br /&gt;
:100A5000ECE2F5E00C94AC077C013B018A01FC015F&lt;br /&gt;
:100A600017821682838181FFC8C1CE0101965C0185&lt;br /&gt;
:100A7000F7019381F30193FD859193FF81913F01EC&lt;br /&gt;
:100A8000882309F453C1853239F493FD859193FF8E&lt;br /&gt;
:100A900081913F01853229F4B70190E00E94160749&lt;br /&gt;
:100AA000E7CF912C212C312CFFE1F31538F08B325C&lt;br /&gt;
:100AB00011F190F4803209F1833229F137FC3CC006&lt;br /&gt;
:100AC00020ED280F2A3050F536FE20C08AE0989E8F&lt;br /&gt;
:100AD000200D1124922E06C08D3291F0803371F7D3&lt;br /&gt;
:100AE000689430F8F30193FD859193FF81913F0164&lt;br /&gt;
:100AF0008111DACF21C0689431F8689432F8F2CFCE&lt;br /&gt;
:100B0000689433F8EFCF689434F8ECCFEAE02E9E87&lt;br /&gt;
:100B1000200D1124222E689435F8E4CF8E3229F46A&lt;br /&gt;
:100B200036FC04C1689436F8DDCF8C3619F468942D&lt;br /&gt;
:100B300037F8D8CF8836B1F2982F9F7D95549330EF&lt;br /&gt;
:100B4000E0F08336A1F18337C1F1833509F063C04A&lt;br /&gt;
:100B50002801F2E04F0E511CF801C080D180692DB0&lt;br /&gt;
:100B600070E036FC02C06FEF7FEFC6010E94000705&lt;br /&gt;
:100B70004C01689437F882010AC00C5F1F4FFFE3F5&lt;br /&gt;
:100B8000F98388248394912C6501E89437F833FE27&lt;br /&gt;
:100B90002DC0522C8114910471F5552009F468CFB1&lt;br /&gt;
:100BA000B70180E290E00E9416075A94F6CFF80150&lt;br /&gt;
:100BB000808189830E5F1F4FE4CF2801F2E04F0E42&lt;br /&gt;
:100BC000511CF801C080D180692D70E036FC02C054&lt;br /&gt;
:100BD0006FEF7FEFC6010E940B074C018201D5CF5A&lt;br /&gt;
:100BE000B70180E290E00E9416072A9428141904A5&lt;br /&gt;
:100BF00009F0B0F7CECFF60137FC859137FE819131&lt;br /&gt;
:100C00006F01B70190E00E94160751105A94F1E06D&lt;br /&gt;
:100C10008F1A9108BFCF843619F0893609F077C052&lt;br /&gt;
:100C2000F80137FE6BC060817181828193810C5F16&lt;br /&gt;
:100C30001F4FF32DFF763F2E97FF09C090958095AB&lt;br /&gt;
:100C4000709561957F4F8F4F9F4F689437F82AE0DA&lt;br /&gt;
:100C500030E0A5010E944607C82ECA188C2C432CF0&lt;br /&gt;
:100C600036FE0CC0E89440F8C91440F434FE05C0C8&lt;br /&gt;
:100C700032FC03C0F32DFE7E4F2E892C44FE95C01E&lt;br /&gt;
:100C8000FE01EC0DF11D8081803309F087C0242D19&lt;br /&gt;
:100C9000297E422E842D8870582E43FC95C040FE3C&lt;br /&gt;
:100CA0008FC09C2C821418F42C0C922C981844FEA3&lt;br /&gt;
:100CB00091C0B70180E390E00E94160742FE09C090&lt;br /&gt;
:100CC00088E790E041FE02C088E590E0B7010E940D&lt;br /&gt;
:100CD0001607C91408F48AC0CA94D12C9FEFC91A08&lt;br /&gt;
:100CE000D90ACA0CDB1CF60182916F01B70190E0B2&lt;br /&gt;
:100CF0000E941607AC14BD04B1F74FCF608171811B&lt;br /&gt;
:100D0000072E000C880B990B0E5F1F4F92CFD32C30&lt;br /&gt;
:100D1000E894D4F82AE030E0853739F1232D297F93&lt;br /&gt;
:100D2000D22E8F3601F148F48835A9F0F70186817B&lt;br /&gt;
:100D300097812B96E2E10C94C807803749F08837F9&lt;br /&gt;
:100D4000A9F7D4FE02C06894D2F820E130E00DC0CB&lt;br /&gt;
:100D50006894D4F8F6CF34FE03C0822F8660D82E74&lt;br /&gt;
:100D600020E132E002C028E030E0F801D7FE0FC0F9&lt;br /&gt;
:100D700060817181828193810C5F1F4FA5010E9468&lt;br /&gt;
:100D80004607C82ECA183D2CE89437F867CF608113&lt;br /&gt;
:100D9000718190E080E00E5F1F4FF0CF42FC02C0F7&lt;br /&gt;
:100DA000839478CF8394839475CF842D867809F4C7&lt;br /&gt;
:100DB00071CFF6CFB70180E290E00E9416078394CE&lt;br /&gt;
:100DC0008214C0F3512C73CF522C5818821408F49B&lt;br /&gt;
:100DD0006ECFF8CF842D867809F47BCF8BE241FE6D&lt;br /&gt;
:100DE00080E247FC8DE2B70190E071CFB70180E36C&lt;br /&gt;
:100DF00090E00E9416079A946CCF8FEF9FEF99CFE7&lt;br /&gt;
:100E0000FC010590615070400110D8F780959095D5&lt;br /&gt;
:100E10008E0F9F1F0895FC016150704001900110DA&lt;br /&gt;
:100E2000D8F7809590958E0F9F1F08950F931F936D&lt;br /&gt;
:100E3000CF93DF93182F092FEB018B8181FD09C020&lt;br /&gt;
:100E40001FEF0FEF812F902FDF91CF911F910F9107&lt;br /&gt;
:100E5000089582FF14C02E813F818C819D812817C7&lt;br /&gt;
:100E600039073CF4E881F981CF01019699838883A1&lt;br /&gt;
:100E700010838E819F8101969F838E83E3CFE885C7&lt;br /&gt;
:100E8000F985812F0995892BA1F3DACFFA01AA27D9&lt;br /&gt;
:100E9000283051F1203181F1E8946F936E7F6E5FBD&lt;br /&gt;
:100EA0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD06B&lt;br /&gt;
:100EB000670F781F891F9A1FA11D680F791F8A1F4E&lt;br /&gt;
:100EC000911DA11D6A0F711D811D911DA11D20D0B5&lt;br /&gt;
:100ED00009F468943F912AE0269F11243019305D6F&lt;br /&gt;
:100EE0003193DEF6CF010895462F4770405D419360&lt;br /&gt;
:100EF000B3E00FD0C9F7F6CF462F4F70405D4A33AD&lt;br /&gt;
:100F000018F0495D31FD4052419302D0A9F7EACF74&lt;br /&gt;
:100F1000B4E0A6959795879577956795BA95C9F7A3&lt;br /&gt;
:100F200000976105710508959B01AC010A2E069496&lt;br /&gt;
:100F30005795479537952795BA95C9F7620F731F4F&lt;br /&gt;
:100F4000841F951FA01D0895E199FECF9FBB8EBB06&lt;br /&gt;
:100F5000E09A99278DB308952F923F924F925F9216&lt;br /&gt;
:100F60006F927F928F929F92AF92BF92CF92DF92B9&lt;br /&gt;
:100F7000EF92FF920F931F93CF93DF93CDB7DEB71E&lt;br /&gt;
:100F8000CA1BDB0B0FB6F894DEBF0FBECDBF0994B2&lt;br /&gt;
:100F90002A88398848885F846E847D848C849B8409&lt;br /&gt;
:100FA000AA84B984C884DF80EE80FD800C811B8117&lt;br /&gt;
:100FB000AA81B981CE0FD11D0FB6F894DEBF0FBE46&lt;br /&gt;
:100FC000CDBFED010895EE0FFF1F0590F491E02DC8&lt;br /&gt;
:100FD0000994AEE0B0E0EFEEF7E00C94BA070D89AB&lt;br /&gt;
:100FE0001E898F89988D26E02C831A83098397FFA9&lt;br /&gt;
:100FF00002C080E090E801979E838D83AE01455E3C&lt;br /&gt;
:101000005F4F698D7A8DCE0101960E9426054D8134&lt;br /&gt;
:101010005E8157FD0AC02F813885421753070CF4B3&lt;br /&gt;
:101020009A01020F131FF80110822E96E4E00C942F&lt;br /&gt;
:06103000D607F894FFCF83&lt;br /&gt;
:101036005001000000007B01DC000901C7013A01F4&lt;br /&gt;
:1010460018012C011F111F001F001D151715151F54&lt;br /&gt;
:1010560007041F17151D1F151D01011F1F151F173B&lt;br /&gt;
:10106600151F1E051E1F150A0E11111F110E1F1525&lt;br /&gt;
:0C107600111F0501140814253032580029&lt;br /&gt;
:00000001FF&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_arduino_cfg.png&amp;diff=5718</id>
		<title>File:LED panel 30x7 arduino cfg.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_arduino_cfg.png&amp;diff=5718"/>
		<updated>2026-10-29T00:09:54Z</updated>

		<summary type="html">&lt;p&gt;Buger: Arduino configuration for LED panel 30x7&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Arduino configuration for LED panel 30x7&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5717</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5717"/>
		<updated>2026-10-29T00:04:46Z</updated>

		<summary type="html">&lt;p&gt;Buger: more info&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display was reached (means all 30 columns received)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flash the FW into the panel ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
!!! 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 !!!&lt;br /&gt;
&lt;br /&gt;
* install avrdude&lt;br /&gt;
* connect USBasp and panel power supply&lt;br /&gt;
* verify that you can communicate with the atmega over USBasp &amp;lt;code&amp;gt;avrdude -c usbasp -p m16&amp;lt;/code&amp;gt; that should say &amp;quot;device signature = 0x1e9403 (probably m16)&amp;quot;&lt;br /&gt;
* erase the locked atmega16 using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -e&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the fuses (16MHz xtal, 4V BOD, jtag off, preserved EEPROM on chip erase, ISP allowed) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U lfuse:w:0x3f:m -U hfuse:w:0xc7:m&amp;lt;/code&amp;gt;&lt;br /&gt;
* set the device address (needs to be in range 0x80-0xFF) using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;lt;/code&amp;gt; replace 0x80 with desired address&lt;br /&gt;
* write and verify the firmware using &amp;lt;code&amp;gt;avrdude -c usbasp -p m16 -U flash:w:firmware.hex:i&amp;lt;/code&amp;gt;&lt;br /&gt;
* done&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5716</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5716"/>
		<updated>2026-10-28T23:51:32Z</updated>

		<summary type="html">&lt;p&gt;Buger: incl code&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
* on power up it reads device address from EEPROM address 0&lt;br /&gt;
* shows the device address for 3 seconds on the screen&lt;br /&gt;
* then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
* it ignores all data until device address is received&lt;br /&gt;
* after it receives its address, it starts to receive graphics data and resets the column counter&lt;br /&gt;
* 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&lt;br /&gt;
* therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
* after each received graphics byte column counter is incremented&lt;br /&gt;
* 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&lt;br /&gt;
* the device ignores all bytes &amp;gt;=0x80 if they are not its device address&lt;br /&gt;
* the device ignores all graphics data if end of display was reached (means all 30 columns received)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;arduino&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;SPI.h&amp;gt;&lt;br /&gt;
#include &amp;lt;EEPROM.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// device address is stored in eeprom on address 0 and should be &amp;gt;=0x80&lt;br /&gt;
// to change it run &amp;quot;avrdude -c usbasp -p m16 -U eeprom:w:0x80:m&amp;quot; and replace 0x80 with your address&lt;br /&gt;
&lt;br /&gt;
// graphics data = all bytes from serial &amp;lt; 0x80 (as we have only 7 LEDs)&lt;br /&gt;
// when device address is received on serial = start receiving graphics data to display buffer&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Konfigurace pinů – ATmega16, MightyCore std pipnout&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t PIN_LATCH = 21;  // PC5&lt;br /&gt;
const uint8_t PIN_OE    = 20;  // PC4&lt;br /&gt;
const uint8_t PIN_S0    = 16;  // PC0&lt;br /&gt;
const uint8_t PIN_S1    = 17;  // PC1&lt;br /&gt;
const uint8_t PIN_S2    = 18;  // PC2&lt;br /&gt;
const uint8_t PIN_EN    = 19;  // PC3&lt;br /&gt;
&lt;br /&gt;
const uint32_t SPI_SPEED = 16000000;  //drivery by mely fungovat do 20MHz&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Parametry displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint8_t WIDTH  = 30;&lt;br /&gt;
const uint8_t HEIGHT = 7;&lt;br /&gt;
&lt;br /&gt;
const uint32_t ROW_TIME_US = 1000;&lt;br /&gt;
&lt;br /&gt;
const uint8_t DECODER_ENABLED  = LOW;&lt;br /&gt;
const uint8_t DECODER_DISABLED = HIGH;&lt;br /&gt;
const uint8_t OUTPUTS_ENABLED  = LOW;&lt;br /&gt;
const uint8_t OUTPUTS_DISABLED = HIGH;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Sériová komunikace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
const uint32_t SERIAL_BAUD = 115200;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Obrazová paměť&lt;br /&gt;
//&lt;br /&gt;
// buffer[row][column]&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
bool buffer[HEIGHT][WIDTH];&lt;br /&gt;
&lt;br /&gt;
// Index následujícího zapisovaného sloupce.&lt;br /&gt;
// WIDTH znamená, že je buffer plný.&lt;br /&gt;
&lt;br /&gt;
uint8_t writeColumn = 0;&lt;br /&gt;
&lt;br /&gt;
uint8_t devAddr = 80;&lt;br /&gt;
uint32_t startupDisplayTime = 0;&lt;br /&gt;
bool startupDisplayActive = true;&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Font 3x5 pro úvodní zobrazení adresy&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
// Každý znak má 3 sloupce, každý sloupec obsahuje 5 bitů.&lt;br /&gt;
// Bit 0 = horní pixel.&lt;br /&gt;
&lt;br /&gt;
const uint8_t font3x5[][3] = {&lt;br /&gt;
  {0x1F, 0x11, 0x1F}, // 0&lt;br /&gt;
  {0x00, 0x1F, 0x00}, // 1&lt;br /&gt;
  {0x1D, 0x15, 0x17}, // 2&lt;br /&gt;
  {0x15, 0x15, 0x1F}, // 3&lt;br /&gt;
  {0x07, 0x04, 0x1F}, // 4&lt;br /&gt;
  {0x17, 0x15, 0x1D}, // 5&lt;br /&gt;
  {0x1F, 0x15, 0x1D}, // 6&lt;br /&gt;
  {0x01, 0x01, 0x1F}, // 7&lt;br /&gt;
  {0x1F, 0x15, 0x1F}, // 8&lt;br /&gt;
  {0x17, 0x15, 0x1F}, // 9&lt;br /&gt;
  {0x1E, 0x05, 0x1E}, // A&lt;br /&gt;
  {0x1F, 0x15, 0x0A}, // B&lt;br /&gt;
  {0x0E, 0x11, 0x11}, // C&lt;br /&gt;
  {0x1F, 0x11, 0x0E}, // D&lt;br /&gt;
  {0x1F, 0x15, 0x11}, // E&lt;br /&gt;
  {0x1F, 0x05, 0x01}, // F&lt;br /&gt;
  {0x14, 0x08, 0x14}  // x&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// Vymazání obrazového bufferu.&lt;br /&gt;
void clearBuffer() {&lt;br /&gt;
  memset(buffer, 0, sizeof(buffer));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Vykreslení jednoho znaku 3x5.&lt;br /&gt;
void drawChar(uint8_t index, uint8_t x, uint8_t y) {&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; 3; col++) {&lt;br /&gt;
    uint8_t bits = font3x5[index][col];&lt;br /&gt;
&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; 5; row++) {&lt;br /&gt;
      if (x + col &amp;lt; WIDTH &amp;amp;&amp;amp; y + row &amp;lt; HEIGHT) {&lt;br /&gt;
        buffer[y + row][x + col] = (bits &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Zobrazení adresy, například 0x83.&lt;br /&gt;
void showDeviceAddress() {&lt;br /&gt;
  clearBuffer();&lt;br /&gt;
&lt;br /&gt;
  char text[5];&lt;br /&gt;
  snprintf(text, sizeof(text), &amp;quot;%02X&amp;quot;, devAddr);&lt;br /&gt;
&lt;br /&gt;
  // Text tvoří 0, x a dvě hexadecimální číslice.&lt;br /&gt;
  // Šířka: 4 znaky * 3 pixely + 3 mezery = 15 pixelů.&lt;br /&gt;
  // Začátek je vypočítán pro vodorovné vycentrování.&lt;br /&gt;
  uint8_t x = (WIDTH - 15) / 2;&lt;br /&gt;
  uint8_t y = (HEIGHT - 5) / 2;&lt;br /&gt;
&lt;br /&gt;
  drawChar(0, x, y);  // 0&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  drawChar(16, x, y);  // x&lt;br /&gt;
  x += 4;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;
    char c = text[i];&lt;br /&gt;
&lt;br /&gt;
    uint8_t index;&lt;br /&gt;
    if (c &amp;gt;= &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
      index = c - &#039;0&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
      index = c - &#039;A&#039; + 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    drawChar(index, x, y);&lt;br /&gt;
    x += 4;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Příjem dat ze sériového portu&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void processSerial() {&lt;br /&gt;
&lt;br /&gt;
  while (Serial.available() &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
    uint8_t data = Serial.read();&lt;br /&gt;
&lt;br /&gt;
    // Bajty s nejvyšším bitem 1 jsou příkazy.&lt;br /&gt;
    if (data &amp;amp; 0x80) {&lt;br /&gt;
&lt;br /&gt;
      // Jediný podporovaný příkaz: reset adresy zápisu pokud je prijat devAddr.&lt;br /&gt;
      if (data == devAddr) {&lt;br /&gt;
        writeColumn = 0;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      // Ostatní ignorovat&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Pokud je buffer plný, další data ignorovat.&lt;br /&gt;
    if (writeColumn &amp;gt;= WIDTH) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Zapsat všech 7 bitů do aktuálního sloupce.&lt;br /&gt;
    for (uint8_t row = 0; row &amp;lt; HEIGHT; row++) {&lt;br /&gt;
&lt;br /&gt;
      buffer[row][writeColumn] = (data &amp;gt;&amp;gt; row) &amp;amp; 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Připravit následující sloupec.&lt;br /&gt;
    writeColumn++;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Výběr řádku přes 74LS138&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void selectRow(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_S0, (row &amp;amp; 0x01) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, (row &amp;amp; 0x02) ? HIGH : LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, (row &amp;amp; 0x04) ? HIGH : LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Zápis sloupců do dvou A6276E&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void writeColumns(uint8_t row) {&lt;br /&gt;
&lt;br /&gt;
  uint32_t word = 0;&lt;br /&gt;
&lt;br /&gt;
  for (uint8_t col = 0; col &amp;lt; WIDTH; col++) {&lt;br /&gt;
&lt;br /&gt;
    if (buffer[row][col]) {&lt;br /&gt;
      word |= (1UL &amp;lt;&amp;lt; col);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, LOW);&lt;br /&gt;
&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 16) &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer((word &amp;gt;&amp;gt; 8)  &amp;amp; 0xFF);&lt;br /&gt;
  SPI.transfer(word &amp;amp; 0xFF);&lt;br /&gt;
&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Multiplexní obsluha displeje&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
uint8_t currentRow = 0;&lt;br /&gt;
uint32_t lastRowChange = 0;&lt;br /&gt;
&lt;br /&gt;
void refreshDisplay() {&lt;br /&gt;
&lt;br /&gt;
  uint32_t now = micros();&lt;br /&gt;
&lt;br /&gt;
  if ((uint32_t)(now - lastRowChange) &amp;lt; ROW_TIME_US) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  lastRowChange = now;&lt;br /&gt;
&lt;br /&gt;
  // 1. Zhasnout výstupy během změny řádku.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 2. Zakázat dekodér.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
&lt;br /&gt;
  // 3. Zapsat data pro aktuální řádek.&lt;br /&gt;
  writeColumns(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 4. Vybrat řádek.&lt;br /&gt;
  selectRow(currentRow);&lt;br /&gt;
&lt;br /&gt;
  // 5. Povolit řádek.&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 6. Povolit výstupy LED driverů.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_ENABLED);&lt;br /&gt;
&lt;br /&gt;
  // 7. Připravit následující řádek.&lt;br /&gt;
  currentRow++;&lt;br /&gt;
&lt;br /&gt;
  if (currentRow &amp;gt;= HEIGHT) {&lt;br /&gt;
    currentRow = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Inicializace&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  // Sériová komunikace 115200 baud.&lt;br /&gt;
  Serial.begin(SERIAL_BAUD);&lt;br /&gt;
&lt;br /&gt;
  // SPI pro LED drivery.&lt;br /&gt;
  SPI.begin();&lt;br /&gt;
&lt;br /&gt;
  SPI.beginTransaction(&lt;br /&gt;
    SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  // Konfigurace pinů.&lt;br /&gt;
  pinMode(PIN_LATCH, OUTPUT);&lt;br /&gt;
  pinMode(PIN_OE, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S0, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S1, OUTPUT);&lt;br /&gt;
  pinMode(PIN_S2, OUTPUT);&lt;br /&gt;
  pinMode(PIN_EN, OUTPUT);&lt;br /&gt;
&lt;br /&gt;
  // Displej při inicializaci zhasnout.&lt;br /&gt;
  digitalWrite(PIN_OE, OUTPUTS_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_EN, DECODER_DISABLED);&lt;br /&gt;
  digitalWrite(PIN_LATCH, HIGH);&lt;br /&gt;
  digitalWrite(PIN_S0, LOW);&lt;br /&gt;
  digitalWrite(PIN_S1, LOW);&lt;br /&gt;
  digitalWrite(PIN_S2, LOW);&lt;br /&gt;
&lt;br /&gt;
  // buffer pointer je po resetu nastaven na WIDTH aby se ignorovala data dokud nedojde odpovidajici devaddr&lt;br /&gt;
  writeColumn = WIDTH;&lt;br /&gt;
&lt;br /&gt;
  // Okamžitá první obnova displeje.&lt;br /&gt;
  currentRow = 0;&lt;br /&gt;
  lastRowChange = micros() - ROW_TIME_US;&lt;br /&gt;
&lt;br /&gt;
  // Adresa zarizeni z EEPROM z adresy 0&lt;br /&gt;
  devAddr = EEPROM.read(0) | 0x80; //nacist adresu z eeprom a ujistit se ze bude &amp;gt;=0x80&lt;br /&gt;
&lt;br /&gt;
  showDeviceAddress();&lt;br /&gt;
&lt;br /&gt;
  startupDisplayTime = millis();&lt;br /&gt;
  startupDisplayActive = true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// =====================================================&lt;br /&gt;
// Hlavní smyčka&lt;br /&gt;
// =====================================================&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
&lt;br /&gt;
  if (!startupDisplayActive) {&lt;br /&gt;
    processSerial();&lt;br /&gt;
  } else if ((uint32_t)(millis() - startupDisplayTime) &amp;gt;= 3000) {&lt;br /&gt;
    // Po 3 sekundách odstranit uvidni screen s adresou a zacit prijimat data&lt;br /&gt;
    startupDisplayActive = false;&lt;br /&gt;
    clearBuffer();    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // obnovovat displej&lt;br /&gt;
  refreshDisplay();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5715</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5715"/>
		<updated>2026-10-28T23:42:28Z</updated>

		<summary type="html">&lt;p&gt;Buger: more info...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
= Hack the protocol! =&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
= Make our own firmware =&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base48&amp;quot; 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. &lt;br /&gt;
&lt;br /&gt;
After some polishing here is the firmware that:&lt;br /&gt;
- on powerup shows the device address for 3 seconds&lt;br /&gt;
- then screen is cleared and it waits for serial data (115200, 8N1)&lt;br /&gt;
- it ignores all data until device address is received&lt;br /&gt;
- after it receives its address, it starts to receive graphics data&lt;br /&gt;
- 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&lt;br /&gt;
- therefore the device address needs to be in 0x80-0xFF range, this way we can handle up to 128 devices on the same bus&lt;br /&gt;
- after each received graphics byte column counter is incremented&lt;br /&gt;
- 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&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5714</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5714"/>
		<updated>2026-10-28T23:20:56Z</updated>

		<summary type="html">&lt;p&gt;Buger: added basic dascr&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=LED_panel_30x7.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= What is this about =&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
To be able to use them we need to find out the protocol, or make our own firmware.&lt;br /&gt;
&lt;br /&gt;
== Hack the protocol! ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
I also tried to read the firmware of the main controller (atmega16) but its locked (as usual).&lt;br /&gt;
&lt;br /&gt;
So I deciced to go &amp;quot;my firmware&amp;quot; way...&lt;br /&gt;
&lt;br /&gt;
== Make our own firmware ==&lt;br /&gt;
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 &lt;br /&gt;
&lt;br /&gt;
[[File:LED_panel_30x7_schematic.jpg|center|frameless|600x600px|LED &amp;amp; driver layout]]&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_schematic.jpg&amp;diff=5713</id>
		<title>File:LED panel 30x7 schematic.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7_schematic.jpg&amp;diff=5713"/>
		<updated>2026-10-28T23:18:19Z</updated>

		<summary type="html">&lt;p&gt;Buger: LED panel 30x7 schematic diagram&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
LED panel 30x7 schematic diagram&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7.jpg&amp;diff=5712</id>
		<title>File:LED panel 30x7.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=File:LED_panel_30x7.jpg&amp;diff=5712"/>
		<updated>2026-10-28T22:57:56Z</updated>

		<summary type="html">&lt;p&gt;Buger: Picture of LED panel 30x7&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Picture of LED panel 30x7&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
	<entry>
		<id>https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5711</id>
		<title>LED Panel 30x7</title>
		<link rel="alternate" type="text/html" href="https://wiki.base48.cz/w/index.php?title=LED_Panel_30x7&amp;diff=5711"/>
		<updated>2026-10-28T22:45:48Z</updated>

		<summary type="html">&lt;p&gt;Buger: create page for LED panels 30x7&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Project&lt;br /&gt;
 |name=LED Panel 30x7&lt;br /&gt;
 |image=Turtle-bots.jpg&lt;br /&gt;
 |founder=Buger&lt;br /&gt;
 |status=active&lt;br /&gt;
 |tags=hw&lt;br /&gt;
 |shortdesc=LED Panels 30x7 - make them working&lt;br /&gt;
 |created=2026-28-10&lt;br /&gt;
}}&lt;br /&gt;
= Placeholder =&lt;/div&gt;</summary>
		<author><name>Buger</name></author>
	</entry>
</feed>