aboutsummaryrefslogtreecommitdiff
path: root/fw/transpose.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/transpose.c')
-rw-r--r--fw/transpose.c47
1 files changed, 45 insertions, 2 deletions
diff --git a/fw/transpose.c b/fw/transpose.c
index a6c7e71..7af3e8e 100644
--- a/fw/transpose.c
+++ b/fw/transpose.c
@@ -4,14 +4,52 @@
#include "transpose.h"
+/* This file contains conversion routines that pre-format the brightness data
+ * received from the UART such that the interrupt service routines only need to
+ * push it out the SPI without further computation, making these ISRs nice and
+ * tight.
+ *
+ * To understand this code note the multiplexing scheme used on the board. The
+ * circuit contains two MBI5026 shift-register LED drivers of 16 channels each
+ * cascaded. Effectively this behaves like a 32-channel LED driver fed data
+ * serially. Each output is connected to a single digit's COM pin. All digit's
+ * segment anode pins are connected together in a large bus fed by one of the
+ * two auxiliary shift registers.
+ *
+ * The firmware is selecting each segment in turn with a full BCM cycle for each
+ * segment before the next one is selected.
+ */
+
+/* This array maps the 32 adressable digits on a board to the 32 bits shifted
+ * out to the LED drivers. */
uint8_t digit_map[33] = {
0, 1, 2, 3, 28,29,30,31,
4, 5, 6, 7, 24,25,26,27,
8, 9,10,11, 20,21,22,23,
12,13,14,15, 16,17,18,19
};
-void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb) {
+
+/* This function produces a 10-bit output buffer ready for the modulation ISRs
+ * from 10-bit input data encoded for the UART. For the precise data format, see
+ * transpose.h.
+ *
+ * On the UART side we have digits in the order defined in digit_map, 10 byte
+ * per digit. The first 8 bytes are the 8 LSBs of each segments brightness value
+ * in the order [A, B, C, D, E, F, G, DECIMAL_POINT]. The two MSBs to make each
+ * value 10-bit are bit-packed into the remaining two bytes in big-endian byte
+ * order starting from DP.
+ *
+ * On the display frame buffer side, data is stored in multiplexing order:
+ * first digits, then time/bits and finally segments. So for each segment you
+ * have a large buffer containing all the bit periods and digits, and for each
+ * bit period you have 32 bits for all 32 digits.
+ */
+void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb)
+{
+ /* FIXME this can probably be removed. */
memset((uint8_t *)out_fb, 0, sizeof(*out_fb));
+
+ /* 8 MSB loop */
struct data_format *rxp = (struct data_format *)rx_buf;
for (int bit=0; bit<8; bit++) { /* bits */
uint32_t bit_mask = 1U<<bit;
@@ -27,6 +65,8 @@ void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb)
*outp = acc;
}
}
+
+ /* 2 packed LSB loop */
for (int bit=0; bit<2; bit++) { /* bits */
volatile uint32_t *frame_data = out_fb->frame[bit].data;
for (int seg=0; seg<8; seg++) { /* segments */
@@ -40,10 +80,13 @@ void transpose_data(volatile uint8_t *rx_buf, volatile struct framebuf *out_fb)
frame_data[seg] = acc;
}
}
+
+ /* Global analog brightness value */
out_fb->brightness = ((volatile struct framebuf *)rx_buf)->brightness;
}
-
+/* This function was used for testing transpose_data. It does precisely the
+ * reverse operation. */
void untranspose_data(struct framebuf *fb, uint8_t *txbuf) {
memset(txbuf, 0, sizeof(*fb));