summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Wiese <tobias@tobiaswiese.com>2021-05-03 23:58:30 +0200
committerTobias Wiese <tobias@tobiaswiese.com>2021-07-22 02:26:29 +0200
commit68b5f182af145fdd9e62c9dde3eedcb9108f5ba4 (patch)
tree67c0011276b30f8f785b934be44044935f78bd73
Initial commitHEADmaster
Signed-off-by: Tobias Wiese <tobias@tobiaswiese.com>
-rw-r--r--.gitignore5
-rw-r--r--Makefile91
-rw-r--r--base.c20
-rw-r--r--blink.c23
-rw-r--r--chars/0.xbm4
-rw-r--r--chars/0.xcfbin0 -> 873 bytes
-rw-r--r--chars/1.xbm4
-rw-r--r--chars/1.xcfbin0 -> 867 bytes
-rw-r--r--chars/2.xbm4
-rw-r--r--chars/2.xcfbin0 -> 831 bytes
-rw-r--r--chars/3.xbm4
-rw-r--r--chars/3.xcfbin0 -> 831 bytes
-rw-r--r--chars/4.xbm4
-rw-r--r--chars/4.xcfbin0 -> 855 bytes
-rw-r--r--chars/5.xbm4
-rw-r--r--chars/5.xcfbin0 -> 831 bytes
-rw-r--r--chars/6.xbm4
-rw-r--r--chars/6.xcfbin0 -> 831 bytes
-rw-r--r--chars/7.xbm4
-rw-r--r--chars/7.xcfbin0 -> 855 bytes
-rw-r--r--chars/8.xbm4
-rw-r--r--chars/8.xcfbin0 -> 831 bytes
-rw-r--r--chars/9.xbm4
-rw-r--r--chars/9.xcfbin0 -> 831 bytes
-rw-r--r--chars/chars.c118
-rw-r--r--chars/chars.h10
-rw-r--r--chars/space.xbm4
-rw-r--r--chars/space.xcfbin0 -> 771 bytes
-rw-r--r--color.c13
-rw-r--r--fade.c41
-rw-r--r--img_mono.c58
-rw-r--r--img_mono.xbm6
-rw-r--r--libleds.c14
-rw-r--r--libleds.h55
-rw-r--r--libleds_asm.S92
-rw-r--r--m16def.inc862
-rw-r--r--numtest.c30
-rw-r--r--pulse.c24
-rw-r--r--test.c22
39 files changed, 1528 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a78512b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/*
+!/*/
+!/Makefile
+!/*.*
+*.[ao]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cc18b7e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,91 @@
+SHELL = /bin/sh
+MCU = atmega16
+F_CPU=16000000
+
+CC = avr-gcc
+CFLAGS = -g -Os -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Wall
+AS = avr-as
+ASFLAGS = $(CFLAGS)
+LD = avr-ld
+LDFLAGS =
+
+TARGETS := test img_mono blink fade pulse numtest
+MAINS := $(addsuffix .o, $(TARGETS))
+C_OBJS := base.o libleds.o chars/chars.o
+S_OBJS := libleds_asm.o
+OBJS := $(C_OBJS) $(S_OBJS)
+DEPS := Makefile libleds.h
+
+COLOR_TARGETS := c_black c_white c_red c_green c_blue
+COLOR_MAINS := $(addsuffix .o, $(COLOR_TARGETS))
+
+NUMBERS = $(shell seq 0 9)
+UPPERCASE = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+LOWERCASE = $(call lc, $(UPPERCASE))
+SPECIAL_CHARS = space
+CHARS = $(NUMBERS) $(UPPERCASE) $(LOWERCASE) $(SPECIAL_CHARS)
+
+NUMBERS_DEP = chars/chars.o $(addprefix chars/, $(addsuffix .xbm, $(NUMBERS)))
+UPPERCASE_DEP = chars/chars.o $(addprefix chars/, $(addsuffix .xbm, $(UPPERCASE)))
+LOWERCASE_DEP = chars/chars.o $(addprefix chars/, $(addsuffix .xbm, $(LOWERCASE)))
+SPECIAL_CHARS_DEP = chars/chars.o $(addprefix chars/, $(addsuffix .xbm, $(SPECIAL_CHARS)))
+CHARS_DEP = chars/chars.o $(addprefix chars/, $(addsuffix .xbm, $(CHARS)))
+
+
+.PHONY: all all-normal all-colors
+all: all-core all-colors
+
+all-core: $(TARGETS)
+.PHONY: color
+all-colors color: $(COLOR_TARGETS)
+
+.PHONY: clean
+clean:
+ rm -f $(TARGETS) $(MAINS) $(OBJS) $(COLOR_TARGETS) $(COLOR_MAINS)
+ rm -f chars/chars.o
+
+.PHONY: list-targets _list-targets-core _list-targets-color
+list-targets: _list-targets-core _list-targets-color
+ @printf "\n"
+
+list-targets-core list-targets-color: % : _%
+ @printf "\n"
+
+_list-targets-core:
+ @printf "%s " "$(TARGETS)"
+
+_list-targets-color:
+ @printf "%s " "$(COLOR_TARGETS)"
+
+
+# Build targets
+
+
+chars/chars.c: %.c: %.h
+ @touch $@
+
+$(MAINS) $(C_OBJS): %.o : %.c $(DEPS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(TARGETS) $(COLOR_TARGETS): % : $(OBJS) %.o
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^
+
+numtest.o: $(NUMBERS_DEP)
+img_mono.o: %.o : %.xbm
+
+# Color Targets
+c_black.o: color.c $(DEPS)
+ $(CC) $(CFLAGS) -c -o $@ $< \
+ -DCOLOR_RED=0x00 -DCOLOR_GREEN=0x00 -DCOLOR_BLUE=0x00
+c_white.o: color.c $(DEPS)
+ $(CC) $(CFLAGS) -c -o $@ $< \
+ -DCOLOR_RED=0x00 -DCOLOR_GREEN=0xFF -DCOLOR_BLUE=0xFF
+c_red.o: color.c $(DEPS)
+ $(CC) $(CFLAGS) -c -o $@ $< \
+ -DCOLOR_RED=0xFF -DCOLOR_GREEN=0x00 -DCOLOR_BLUE=0x00
+c_green.o: color.c $(DEPS)
+ $(CC) $(CFLAGS) -c -o $@ $< \
+ -DCOLOR_RED=0x00 -DCOLOR_GREEN=0xFF -DCOLOR_BLUE=0x00
+c_blue.o: color.c $(DEPS)
+ $(CC) $(CFLAGS) -c -o $@ $< \
+ -DCOLOR_RED=0x00 -DCOLOR_GREEN=0x00 -DCOLOR_BLUE=0xFF
diff --git a/base.c b/base.c
new file mode 100644
index 0000000..5ebe2a7
--- /dev/null
+++ b/base.c
@@ -0,0 +1,20 @@
+#include <avr/io.h>
+#include "libleds.h"
+
+static uint16_t const STRIP_LENGTH = 8*32;
+static char const PORT = 0;
+static char const PINS = 1<<7;
+
+void led_main();
+
+void init()
+{
+ DDRD = 255;
+}
+
+int main()
+{
+ init();
+ led_main();
+ return 0;
+}
diff --git a/blink.c b/blink.c
new file mode 100644
index 0000000..7bf248f
--- /dev/null
+++ b/blink.c
@@ -0,0 +1,23 @@
+#include <util/delay.h>
+#include "libleds.h"
+
+static struct led_obj const PANEL = {0, 1<<7, 32, 8};
+static unsigned char const INTENSITY = 0x15;
+static unsigned int const DELAY_MS = 150;
+
+void led_main()
+{
+ struct led_color const colors[] = {
+ {INTENSITY, 0x00, 0x00},
+ {0x00, INTENSITY, 0x00},
+ {0x00, 0x00, INTENSITY},
+ };
+
+ unsigned char i = 0;
+
+ while (1) {
+ led_write_rgb_all(PANEL, colors[i]);
+ _delay_ms(DELAY_MS);
+ i = (i + 1) % (sizeof(colors) / sizeof(colors[0]));
+ }
+}
diff --git a/chars/0.xbm b/chars/0.xbm
new file mode 100644
index 0000000..420af7e
--- /dev/null
+++ b/chars/0.xbm
@@ -0,0 +1,4 @@
+#define c0_width 5
+#define c0_height 8
+static unsigned char c0_bits[] = {
+ 0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e };
diff --git a/chars/0.xcf b/chars/0.xcf
new file mode 100644
index 0000000..a3ab875
--- /dev/null
+++ b/chars/0.xcf
Binary files differ
diff --git a/chars/1.xbm b/chars/1.xbm
new file mode 100644
index 0000000..0e3b28c
--- /dev/null
+++ b/chars/1.xbm
@@ -0,0 +1,4 @@
+#define c1_width 5
+#define c1_height 8
+static unsigned char c1_bits[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
diff --git a/chars/1.xcf b/chars/1.xcf
new file mode 100644
index 0000000..9ca02a3
--- /dev/null
+++ b/chars/1.xcf
Binary files differ
diff --git a/chars/2.xbm b/chars/2.xbm
new file mode 100644
index 0000000..b88cc50
--- /dev/null
+++ b/chars/2.xbm
@@ -0,0 +1,4 @@
+#define c2_width 5
+#define c2_height 8
+static unsigned char c2_bits[] = {
+ 0x1f, 0x10, 0x10, 0x1f, 0x01, 0x01, 0x01, 0x1f };
diff --git a/chars/2.xcf b/chars/2.xcf
new file mode 100644
index 0000000..05d2415
--- /dev/null
+++ b/chars/2.xcf
Binary files differ
diff --git a/chars/3.xbm b/chars/3.xbm
new file mode 100644
index 0000000..5723c18
--- /dev/null
+++ b/chars/3.xbm
@@ -0,0 +1,4 @@
+#define c3_width 5
+#define c3_height 8
+static unsigned char c3_bits[] = {
+ 0x1f, 0x10, 0x10, 0x1f, 0x10, 0x10, 0x10, 0x1f };
diff --git a/chars/3.xcf b/chars/3.xcf
new file mode 100644
index 0000000..f1796d3
--- /dev/null
+++ b/chars/3.xcf
Binary files differ
diff --git a/chars/4.xbm b/chars/4.xbm
new file mode 100644
index 0000000..419d375
--- /dev/null
+++ b/chars/4.xbm
@@ -0,0 +1,4 @@
+#define c4_width 5
+#define c4_height 8
+static unsigned char c4_bits[] = {
+ 0x11, 0x11, 0x11, 0x1f, 0x10, 0x10, 0x10, 0x10 };
diff --git a/chars/4.xcf b/chars/4.xcf
new file mode 100644
index 0000000..6eb8a27
--- /dev/null
+++ b/chars/4.xcf
Binary files differ
diff --git a/chars/5.xbm b/chars/5.xbm
new file mode 100644
index 0000000..00eb4bc
--- /dev/null
+++ b/chars/5.xbm
@@ -0,0 +1,4 @@
+#define c5_width 5
+#define c5_height 8
+static unsigned char c5_bits[] = {
+ 0x1f, 0x01, 0x01, 0x1f, 0x10, 0x10, 0x10, 0x1f };
diff --git a/chars/5.xcf b/chars/5.xcf
new file mode 100644
index 0000000..48b178e
--- /dev/null
+++ b/chars/5.xcf
Binary files differ
diff --git a/chars/6.xbm b/chars/6.xbm
new file mode 100644
index 0000000..4b307c3
--- /dev/null
+++ b/chars/6.xbm
@@ -0,0 +1,4 @@
+#define c6_width 5
+#define c6_height 8
+static unsigned char c6_bits[] = {
+ 0x1f, 0x01, 0x01, 0x1f, 0x11, 0x11, 0x11, 0x1f };
diff --git a/chars/6.xcf b/chars/6.xcf
new file mode 100644
index 0000000..402e31c
--- /dev/null
+++ b/chars/6.xcf
Binary files differ
diff --git a/chars/7.xbm b/chars/7.xbm
new file mode 100644
index 0000000..345352e
--- /dev/null
+++ b/chars/7.xbm
@@ -0,0 +1,4 @@
+#define c7_width 5
+#define c7_height 8
+static unsigned char c7_bits[] = {
+ 0x1f, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 };
diff --git a/chars/7.xcf b/chars/7.xcf
new file mode 100644
index 0000000..49ad0eb
--- /dev/null
+++ b/chars/7.xcf
Binary files differ
diff --git a/chars/8.xbm b/chars/8.xbm
new file mode 100644
index 0000000..0b1b1ca
--- /dev/null
+++ b/chars/8.xbm
@@ -0,0 +1,4 @@
+#define c8_width 5
+#define c8_height 8
+static unsigned char c8_bits[] = {
+ 0x1f, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11, 0x1f };
diff --git a/chars/8.xcf b/chars/8.xcf
new file mode 100644
index 0000000..879b641
--- /dev/null
+++ b/chars/8.xcf
Binary files differ
diff --git a/chars/9.xbm b/chars/9.xbm
new file mode 100644
index 0000000..2e6c2cd
--- /dev/null
+++ b/chars/9.xbm
@@ -0,0 +1,4 @@
+#define c9_width 5
+#define c9_height 8
+static unsigned char c9_bits[] = {
+ 0x1f, 0x11, 0x11, 0x1f, 0x10, 0x10, 0x10, 0x1f };
diff --git a/chars/9.xcf b/chars/9.xcf
new file mode 100644
index 0000000..8c7c6fd
--- /dev/null
+++ b/chars/9.xcf
Binary files differ
diff --git a/chars/chars.c b/chars/chars.c
new file mode 100644
index 0000000..de72a10
--- /dev/null
+++ b/chars/chars.c
@@ -0,0 +1,118 @@
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "../libleds.h"
+#include "chars.h"
+
+#include "space.xbm"
+#include "0.xbm"
+#include "1.xbm"
+#include "2.xbm"
+#include "3.xbm"
+#include "4.xbm"
+#include "5.xbm"
+#include "6.xbm"
+#include "7.xbm"
+#include "8.xbm"
+#include "9.xbm"
+
+static unsigned char *get_char_bits(char c) {
+ switch (c) {
+ case ' ':
+ return cspace_bits;
+ case '0':
+ return c0_bits;
+ case '1':
+ return c1_bits;
+ case '2':
+ return c2_bits;
+ case '3':
+ return c3_bits;
+ case '4':
+ return c4_bits;
+ case '5':
+ return c5_bits;
+ case '6':
+ return c6_bits;
+ case '7':
+ return c7_bits;
+ case '8':
+ return c8_bits;
+ case '9':
+ return c9_bits;
+ default:
+ return NULL;
+ }
+}
+
+static char is_active(unsigned char const *bits, unsigned int const i)
+{
+ /*
+ * The first led is in the top left corner.
+ * After that it goes down the column, then up the next and so on.
+ *
+ * This means all columns with an even index count down.
+ * Those with an odd index count up.
+ *
+ *
+ * With a height of 8 the led numbers would look like this:
+ *
+ * 00 0F 10 1F 20 ...
+ * 01 0E 11 1E 21 ...
+ * 02 0D 12 1D ...
+ * 03 0C 13 1C ...
+ * 04 0B 14 1B ...
+ * 05 0A 15 1A ...
+ * 06 09 16 19 ...
+ * 07 08 17 18 ...
+ */
+
+ unsigned int const bytes_per_row = ceil(char_width / 8.0);
+ unsigned int col = i / char_height;
+ unsigned int row = i % char_height;
+ if (col % 2)
+ row = char_height - 1 - row;
+
+ // calculate byte to access
+ unsigned int byte = row * bytes_per_row;
+ byte += col / 8;
+
+ unsigned char data = bits[byte];
+ unsigned char mask = 1<<(col % 8);
+ return data & mask;
+}
+
+static char leds_write_char(const struct led_color color, char c, struct led_color *buf)
+{
+ unsigned char *bits = get_char_bits(c);
+ if (bits == NULL)
+ return 0;
+
+ for (unsigned int i = 0; i < char_length; i++) {
+ if (is_active(bits, i))
+ buf[i] = color;
+ else
+ buf[i] = (struct led_color){0, 0, 0};
+ }
+
+ return 1;
+}
+
+struct led_color *leds_text(struct led_color const color, const char *text)
+{
+ unsigned int const len = strlen(text);
+ struct led_color *buf = calloc(
+ sizeof(struct led_color), len * char_length
+ );
+
+ for (unsigned int i = 0; i < len; i++) {
+ if (!leds_write_char(color, text[i], buf + i*char_length)) {
+ // Invalid char
+ free(buf);
+ return NULL;
+ }
+ }
+
+ return buf;
+}
diff --git a/chars/chars.h b/chars/chars.h
new file mode 100644
index 0000000..91c7ea7
--- /dev/null
+++ b/chars/chars.h
@@ -0,0 +1,10 @@
+#ifndef CHARS_CHARS_H
+#define CHARS_CHARS_H
+
+#define char_width (5+1)
+#define char_height 8
+#define char_length (char_width * char_height)
+
+struct led_color *leds_text(struct led_color const color, const char *text);
+
+#endif /* !CHARS_CHARS_H */
diff --git a/chars/space.xbm b/chars/space.xbm
new file mode 100644
index 0000000..7b4791b
--- /dev/null
+++ b/chars/space.xbm
@@ -0,0 +1,4 @@
+#define cspace_width 5
+#define cspace_height 8
+static unsigned char cspace_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/chars/space.xcf b/chars/space.xcf
new file mode 100644
index 0000000..c32a481
--- /dev/null
+++ b/chars/space.xcf
Binary files differ
diff --git a/color.c b/color.c
new file mode 100644
index 0000000..f7c1261
--- /dev/null
+++ b/color.c
@@ -0,0 +1,13 @@
+#include "libleds.h"
+
+#if !defined(COLOR_RED) || !defined(COLOR_GREEN) || !defined(COLOR_BLUE)
+# error Requires COLOR_* symbols to be set.
+#endif
+
+static struct led_obj const PANEL = {0, 1<<7, 32, 8};
+
+void led_main()
+{
+ struct led_color const color = { COLOR_RED, COLOR_GREEN, COLOR_BLUE};
+ led_write_rgb_all(PANEL, color);
+}
diff --git a/fade.c b/fade.c
new file mode 100644
index 0000000..09d6233
--- /dev/null
+++ b/fade.c
@@ -0,0 +1,41 @@
+#include "libleds.h"
+
+static struct led_obj const PANEL = {0, 1<<7, 32, 8};
+
+void write_all(struct led_color const color)
+{
+ led_write_rgb_all(PANEL, color);
+ led_latch();
+}
+
+void led_main()
+{
+ static int const STEP = 0x04;
+ static int const MIN = 0x10;
+ static int const MAX = 0xF0;
+
+ struct led_color color = {MAX, MIN, MIN};
+ while (1) {
+ for (int i = MIN; i < MAX; i += STEP) {
+ color.red -= STEP;
+ color.green += STEP;
+ write_all(color);
+ }
+ color.red = MIN;
+ color.green = MAX;
+ for (int i = MIN; i < MAX; i += STEP) {
+ color.green -= STEP;
+ color.blue += STEP;
+ write_all(color);
+ }
+ color.green = MIN;
+ color.blue = MAX;
+ for (int i = MIN; i < MAX; i += STEP) {
+ color.blue -= STEP;
+ color.red += STEP;
+ write_all(color);
+ }
+ color.blue = MIN;
+ color.red = MAX;
+ }
+}
diff --git a/img_mono.c b/img_mono.c
new file mode 100644
index 0000000..b711a6b
--- /dev/null
+++ b/img_mono.c
@@ -0,0 +1,58 @@
+#include <math.h>
+#include "libleds.h"
+#include "img_mono.xbm"
+
+static char const PORT = 0;
+static char const PINS = 1<<7;
+
+char const is_active(unsigned int const n)
+{
+ /*
+ * The first led is in the top left corner.
+ * After that it goes down the column, then up the next and so on.
+ *
+ * This means all columns with an even index count down.
+ * Those with an odd index count up.
+ *
+ *
+ * With a height of 8 the led numbers would look like this:
+ *
+ * 00 0F 10 1F 20 ...
+ * 01 0E 11 1E 21 ...
+ * 02 0D 12 1D ...
+ * 03 0C 13 1C ...
+ * 04 0B 14 1B ...
+ * 05 0A 15 1A ...
+ * 06 09 16 19 ...
+ * 07 08 17 18 ...
+ */
+
+ unsigned int const bytes_per_row = ceil(img_width / 8.0);
+ unsigned int col = n / img_height;
+ unsigned int row = n % img_height;
+ if (col % 2)
+ row = img_height - 1 - row;
+
+ // calculate byte to access
+ unsigned int byte = row * bytes_per_row;
+ byte += col / 8;
+
+ unsigned char data = img_bits[byte];
+ unsigned char mask = 1<<(col % 8);
+ return data & mask;
+}
+
+void led_main()
+{
+ const int length = img_width * img_height;
+
+ struct led_color pixel[length];
+
+ for (unsigned int i = 0; i < length; i++) {
+ unsigned char out = is_active(i) ? 0xFF : 0x00;
+ pixel[i] = (struct led_color){out, out, out};
+ }
+
+ for (unsigned int i = 0; i < length; i++)
+ led_write_rgb(PORT, PINS, pixel[i]);
+}
diff --git a/img_mono.xbm b/img_mono.xbm
new file mode 100644
index 0000000..81f61b4
--- /dev/null
+++ b/img_mono.xbm
@@ -0,0 +1,6 @@
+#define img_width 32
+#define img_height 8
+static unsigned char img_bits[] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55 };
diff --git a/libleds.c b/libleds.c
new file mode 100644
index 0000000..1e32d90
--- /dev/null
+++ b/libleds.c
@@ -0,0 +1,14 @@
+#include <util/delay.h>
+#include "libleds.h"
+
+void led_write_rgb_all(struct led_obj const obj, struct led_color const color)
+{
+ for (int i = 0; i < obj.width * obj.height; i++) {
+ led_write_rgb(obj.port, obj.pins, color);
+ }
+}
+
+void led_latch(void)
+{
+ _delay_us(280);
+}
diff --git a/libleds.h b/libleds.h
new file mode 100644
index 0000000..2af1325
--- /dev/null
+++ b/libleds.h
@@ -0,0 +1,55 @@
+#ifndef LIBLEDS_H
+#define LIBLEDS_H
+#include <stdio.h>
+
+struct led_color {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+};
+
+struct led_obj {
+ /*
+ * port to use as output.
+ *
+ * The port must already be configured for output.
+ *
+ * currently this is not used and PORTD is used instead.
+ */
+ uint16_t port;
+
+ /*
+ * bitmask specifing with ports to use.
+ *
+ * currently this is not used and 0xFF is used instead.
+ */
+ unsigned char pins;
+
+ /*
+ * the width of the object.
+ *
+ * Might be 0 if the width is unknown. Some function that depend on
+ * knowing the number of elements will not work.
+ */
+ unsigned int width;
+
+ /*
+ * the height of the object.
+ *
+ * Might be 0 if the height is unknown. Some function that depend on
+ * knowing the number of elements will not work.
+ *
+ * If the object is not a rectangle this should be set to 1.
+ * width is then the number of leds in the strip / star / ...
+ */
+ unsigned int height;
+};
+
+void led_write_rgb(uint16_t const port, unsigned char const pins,
+ struct led_color color);
+
+void led_write_rgb_all(struct led_obj const obj, struct led_color const color);
+
+void led_latch();
+
+#endif /* !LIBLEDS_H */
diff --git a/libleds_asm.S b/libleds_asm.S
new file mode 100644
index 0000000..fd7e67c
--- /dev/null
+++ b/libleds_asm.S
@@ -0,0 +1,92 @@
+.include "m16def.inc"
+
+#ifndef F_CPU
+# error The LEDs are timing sensitive. F_CPU required.
+#elif F_CPU < 4000000
+# error The LEDs are timing sensitive. CPU Frequency must be at least 4MHz
+#elif F_CPU == 4000000
+
+// 4MHz
+#define nop_short
+#define nop_long nop $ nop
+
+#elif F_CPU == 8000000
+
+// 8MHz
+#define nop_short nop
+#define nop_long nop $ nop $ nop $ nop $ nop
+
+#elif F_CPU == 16000000
+
+// 16MHz
+#define nop_short nop $ nop $ nop
+#define nop_long nop $ nop $ nop $ nop $ nop $ nop $ nop $ nop $ nop $ nop $ nop
+
+#else
+# error Missing nop definitions for your CPU frequency.
+#endif
+
+
+.global led_write_rgb
+ .type led_write_rgb, @function
+; void (uint16_t port, char pins, char r, char g, char b);
+;
+; Args:
+; port: r25, r24
+; pins: r22
+; b: r20
+; g: r19
+; r: r18
+;
+; destroys: r19
+;
+; The leds expect the data in G-R-B order
+led_write_rgb:
+ clr r0
+ dec r0
+
+ call L_led_write_byte
+ mov r19, r18
+ call L_led_write_byte
+ mov r19, r20
+ call L_led_write_byte
+ ret
+
+; Args:
+; port: X -- curently ignored, hadcoded to PORTD
+; pins: r22 -- currently ignored, hardcoded to 0xFF
+; byte: r19 (!)
+;
+; Prerequisites:
+; r0 must be 0xFF
+;
+; destroys: r21 -- will be 0 afterwards
+; destroys: r19 -- call rol on it once to restore
+L_led_write_byte:
+
+ ldi r21, 8
+
+L_led_write_byte__loop_head:
+ rol r19
+ brcc L_led_write_byte__zero
+
+L_led_write_byte__one:
+ out PORTD, r0
+ nop_long
+ out PORTD, r1
+ nop_short
+ rjmp L_led_write_byte__loop_ctrl
+
+L_led_write_byte__zero:
+ out PORTD, r0
+ nop_short
+ out PORTD, r1
+ nop_long
+
+L_led_write_byte__loop_ctrl:
+ ; loop ctrl
+ dec r21
+ brne L_led_write_byte__loop_head
+
+L_led_write_byte__out:
+ ret
diff --git a/m16def.inc b/m16def.inc
new file mode 100644
index 0000000..27cc811
--- /dev/null
+++ b/m16def.inc
@@ -0,0 +1,862 @@
+;* A P P L I C A T I O N N O T E F O R T H E A V R F A M I L Y
+;*
+;* Number : AVR000
+;* File Name : "m16def.inc"
+;* Title : Register/Bit Definitions for the ATmega16
+;* Date : 2011-02-09
+;* Version : 2.35
+;* Support E-mail : avr@atmel.com
+;* Target MCU : ATmega16
+;*
+;* DESCRIPTION
+;* When including this file in the assembly program file, all I/O register
+;* names and I/O register bit names appearing in the data book can be used.
+;* In addition, the six registers forming the three data pointers X, Y and
+;* Z have been assigned names XL - ZH. Highest RAM address for Internal
+;* SRAM is also defined
+;*
+;* The Register names are represented by their hexadecimal address.
+;*
+;* The Register Bit names are represented by their bit number (0-7).
+;*
+;* Please observe the difference in using the bit names with instructions
+;* such as "sbr"/"cbr" (set/clear bit in register) and "sbrs"/"sbrc"
+;* (skip if bit in register set/cleared). The following example illustrates
+;* this:
+;*
+;* in r16,PORTB ;read PORTB latch
+;* sbr r16,(1<<PB6)+(1<<PB5) ;set PB6 and PB5 (use masks, not bit#)
+;* out PORTB,r16 ;output to PORTB
+;*
+;* in r16,TIFR ;read the Timer Interrupt Flag Register
+;* sbrc r16,TOV0 ;test the overflow flag (use bit#)
+;* rjmp TOV0_is_set ;jump if set
+;* ... ;otherwise do something else
+;*************************************************************************
+
+#ifndef _M16DEF_INC_
+#define _M16DEF_INC_
+
+
+#pragma partinc 0
+
+; ***** SPECIFY DEVICE ***************************************************
+;.device ATmega16
+#pragma AVRPART ADMIN PART_NAME ATmega16
+.equ SIGNATURE_000, 0x1e
+.equ SIGNATURE_001, 0x94
+.equ SIGNATURE_002, 0x03
+
+#pragma AVRPART CORE CORE_VERSION V2E
+
+
+; ***** I/O REGISTER DEFINITIONS *****************************************
+; NOTE:
+; Definitions marked "MEMORY MAPPED"are extended I/O ports
+; and cannot be used with IN/OUT instructions
+.equ SREG, 0x3f
+.equ SPL, 0x3d
+.equ SPH, 0x3e
+.equ OCR0, 0x3c
+.equ GICR, 0x3b
+.equ GIFR, 0x3a
+.equ TIMSK, 0x39
+.equ TIFR, 0x38
+.equ SPMCSR, 0x37
+.equ TWCR, 0x36
+.equ MCUCR, 0x35
+.equ MCUCSR, 0x34
+.equ TCCR0, 0x33
+.equ TCNT0, 0x32
+.equ OSCCAL, 0x31
+.equ OCDR, 0x31
+.equ SFIOR, 0x30
+.equ TCCR1A, 0x2f
+.equ TCCR1B, 0x2e
+.equ TCNT1L, 0x2c
+.equ TCNT1H, 0x2d
+.equ OCR1AL, 0x2a
+.equ OCR1AH, 0x2b
+.equ OCR1BL, 0x28
+.equ OCR1BH, 0x29
+.equ ICR1L, 0x26
+.equ ICR1H, 0x27
+.equ TCCR2, 0x25
+.equ TCNT2, 0x24
+.equ OCR2, 0x23
+.equ ASSR, 0x22
+.equ WDTCR, 0x21
+.equ UBRRH, 0x20
+.equ UCSRC, 0x20
+.equ EEARL, 0x1e
+.equ EEARH, 0x1f
+.equ EEDR, 0x1d
+.equ EECR, 0x1c
+.equ PORTA, 0x1b
+.equ DDRA, 0x1a
+.equ PINA, 0x19
+.equ PORTB, 0x18
+.equ DDRB, 0x17
+.equ PINB, 0x16
+.equ PORTC, 0x15
+.equ DDRC, 0x14
+.equ PINC, 0x13
+.equ PORTD, 0x12
+.equ DDRD, 0x11
+.equ PIND, 0x10
+.equ SPDR, 0x0f
+.equ SPSR, 0x0e
+.equ SPCR, 0x0d
+.equ UDR, 0x0c
+.equ UCSRA, 0x0b
+.equ UCSRB, 0x0a
+.equ UBRRL, 0x09
+.equ ACSR, 0x08
+.equ ADMUX, 0x07
+.equ ADCSRA, 0x06
+.equ ADCH, 0x05
+.equ ADCL, 0x04
+.equ TWDR, 0x03
+.equ TWAR, 0x02
+.equ TWSR, 0x01
+.equ TWBR, 0x00
+
+
+; ***** BIT DEFINITIONS **************************************************
+
+; ***** TIMER_COUNTER_0 **************
+; TCCR0 - Timer/Counter Control Register
+.equ CS00, 0 ; Clock Select 1
+.equ CS01, 1 ; Clock Select 1
+.equ CS02, 2 ; Clock Select 2
+.equ WGM01, 3 ; Waveform Generation Mode 1
+.equ CTC0, WGM01 ; For compatibility
+.equ COM00, 4 ; Compare match Output Mode 0
+.equ COM01, 5 ; Compare Match Output Mode 1
+.equ WGM00, 6 ; Waveform Generation Mode 0
+.equ PWM0, WGM00 ; For compatibility
+.equ FOC0, 7 ; Force Output Compare
+
+; TCNT0 - Timer/Counter Register
+.equ TCNT0_0, 0 ;
+.equ TCNT0_1, 1 ;
+.equ TCNT0_2, 2 ;
+.equ TCNT0_3, 3 ;
+.equ TCNT0_4, 4 ;
+.equ TCNT0_5, 5 ;
+.equ TCNT0_6, 6 ;
+.equ TCNT0_7, 7 ;
+
+; OCR0 - Output Compare Register
+.equ OCR0_0, 0 ;
+.equ OCR0_1, 1 ;
+.equ OCR0_2, 2 ;
+.equ OCR0_3, 3 ;
+.equ OCR0_4, 4 ;
+.equ OCR0_5, 5 ;
+.equ OCR0_6, 6 ;
+.equ OCR0_7, 7 ;
+
+; TIMSK - Timer/Counter Interrupt Mask Register
+.equ TOIE0, 0 ; Timer/Counter0 Overflow Interrupt Enable
+.equ OCIE0, 1 ; Timer/Counter0 Output Compare Match Interrupt register
+
+; TIFR - Timer/Counter Interrupt Flag register
+.equ TOV0, 0 ; Timer/Counter0 Overflow Flag
+.equ OCF0, 1 ; Output Compare Flag 0
+
+; SFIOR - Special Function IO Register
+.equ PSR10, 0 ; Prescaler Reset Timer/Counter1 and Timer/Counter0
+
+
+; ***** TIMER_COUNTER_1 **************
+; TIMSK - Timer/Counter Interrupt Mask Register
+.equ TOIE1, 2 ; Timer/Counter1 Overflow Interrupt Enable
+.equ OCIE1B, 3 ; Timer/Counter1 Output CompareB Match Interrupt Enable
+.equ OCIE1A, 4 ; Timer/Counter1 Output CompareA Match Interrupt Enable
+.equ TICIE1, 5 ; Timer/Counter1 Input Capture Interrupt Enable
+
+; TIFR - Timer/Counter Interrupt Flag register
+.equ TOV1, 2 ; Timer/Counter1 Overflow Flag
+.equ OCF1B, 3 ; Output Compare Flag 1B
+.equ OCF1A, 4 ; Output Compare Flag 1A
+.equ ICF1, 5 ; Input Capture Flag 1
+
+; TCCR1A - Timer/Counter1 Control Register A
+.equ WGM10, 0 ; Waveform Generation Mode
+.equ PWM10, WGM10 ; For compatibility
+.equ WGM11, 1 ; Waveform Generation Mode
+.equ PWM11, WGM11 ; For compatibility
+.equ FOC1B, 2 ; Force Output Compare 1B
+.equ FOC1A, 3 ; Force Output Compare 1A
+.equ COM1B0, 4 ; Compare Output Mode 1B, bit 0
+.equ COM1B1, 5 ; Compare Output Mode 1B, bit 1
+.equ COM1A0, 6 ; Compare Ouput Mode 1A, bit 0
+.equ COM1A1, 7 ; Compare Output Mode 1A, bit 1
+
+; TCCR1B - Timer/Counter1 Control Register B
+.equ CS10, 0 ; Prescaler source of Timer/Counter 1
+.equ CS11, 1 ; Prescaler source of Timer/Counter 1
+.equ CS12, 2 ; Prescaler source of Timer/Counter 1
+.equ WGM12, 3 ; Waveform Generation Mode
+.equ CTC10, WGM12 ; For compatibility
+.equ CTC1, WGM12 ; For compatibility
+.equ WGM13, 4 ; Waveform Generation Mode
+.equ CTC11, WGM13 ; For compatibility
+.equ ICES1, 6 ; Input Capture 1 Edge Select
+.equ ICNC1, 7 ; Input Capture 1 Noise Canceler
+
+
+; ***** EXTERNAL_INTERRUPT ***********
+; GICR - General Interrupt Control Register
+.equ GIMSK, GICR ; For compatibility
+.equ IVCE, 0 ; Interrupt Vector Change Enable
+.equ IVSEL, 1 ; Interrupt Vector Select
+.equ INT2, 5 ; External Interrupt Request 2 Enable
+.equ INT0, 6 ; External Interrupt Request 0 Enable
+.equ INT1, 7 ; External Interrupt Request 1 Enable
+
+; GIFR - General Interrupt Flag Register
+.equ INTF2, 5 ; External Interrupt Flag 2
+.equ INTF0, 6 ; External Interrupt Flag 0
+.equ INTF1, 7 ; External Interrupt Flag 1
+
+; MCUCR - General Interrupt Control Register
+.equ ISC00, 0 ; Interrupt Sense Control 0 Bit 0
+.equ ISC01, 1 ; Interrupt Sense Control 0 Bit 1
+.equ ISC10, 2 ; Interrupt Sense Control 1 Bit 0
+.equ ISC11, 3 ; Interrupt Sense Control 1 Bit 1
+
+; MCUCSR - MCU Control And Status Register
+.equ ISC2, 6 ; Interrupt Sense Control 2
+
+
+; ***** EEPROM ***********************
+; EEDR - EEPROM Data Register
+.equ EEDR0, 0 ; EEPROM Data Register bit 0
+.equ EEDR1, 1 ; EEPROM Data Register bit 1
+.equ EEDR2, 2 ; EEPROM Data Register bit 2
+.equ EEDR3, 3 ; EEPROM Data Register bit 3
+.equ EEDR4, 4 ; EEPROM Data Register bit 4
+.equ EEDR5, 5 ; EEPROM Data Register bit 5
+.equ EEDR6, 6 ; EEPROM Data Register bit 6
+.equ EEDR7, 7 ; EEPROM Data Register bit 7
+
+; EECR - EEPROM Control Register
+.equ EERE, 0 ; EEPROM Read Enable
+.equ EEWE, 1 ; EEPROM Write Enable
+.equ EEMWE, 2 ; EEPROM Master Write Enable
+.equ EEWEE, EEMWE ; For compatibility
+.equ EERIE, 3 ; EEPROM Ready Interrupt Enable
+
+
+; ***** CPU **************************
+; SREG - Status Register
+.equ SREG_C, 0 ; Carry Flag
+.equ SREG_Z, 1 ; Zero Flag
+.equ SREG_N, 2 ; Negative Flag
+.equ SREG_V, 3 ; Two's Complement Overflow Flag
+.equ SREG_S, 4 ; Sign Bit
+.equ SREG_H, 5 ; Half Carry Flag
+.equ SREG_T, 6 ; Bit Copy Storage
+.equ SREG_I, 7 ; Global Interrupt Enable
+
+; MCUCR - MCU Control Register
+;.equ ISC00, 0 ; Interrupt Sense Control 0 Bit 0
+;.equ ISC01, 1 ; Interrupt Sense Control 0 Bit 1
+;.equ ISC10, 2 ; Interrupt Sense Control 1 Bit 0
+;.equ ISC11, 3 ; Interrupt Sense Control 1 Bit 1
+.equ SM0, 4 ; Sleep Mode Select
+.equ SM1, 5 ; Sleep Mode Select
+.equ SE, 6 ; Sleep Enable
+.equ SM2, 7 ; Sleep Mode Select
+
+; MCUCSR - MCU Control And Status Register
+.equ MCUSR, MCUCSR ; For compatibility
+.equ PORF, 0 ; Power-on reset flag
+.equ EXTRF, 1 ; External Reset Flag
+.equ EXTREF, EXTRF ; For compatibility
+.equ BORF, 2 ; Brown-out Reset Flag
+.equ WDRF, 3 ; Watchdog Reset Flag
+.equ JTRF, 4 ; JTAG Reset Flag
+.equ JTD, 7 ; JTAG Interface Disable
+
+; OSCCAL - Oscillator Calibration Value
+.equ CAL0, 0 ; Oscillator Calibration Value Bit0
+.equ CAL1, 1 ; Oscillator Calibration Value Bit1
+.equ CAL2, 2 ; Oscillator Calibration Value Bit2
+.equ CAL3, 3 ; Oscillator Calibration Value Bit3
+.equ CAL4, 4 ; Oscillator Calibration Value Bit4
+.equ CAL5, 5 ; Oscillator Calibration Value Bit5
+.equ CAL6, 6 ; Oscillator Calibration Value Bit6
+.equ CAL7, 7 ; Oscillator Calibration Value Bit7
+
+; SFIOR - Special function I/O register
+;.equ PSR10, 0 ; Prescaler reset
+.equ PSR2, 1 ; Prescaler reset
+.equ PUD, 2 ; Pull-up Disable
+
+
+; ***** TIMER_COUNTER_2 **************
+; TIMSK - Timer/Counter Interrupt Mask register
+.equ TOIE2, 6 ; Timer/Counter2 Overflow Interrupt Enable
+.equ OCIE2, 7 ; Timer/Counter2 Output Compare Match Interrupt Enable
+
+; TIFR - Timer/Counter Interrupt Flag Register
+.equ TOV2, 6 ; Timer/Counter2 Overflow Flag
+.equ OCF2, 7 ; Output Compare Flag 2
+
+; TCCR2 - Timer/Counter2 Control Register
+.equ CS20, 0 ; Clock Select bit 0
+.equ CS21, 1 ; Clock Select bit 1
+.equ CS22, 2 ; Clock Select bit 2
+.equ WGM21, 3 ; Waveform Generation Mode
+.equ CTC2, WGM21 ; For compatibility
+.equ COM20, 4 ; Compare Output Mode bit 0
+.equ COM21, 5 ; Compare Output Mode bit 1
+.equ WGM20, 6 ; Waveform Genration Mode
+.equ PWM2, WGM20 ; For compatibility
+.equ FOC2, 7 ; Force Output Compare
+
+; TCNT2 - Timer/Counter2
+.equ TCNT2_0, 0 ; Timer/Counter 2 bit 0
+.equ TCNT2_1, 1 ; Timer/Counter 2 bit 1
+.equ TCNT2_2, 2 ; Timer/Counter 2 bit 2
+.equ TCNT2_3, 3 ; Timer/Counter 2 bit 3
+.equ TCNT2_4, 4 ; Timer/Counter 2 bit 4
+.equ TCNT2_5, 5 ; Timer/Counter 2 bit 5
+.equ TCNT2_6, 6 ; Timer/Counter 2 bit 6
+.equ TCNT2_7, 7 ; Timer/Counter 2 bit 7
+
+; OCR2 - Timer/Counter2 Output Compare Register
+.equ OCR2_0, 0 ; Timer/Counter2 Output Compare Register Bit 0
+.equ OCR2_1, 1 ; Timer/Counter2 Output Compare Register Bit 1
+.equ OCR2_2, 2 ; Timer/Counter2 Output Compare Register Bit 2
+.equ OCR2_3, 3 ; Timer/Counter2 Output Compare Register Bit 3
+.equ OCR2_4, 4 ; Timer/Counter2 Output Compare Register Bit 4
+.equ OCR2_5, 5 ; Timer/Counter2 Output Compare Register Bit 5
+.equ OCR2_6, 6 ; Timer/Counter2 Output Compare Register Bit 6
+.equ OCR2_7, 7 ; Timer/Counter2 Output Compare Register Bit 7
+
+; ASSR - Asynchronous Status Register
+.equ TCR2UB, 0 ; Timer/counter Control Register2 Update Busy
+.equ OCR2UB, 1 ; Output Compare Register2 Update Busy
+.equ TCN2UB, 2 ; Timer/Counter2 Update Busy
+.equ AS2, 3 ; Asynchronous Timer/counter2
+
+; SFIOR - Special Function IO Register
+;.equ PSR2, 1 ; Prescaler Reset Timer/Counter2
+
+
+; ***** SPI **************************
+; SPDR - SPI Data Register
+.equ SPDR0, 0 ; SPI Data Register bit 0
+.equ SPDR1, 1 ; SPI Data Register bit 1
+.equ SPDR2, 2 ; SPI Data Register bit 2
+.equ SPDR3, 3 ; SPI Data Register bit 3
+.equ SPDR4, 4 ; SPI Data Register bit 4
+.equ SPDR5, 5 ; SPI Data Register bit 5
+.equ SPDR6, 6 ; SPI Data Register bit 6
+.equ SPDR7, 7 ; SPI Data Register bit 7
+
+; SPSR - SPI Status Register
+.equ SPI2X, 0 ; Double SPI Speed Bit
+.equ WCOL, 6 ; Write Collision Flag
+.equ SPIF, 7 ; SPI Interrupt Flag
+
+; SPCR - SPI Control Register
+.equ SPR0, 0 ; SPI Clock Rate Select 0
+.equ SPR1, 1 ; SPI Clock Rate Select 1
+.equ CPHA, 2 ; Clock Phase
+.equ CPOL, 3 ; Clock polarity
+.equ MSTR, 4 ; Master/Slave Select
+.equ DORD, 5 ; Data Order
+.equ SPE, 6 ; SPI Enable
+.equ SPIE, 7 ; SPI Interrupt Enable
+
+
+; ***** USART ************************
+; UDR - USART I/O Data Register
+.equ UDR0, 0 ; USART I/O Data Register bit 0
+.equ UDR1, 1 ; USART I/O Data Register bit 1
+.equ UDR2, 2 ; USART I/O Data Register bit 2
+.equ UDR3, 3 ; USART I/O Data Register bit 3
+.equ UDR4, 4 ; USART I/O Data Register bit 4
+.equ UDR5, 5 ; USART I/O Data Register bit 5
+.equ UDR6, 6 ; USART I/O Data Register bit 6
+.equ UDR7, 7 ; USART I/O Data Register bit 7
+
+; UCSRA - USART Control and Status Register A
+.equ USR, UCSRA ; For compatibility
+.equ MPCM, 0 ; Multi-processor Communication Mode
+.equ U2X, 1 ; Double the USART transmission speed
+.equ UPE, 2 ; Parity Error
+.equ PE, UPE ; For compatibility
+.equ DOR, 3 ; Data overRun
+.equ FE, 4 ; Framing Error
+.equ UDRE, 5 ; USART Data Register Empty
+.equ TXC, 6 ; USART Transmitt Complete
+.equ RXC, 7 ; USART Receive Complete
+
+; UCSRB - USART Control and Status Register B
+.equ UCR, UCSRB ; For compatibility
+.equ TXB8, 0 ; Transmit Data Bit 8
+.equ RXB8, 1 ; Receive Data Bit 8
+.equ UCSZ2, 2 ; Character Size
+.equ CHR9, UCSZ2 ; For compatibility
+.equ TXEN, 3 ; Transmitter Enable
+.equ RXEN, 4 ; Receiver Enable
+.equ UDRIE, 5 ; USART Data register Empty Interrupt Enable
+.equ TXCIE, 6 ; TX Complete Interrupt Enable
+.equ RXCIE, 7 ; RX Complete Interrupt Enable
+
+; UCSRC - USART Control and Status Register C
+.equ UCPOL, 0 ; Clock Polarity
+.equ UCSZ0, 1 ; Character Size
+.equ UCSZ1, 2 ; Character Size
+.equ USBS, 3 ; Stop Bit Select
+.equ UPM0, 4 ; Parity Mode Bit 0
+.equ UPM1, 5 ; Parity Mode Bit 1
+.equ UMSEL, 6 ; USART Mode Select
+.equ URSEL, 7 ; Register Select
+
+.equ UBRRHI, UBRRH ; For compatibility
+
+; ***** TWI **************************
+; TWBR - TWI Bit Rate register
+.equ I2BR, TWBR ; For compatibility
+.equ TWBR0, 0 ;
+.equ TWBR1, 1 ;
+.equ TWBR2, 2 ;
+.equ TWBR3, 3 ;
+.equ TWBR4, 4 ;
+.equ TWBR5, 5 ;
+.equ TWBR6, 6 ;
+.equ TWBR7, 7 ;
+
+; TWCR - TWI Control Register
+.equ I2CR, TWCR ; For compatibility
+.equ TWIE, 0 ; TWI Interrupt Enable
+.equ I2IE, TWIE ; For compatibility
+.equ TWEN, 2 ; TWI Enable Bit
+.equ I2EN, TWEN ; For compatibility
+.equ ENI2C, TWEN ; For compatibility
+.equ TWWC, 3 ; TWI Write Collition Flag
+.equ I2WC, TWWC ; For compatibility
+.equ TWSTO, 4 ; TWI Stop Condition Bit
+.equ I2STO, TWSTO ; For compatibility
+.equ TWSTA, 5 ; TWI Start Condition Bit
+.equ I2STA, TWSTA ; For compatibility
+.equ TWEA, 6 ; TWI Enable Acknowledge Bit
+.equ I2EA, TWEA ; For compatibility
+.equ TWINT, 7 ; TWI Interrupt Flag
+.equ I2INT, TWINT ; For compatibility
+
+; TWSR - TWI Status Register
+.equ I2SR, TWSR ; For compatibility
+.equ TWPS0, 0 ; TWI Prescaler
+.equ TWS0, TWPS0 ; For compatibility
+.equ I2GCE, TWPS0 ; For compatibility
+.equ TWPS1, 1 ; TWI Prescaler
+.equ TWS1, TWPS1 ; For compatibility
+.equ TWS3, 3 ; TWI Status
+.equ I2S3, TWS3 ; For compatibility
+.equ TWS4, 4 ; TWI Status
+.equ I2S4, TWS4 ; For compatibility
+.equ TWS5, 5 ; TWI Status
+.equ I2S5, TWS5 ; For compatibility
+.equ TWS6, 6 ; TWI Status
+.equ I2S6, TWS6 ; For compatibility
+.equ TWS7, 7 ; TWI Status
+.equ I2S7, TWS7 ; For compatibility
+
+; TWDR - TWI Data register
+.equ I2DR, TWDR ; For compatibility
+.equ TWD0, 0 ; TWI Data Register Bit 0
+.equ TWD1, 1 ; TWI Data Register Bit 1
+.equ TWD2, 2 ; TWI Data Register Bit 2
+.equ TWD3, 3 ; TWI Data Register Bit 3
+.equ TWD4, 4 ; TWI Data Register Bit 4
+.equ TWD5, 5 ; TWI Data Register Bit 5
+.equ TWD6, 6 ; TWI Data Register Bit 6
+.equ TWD7, 7 ; TWI Data Register Bit 7
+
+; TWAR - TWI (Slave) Address register
+.equ I2AR, TWAR ; For compatibility
+.equ TWGCE, 0 ; TWI General Call Recognition Enable Bit
+.equ TWA0, 1 ; TWI (Slave) Address register Bit 0
+.equ TWA1, 2 ; TWI (Slave) Address register Bit 1
+.equ TWA2, 3 ; TWI (Slave) Address register Bit 2
+.equ TWA3, 4 ; TWI (Slave) Address register Bit 3
+.equ TWA4, 5 ; TWI (Slave) Address register Bit 4
+.equ TWA5, 6 ; TWI (Slave) Address register Bit 5
+.equ TWA6, 7 ; TWI (Slave) Address register Bit 6
+
+
+; ***** ANALOG_COMPARATOR ************
+; SFIOR - Special Function IO Register
+.equ ACME, 3 ; Analog Comparator Multiplexer Enable
+
+; ACSR - Analog Comparator Control And Status Register
+.equ ACIS0, 0 ; Analog Comparator Interrupt Mode Select bit 0
+.equ ACIS1, 1 ; Analog Comparator Interrupt Mode Select bit 1
+.equ ACIC, 2 ; Analog Comparator Input Capture Enable
+.equ ACIE, 3 ; Analog Comparator Interrupt Enable
+.equ ACI, 4 ; Analog Comparator Interrupt Flag
+.equ ACO, 5 ; Analog Compare Output
+.equ ACBG, 6 ; Analog Comparator Bandgap Select
+.equ ACD, 7 ; Analog Comparator Disable
+
+
+; ***** AD_CONVERTER *****************
+; ADMUX - The ADC multiplexer Selection Register
+.equ MUX0, 0 ; Analog Channel and Gain Selection Bits
+.equ MUX1, 1 ; Analog Channel and Gain Selection Bits
+.equ MUX2, 2 ; Analog Channel and Gain Selection Bits
+.equ MUX3, 3 ; Analog Channel and Gain Selection Bits
+.equ MUX4, 4 ; Analog Channel and Gain Selection Bits
+.equ ADLAR, 5 ; Left Adjust Result
+.equ REFS0, 6 ; Reference Selection Bit 0
+.equ REFS1, 7 ; Reference Selection Bit 1
+
+; ADCSRA - The ADC Control and Status register
+.equ ADCSR, ADCSRA ; For compatibility
+.equ ADPS0, 0 ; ADC Prescaler Select Bits
+.equ ADPS1, 1 ; ADC Prescaler Select Bits
+.equ ADPS2, 2 ; ADC Prescaler Select Bits
+.equ ADIE, 3 ; ADC Interrupt Enable
+.equ ADIF, 4 ; ADC Interrupt Flag
+.equ ADATE, 5 ; When this bit is written to one,the Timer/Counter2 prescaler will be reset.The bit will be cleared by hardware after the operation is performed.Writing a zero to this bit will have no effect.This bit will always be read as zero if Timer/Counter2 is clocked by the internal CPU clock.If this bit is written when Timer/Counter2 is operating in asynchronous mode,the bit will remain one until the prescaler has been reset.
+.equ ADFR, ADATE ; For compatibility
+.equ ADSC, 6 ; ADC Start Conversion
+.equ ADEN, 7 ; ADC Enable
+
+; ADCH - ADC Data Register High Byte
+.equ ADCH0, 0 ; ADC Data Register High Byte Bit 0
+.equ ADCH1, 1 ; ADC Data Register High Byte Bit 1
+.equ ADCH2, 2 ; ADC Data Register High Byte Bit 2
+.equ ADCH3, 3 ; ADC Data Register High Byte Bit 3
+.equ ADCH4, 4 ; ADC Data Register High Byte Bit 4
+.equ ADCH5, 5 ; ADC Data Register High Byte Bit 5
+.equ ADCH6, 6 ; ADC Data Register High Byte Bit 6
+.equ ADCH7, 7 ; ADC Data Register High Byte Bit 7
+
+; ADCL - ADC Data Register Low Byte
+.equ ADCL0, 0 ; ADC Data Register Low Byte Bit 0
+.equ ADCL1, 1 ; ADC Data Register Low Byte Bit 1
+.equ ADCL2, 2 ; ADC Data Register Low Byte Bit 2
+.equ ADCL3, 3 ; ADC Data Register Low Byte Bit 3
+.equ ADCL4, 4 ; ADC Data Register Low Byte Bit 4
+.equ ADCL5, 5 ; ADC Data Register Low Byte Bit 5
+.equ ADCL6, 6 ; ADC Data Register Low Byte Bit 6
+.equ ADCL7, 7 ; ADC Data Register Low Byte Bit 7
+
+; SFIOR - Special Function IO Register
+.equ ADTS0, 5 ; ADC Auto Trigger Source 0
+.equ ADTS1, 6 ; ADC Auto Trigger Source 1
+.equ ADTS2, 7 ; ADC Auto Trigger Source 2
+
+
+; ***** JTAG *************************
+; OCDR - On-Chip Debug Related Register in I/O Memory
+.equ OCDR0, 0 ; On-Chip Debug Register Bit 0
+.equ OCDR1, 1 ; On-Chip Debug Register Bit 1
+.equ OCDR2, 2 ; On-Chip Debug Register Bit 2
+.equ OCDR3, 3 ; On-Chip Debug Register Bit 3
+.equ OCDR4, 4 ; On-Chip Debug Register Bit 4
+.equ OCDR5, 5 ; On-Chip Debug Register Bit 5
+.equ OCDR6, 6 ; On-Chip Debug Register Bit 6
+.equ OCDR7, 7 ; On-Chip Debug Register Bit 7
+.equ IDRD, OCDR7 ; For compatibility
+
+; MCUCSR - MCU Control And Status Register
+;.equ JTRF, 4 ; JTAG Reset Flag
+;.equ JTD, 7 ; JTAG Interface Disable
+
+
+; ***** BOOT_LOAD ********************
+; SPMCSR - Store Program Memory Control Register
+.equ SPMCR, SPMCSR ; For compatibility
+.equ SPMEN, 0 ; Store Program Memory Enable
+.equ PGERS, 1 ; Page Erase
+.equ PGWRT, 2 ; Page Write
+.equ BLBSET, 3 ; Boot Lock Bit Set
+.equ RWWSRE, 4 ; Read While Write section read enable
+.equ ASRE, RWWSRE ; For compatibility
+.equ RWWSB, 6 ; Read While Write Section Busy
+.equ ASB, RWWSB ; For compatibility
+.equ SPMIE, 7 ; SPM Interrupt Enable
+
+
+; ***** PORTA ************************
+; PORTA - Port A Data Register
+.equ PORTA0, 0 ; Port A Data Register bit 0
+.equ PA0, 0 ; For compatibility
+.equ PORTA1, 1 ; Port A Data Register bit 1
+.equ PA1, 1 ; For compatibility
+.equ PORTA2, 2 ; Port A Data Register bit 2
+.equ PA2, 2 ; For compatibility
+.equ PORTA3, 3 ; Port A Data Register bit 3
+.equ PA3, 3 ; For compatibility
+.equ PORTA4, 4 ; Port A Data Register bit 4
+.equ PA4, 4 ; For compatibility
+.equ PORTA5, 5 ; Port A Data Register bit 5
+.equ PA5, 5 ; For compatibility
+.equ PORTA6, 6 ; Port A Data Register bit 6
+.equ PA6, 6 ; For compatibility
+.equ PORTA7, 7 ; Port A Data Register bit 7
+.equ PA7, 7 ; For compatibility
+
+; DDRA - Port A Data Direction Register
+.equ DDA0, 0 ; Data Direction Register, Port A, bit 0
+.equ DDA1, 1 ; Data Direction Register, Port A, bit 1
+.equ DDA2, 2 ; Data Direction Register, Port A, bit 2
+.equ DDA3, 3 ; Data Direction Register, Port A, bit 3
+.equ DDA4, 4 ; Data Direction Register, Port A, bit 4
+.equ DDA5, 5 ; Data Direction Register, Port A, bit 5
+.equ DDA6, 6 ; Data Direction Register, Port A, bit 6
+.equ DDA7, 7 ; Data Direction Register, Port A, bit 7
+
+; PINA - Port A Input Pins
+.equ PINA0, 0 ; Input Pins, Port A bit 0
+.equ PINA1, 1 ; Input Pins, Port A bit 1
+.equ PINA2, 2 ; Input Pins, Port A bit 2
+.equ PINA3, 3 ; Input Pins, Port A bit 3
+.equ PINA4, 4 ; Input Pins, Port A bit 4
+.equ PINA5, 5 ; Input Pins, Port A bit 5
+.equ PINA6, 6 ; Input Pins, Port A bit 6
+.equ PINA7, 7 ; Input Pins, Port A bit 7
+
+
+; ***** PORTB ************************
+; PORTB - Port B Data Register
+.equ PORTB0, 0 ; Port B Data Register bit 0
+.equ PB0, 0 ; For compatibility
+.equ PORTB1, 1 ; Port B Data Register bit 1
+.equ PB1, 1 ; For compatibility
+.equ PORTB2, 2 ; Port B Data Register bit 2
+.equ PB2, 2 ; For compatibility
+.equ PORTB3, 3 ; Port B Data Register bit 3
+.equ PB3, 3 ; For compatibility
+.equ PORTB4, 4 ; Port B Data Register bit 4
+.equ PB4, 4 ; For compatibility
+.equ PORTB5, 5 ; Port B Data Register bit 5
+.equ PB5, 5 ; For compatibility
+.equ PORTB6, 6 ; Port B Data Register bit 6
+.equ PB6, 6 ; For compatibility
+.equ PORTB7, 7 ; Port B Data Register bit 7
+.equ PB7, 7 ; For compatibility
+
+; DDRB - Port B Data Direction Register
+.equ DDB0, 0 ; Port B Data Direction Register bit 0
+.equ DDB1, 1 ; Port B Data Direction Register bit 1
+.equ DDB2, 2 ; Port B Data Direction Register bit 2
+.equ DDB3, 3 ; Port B Data Direction Register bit 3
+.equ DDB4, 4 ; Port B Data Direction Register bit 4
+.equ DDB5, 5 ; Port B Data Direction Register bit 5
+.equ DDB6, 6 ; Port B Data Direction Register bit 6
+.equ DDB7, 7 ; Port B Data Direction Register bit 7
+
+; PINB - Port B Input Pins
+.equ PINB0, 0 ; Port B Input Pins bit 0
+.equ PINB1, 1 ; Port B Input Pins bit 1
+.equ PINB2, 2 ; Port B Input Pins bit 2
+.equ PINB3, 3 ; Port B Input Pins bit 3
+.equ PINB4, 4 ; Port B Input Pins bit 4
+.equ PINB5, 5 ; Port B Input Pins bit 5
+.equ PINB6, 6 ; Port B Input Pins bit 6
+.equ PINB7, 7 ; Port B Input Pins bit 7
+
+
+; ***** PORTC ************************
+; PORTC - Port C Data Register
+.equ PORTC0, 0 ; Port C Data Register bit 0
+.equ PC0, 0 ; For compatibility
+.equ PORTC1, 1 ; Port C Data Register bit 1
+.equ PC1, 1 ; For compatibility
+.equ PORTC2, 2 ; Port C Data Register bit 2
+.equ PC2, 2 ; For compatibility
+.equ PORTC3, 3 ; Port C Data Register bit 3
+.equ PC3, 3 ; For compatibility
+.equ PORTC4, 4 ; Port C Data Register bit 4
+.equ PC4, 4 ; For compatibility
+.equ PORTC5, 5 ; Port C Data Register bit 5
+.equ PC5, 5 ; For compatibility
+.equ PORTC6, 6 ; Port C Data Register bit 6
+.equ PC6, 6 ; For compatibility
+.equ PORTC7, 7 ; Port C Data Register bit 7
+.equ PC7, 7 ; For compatibility
+
+; DDRC - Port C Data Direction Register
+.equ DDC0, 0 ; Port C Data Direction Register bit 0
+.equ DDC1, 1 ; Port C Data Direction Register bit 1
+.equ DDC2, 2 ; Port C Data Direction Register bit 2
+.equ DDC3, 3 ; Port C Data Direction Register bit 3
+.equ DDC4, 4 ; Port C Data Direction Register bit 4
+.equ DDC5, 5 ; Port C Data Direction Register bit 5
+.equ DDC6, 6 ; Port C Data Direction Register bit 6
+.equ DDC7, 7 ; Port C Data Direction Register bit 7
+
+; PINC - Port C Input Pins
+.equ PINC0, 0 ; Port C Input Pins bit 0
+.equ PINC1, 1 ; Port C Input Pins bit 1
+.equ PINC2, 2 ; Port C Input Pins bit 2
+.equ PINC3, 3 ; Port C Input Pins bit 3
+.equ PINC4, 4 ; Port C Input Pins bit 4
+.equ PINC5, 5 ; Port C Input Pins bit 5
+.equ PINC6, 6 ; Port C Input Pins bit 6
+.equ PINC7, 7 ; Port C Input Pins bit 7
+
+
+; ***** PORTD ************************
+; PORTD - Port D Data Register
+.equ PORTD0, 0 ; Port D Data Register bit 0
+.equ PD0, 0 ; For compatibility
+.equ PORTD1, 1 ; Port D Data Register bit 1
+.equ PD1, 1 ; For compatibility
+.equ PORTD2, 2 ; Port D Data Register bit 2
+.equ PD2, 2 ; For compatibility
+.equ PORTD3, 3 ; Port D Data Register bit 3
+.equ PD3, 3 ; For compatibility
+.equ PORTD4, 4 ; Port D Data Register bit 4
+.equ PD4, 4 ; For compatibility
+.equ PORTD5, 5 ; Port D Data Register bit 5
+.equ PD5, 5 ; For compatibility
+.equ PORTD6, 6 ; Port D Data Register bit 6
+.equ PD6, 6 ; For compatibility
+.equ PORTD7, 7 ; Port D Data Register bit 7
+.equ PD7, 7 ; For compatibility
+
+; DDRD - Port D Data Direction Register
+.equ DDD0, 0 ; Port D Data Direction Register bit 0
+.equ DDD1, 1 ; Port D Data Direction Register bit 1
+.equ DDD2, 2 ; Port D Data Direction Register bit 2
+.equ DDD3, 3 ; Port D Data Direction Register bit 3
+.equ DDD4, 4 ; Port D Data Direction Register bit 4
+.equ DDD5, 5 ; Port D Data Direction Register bit 5
+.equ DDD6, 6 ; Port D Data Direction Register bit 6
+.equ DDD7, 7 ; Port D Data Direction Register bit 7
+
+; PIND - Port D Input Pins
+.equ PIND0, 0 ; Port D Input Pins bit 0
+.equ PIND1, 1 ; Port D Input Pins bit 1
+.equ PIND2, 2 ; Port D Input Pins bit 2
+.equ PIND3, 3 ; Port D Input Pins bit 3
+.equ PIND4, 4 ; Port D Input Pins bit 4
+.equ PIND5, 5 ; Port D Input Pins bit 5
+.equ PIND6, 6 ; Port D Input Pins bit 6
+.equ PIND7, 7 ; Port D Input Pins bit 7
+
+
+; ***** WATCHDOG *********************
+; WDTCR - Watchdog Timer Control Register
+.equ WDP0, 0 ; Watch Dog Timer Prescaler bit 0
+.equ WDP1, 1 ; Watch Dog Timer Prescaler bit 1
+.equ WDP2, 2 ; Watch Dog Timer Prescaler bit 2
+.equ WDE, 3 ; Watch Dog Enable
+.equ WDTOE, 4 ; RW
+.equ WDDE, WDTOE ; For compatibility
+
+
+
+; ***** LOCKSBITS ********************************************************
+.equ LB1, 0 ; Lock bit
+.equ LB2, 1 ; Lock bit
+.equ BLB01, 2 ; Boot Lock bit
+.equ BLB02, 3 ; Boot Lock bit
+.equ BLB11, 4 ; Boot lock bit
+.equ BLB12, 5 ; Boot lock bit
+
+
+; ***** FUSES ************************************************************
+; LOW fuse bits
+.equ CKSEL0, 0 ; Select Clock Source
+.equ CKSEL1, 1 ; Select Clock Source
+.equ CKSEL2, 2 ; Select Clock Source
+.equ CKSEL3, 3 ; Select Clock Source
+.equ SUT0, 4 ; Select start-up time
+.equ SUT1, 5 ; Select start-up time
+.equ BODEN, 6 ; Brown out detector enable
+.equ BODLEVEL, 7 ; Brown out detector trigger level
+
+; HIGH fuse bits
+.equ BOOTRST, 0 ; Select Reset Vector
+.equ BOOTSZ0, 1 ; Select Boot Size
+.equ BOOTSZ1, 2 ; Select Boot Size
+.equ EESAVE, 3 ; EEPROM memory is preserved through chip erase
+.equ CKOPT, 4 ; Oscillator Options
+.equ SPIEN, 5 ; Enable Serial programming and Data Downloading
+.equ JTAGEN, 6 ; Enable JTAG
+.equ OCDEN, 7 ; Enable OCD
+
+
+
+; ***** CPU REGISTER DEFINITIONS *****************************************
+#define XH r27
+#define XL r26
+#define YH r29
+#define YL r28
+#define ZH r31
+#define ZL r30
+
+
+
+; ***** DATA MEMORY DECLARATIONS *****************************************
+.equ FLASHEND, 0x1fff ; Note: Word address
+.equ IOEND, 0x003f
+.equ SRAM_START, 0x0060
+.equ SRAM_SIZE, 1024
+.equ RAMEND, 0x045f
+.equ XRAMEND, 0x0000
+.equ E2END, 0x01ff
+.equ EEPROMEND, 0x01ff
+.equ EEADRBITS, 9
+#pragma AVRPART MEMORY PROG_FLASH 16384
+#pragma AVRPART MEMORY EEPROM 512
+#pragma AVRPART MEMORY INT_SRAM SIZE 1024
+#pragma AVRPART MEMORY INT_SRAM START_ADDR 0x60
+
+
+
+; ***** BOOTLOADER DECLARATIONS ******************************************
+.equ NRWW_START_ADDR, 0x1c00
+.equ NRWW_STOP_ADDR, 0x1fff
+.equ RWW_START_ADDR, 0x0
+.equ RWW_STOP_ADDR, 0x1bff
+.equ PAGESIZE, 64
+.equ FIRSTBOOTSTART, 0x1f80
+.equ SECONDBOOTSTART, 0x1f00
+.equ THIRDBOOTSTART, 0x1e00
+.equ FOURTHBOOTSTART, 0x1c00
+.equ SMALLBOOTSTART, FIRSTBOOTSTART
+.equ LARGEBOOTSTART, FOURTHBOOTSTART
+
+
+
+; ***** INTERRUPT VECTORS ************************************************
+.equ INT0addr, 0x0002 ; External Interrupt Request 0
+.equ INT1addr, 0x0004 ; External Interrupt Request 1
+.equ OC2addr, 0x0006 ; Timer/Counter2 Compare Match
+.equ OVF2addr, 0x0008 ; Timer/Counter2 Overflow
+.equ ICP1addr, 0x000a ; Timer/Counter1 Capture Event
+.equ OC1Aaddr, 0x000c ; Timer/Counter1 Compare Match A
+.equ OC1Baddr, 0x000e ; Timer/Counter1 Compare Match B
+.equ OVF1addr, 0x0010 ; Timer/Counter1 Overflow
+.equ OVF0addr, 0x0012 ; Timer/Counter0 Overflow
+.equ SPIaddr, 0x0014 ; Serial Transfer Complete
+.equ URXCaddr, 0x0016 ; USART, Rx Complete
+.equ UDREaddr, 0x0018 ; USART Data Register Empty
+.equ UTXCaddr, 0x001a ; USART, Tx Complete
+.equ ADCCaddr, 0x001c ; ADC Conversion Complete
+.equ ERDYaddr, 0x001e ; EEPROM Ready
+.equ ACIaddr, 0x0020 ; Analog Comparator
+.equ TWIaddr, 0x0022 ; 2-wire Serial Interface
+.equ INT2addr, 0x0024 ; External Interrupt Request 2
+.equ OC0addr, 0x0026 ; Timer/Counter0 Compare Match
+.equ SPMRaddr, 0x0028 ; Store Program Memory Ready
+
+.equ INT_VECTORS_SIZE, 42 ; size in words
+
+#endif /* _M16DEF_INC_ */
+
+; ***** END OF FILE ******************************************************
diff --git a/numtest.c b/numtest.c
new file mode 100644
index 0000000..50aeca4
--- /dev/null
+++ b/numtest.c
@@ -0,0 +1,30 @@
+#include <util/delay.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libleds.h"
+#include "chars/chars.h"
+
+static struct led_obj const PANEL = {0, 1<<7, 32, 8};
+
+void led_main()
+{
+ // clear
+ struct led_color const clear_color = { 0, 0, 0 };
+ led_write_rgb_all(PANEL, clear_color);
+
+ const struct led_color active_color = {0x10, 0x10, 0x10};
+ const char *text = "0123";
+ struct led_color *buf = leds_text(active_color, text);
+
+ if (buf == NULL) {
+ return;
+ }
+
+ struct led_color const padding = { 0, 0, 0 };
+ for (unsigned int i = 0; i < 4*char_height; i++)
+ led_write_rgb(PANEL.port, PANEL.pins, padding);
+ for (unsigned int i = 0; i < char_length * strlen(text); i++)
+ led_write_rgb(PANEL.port, PANEL.pins, buf[i]);
+
+ free(buf);
+}
diff --git a/pulse.c b/pulse.c
new file mode 100644
index 0000000..d5d186e
--- /dev/null
+++ b/pulse.c
@@ -0,0 +1,24 @@
+#include "libleds.h"
+
+static struct led_obj const PANEL = {0, 1<<7, 32, 8};
+
+void update(int i)
+{
+ struct led_color const color = {i, i, i};
+ led_write_rgb_all(PANEL, color);
+ led_latch();
+}
+
+void led_main()
+{
+ static int const STEP = 0x01;
+ static int const MIN = 0x00;
+ static int const MAX = 0xFF;
+
+ while (1) {
+ for (int i = MIN; i < MAX; i += STEP)
+ update(i);
+ for (int i = MAX; i > MIN; i += STEP)
+ update(i);
+ }
+}
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..176223f
--- /dev/null
+++ b/test.c
@@ -0,0 +1,22 @@
+#include "libleds.h"
+
+static struct led_obj const PANEL = {0, 1<<7, 32, 8};
+static unsigned char const INTENSITY = 0x01;
+
+void led_main()
+{
+ struct led_color const colors[] = {
+ {0x0000000, 0x0000000, 0x0000000},
+ {INTENSITY, 0x0000000, 0x0000000},
+ {0x0000000, INTENSITY, 0x0000000},
+ {INTENSITY, INTENSITY, 0x0000000},
+ {0x0000000, 0x0000000, INTENSITY},
+ {INTENSITY, 0x0000000, INTENSITY},
+ {0x0000000, INTENSITY, INTENSITY},
+ {INTENSITY, INTENSITY, INTENSITY},
+ };
+
+ for(int x = 0; x < PANEL.width; x++)
+ for (int i = 0; i < (sizeof(colors) / sizeof(colors[0])); i++)
+ led_write_rgb(PANEL.port, PANEL.pins, colors[i]);
+}