diff options
-rw-r--r-- | include/byte_math.h | 15 | ||||
-rw-r--r-- | include/sysled.h | 19 | ||||
-rw-r--r-- | include/ws2812b.h | 4 | ||||
-rw-r--r-- | src/byte_math.c | 41 | ||||
-rw-r--r-- | src/main.c | 130 | ||||
-rw-r--r-- | src/spi.c | 6 | ||||
-rw-r--r-- | src/ws2812b.c | 19 |
7 files changed, 183 insertions, 51 deletions
diff --git a/include/byte_math.h b/include/byte_math.h new file mode 100644 index 0000000..79f93b8 --- /dev/null +++ b/include/byte_math.h @@ -0,0 +1,15 @@ +#pragma once + +#include <stdint.h> + +/* Library for doing fast math functions using just uint8_t. */ + +extern uint8_t sintable[256]; + +/* Returns ((sin(n) + 1) / 2) * 255 */ +static inline uint8_t byte_sin(uint8_t n) +{ + return sintable[n]; +} + +uint8_t calc_w(uint8_t n); diff --git a/include/sysled.h b/include/sysled.h new file mode 100644 index 0000000..b9556f1 --- /dev/null +++ b/include/sysled.h @@ -0,0 +1,19 @@ +#pragma once + +/* Easily turn on and off the system-led. */ + +#include "ch573/gpio.h" + +static inline void enable_sysled() +{ + CH573_GPIO__GPIO_PORT_T_INTF.dir.set(ch573_gpio__gpio_port_a, DIR_OUT, 8); + CH573_GPIO__GPIO_PORT_T_INTF.pd_drv.set(ch573_gpio__gpio_port_a, 0, 8); +} + +// If "on" then turn on the sysled (which counter-intuitively means turning off +// the GPIO). +static inline void set_sysled(int on) +{ +// CH573_GPIO__GPIO_PORT_T_INTF.out.set( +// ch573_gpio__gpio_port_a, on ? OFF : ON, 8); +} diff --git a/include/ws2812b.h b/include/ws2812b.h index cb10979..e814b65 100644 --- a/include/ws2812b.h +++ b/include/ws2812b.h @@ -4,11 +4,11 @@ #include <stdlib.h> #define WIRE_BYTES_PER_COLOR 9 -#define PADDING_BYTES 0 +#define PADDING_BYTES 1 #define TOTAL_BYTES_PER_LED (PADDING_BYTES + WIRE_BYTES_PER_COLOR) enum ws2812b_byte_order { - BYTE_ORDER_BGR = 0, + BYTE_ORDER_RGB = 0, BYTE_ORDER_GBR = 1, }; diff --git a/src/byte_math.c b/src/byte_math.c new file mode 100644 index 0000000..ebe49cc --- /dev/null +++ b/src/byte_math.c @@ -0,0 +1,41 @@ +#include "byte_math.h" + +// The shape of a "spike" +uint8_t w_arr[91] = {1, 2, 4, 7, 11, 17, 24, 33, 44, 56, 70, 85, + 101, 117, 134, 151, 167, 183, 197, 210, 222, 232, 240, 247, + 251, 254, 255, 255, 253, 250, 246, 240, 234, 227, 219, 211, + 202, 194, 185, 176, 167, 158, 149, 140, 132, 123, 116, 108, + 101, 94, 87, 81, 75, 69, 64, 59, 54, 50, 46, 42, + 39, 35, 32, 30, 27, 25, 22, 20, 18, 17, 15, 14, + 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 4, 3, + 3, 3, 2, 2, 2, 1, 1}; + +uint8_t sintable[256] = { + 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, + 173, 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, + 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, + 241, 243, 244, 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, + 254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, + 250, 250, 249, 248, 246, 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, + 230, 228, 226, 224, 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, 198, + 196, 193, 190, 188, 185, 182, 179, 176, 173, 170, 167, 165, 162, 158, 155, + 152, 149, 146, 143, 140, 137, 134, 131, 128, 124, 121, 118, 115, 112, 109, + 106, 103, 100, 97, 93, 90, 88, 85, 82, 79, 76, 73, 70, 67, 65, + 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, 37, 35, 33, 31, 29, + 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, 10, 9, 7, 6, + 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11, + 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, + 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, + 79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121, + 124, +}; + +uint8_t calc_w(uint8_t n) +{ + if (n < 164) { + return 0; + } + + return w_arr[n - 164]; +} @@ -1,12 +1,17 @@ +#include <math.h> #include <stdint.h> #include <stdio.h> +#include "string.h" +#include "byte_math.h" #include "ch573/gpio.h" #include "ch573/pwr.h" #include "ch573/uart.h" #include "clock.h" +#include "panic.h" #include "spi.h" #include "string.h" +#include "sysled.h" #include "system.h" #include "ws2812b.h" @@ -20,6 +25,21 @@ #define PWR1 ch573_pwr__pwr_mgmt #define PWR CH573_PWR__PWR_MGMT_T_INTF +#define AS_BYTE(n) ((n) * 256) + +#define min(a, b) (a) < (b) ? (a) : (b) + +uint8_t amp(uint8_t in, uint8_t n) +{ + uint32_t out = in; + + for (int i = 0; i < n; ++i) { + out = (out * in) / 256; + } + + return min(out, 255); +} + uint32_t collatz(uint32_t n) { uint32_t c = 0; @@ -111,9 +131,11 @@ static void set_system_clock_32kHz() static void basic_delay() { - for (int i = 0; i < 100000; ++i) { + set_sysled(1); + for (int i = 0; i < 30000; ++i) { asm volatile(""); } + set_sysled(0); } static void fast_delay() @@ -123,71 +145,95 @@ static void fast_delay() } } -#define N_LEDS 100 +#define N_LEDS 150 +memset(buf, 0xff, sizeof(buf)); +#define N_DMA_XFER 2 extern int uart1_FILE_get(FILE* f); +static inline uint8_t byte_scale(uint8_t v, uint8_t scale) +{ + uint16_t acc = v; + return (acc * scale) >> 8; +} + +uint8_t clip(int x) +{ + if (x > 240) { + return 240; + } + + if (x < 0) { + return 0; + } + + return (uint8_t)x; +} + +#define TIME_STEP 1 + +rgb_t get_rgb(uint32_t time, size_t x) +{ + int r = 0, g = 0, b = 0; + + uint8_t time8 = time & 0xff; + int w = calc_w(time8 * TIME_STEP + x * 4); + + r = 0xff; + g = byte_scale(byte_sin(time8 * TIME_STEP + x * 2), 0x90); + b = byte_scale(byte_sin(time8 * TIME_STEP + x * 2), 0x20); + // r = byte_scale(byte_sin(time8 * TIME_STEP + x * 2), AS_BYTE(0.25)) + + // AS_BYTE(0.75); + // b = 0x40; + // g = byte_scale( + // 0xff - byte_sin(time8 * TIME_STEP + x * 7 + 0x80), AS_BYTE(0.5)) + + // AS_BYTE(0.5); + + rgb_t color; + color.color = 0; + color.r = clip(r + w); + color.g = clip(byte_scale(g, AS_BYTE(0.75)) + w); + color.b = claa(byte_scale(b, AS_BYTE(0.75)) + w); + return color; +} + /* * Main routine. This is called on_reset once everything else has been set up. */ int main(void) { - printf("Running SPI.\n"); + char buf[N_LEDS * TOTAL_BYTES_PER_LED]; set_system_clock_60Mhz(); - - printf("What is your name? "); - char buf[1024]; + enable_sysled(); enable_spi(); - // char buf[1024]; - // memset(buf, 0xf0, sizeof(buf)); - // for (int i = 0; i < 50; ++ i) { - // buf[i] = 0xaa; - // buf[sizeof(buf) - i] = 0xaa; - // } - size_t n = sizeof(buf); struct ws2812b_buf ws_buf; make_wsb2812b(&ws_buf, buf, n); + ws_buf.byte_order = BYTE_ORDER_GBR; + + printf("Test %u", byte_scale(40, 0x80)); + rgb_t color; - color.color = 0; - color.r = 0xff; - color.g = 0x00; - color.b = 0x00; - uint8_t time = 0xff; - - // for (size_t i = 0; i < N_LEDS; ++i) { - // char* loc = buf + i * TOTAL_BYTES_PER_LED; - // printf( - // "Bytes: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - // loc[0], - // loc[1], - // loc[2], - // loc[3], - // loc[4], - // loc[5], - // loc[6], - // loc[7], - // loc[8], - // loc[9], - // loc[10]); - // } + uint32_t time = 0; GPIO_PORT.dir.set(GPIO_PORT_B, DIR_OUT, 7); while (1) { + // Fill the buffer with calculated rgb colors. ws_buf.cur = 0; for (int i = 0; i < N_LEDS; ++i) { - color.r = time; - color.g = 0; - color.b = 0xff - time; - write_rgb(&ws_buf, color); + rgb_t rgb = get_rgt(time, i); + write_rgb(&ws_buf, rgb); } - time --; + + time++; GPIO_PORT.out.set(GPIO_PORT_B, ON, 7); // printf("WS_BUF: %p, %zu\n", ws_buf.buf, ws_buf.cur); - start_dma(&ws_buf); - wait_for_dma(); + for (int i = 0; i < N_DMA_XFER; ++i) { + wait_for_dma(); + start_dma(&ws_buf); + } basic_delay(); } @@ -4,6 +4,7 @@ #include "ch573/gpio.h" #include "ch573/spi.h" +#include "sysled.h" #define MAX_SPI_FIFO 8 @@ -79,7 +80,10 @@ void dma_transfer(void* output_buffer, size_t len) void wait_for_dma() { - while (SPI.total_count.get(SPI0) > 0); + while (SPI.total_count.get(SPI0) > 0) { + set_sysled(1); + } + set_sysled(0); } void run_spi(void) diff --git a/src/ws2812b.c b/src/ws2812b.c index 8547b5d..3721b23 100644 --- a/src/ws2812b.c +++ b/src/ws2812b.c @@ -3,6 +3,7 @@ #include <string.h> #include "spi.h" +#include "sysled.h" // either 0b110 when (n) is true, otherwise 0b100 #define BIT_TO_SPI_DATA(v, n) ((BIT_N(v, n)) ? 6 : 4) @@ -32,20 +33,24 @@ inline static void complie_color_inline( rgb_t color, struct rgb_compiled* out, enum ws2812b_byte_order byte_order) { if (byte_order == BYTE_ORDER_GBR) { - uint8_t tmp = color.b; - color.b = color.g; + uint8_t tmp = color.r; + color.r = color.g; color.g = tmp; } + color.r = color.r; + color.g = color.g; + color.b = color.b; + out->first_bits = - BYTE_1(COLOR_BYTE_1(color.b)) | BYTE_2(COLOR_BYTE_2(color.b)) | - BYTE_3(COLOR_BYTE_3(color.b)) | BYTE_4(COLOR_BYTE_1(color.g)); + BYTE_1(COLOR_BYTE_1(color.r)) | BYTE_2(COLOR_BYTE_2(color.r)) | + BYTE_3(COLOR_BYTE_3(color.r)) | BYTE_4(COLOR_BYTE_1(color.g)); out->second_bits = BYTE_1(COLOR_BYTE_2(color.g)) | BYTE_2(COLOR_BYTE_3(color.g)) | - BYTE_3(COLOR_BYTE_1(color.r)) | BYTE_4(COLOR_BYTE_2(color.r)); + BYTE_3(COLOR_BYTE_1(color.b)) | BYTE_4(COLOR_BYTE_2(color.b)); - out->last_bits = COLOR_BYTE_3(color.r); + out->last_bits = COLOR_BYTE_3(color.b); } void compile_color( @@ -74,8 +79,10 @@ int write_rgb(struct ws2812b_buf* out, rgb_t color) while ((dma_loc - CLIP_TO_DMA_BITS(out->buf + out->cur) < TOTAL_BYTES_PER_LED) && (dma_loc < dma_end)) { + set_sysled(1); // Little indication to tell if we are waiting for the DMA. dma_loc = *dma_now; } + set_sysled(0); } memcpy(out->buf + out->cur, comp.buf, WIRE_BYTES_PER_COLOR); |