| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| #pragma once | ||
|
|
||
| // HOLLY defines | ||
| #define WS2812_PIN 8 | ||
| #define LED_VCC1_EN 7 | ||
| #define LED_VCC2_EN 6 | ||
| #define NUM_SWITCHES 6 | ||
| #define S1_PIN 27 | ||
| #define S2_PIN 25 | ||
| #define S3_PIN 23 | ||
| #define S4_PIN 21 | ||
| #define S5_PIN 19 | ||
| #define S6_PIN 10 | ||
|
|
||
| #define NUM_LEDS 6 | ||
| #define MIN_SPARKLES 3 | ||
| #define MAX_SPARKLES 5 | ||
| #define FADE_STEPS 10 | ||
|
|
||
| #define FADE_DELAY 8 | ||
| #define DWELL_DELAY 10 | ||
| #define CYCLE_DELAY 10 | ||
| #define LOOP_DELAY_S 7 | ||
| #define LOOP_DELAY_MS (LOOP_DELAY_S * 1000) | ||
|
|
||
| #if LIB_PICO_STDIO_USB | ||
| #define NUM_CYCLES 5 // Enter shutdown early for testing | ||
| #else | ||
| #define NUM_CYCLES ((3600 * 3) / LOOP_DELAY_S) // 3 hours | ||
| #endif | ||
|
|
||
| #if LIB_PICO_STDIO_USB | ||
| #define DBG_PRINTF(...) printf(__VA_ARGS__) | ||
| #else | ||
| #define DBG_PRINTF(...) | ||
| #endif | ||
|
|
||
| // On some samples, the xosc can take longer to stabilize than is usual | ||
| #ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER | ||
| #define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 | ||
| #endif | ||
|
|
||
| //------------- UART -------------// | ||
| #ifndef PICO_DEFAULT_UART | ||
| #define PICO_DEFAULT_UART 1 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_UART_TX_PIN | ||
| #define PICO_DEFAULT_UART_TX_PIN 4 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_UART_RX_PIN | ||
| #define PICO_DEFAULT_UART_RX_PIN 5 | ||
| #endif | ||
|
|
||
| //------------- LED -------------// | ||
| #ifndef PICO_DEFAULT_LED_PIN | ||
| #define PICO_DEFAULT_LED_PIN 3 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_WS2812_PIN | ||
| #define PICO_DEFAULT_WS2812_PIN 13 | ||
| #endif | ||
|
|
||
| //------------- I2C -------------// | ||
| #ifndef PICO_DEFAULT_I2C | ||
| #define PICO_DEFAULT_I2C 1 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_I2C_SDA_PIN | ||
| #define PICO_DEFAULT_I2C_SDA_PIN 14 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_I2C_SCL_PIN | ||
| #define PICO_DEFAULT_I2C_SCL_PIN 15 | ||
| #endif | ||
|
|
||
| //------------- SPI -------------// | ||
| #ifndef PICO_DEFAULT_SPI | ||
| #define PICO_DEFAULT_SPI 0 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_SPI_TX_PIN | ||
| #define PICO_DEFAULT_SPI_TX_PIN 23 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_SPI_RX_PIN | ||
| #define PICO_DEFAULT_SPI_RX_PIN 20 | ||
| #endif | ||
|
|
||
| #ifndef PICO_DEFAULT_SPI_SCK_PIN | ||
| #define PICO_DEFAULT_SPI_SCK_PIN 22 | ||
| #endif | ||
|
|
||
| //------------- FLASH -------------// | ||
|
|
||
| // Use slower generic flash access | ||
| #define PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H 1 | ||
|
|
||
| #ifndef PICO_FLASH_SPI_CLKDIV | ||
| #define PICO_FLASH_SPI_CLKDIV 2 | ||
| #endif | ||
|
|
||
| #ifndef PICO_FLASH_SIZE_BYTES | ||
| #define PICO_FLASH_SIZE_BYTES (1 * 512 * 1024) | ||
| #endif | ||
|
|
||
| // All boards have B1 RP2040 | ||
| #ifndef PICO_RP2040_B0_SUPPORTED | ||
| #define PICO_RP2040_B0_SUPPORTED 0 | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| #include <limits.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include "pico/stdlib.h" | ||
|
|
||
| #include "clocks.h" | ||
| #include "peripherals.h" | ||
| #include "sleep.h" | ||
|
|
||
| int main() { | ||
| configure_clocks(); | ||
| configure_hardware(); | ||
|
|
||
| #if LIB_PICO_STDIO_USB | ||
| #pragma message "USB is enabled. Deep sleep is disabled!!" | ||
| #endif | ||
|
|
||
| // Read switch states on boot | ||
| sw_t sw_state = read_switches(); | ||
|
|
||
| // Track number of cycles | ||
| uint16_t num = 0; | ||
|
|
||
| while (true) { | ||
| // Use switch state to choose color and animation | ||
| if (sw_state.s6) led_snake(COLOR_MODE_SILVER); | ||
| else if (sw_state.s5) led_snake(COLOR_MODE_XMAS); | ||
| else if (sw_state.s4) led_snake(COLOR_MODE_RGB); | ||
| else if (sw_state.s3) led_sparkle(COLOR_MODE_SILVER); | ||
| else if (sw_state.s2) led_sparkle(COLOR_MODE_XMAS); | ||
| else led_sparkle(COLOR_MODE_RGB); | ||
|
|
||
| // Only enter deep sleep if USB is disabled | ||
| #if !LIB_PICO_STDIO_USB | ||
| deep_sleep(); | ||
| restore_clocks(); | ||
| #else | ||
| sleep_ms(LOOP_DELAY_MS); | ||
| #endif | ||
|
|
||
| // Enter shutdown after NUM_CYCLES | ||
| if (++num >= NUM_CYCLES) { | ||
| shutdown(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| /* Based on GCC ARM embedded samples. | ||
| Defines the following symbols for use by code: | ||
| __exidx_start | ||
| __exidx_end | ||
| __etext | ||
| __data_start__ | ||
| __preinit_array_start | ||
| __preinit_array_end | ||
| __init_array_start | ||
| __init_array_end | ||
| __fini_array_start | ||
| __fini_array_end | ||
| __data_end__ | ||
| __bss_start__ | ||
| __bss_end__ | ||
| __end__ | ||
| end | ||
| __HeapLimit | ||
| __StackLimit | ||
| __StackTop | ||
| __stack (== StackTop) | ||
| */ | ||
|
|
||
| /* Skip 32kB at the start of flash, that's where our main program is */ | ||
| MEMORY | ||
| { | ||
| FLASH(rx) : ORIGIN = 0x1000b400, LENGTH = 512k - 0xb400 | ||
| RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k | ||
| SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k | ||
| SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k | ||
| } | ||
|
|
||
| ENTRY(_entry_point) | ||
|
|
||
| SECTIONS | ||
| { | ||
| .flash_begin : { | ||
| __flash_binary_start = .; | ||
| } > FLASH | ||
|
|
||
| /* boot2 would go here, but we don't want it */ | ||
|
|
||
| .text : { | ||
| __logical_binary_start = .; | ||
| KEEP (*(.vectors)) | ||
| KEEP (*(.binary_info_header)) | ||
| __binary_info_header_end = .; | ||
| KEEP (*(.reset)) | ||
| /* TODO revisit this now memset/memcpy/float in ROM */ | ||
| /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from | ||
| * FLASH ... we will include any thing excluded here in .data below by default */ | ||
| *(.init) | ||
| *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) | ||
| *(.fini) | ||
| /* Pull all c'tors into .text */ | ||
| *crtbegin.o(.ctors) | ||
| *crtbegin?.o(.ctors) | ||
| *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) | ||
| *(SORT(.ctors.*)) | ||
| *(.ctors) | ||
| /* Followed by destructors */ | ||
| *crtbegin.o(.dtors) | ||
| *crtbegin?.o(.dtors) | ||
| *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) | ||
| *(SORT(.dtors.*)) | ||
| *(.dtors) | ||
|
|
||
| *(.eh_frame*) | ||
| . = ALIGN(4); | ||
| } > FLASH | ||
|
|
||
| .rodata : { | ||
| *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) | ||
| . = ALIGN(4); | ||
| *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) | ||
| . = ALIGN(4); | ||
| } > FLASH | ||
|
|
||
| .ARM.extab : | ||
| { | ||
| *(.ARM.extab* .gnu.linkonce.armextab.*) | ||
| } > FLASH | ||
|
|
||
| __exidx_start = .; | ||
| .ARM.exidx : | ||
| { | ||
| *(.ARM.exidx* .gnu.linkonce.armexidx.*) | ||
| } > FLASH | ||
| __exidx_end = .; | ||
|
|
||
| /* Machine inspectable binary information */ | ||
| . = ALIGN(4); | ||
| __binary_info_start = .; | ||
| .binary_info : | ||
| { | ||
| KEEP(*(.binary_info.keep.*)) | ||
| *(.binary_info.*) | ||
| } > FLASH | ||
| __binary_info_end = .; | ||
| . = ALIGN(4); | ||
|
|
||
| /* End of .text-like segments */ | ||
| __etext = .; | ||
|
|
||
| .ram_vector_table (COPY): { | ||
| *(.ram_vector_table) | ||
| } > RAM | ||
|
|
||
| .data : { | ||
| __data_start__ = .; | ||
| *(vtable) | ||
|
|
||
| *(.time_critical*) | ||
|
|
||
| /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ | ||
| *(.text*) | ||
| . = ALIGN(4); | ||
| *(.rodata*) | ||
| . = ALIGN(4); | ||
|
|
||
| *(.data*) | ||
|
|
||
| . = ALIGN(4); | ||
| *(.after_data.*) | ||
| . = ALIGN(4); | ||
| /* preinit data */ | ||
| PROVIDE_HIDDEN (__mutex_array_start = .); | ||
| KEEP(*(SORT(.mutex_array.*))) | ||
| KEEP(*(.mutex_array)) | ||
| PROVIDE_HIDDEN (__mutex_array_end = .); | ||
|
|
||
| . = ALIGN(4); | ||
| /* preinit data */ | ||
| PROVIDE_HIDDEN (__preinit_array_start = .); | ||
| KEEP(*(SORT(.preinit_array.*))) | ||
| KEEP(*(.preinit_array)) | ||
| PROVIDE_HIDDEN (__preinit_array_end = .); | ||
|
|
||
| . = ALIGN(4); | ||
| /* init data */ | ||
| PROVIDE_HIDDEN (__init_array_start = .); | ||
| KEEP(*(SORT(.init_array.*))) | ||
| KEEP(*(.init_array)) | ||
| PROVIDE_HIDDEN (__init_array_end = .); | ||
|
|
||
| . = ALIGN(4); | ||
| /* finit data */ | ||
| PROVIDE_HIDDEN (__fini_array_start = .); | ||
| *(SORT(.fini_array.*)) | ||
| *(.fini_array) | ||
| PROVIDE_HIDDEN (__fini_array_end = .); | ||
|
|
||
| *(.jcr) | ||
| . = ALIGN(4); | ||
| /* All data end */ | ||
| __data_end__ = .; | ||
| } > RAM AT> FLASH | ||
|
|
||
| .uninitialized_data (COPY): { | ||
| . = ALIGN(4); | ||
| *(.uninitialized_data*) | ||
| } > RAM | ||
|
|
||
| /* Start and end symbols must be word-aligned */ | ||
| .scratch_x : { | ||
| __scratch_x_start__ = .; | ||
| *(.scratch_x.*) | ||
| . = ALIGN(4); | ||
| __scratch_x_end__ = .; | ||
| } > SCRATCH_X AT > FLASH | ||
| __scratch_x_source__ = LOADADDR(.scratch_x); | ||
|
|
||
| .scratch_y : { | ||
| __scratch_y_start__ = .; | ||
| *(.scratch_y.*) | ||
| . = ALIGN(4); | ||
| __scratch_y_end__ = .; | ||
| } > SCRATCH_Y AT > FLASH | ||
| __scratch_y_source__ = LOADADDR(.scratch_y); | ||
|
|
||
| .bss : { | ||
| . = ALIGN(4); | ||
| __bss_start__ = .; | ||
| *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) | ||
| *(COMMON) | ||
| . = ALIGN(4); | ||
| __bss_end__ = .; | ||
| } > RAM | ||
|
|
||
| .heap (COPY): | ||
| { | ||
| __end__ = .; | ||
| end = __end__; | ||
| *(.heap*) | ||
| __HeapLimit = .; | ||
| } > RAM | ||
|
|
||
| /* .stack*_dummy section doesn't contains any symbols. It is only | ||
| * used for linker to calculate size of stack sections, and assign | ||
| * values to stack symbols later | ||
| * | ||
| * stack1 section may be empty/missing if platform_launch_core1 is not used */ | ||
|
|
||
| /* by default we put core 0 stack at the end of scratch Y, so that if core 1 | ||
| * stack is not used then all of SCRATCH_X is free. | ||
| */ | ||
| .stack1_dummy (COPY): | ||
| { | ||
| *(.stack1*) | ||
| } > SCRATCH_X | ||
| .stack_dummy (COPY): | ||
| { | ||
| *(.stack*) | ||
| } > SCRATCH_Y | ||
|
|
||
| .flash_end : { | ||
| __flash_binary_end = .; | ||
| } > FLASH | ||
|
|
||
| /* stack limit is poorly named, but historically is maximum heap ptr */ | ||
| __StackLimit = ORIGIN(RAM) + LENGTH(RAM); | ||
| __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); | ||
| __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); | ||
| __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); | ||
| __StackBottom = __StackTop - SIZEOF(.stack_dummy); | ||
| PROVIDE(__stack = __StackTop); | ||
|
|
||
| /* Check if data + heap + stack exceeds RAM limit */ | ||
| ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") | ||
|
|
||
| ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") | ||
| /* todo assert on extra code */ | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,249 @@ | ||
| #include "colors.h" | ||
| #include "peripherals.h" | ||
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include "pico/stdlib.h" | ||
|
|
||
| #include "hardware/pio.h" | ||
| #include "hardware/vreg.h" | ||
| #include "ws2812.pio.h" | ||
|
|
||
| void configure_hardware(void) { | ||
| // Lower core voltage | ||
| #if !LIB_PICO_STDIO_USB | ||
| vreg_set_voltage(VREG_VOLTAGE_1_00); | ||
| #endif | ||
|
|
||
| // Init switch GPIOs | ||
| gpio_init(S1_PIN); | ||
| gpio_init(S2_PIN); | ||
| gpio_init(S3_PIN); | ||
| gpio_init(S4_PIN); | ||
| gpio_init(S5_PIN); | ||
| gpio_init(S6_PIN); | ||
|
|
||
| gpio_pull_up(S1_PIN); | ||
| gpio_pull_up(S2_PIN); | ||
| gpio_pull_up(S3_PIN); | ||
| gpio_pull_up(S4_PIN); | ||
| gpio_pull_up(S5_PIN); | ||
| gpio_pull_up(S6_PIN); | ||
|
|
||
| // Init PIO | ||
| PIO pio = pio0; | ||
| int sm = 0; | ||
| uint offset = pio_add_program(pio, &ws2812_program); | ||
| ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, false); | ||
| } | ||
|
|
||
| sw_t read_switches(void) { | ||
| sw_t sw; | ||
|
|
||
| sw.s1 = !gpio_get(S1_PIN); | ||
| sw.s2 = !gpio_get(S2_PIN); | ||
| sw.s3 = !gpio_get(S3_PIN); | ||
| sw.s4 = !gpio_get(S4_PIN); | ||
| sw.s5 = !gpio_get(S5_PIN); | ||
| sw.s6 = !gpio_get(S6_PIN); | ||
|
|
||
| return sw; | ||
| } | ||
|
|
||
| static inline void put_pixel(uint32_t pixel_grb) { | ||
| pio_sm_put_blocking(pio0, 0, pixel_grb << 8u); | ||
| } | ||
|
|
||
| static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) { | ||
| return ((uint32_t) (r) << 8) | ((uint32_t) (g) << 16) | (uint32_t) (b); | ||
| } | ||
|
|
||
| static inline void enable_led_vcc(uint8_t index) { | ||
| if (index == 1) { | ||
| gpio_init(LED_VCC1_EN); | ||
| gpio_set_dir(LED_VCC1_EN, GPIO_OUT); | ||
| gpio_put(LED_VCC1_EN, 1); | ||
|
|
||
| } else if (index == 2) { | ||
| gpio_init(LED_VCC2_EN); | ||
| gpio_set_dir(LED_VCC2_EN, GPIO_OUT); | ||
| gpio_put(LED_VCC2_EN, 1); | ||
| } | ||
| sleep_ms(1); | ||
| } | ||
|
|
||
| static inline void disable_led_vcc(void) { | ||
| gpio_init(LED_VCC1_EN); | ||
| gpio_set_dir(LED_VCC1_EN, GPIO_IN); | ||
| gpio_init(LED_VCC2_EN); | ||
| gpio_set_dir(LED_VCC2_EN, GPIO_IN); | ||
| } | ||
|
|
||
| static void set_led(uint8_t led_index, uint8_t r,uint8_t g, uint8_t b) { | ||
| // Write up to led_index with zero brightness | ||
| for (int l=0; l<led_index; l++) { | ||
| put_pixel(0); | ||
| } | ||
|
|
||
| // Write led_index with desired color | ||
| put_pixel(urgb_u32(r, g, b)); | ||
| } | ||
|
|
||
| static inline void fade_in(uint8_t l, uint8_t r, uint8_t g, uint8_t b) { | ||
| uint8_t ri=0, gi=0, bi=0; | ||
| for (int s=0; s<FADE_STEPS; s++) { | ||
| ri = (ri >= r) ? r : ++ri; | ||
| gi = (gi >= g) ? g : ++gi; | ||
| bi = (bi >= b) ? b : ++bi; | ||
| set_led(l, ri, gi, bi); | ||
| sleep_ms(FADE_DELAY); | ||
| } | ||
| } | ||
|
|
||
| static inline void fade_out(uint8_t l, uint8_t r, uint8_t g, uint8_t b) { | ||
| uint8_t ri=r, gi=g, bi=b; | ||
| for (int s=1; s<=FADE_STEPS; s++) { | ||
| ri = (ri > 0) ? --ri : 0; | ||
| gi = (gi > 0) ? --gi : 0; | ||
| bi = (bi > 0) ? --bi : 0; | ||
| set_led(l, ri, gi, bi); | ||
| sleep_ms(FADE_DELAY); | ||
| } | ||
| } | ||
|
|
||
| void clear_leds(void) { | ||
| for (int l=0; l<NUM_LEDS; l++) { | ||
| enable_led_vcc(1); | ||
| if (l > 2) { | ||
| enable_led_vcc(2); | ||
| } | ||
|
|
||
| set_led(l, 0, 0, 0); | ||
| } | ||
| disable_led_vcc(); | ||
| } | ||
|
|
||
| // Snake animation with various colors | ||
| void led_snake(uint8_t mode) { | ||
| DBG_PRINTF("led_snake mode %d\n", mode); | ||
|
|
||
| uint8_t num_colors; | ||
| if (mode == COLOR_MODE_SILVER) num_colors = NUM_SILVER_COLORS; | ||
| else if (mode == COLOR_MODE_XMAS) num_colors = NUM_XMAS_COLORS; | ||
| else num_colors = NUM_RGB_COLORS; | ||
| uint8_t p = num_colors, c = num_colors; | ||
|
|
||
| for (int l=0; l<NUM_LEDS; l++) { | ||
| // Ensure we don't get the same color twice in a row | ||
| while(c == p) { | ||
| c = rand() % num_colors; | ||
| } | ||
| p = c; | ||
|
|
||
| uint8_t r, g, b; | ||
| if (mode == COLOR_MODE_SILVER) { | ||
| r=silver_lut[c][R], g=silver_lut[c][G], b=silver_lut[c][B]; | ||
| } else if (mode == COLOR_MODE_XMAS) { | ||
| r=xmas_lut[c][R], g=xmas_lut[c][G], b=xmas_lut[c][B]; | ||
| } else { | ||
| r=rgb_lut[c][R], g=rgb_lut[c][G], b=rgb_lut[c][B]; | ||
| } | ||
|
|
||
| enable_led_vcc(1); | ||
| if (l > 2) { | ||
| enable_led_vcc(2); | ||
| } | ||
|
|
||
| DBG_PRINTF("c/l (r/g/b): %d/%d (%d/%d/%d)\n", c, l, r, g, b); | ||
|
|
||
| fade_in(l, r, g, b); | ||
| sleep_ms(DWELL_DELAY); | ||
| fade_out(l, r, g, b); | ||
|
|
||
| disable_led_vcc(); | ||
| sleep_ms(CYCLE_DELAY); | ||
| } | ||
| } | ||
|
|
||
| // Sparkle animation with various colors | ||
| void led_sparkle(uint8_t mode) { | ||
| DBG_PRINTF("led_sparkle mode %d\n", mode); | ||
|
|
||
| uint8_t num_colors; | ||
| if (mode == COLOR_MODE_SILVER) num_colors = NUM_SILVER_COLORS; | ||
| else if (mode == COLOR_MODE_XMAS) num_colors = NUM_XMAS_COLORS; | ||
| else num_colors = NUM_RGB_COLORS; | ||
| uint8_t p = num_colors, c = num_colors; | ||
|
|
||
| uint8_t n = rand() % (MAX_SPARKLES + 1 - MIN_SPARKLES) + MIN_SPARKLES; | ||
|
|
||
| for (int i=0; i<n; i++) { | ||
|
|
||
| // Ensure we don't get the same color twice in a row | ||
| while(c == p) { | ||
| c = rand() % num_colors; | ||
| } | ||
| p = c; | ||
|
|
||
| // Ensure we don't get the same LED twice in a row | ||
| static uint8_t q = NUM_LEDS, l = NUM_LEDS; | ||
| while(l == q) { | ||
| l = rand() % NUM_LEDS; | ||
| } | ||
| q = l; | ||
|
|
||
| uint8_t c = rand() % num_colors; | ||
|
|
||
| uint8_t r, g, b; | ||
| if (mode == COLOR_MODE_SILVER) { | ||
| r=silver_lut[c][R], g=silver_lut[c][G], b=silver_lut[c][B]; | ||
| } else if (mode == COLOR_MODE_XMAS) { | ||
| r=xmas_lut[c][R], g=xmas_lut[c][G], b=xmas_lut[c][B]; | ||
| } else { | ||
| r=rgb_lut[c][R], g=rgb_lut[c][G], b=rgb_lut[c][B]; | ||
| } | ||
|
|
||
| enable_led_vcc(1); | ||
| if (l > 2) { | ||
| enable_led_vcc(2); | ||
| } | ||
|
|
||
| DBG_PRINTF("n/c/l (r/g/b): %d/%d/%d (%d/%d/%d)\n", n, c, l, r, g, b); | ||
|
|
||
| fade_in(l, r, g, b); | ||
| sleep_ms(DWELL_DELAY); | ||
| fade_out(l, r, g, b); | ||
|
|
||
| disable_led_vcc(); | ||
| sleep_ms(CYCLE_DELAY); | ||
| } | ||
| } | ||
|
|
||
| void led_test(void) { | ||
| for (int l=0; l<NUM_LEDS; l++) { | ||
| // Turn on LEDs | ||
| enable_led_vcc(1); | ||
| if (l > 2) { | ||
| enable_led_vcc(2); | ||
| } | ||
|
|
||
| // Cycle through each RGB color on each LED | ||
| for (int c=0; c<NUM_RGB_COLORS; c++) { | ||
| uint8_t r=rgb_lut[c][R], g=rgb_lut[c][G], b=rgb_lut[c][B]; | ||
| DBG_PRINTF("c/l (r/g/b): %d/%d (%d/%d/%d)\n", c, l, r, g, b); | ||
| fade_in(l, r, g, b); | ||
| sleep_ms(10 * CYCLE_DELAY); | ||
| fade_out(l, r, g, b); | ||
| } | ||
| sleep_ms(10 * CYCLE_DELAY); | ||
| // Cycle through each xmas color on each LED | ||
| for (int c=0; c<NUM_XMAS_COLORS; c++) { | ||
| uint8_t r=xmas_lut[c][R], g=xmas_lut[c][G], b=xmas_lut[c][B]; | ||
| DBG_PRINTF("c/l (r/g/b): %d/%d (%d/%d/%d)\n", c, l, r, g, b); | ||
| fade_in(l, r, g, b); | ||
| sleep_ms(10 * CYCLE_DELAY); | ||
| fade_out(l, r, g, b); | ||
| } | ||
| disable_led_vcc(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #pragma once | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #define COLOR_MODE_RGB 0 | ||
| #define COLOR_MODE_XMAS 1 | ||
| #define COLOR_MODE_SILVER 2 | ||
|
|
||
| typedef struct { | ||
| uint8_t s1 : 1; | ||
| uint8_t s2 : 1; | ||
| uint8_t s3 : 1; | ||
| uint8_t s4 : 1; | ||
| uint8_t s5 : 1; | ||
| uint8_t s6 : 1; | ||
| uint8_t unused : 2; | ||
| } sw_t; | ||
|
|
||
| void configure_hardware(void); | ||
| sw_t read_switches(void); | ||
| void clear_leds(void); | ||
| void led_test(void); | ||
| void led_sparkle(uint8_t mode); | ||
| void led_snake(uint8_t mode); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake | ||
|
|
||
| # This can be dropped into an external project to help locate this SDK | ||
| # It should be include()ed prior to project() | ||
|
|
||
| if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) | ||
| set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) | ||
| message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") | ||
| endif () | ||
|
|
||
| if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) | ||
| set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) | ||
| message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") | ||
| endif () | ||
|
|
||
| if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) | ||
| set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) | ||
| message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") | ||
| endif () | ||
|
|
||
| set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") | ||
| set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") | ||
| set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") | ||
|
|
||
| if (NOT PICO_SDK_PATH) | ||
| if (PICO_SDK_FETCH_FROM_GIT) | ||
| include(FetchContent) | ||
| set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) | ||
| if (PICO_SDK_FETCH_FROM_GIT_PATH) | ||
| get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") | ||
| endif () | ||
| # GIT_SUBMODULES_RECURSE was added in 3.17 | ||
| if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") | ||
| FetchContent_Declare( | ||
| pico_sdk | ||
| GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk | ||
| GIT_TAG master | ||
| GIT_SUBMODULES_RECURSE FALSE | ||
| ) | ||
| else () | ||
| FetchContent_Declare( | ||
| pico_sdk | ||
| GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk | ||
| GIT_TAG master | ||
| ) | ||
| endif () | ||
|
|
||
| if (NOT pico_sdk) | ||
| message("Downloading Raspberry Pi Pico SDK") | ||
| FetchContent_Populate(pico_sdk) | ||
| set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) | ||
| endif () | ||
| set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) | ||
| else () | ||
| message(FATAL_ERROR | ||
| "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." | ||
| ) | ||
| endif () | ||
| endif () | ||
|
|
||
| get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") | ||
| if (NOT EXISTS ${PICO_SDK_PATH}) | ||
| message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") | ||
| endif () | ||
|
|
||
| set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) | ||
| if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) | ||
| message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") | ||
| endif () | ||
|
|
||
| set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) | ||
|
|
||
| include(${PICO_SDK_INIT_CMAKE_FILE}) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| #include "sleep.h" | ||
|
|
||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include "pico/stdlib.h" | ||
|
|
||
| #include "hardware/clocks.h" | ||
| #include "hardware/structs/scb.h" | ||
| #include "hardware/sync.h" | ||
| #include "hardware/rtc.h" | ||
| #include "hardware/vreg.h" | ||
|
|
||
| // Go to sleep until woken up by the RTC | ||
| static void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback) { | ||
| clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS; | ||
| clocks_hw->sleep_en1 = 0x0; | ||
|
|
||
| rtc_set_alarm(t, callback); | ||
|
|
||
| uint save = scb_hw->scr; | ||
| scb_hw->scr = save | M0PLUS_SCR_SLEEPDEEP_BITS; | ||
|
|
||
| __wfi(); | ||
| } | ||
|
|
||
| void deep_sleep(void) { | ||
| datetime_t t = { | ||
| .year = 2023, | ||
| .month = 1, | ||
| .day = 1, | ||
| .dotw = 0, | ||
| .hour = 0, | ||
| .min = 0, | ||
| .sec = 0 | ||
| }; | ||
| rtc_init(); | ||
| rtc_set_datetime(&t); | ||
| t.sec = LOOP_DELAY_S; | ||
|
|
||
| sleep_goto_sleep_until(&t, NULL); | ||
| } | ||
|
|
||
| void shutdown(void) { | ||
| DBG_PRINTF("Entering shutdown!\n"); | ||
| hw_write_masked(&vreg_and_chip_reset_hw->bod, 0, VREG_AND_CHIP_RESET_BOD_BITS); | ||
| hw_write_masked(&vreg_and_chip_reset_hw->vreg, 0, VREG_AND_CHIP_RESET_VREG_EN_BITS); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #pragma once | ||
|
|
||
| void deep_sleep(void); | ||
| void shutdown(void); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,374 @@ | ||
| #!/usr/bin/env python3 | ||
| # yapf: disable | ||
| import sys | ||
| import struct | ||
| import subprocess | ||
| import re | ||
| import os | ||
| import os.path | ||
| import argparse | ||
| import json | ||
| from time import sleep | ||
|
|
||
|
|
||
| UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" | ||
| UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected | ||
| UF2_MAGIC_END = 0x0AB16F30 # Ditto | ||
|
|
||
| INFO_FILE = "/INFO_UF2.TXT" | ||
|
|
||
| appstartaddr = 0x2000 | ||
| familyid = 0x0 | ||
|
|
||
|
|
||
| def is_uf2(buf): | ||
| w = struct.unpack("<II", buf[0:8]) | ||
| return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1 | ||
|
|
||
| def is_hex(buf): | ||
| try: | ||
| w = buf[0:30].decode("utf-8") | ||
| except UnicodeDecodeError: | ||
| return False | ||
| if w[0] == ':' and re.match(b"^[:0-9a-fA-F\r\n]+$", buf): | ||
| return True | ||
| return False | ||
|
|
||
| def convert_from_uf2(buf): | ||
| global appstartaddr | ||
| global familyid | ||
| numblocks = len(buf) // 512 | ||
| curraddr = None | ||
| currfamilyid = None | ||
| families_found = {} | ||
| prev_flag = None | ||
| all_flags_same = True | ||
| outp = [] | ||
| for blockno in range(numblocks): | ||
| ptr = blockno * 512 | ||
| block = buf[ptr:ptr + 512] | ||
| hd = struct.unpack(b"<IIIIIIII", block[0:32]) | ||
| if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1: | ||
| print("Skipping block at " + ptr + "; bad magic") | ||
| continue | ||
| if hd[2] & 1: | ||
| # NO-flash flag set; skip block | ||
| continue | ||
| datalen = hd[4] | ||
| if datalen > 476: | ||
| assert False, "Invalid UF2 data size at " + ptr | ||
| newaddr = hd[3] | ||
| if (hd[2] & 0x2000) and (currfamilyid == None): | ||
| currfamilyid = hd[7] | ||
| if curraddr == None or ((hd[2] & 0x2000) and hd[7] != currfamilyid): | ||
| currfamilyid = hd[7] | ||
| curraddr = newaddr | ||
| if familyid == 0x0 or familyid == hd[7]: | ||
| appstartaddr = newaddr | ||
| padding = newaddr - curraddr | ||
| if padding < 0: | ||
| assert False, "Block out of order at " + ptr | ||
| if padding > 10*1024*1024: | ||
| assert False, "More than 10M of padding needed at " + ptr | ||
| if padding % 4 != 0: | ||
| assert False, "Non-word padding size at " + ptr | ||
| while padding > 0: | ||
| padding -= 4 | ||
| outp.append(b"\x00\x00\x00\x00") | ||
| if familyid == 0x0 or ((hd[2] & 0x2000) and familyid == hd[7]): | ||
| outp.append(block[32 : 32 + datalen]) | ||
| curraddr = newaddr + datalen | ||
| if hd[2] & 0x2000: | ||
| if hd[7] in families_found.keys(): | ||
| if families_found[hd[7]] > newaddr: | ||
| families_found[hd[7]] = newaddr | ||
| else: | ||
| families_found[hd[7]] = newaddr | ||
| if prev_flag == None: | ||
| prev_flag = hd[2] | ||
| if prev_flag != hd[2]: | ||
| all_flags_same = False | ||
| if blockno == (numblocks - 1): | ||
| print("--- UF2 File Header Info ---") | ||
| families = load_families() | ||
| for family_hex in families_found.keys(): | ||
| family_short_name = "" | ||
| for name, value in families.items(): | ||
| if value == family_hex: | ||
| family_short_name = name | ||
| print("Family ID is {:s}, hex value is 0x{:08x}".format(family_short_name,family_hex)) | ||
| print("Target Address is 0x{:08x}".format(families_found[family_hex])) | ||
| if all_flags_same: | ||
| print("All block flag values consistent, 0x{:04x}".format(hd[2])) | ||
| else: | ||
| print("Flags were not all the same") | ||
| print("----------------------------") | ||
| if len(families_found) > 1 and familyid == 0x0: | ||
| outp = [] | ||
| appstartaddr = 0x0 | ||
| return b"".join(outp) | ||
|
|
||
| def convert_to_carray(file_content): | ||
| outp = "#pragma once\n\n" | ||
| outp += f"// generated with {' '.join(str(v) for v in sys.argv[:])}\n" | ||
| outp += f"const unsigned long bindata_len = {hex(len(file_content))};\n" | ||
| outp += f"uint8_t __attribute__((aligned(512), section( \".rodata\"))) bindata[{len(file_content)}] = {{" | ||
| for i in range(len(file_content)): | ||
| if i % 16 == 0: | ||
| outp += "\n" | ||
| outp += "0x%02x, " % file_content[i] | ||
| outp += "\n};\n" | ||
| return bytes(outp, "utf-8") | ||
|
|
||
| def convert_to_uf2(file_content): | ||
| global familyid | ||
| datapadding = b"" | ||
| while len(datapadding) < 512 - 256 - 32 - 4: | ||
| datapadding += b"\x00\x00\x00\x00" | ||
| numblocks = (len(file_content) + 255) // 256 | ||
| outp = [] | ||
| for blockno in range(numblocks): | ||
| ptr = 256 * blockno | ||
| chunk = file_content[ptr:ptr + 256] | ||
| flags = 0x0 | ||
| if familyid: | ||
| flags |= 0x2000 | ||
| hd = struct.pack(b"<IIIIIIII", | ||
| UF2_MAGIC_START0, UF2_MAGIC_START1, | ||
| flags, ptr + appstartaddr, 256, blockno, numblocks, familyid) | ||
| while len(chunk) < 256: | ||
| chunk += b"\x00" | ||
| block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END) | ||
| assert len(block) == 512 | ||
| outp.append(block) | ||
| return b"".join(outp) | ||
|
|
||
| class Block: | ||
| def __init__(self, addr): | ||
| self.addr = addr | ||
| self.bytes = bytearray(256) | ||
|
|
||
| def encode(self, blockno, numblocks): | ||
| global familyid | ||
| flags = 0x0 | ||
| if familyid: | ||
| flags |= 0x2000 | ||
| if devicetype: | ||
| flags |= 0x8000 | ||
| hd = struct.pack("<IIIIIIII", | ||
| UF2_MAGIC_START0, UF2_MAGIC_START1, | ||
| flags, self.addr, 256, blockno, numblocks, familyid) | ||
| hd += self.bytes[0:256] | ||
| if devicetype: | ||
| hd += bytearray(b'\x08\x29\xa7\xc8') | ||
| hd += bytearray(devicetype.to_bytes(4, 'little')) | ||
| while len(hd) < 512 - 4: | ||
| hd += b"\x00" | ||
| hd += struct.pack("<I", UF2_MAGIC_END) | ||
| return hd | ||
|
|
||
| def convert_from_hex_to_uf2(buf): | ||
| global appstartaddr | ||
| appstartaddr = None | ||
| upper = 0 | ||
| currblock = None | ||
| blocks = [] | ||
| for line in buf.split('\n'): | ||
| if line[0] != ":": | ||
| continue | ||
| i = 1 | ||
| rec = [] | ||
| while i < len(line) - 1: | ||
| rec.append(int(line[i:i+2], 16)) | ||
| i += 2 | ||
| tp = rec[3] | ||
| if tp == 4: | ||
| upper = ((rec[4] << 8) | rec[5]) << 16 | ||
| elif tp == 2: | ||
| upper = ((rec[4] << 8) | rec[5]) << 4 | ||
| elif tp == 1: | ||
| break | ||
| elif tp == 0: | ||
| addr = upper + ((rec[1] << 8) | rec[2]) | ||
| if appstartaddr == None: | ||
| appstartaddr = addr | ||
| i = 4 | ||
| while i < len(rec) - 1: | ||
| if not currblock or currblock.addr & ~0xff != addr & ~0xff: | ||
| currblock = Block(addr & ~0xff) | ||
| blocks.append(currblock) | ||
| currblock.bytes[addr & 0xff] = rec[i] | ||
| addr += 1 | ||
| i += 1 | ||
| numblocks = len(blocks) | ||
| resfile = b"" | ||
| for i in range(0, numblocks): | ||
| resfile += blocks[i].encode(i, numblocks) | ||
| return resfile | ||
|
|
||
| def to_str(b): | ||
| return b.decode("utf-8") | ||
|
|
||
| def get_drives(): | ||
| drives = [] | ||
| if sys.platform == "win32": | ||
| r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk", | ||
| "get", "DeviceID,", "VolumeName,", | ||
| "FileSystem,", "DriveType"]) | ||
| for line in to_str(r).split('\n'): | ||
| words = re.split('\s+', line) | ||
| if len(words) >= 3 and words[1] == "2" and words[2] == "FAT": | ||
| drives.append(words[0]) | ||
| else: | ||
| searchpaths = ["/media"] | ||
| if sys.platform == "darwin": | ||
| searchpaths = ["/Volumes"] | ||
| elif sys.platform == "linux": | ||
| searchpaths += ["/media/" + os.environ["USER"], '/run/media/' + os.environ["USER"]] | ||
|
|
||
| for rootpath in searchpaths: | ||
| if os.path.isdir(rootpath): | ||
| for d in os.listdir(rootpath): | ||
| if os.path.isdir(rootpath): | ||
| drives.append(os.path.join(rootpath, d)) | ||
|
|
||
|
|
||
| def has_info(d): | ||
| try: | ||
| return os.path.isfile(d + INFO_FILE) | ||
| except: | ||
| return False | ||
|
|
||
| return list(filter(has_info, drives)) | ||
|
|
||
|
|
||
| def board_id(path): | ||
| with open(path + INFO_FILE, mode='r') as file: | ||
| file_content = file.read() | ||
| return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) | ||
|
|
||
|
|
||
| def list_drives(): | ||
| for d in get_drives(): | ||
| print(d, board_id(d)) | ||
|
|
||
|
|
||
| def write_file(name, buf): | ||
| with open(name, "wb") as f: | ||
| f.write(buf) | ||
| print("Wrote %d bytes to %s" % (len(buf), name)) | ||
|
|
||
|
|
||
| def load_families(): | ||
| # The expectation is that the `uf2families.json` file is in the same | ||
| # directory as this script. Make a path that works using `__file__` | ||
| # which contains the full path to this script. | ||
| filename = "uf2families.json" | ||
| pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) | ||
| with open(pathname) as f: | ||
| raw_families = json.load(f) | ||
|
|
||
| families = {} | ||
| for family in raw_families: | ||
| families[family["short_name"]] = int(family["id"], 0) | ||
|
|
||
| return families | ||
|
|
||
|
|
||
| def main(): | ||
| global appstartaddr, familyid | ||
| def error(msg): | ||
| print(msg, file=sys.stderr) | ||
| sys.exit(1) | ||
| parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') | ||
| parser.add_argument('input', metavar='INPUT', type=str, nargs='?', | ||
| help='input file (HEX, BIN or UF2)') | ||
| parser.add_argument('-b', '--base', dest='base', type=str, | ||
| default="0x2000", | ||
| help='set base address of application for BIN format (default: 0x2000)') | ||
| parser.add_argument('-f', '--family', dest='family', type=str, | ||
| default="0x0", | ||
| help='specify familyID - number or name (default: 0x0)') | ||
| parser.add_argument('-t' , '--device-type', dest='devicetype', type=str, | ||
| help='specify deviceTypeID extension tag - number') | ||
| parser.add_argument('-o', '--output', metavar="FILE", dest='output', type=str, | ||
| help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') | ||
| parser.add_argument('-d', '--device', dest="device_path", | ||
| help='select a device path to flash') | ||
| parser.add_argument('-l', '--list', action='store_true', | ||
| help='list connected devices') | ||
| parser.add_argument('-c', '--convert', action='store_true', | ||
| help='do not flash, just convert') | ||
| parser.add_argument('-D', '--deploy', action='store_true', | ||
| help='just flash, do not convert') | ||
| parser.add_argument('-w', '--wait', action='store_true', | ||
| help='wait for device to flash') | ||
| parser.add_argument('-C', '--carray', action='store_true', | ||
| help='convert binary file to a C array, not UF2') | ||
| parser.add_argument('-i', '--info', action='store_true', | ||
| help='display header information from UF2, do not convert') | ||
| args = parser.parse_args() | ||
| appstartaddr = int(args.base, 0) | ||
|
|
||
| families = load_families() | ||
|
|
||
| if args.family.upper() in families: | ||
| familyid = families[args.family.upper()] | ||
| else: | ||
| try: | ||
| familyid = int(args.family, 0) | ||
| except ValueError: | ||
| error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) | ||
|
|
||
| global devicetype | ||
| devicetype = int(args.devicetype, 0) if args.devicetype else None | ||
|
|
||
| if args.list: | ||
| list_drives() | ||
| else: | ||
| if not args.input: | ||
| error("Need input file") | ||
| with open(args.input, mode='rb') as f: | ||
| inpbuf = f.read() | ||
| from_uf2 = is_uf2(inpbuf) | ||
| ext = "uf2" | ||
| if args.deploy: | ||
| outbuf = inpbuf | ||
| elif from_uf2 and not args.info: | ||
| outbuf = convert_from_uf2(inpbuf) | ||
| ext = "bin" | ||
| elif from_uf2 and args.info: | ||
| outbuf = "" | ||
| convert_from_uf2(inpbuf) | ||
| elif is_hex(inpbuf): | ||
| outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) | ||
| elif args.carray: | ||
| outbuf = convert_to_carray(inpbuf) | ||
| ext = "h" | ||
| else: | ||
| outbuf = convert_to_uf2(inpbuf) | ||
| if not args.deploy and not args.info: | ||
| print("Converted to %s, output size: %d, start address: 0x%x" % | ||
| (ext, len(outbuf), appstartaddr)) | ||
| if args.convert or ext != "uf2": | ||
| if args.output == None: | ||
| args.output = "flash." + ext | ||
| if args.output: | ||
| write_file(args.output, outbuf) | ||
| if ext == "uf2" and not args.convert and not args.info: | ||
| drives = get_drives() | ||
| if len(drives) == 0: | ||
| if args.wait: | ||
| print("Waiting for drive to deploy...") | ||
| while len(drives) == 0: | ||
| sleep(0.1) | ||
| drives = get_drives() | ||
| elif not args.output: | ||
| error("No drive to deploy.") | ||
| for d in drives: | ||
| print("Flashing %s (%s)" % (d, board_id(d))) | ||
| write_file(d + "/NEW.UF2", outbuf) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,217 @@ | ||
| [ | ||
| { | ||
| "id": "0x16573617", | ||
| "short_name": "ATMEGA32", | ||
| "description": "Microchip (Atmel) ATmega32" | ||
| }, | ||
| { | ||
| "id": "0x1851780a", | ||
| "short_name": "SAML21", | ||
| "description": "Microchip (Atmel) SAML21" | ||
| }, | ||
| { | ||
| "id": "0x1b57745f", | ||
| "short_name": "NRF52", | ||
| "description": "Nordic NRF52" | ||
| }, | ||
| { | ||
| "id": "0x1c5f21b0", | ||
| "short_name": "ESP32", | ||
| "description": "ESP32" | ||
| }, | ||
| { | ||
| "id": "0x1e1f432d", | ||
| "short_name": "STM32L1", | ||
| "description": "ST STM32L1xx" | ||
| }, | ||
| { | ||
| "id": "0x202e3a91", | ||
| "short_name": "STM32L0", | ||
| "description": "ST STM32L0xx" | ||
| }, | ||
| { | ||
| "id": "0x21460ff0", | ||
| "short_name": "STM32WL", | ||
| "description": "ST STM32WLxx" | ||
| }, | ||
| { | ||
| "id": "0x2abc77ec", | ||
| "short_name": "LPC55", | ||
| "description": "NXP LPC55xx" | ||
| }, | ||
| { | ||
| "id": "0x300f5633", | ||
| "short_name": "STM32G0", | ||
| "description": "ST STM32G0xx" | ||
| }, | ||
| { | ||
| "id": "0x31d228c6", | ||
| "short_name": "GD32F350", | ||
| "description": "GD32F350" | ||
| }, | ||
| { | ||
| "id": "0x04240bdf", | ||
| "short_name": "STM32L5", | ||
| "description": "ST STM32L5xx" | ||
| }, | ||
| { | ||
| "id": "0x4c71240a", | ||
| "short_name": "STM32G4", | ||
| "description": "ST STM32G4xx" | ||
| }, | ||
| { | ||
| "id": "0x4fb2d5bd", | ||
| "short_name": "MIMXRT10XX", | ||
| "description": "NXP i.MX RT10XX" | ||
| }, | ||
| { | ||
| "id": "0x53b80f00", | ||
| "short_name": "STM32F7", | ||
| "description": "ST STM32F7xx" | ||
| }, | ||
| { | ||
| "id": "0x55114460", | ||
| "short_name": "SAMD51", | ||
| "description": "Microchip (Atmel) SAMD51" | ||
| }, | ||
| { | ||
| "id": "0x57755a57", | ||
| "short_name": "STM32F4", | ||
| "description": "ST STM32F4xx" | ||
| }, | ||
| { | ||
| "id": "0x5a18069b", | ||
| "short_name": "FX2", | ||
| "description": "Cypress FX2" | ||
| }, | ||
| { | ||
| "id": "0x5d1a0a2e", | ||
| "short_name": "STM32F2", | ||
| "description": "ST STM32F2xx" | ||
| }, | ||
| { | ||
| "id": "0x5ee21072", | ||
| "short_name": "STM32F1", | ||
| "description": "ST STM32F103" | ||
| }, | ||
| { | ||
| "id": "0x621e937a", | ||
| "short_name": "NRF52833", | ||
| "description": "Nordic NRF52833" | ||
| }, | ||
| { | ||
| "id": "0x647824b6", | ||
| "short_name": "STM32F0", | ||
| "description": "ST STM32F0xx" | ||
| }, | ||
| { | ||
| "id": "0x68ed2b88", | ||
| "short_name": "SAMD21", | ||
| "description": "Microchip (Atmel) SAMD21" | ||
| }, | ||
| { | ||
| "id": "0x6b846188", | ||
| "short_name": "STM32F3", | ||
| "description": "ST STM32F3xx" | ||
| }, | ||
| { | ||
| "id": "0x6d0922fa", | ||
| "short_name": "STM32F407", | ||
| "description": "ST STM32F407" | ||
| }, | ||
| { | ||
| "id": "0x6db66082", | ||
| "short_name": "STM32H7", | ||
| "description": "ST STM32H7xx" | ||
| }, | ||
| { | ||
| "id": "0x70d16653", | ||
| "short_name": "STM32WB", | ||
| "description": "ST STM32WBxx" | ||
| }, | ||
| { | ||
| "id": "0x7eab61ed", | ||
| "short_name": "ESP8266", | ||
| "description": "ESP8266" | ||
| }, | ||
| { | ||
| "id": "0x7f83e793", | ||
| "short_name": "KL32L2", | ||
| "description": "NXP KL32L2x" | ||
| }, | ||
| { | ||
| "id": "0x8fb060fe", | ||
| "short_name": "STM32F407VG", | ||
| "description": "ST STM32F407VG" | ||
| }, | ||
| { | ||
| "id": "0xada52840", | ||
| "short_name": "NRF52840", | ||
| "description": "Nordic NRF52840" | ||
| }, | ||
| { | ||
| "id": "0xbfdd4eee", | ||
| "short_name": "ESP32S2", | ||
| "description": "ESP32-S2" | ||
| }, | ||
| { | ||
| "id": "0xc47e5767", | ||
| "short_name": "ESP32S3", | ||
| "description": "ESP32-S3" | ||
| }, | ||
| { | ||
| "id": "0xd42ba06c", | ||
| "short_name": "ESP32C3", | ||
| "description": "ESP32-C3" | ||
| }, | ||
| { | ||
| "id": "0x2b88d29c", | ||
| "short_name": "ESP32C2", | ||
| "description": "ESP32-C2" | ||
| }, | ||
| { | ||
| "id": "0x332726f6", | ||
| "short_name": "ESP32H2", | ||
| "description": "ESP32-H2" | ||
| }, | ||
| { | ||
| "id": "0xe48bff56", | ||
| "short_name": "RP2040", | ||
| "description": "Raspberry Pi RP2040" | ||
| }, | ||
| { | ||
| "id": "0x00ff6919", | ||
| "short_name": "STM32L4", | ||
| "description": "ST STM32L4xx" | ||
| }, | ||
| { | ||
| "id": "0x9af03e33", | ||
| "short_name": "GD32VF103", | ||
| "description": "GigaDevice GD32VF103" | ||
| }, | ||
| { | ||
| "id": "0x4f6ace52", | ||
| "short_name": "CSK4", | ||
| "description": "LISTENAI CSK300x/400x" | ||
| }, | ||
| { | ||
| "id": "0x6e7348a8", | ||
| "short_name": "CSK6", | ||
| "description": "LISTENAI CSK60xx" | ||
| }, | ||
| { | ||
| "id": "0x11de784a", | ||
| "short_name": "M0SENSE", | ||
| "description": "M0SENSE BL702" | ||
| }, | ||
| { | ||
| "id": "0x4b684d71", | ||
| "short_name": "MaixPlay-U4", | ||
| "description": "Sipeed MaixPlay-U4(BL618)" | ||
| }, | ||
| { | ||
| "id": "0x9517422f", | ||
| "short_name": "RZA1LU", | ||
| "description": "Renesas RZ/A1LU (R7S7210xx)" | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| // -------------------------------------------------- // | ||
| // This file is autogenerated by pioasm; do not edit! // | ||
| // -------------------------------------------------- // | ||
|
|
||
| #pragma once | ||
|
|
||
| #if !PICO_NO_HARDWARE | ||
| #include "hardware/pio.h" | ||
| #endif | ||
|
|
||
| // ------ // | ||
| // ws2812 // | ||
| // ------ // | ||
|
|
||
| #define ws2812_wrap_target 0 | ||
| #define ws2812_wrap 3 | ||
|
|
||
| #define ws2812_T1 2 | ||
| #define ws2812_T2 5 | ||
| #define ws2812_T3 3 | ||
|
|
||
| static const uint16_t ws2812_program_instructions[] = { | ||
| // .wrap_target | ||
| 0x6221, // 0: out x, 1 side 0 [2] | ||
| 0x1123, // 1: jmp !x, 3 side 1 [1] | ||
| 0x1400, // 2: jmp 0 side 1 [4] | ||
| 0xa442, // 3: nop side 0 [4] | ||
| // .wrap | ||
| }; | ||
|
|
||
| #if !PICO_NO_HARDWARE | ||
| static const struct pio_program ws2812_program = { | ||
| .instructions = ws2812_program_instructions, | ||
| .length = 4, | ||
| .origin = -1, | ||
| }; | ||
|
|
||
| static inline pio_sm_config ws2812_program_get_default_config(uint offset) { | ||
| pio_sm_config c = pio_get_default_sm_config(); | ||
| sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap); | ||
| sm_config_set_sideset(&c, 1, false, false); | ||
| return c; | ||
| } | ||
|
|
||
| #include "hardware/clocks.h" | ||
| static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) { | ||
| pio_gpio_init(pio, pin); | ||
| pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); | ||
| pio_sm_config c = ws2812_program_get_default_config(offset); | ||
| sm_config_set_sideset_pins(&c, pin); | ||
| sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); | ||
| sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); | ||
| int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3; | ||
| float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit); | ||
| div = (div < 1.0) ? 1 : div; | ||
| sm_config_set_clkdiv(&c, div); | ||
| pio_sm_init(pio, sm, offset, &c); | ||
| pio_sm_set_enabled(pio, sm, true); | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| // --------------- // | ||
| // ws2812_parallel // | ||
| // --------------- // | ||
|
|
||
| #define ws2812_parallel_wrap_target 0 | ||
| #define ws2812_parallel_wrap 3 | ||
|
|
||
| #define ws2812_parallel_T1 2 | ||
| #define ws2812_parallel_T2 5 | ||
| #define ws2812_parallel_T3 3 | ||
|
|
||
| static const uint16_t ws2812_parallel_program_instructions[] = { | ||
| // .wrap_target | ||
| 0x6020, // 0: out x, 32 | ||
| 0xa10b, // 1: mov pins, !null [1] | ||
| 0xa401, // 2: mov pins, x [4] | ||
| 0xa103, // 3: mov pins, null [1] | ||
| // .wrap | ||
| }; | ||
|
|
||
| #if !PICO_NO_HARDWARE | ||
| static const struct pio_program ws2812_parallel_program = { | ||
| .instructions = ws2812_parallel_program_instructions, | ||
| .length = 4, | ||
| .origin = -1, | ||
| }; | ||
|
|
||
| static inline pio_sm_config ws2812_parallel_program_get_default_config(uint offset) { | ||
| pio_sm_config c = pio_get_default_sm_config(); | ||
| sm_config_set_wrap(&c, offset + ws2812_parallel_wrap_target, offset + ws2812_parallel_wrap); | ||
| return c; | ||
| } | ||
|
|
||
| #include "hardware/clocks.h" | ||
| static inline void ws2812_parallel_program_init(PIO pio, uint sm, uint offset, uint pin_base, uint pin_count, float freq) { | ||
| for(uint i=pin_base; i<pin_base+pin_count; i++) { | ||
| pio_gpio_init(pio, i); | ||
| } | ||
| pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, true); | ||
| pio_sm_config c = ws2812_parallel_program_get_default_config(offset); | ||
| sm_config_set_out_shift(&c, true, true, 32); | ||
| sm_config_set_out_pins(&c, pin_base, pin_count); | ||
| sm_config_set_set_pins(&c, pin_base, pin_count); | ||
| sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); | ||
| int cycles_per_bit = ws2812_parallel_T1 + ws2812_parallel_T2 + ws2812_parallel_T3; | ||
| float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit); | ||
| sm_config_set_clkdiv(&c, div); | ||
| pio_sm_init(pio, sm, offset, &c); | ||
| pio_sm_set_enabled(pio, sm, true); | ||
| } | ||
|
|
||
| #endif | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| { | ||
| "keyboard_name": "HOLLY", | ||
| "manufacturer": "nullbits", | ||
| "url": "https://nullbits.co/holly", | ||
| "maintainer": "jaygreco", | ||
| "usb": { | ||
| "vid": "0x6E61", | ||
| "pid": "0x6062", | ||
| "device_version": "0.0.1", | ||
| "no_startup_check": true | ||
| }, | ||
| "debounce": 10, | ||
| "layouts": { | ||
| "LAYOUT": { | ||
| "layout": [ | ||
| {"x": 0, "y": 0, "matrix": [0, 0]}, | ||
| {"x": 1, "y": 0, "matrix": [0, 1]}, | ||
| {"x": 2, "y": 0, "matrix": [0, 2]}, | ||
| {"x": 0, "y": 1, "matrix": [1, 0]}, | ||
| {"x": 1, "y": 1, "matrix": [1, 1]}, | ||
| {"x": 2, "y": 1, "matrix": [1, 2]} | ||
| ] | ||
| } | ||
| }, | ||
| "qmk": { | ||
| "tap_keycode_delay": 10 | ||
| }, | ||
| "processor": "RP2040", | ||
| "bootloader": "rp2040", | ||
| "matrix_pins": { | ||
| "direct": [ | ||
| ["GP27", "GP25", "GP23"], | ||
| ["GP21", "GP19", "GP10"] | ||
| ] | ||
| }, | ||
| "rgblight": { | ||
| "led_count": 6, | ||
| "max_brightness": 64, | ||
| "animations": { | ||
| "breathing": true, | ||
| "rainbow_mood": true, | ||
| "rainbow_swirl": true, | ||
| "snake": true, | ||
| "knight": true, | ||
| "christmas": true, | ||
| "static_gradient": true, | ||
| "rgb_test": true, | ||
| "alternating": true, | ||
| "twinkle": true | ||
| } | ||
| }, | ||
| "ws2812": { | ||
| "pin": "GP8", | ||
| "driver": "vendor" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| "name": "HOLLY", | ||
| "vendorId": "0x6E61", | ||
| "productId": "0x6062", | ||
| "keycodes": ["qmk_lighting"], | ||
| "menus": ["qmk_rgblight"], | ||
| "matrix": {"rows": 2, "cols": 3}, | ||
| "layouts": { | ||
| "keymap": [ | ||
| [{"c": "#777777"}, "0,0", "0,1", "0,2"], | ||
| ["1,0", "1,1", "1,2"] | ||
| ] | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /* | ||
| Copyright 2021 Jay Greco | ||
| This program is free software: you can redistribute it and/or modify | ||
| it under the terms of the GNU General Public License as published by | ||
| the Free Software Foundation, either version 2 of the License, or | ||
| (at your option) any later version. | ||
| This program is distributed in the hope that it will be useful, | ||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| GNU General Public License for more details. | ||
| You should have received a copy of the GNU General Public License | ||
| along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| #include QMK_KEYBOARD_H | ||
|
|
||
| enum layer_names { | ||
| _BASE, | ||
| _VIA1, | ||
| _VIA2, | ||
| _VIA3 | ||
| }; | ||
|
|
||
| const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
|
|
||
| [_BASE] = LAYOUT( | ||
| KC_F1, KC_F2, KC_F3, | ||
| KC_F4, KC_F5, KC_F6 | ||
| ), | ||
|
|
||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| // Copyright 2022 Jay Greco | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
|
|
||
| #pragma once | ||
|
|
||
| #include_next <mcuconf.h> | ||
|
|
||
| #undef RP_ADC_USE_ADC1 | ||
| #define RP_ADC_USE_ADC1 TRUE |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # HOLLY | ||
|
|
||
|  | ||
|
|
||
| A 6-switch RP2040 macropad and ornament built by nullbits. | ||
|
|
||
| Insert a CR2032 coin cell into the coin cell holder and slide the switch to the left (away from the USB connector) to enter ornament mode. The LEDs will sparkle for several hours before shutting off to conserve power. | ||
|
|
||
| In order to enter the bootloader, hold switch #1 while plugging in the USB cable. | ||
|
|
||
| To build in QMK, clone or symlink the `holly` directory into your QMK firmware directory: `keyboards/nullbitsco/`. | ||
| Then, build with `qmk compile -kb nullbitsco/holly -km all`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Build Options | ||
| # change yes to no to disable | ||
| # | ||
| BOOTMAGIC_ENABLE = no # Enable Bootmagic Lite | ||
| MOUSEKEY_ENABLE = yes # Mouse keys | ||
| EXTRAKEY_ENABLE = yes # Audio control and System control | ||
| CONSOLE_ENABLE = yes # Console for debug | ||
| COMMAND_ENABLE = no # Commands for debug and configuration | ||
| NKRO_ENABLE = no # Enable N-Key Rollover | ||
| BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | ||
| RGBLIGHT_ENABLE = yes # Enable keyboard RGB underglow | ||
| AUDIO_ENABLE = no # Audio output | ||
| ENCODER_ENABLE = no # Use rotary encoder | ||
| VIA_ENABLE = yes # Enable VIA | ||
|
|
||
| SRC += analog.c |