diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 4a382465..c8e4cbb8 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(button) add_subdirectory(plasma) add_subdirectory(rgbled) add_subdirectory(icp10125) +add_subdirectory(hub75) diff --git a/drivers/hub75/CMakeLists.txt b/drivers/hub75/CMakeLists.txt new file mode 100644 index 00000000..95895379 --- /dev/null +++ b/drivers/hub75/CMakeLists.txt @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/hub75.cmake) \ No newline at end of file diff --git a/drivers/hub75/hub75.cmake b/drivers/hub75/hub75.cmake new file mode 100644 index 00000000..e8a10567 --- /dev/null +++ b/drivers/hub75/hub75.cmake @@ -0,0 +1,11 @@ +add_library(hub75 INTERFACE) + +target_sources(hub75 INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/hub75.cpp) + +target_include_directories(hub75 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(hub75 INTERFACE pico_stdlib hardware_pio hardware_dma) + +pico_generate_pio_header(hub75 ${CMAKE_CURRENT_LIST_DIR}/hub75.pio) \ No newline at end of file diff --git a/micropython/modules/hub75/lib/hub75.cpp b/drivers/hub75/hub75.cpp similarity index 95% rename from micropython/modules/hub75/lib/hub75.cpp rename to drivers/hub75/hub75.cpp index 8ce50211..278112a4 100644 --- a/micropython/modules/hub75/lib/hub75.cpp +++ b/drivers/hub75/hub75.cpp @@ -38,7 +38,7 @@ Pixel hsv_to_rgb(float h, float s, float v) { Hub75::Hub75(uint8_t width, uint8_t height, Pixel *buffer, PanelType panel_type) - : width(width), height(height), front_buffer(buffer), back_buffer(buffer + width * height) + : width(width), height(height), panel_type(panel_type) { // Set up allllll the GPIO gpio_init(pin_r0); gpio_set_function(pin_r0, GPIO_FUNC_SIO); gpio_set_dir(pin_r0, true); gpio_put(pin_r0, 0); @@ -59,8 +59,14 @@ Hub75::Hub75(uint8_t width, uint8_t height, Pixel *buffer, PanelType panel_type) gpio_init(pin_stb); gpio_set_function(pin_stb, GPIO_FUNC_SIO); gpio_set_dir(pin_stb, true); gpio_put(pin_clk, !stb_polarity); gpio_init(pin_oe); gpio_set_function(pin_oe, GPIO_FUNC_SIO); gpio_set_dir(pin_oe, true); gpio_put(pin_clk, !oe_polarity); - if (panel_type == PANEL_FM6126A) { - FM6126A_setup(); + if (buffer == nullptr) { + front_buffer = new Pixel[width * height]; + back_buffer = new Pixel[width * height]; + managed_buffer = true; + } else { + front_buffer = buffer; + back_buffer = buffer + width * height; + managed_buffer = false; } } @@ -135,6 +141,10 @@ void Hub75::start(irq_handler_t handler) { pio_clear_instruction_memory(pio); } + if (panel_type == PANEL_FM6126A) { + FM6126A_setup(); + } + pio_sm_claim(pio, sm_data); pio_sm_claim(pio, sm_row); @@ -204,6 +214,10 @@ void Hub75::stop(irq_handler_t handler) { } Hub75::~Hub75() { + if (managed_buffer) { + delete[] front_buffer; + delete[] back_buffer; + } } void Hub75::clear() { diff --git a/micropython/modules/hub75/lib/hub75.hpp b/drivers/hub75/hub75.hpp similarity index 98% rename from micropython/modules/hub75/lib/hub75.hpp rename to drivers/hub75/hub75.hpp index 573233e8..c8e2ada3 100644 --- a/micropython/modules/hub75/lib/hub75.hpp +++ b/drivers/hub75/hub75.hpp @@ -56,7 +56,9 @@ class Hub75 { uint8_t height; Pixel *front_buffer; Pixel *back_buffer; + bool managed_buffer = false; bool running = false; + PanelType panel_type; // DMA & PIO uint dma_channel = 0; diff --git a/micropython/modules/hub75/lib/hub75.pio b/drivers/hub75/hub75.pio similarity index 100% rename from micropython/modules/hub75/lib/hub75.pio rename to drivers/hub75/hub75.pio diff --git a/examples/interstate75/CMakeLists.txt b/examples/interstate75/CMakeLists.txt index 17a3cfc7..a0c31fbc 100644 --- a/examples/interstate75/CMakeLists.txt +++ b/examples/interstate75/CMakeLists.txt @@ -1 +1,2 @@ -include(interstate75_hello_world.cmake) \ No newline at end of file +include(interstate75_hello_world.cmake) +include(interstate75_pio_dma.cmake) \ No newline at end of file diff --git a/examples/interstate75/hub75.pio b/examples/interstate75/hub75.pio deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/interstate75/interstate75_hello_world.cmake b/examples/interstate75/interstate75_hello_world.cmake index 4285c9c3..c7b7507b 100644 --- a/examples/interstate75/interstate75_hello_world.cmake +++ b/examples/interstate75/interstate75_hello_world.cmake @@ -9,8 +9,4 @@ pico_add_extra_outputs(${OUTPUT_NAME}) target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_multicore - hardware_pio - hardware_dma - ) - -pico_generate_pio_header(${OUTPUT_NAME} ${CMAKE_CURRENT_LIST_DIR}/hub75.pio) +) diff --git a/examples/interstate75/interstate75_hello_world.cpp b/examples/interstate75/interstate75_hello_world.cpp index 30715f33..3ed65cef 100644 --- a/examples/interstate75/interstate75_hello_world.cpp +++ b/examples/interstate75/interstate75_hello_world.cpp @@ -234,12 +234,14 @@ void hub75_display_update() { // This latches all the values we've just clocked into the column shift registers. // The values will appear on the output pins, ready for the display to be driven. gpio_put(PIN_STB, STB_POLARITY); + asm volatile("nop \nnop"); // Batman! + gpio_put(PIN_STB, !STB_POLARITY); // 4. Asset the output-enable signal (OE) // This turns on the display for a brief period to light the selected rows/columns. gpio_put(PIN_OE, OE_POLARITY); - // 4. Delay + // 5. Delay // Delay for a period of time coressponding to "bit"'s significance for(auto s = 0u; s < bit; ++s) { // The basic premise here is that "bit" will step through the values: @@ -252,12 +254,11 @@ void hub75_display_update() { asm volatile("nop \nnop"); // Batman! } - // 5. De-assert latch/strobe signal (STB) + output-enable signal (OE) + // 6. De-assert output-enable signal (OE) // Ready to go again! - gpio_put(PIN_STB, !STB_POLARITY); gpio_put(PIN_OE, !OE_POLARITY); - // 6. GOTO 1. + // 7. GOTO 1. } sleep_us(1); } diff --git a/examples/interstate75/interstate75_pio_dma.cmake b/examples/interstate75/interstate75_pio_dma.cmake new file mode 100644 index 00000000..e64a68bd --- /dev/null +++ b/examples/interstate75/interstate75_pio_dma.cmake @@ -0,0 +1,13 @@ +set(OUTPUT_NAME interstate75_pio_dma) +add_executable(${OUTPUT_NAME} interstate75_pio_dma.cpp) + +# enable usb output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) + +pico_add_extra_outputs(${OUTPUT_NAME}) + +target_link_libraries(${OUTPUT_NAME} + pico_stdlib + pico_multicore + hub75 +) diff --git a/examples/interstate75/interstate75_pio_dma.cpp b/examples/interstate75/interstate75_pio_dma.cpp new file mode 100644 index 00000000..1ff206d8 --- /dev/null +++ b/examples/interstate75/interstate75_pio_dma.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include "pico/stdlib.h" + +#include "common/pimoroni_common.hpp" + +#include "hub75.hpp" + +using namespace pimoroni; + +// Display size in pixels +// Should be either 64x64 or 32x32 but perhaps 64x32 an other sizes will work. +// Note: this example uses only 5 address lines so it's limited to 32*2 pixels. +const uint8_t WIDTH = 32; +const uint8_t HEIGHT = 32; + +Hub75 hub75(WIDTH, HEIGHT, nullptr); + +void __isr dma_complete() { + hub75.dma_complete(); +} + +int main() { + hub75.start(dma_complete); + + // Basic loop to draw something to the screen. + // This gets the distance from the middle of the display and uses it to paint a circular colour cycle. + while (true) { + float offset = millis() / 10000.0f; + for(auto x = 0u; x < WIDTH; x++) { + for(auto y = 0u; y < HEIGHT; y++) { + // Center our rainbow circles + float x1 = ((int)x - WIDTH / 2); + float y1 = ((int)y - HEIGHT / 2); + // Get hue as the distance from the display center as float from 0.0 to 1.0f. + float h = float(x1*x1 + y1*y1) / float(WIDTH*WIDTH + HEIGHT*HEIGHT); + // Offset our hue to animate the effect + h -= offset; + hub75.set_hsv(x, y, h, 1.0f, 1.0f); + } + } + + hub75.flip(); + + sleep_ms(1000 / 60); + } +} diff --git a/micropython/examples/interstate75/i75_32x32_generic.py b/micropython/examples/interstate75/i75_32x32_generic.py new file mode 100644 index 00000000..9020ef9b --- /dev/null +++ b/micropython/examples/interstate75/i75_32x32_generic.py @@ -0,0 +1,23 @@ +import hub75 +import time + +WIDTH, HEIGHT = 32, 32 + +hub = hub75.Hub75(WIDTH, HEIGHT, panel_type=hub75.PANEL_GENERIC) + +hub.start() +hub.clear() +hub.flip() + +while True: + h = time.ticks_ms() / 5000.0 + hub.set_all_hsv(h, 1.0, 1.0) + for y in range(8): + for x in range(WIDTH): + c = int(x * 255 / WIDTH) + hub.set_rgb(x, y, c, c, c) + for x in range(WIDTH): + hub.set_rgb(x, x, 255, 0, 0) + hub.set_rgb(WIDTH - 1 - x, x, 255, 0, 0) + hub.flip() + time.sleep(1.0 / 60) diff --git a/micropython/examples/interstate75/i75_64x64_fm6126a.py b/micropython/examples/interstate75/i75_64x64_fm6126a.py new file mode 100644 index 00000000..3244f498 --- /dev/null +++ b/micropython/examples/interstate75/i75_64x64_fm6126a.py @@ -0,0 +1,23 @@ +import hub75 +import time + +WIDTH, HEIGHT = 64, 64 + +hub = hub75.Hub75(WIDTH, HEIGHT, panel_type=hub75.PANEL_FM6126A) + +hub.start() +hub.clear() +hub.flip() + +while True: + h = time.ticks_ms() / 5000.0 + hub.set_all_hsv(h, 1.0, 1.0) + for y in range(8): + for x in range(WIDTH): + c = int(x * 255 / WIDTH) + hub.set_rgb(x, y, c, c, c) + for x in range(WIDTH): + hub.set_rgb(x, x, 255, 0, 0) + hub.set_rgb(WIDTH - 1 - x, x, 255, 0, 0) + hub.flip() + time.sleep(1.0 / 60) diff --git a/micropython/examples/interstate75/i75_64x64_generic.py b/micropython/examples/interstate75/i75_64x64_generic.py new file mode 100644 index 00000000..586583f9 --- /dev/null +++ b/micropython/examples/interstate75/i75_64x64_generic.py @@ -0,0 +1,23 @@ +import hub75 +import time + +WIDTH, HEIGHT = 64, 64 + +hub = hub75.Hub75(WIDTH, HEIGHT, panel_type=hub75.PANEL_GENERIC) + +hub.start() +hub.clear() +hub.flip() + +while True: + h = time.ticks_ms() / 5000.0 + hub.set_all_hsv(h, 1.0, 1.0) + for y in range(8): + for x in range(WIDTH): + c = int(x * 255 / WIDTH) + hub.set_rgb(x, y, c, c, c) + for x in range(WIDTH): + hub.set_rgb(x, x, 255, 0, 0) + hub.set_rgb(WIDTH - 1 - x, x, 255, 0, 0) + hub.flip() + time.sleep(1.0 / 60) diff --git a/micropython/modules/hub75/hub75.cpp b/micropython/modules/hub75/hub75.cpp index 381b77e3..9a329f6e 100644 --- a/micropython/modules/hub75/hub75.cpp +++ b/micropython/modules/hub75/hub75.cpp @@ -1,5 +1,5 @@ #include -#include "lib/hub75.hpp" +#include "hub75.hpp" #include "pico/multicore.h" #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) @@ -37,19 +37,28 @@ void __isr dma_complete() { void Hub75_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; // Unused input parameter _Hub75_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Hub75_obj_t); - mp_print_str(print, "Hub75("); + mp_print_str(print, "Hub75( "); mp_print_str(print, "dimensions = "); mp_obj_print_helper(print, mp_obj_new_int(self->hub75->width), PRINT_REPR); mp_print_str(print, " x "); mp_obj_print_helper(print, mp_obj_new_int(self->hub75->height), PRINT_REPR); - mp_print_str(print, "addr = front: "); + mp_print_str(print, ", addr = front: "); mp_obj_print_helper(print, mp_obj_new_int((uint32_t)&self->hub75->front_buffer[0]), PRINT_REPR); mp_print_str(print, " back: "); mp_obj_print_helper(print, mp_obj_new_int((uint32_t)&self->hub75->back_buffer[0]), PRINT_REPR); - mp_print_str(print, ")"); + switch(self->hub75->panel_type) { + case PANEL_GENERIC: + mp_print_str(print, ", panel: generic "); + break; + case PANEL_FM6126A: + mp_print_str(print, ", panel: generic "); + break; + } + + mp_print_str(print, " )"); } /***** Destructor ******/ diff --git a/micropython/modules/hub75/micropython.cmake b/micropython/modules/hub75/micropython.cmake index 03267378..e7558bd7 100644 --- a/micropython/modules/hub75/micropython.cmake +++ b/micropython/modules/hub75/micropython.cmake @@ -3,11 +3,12 @@ add_library(usermod_hub75 INTERFACE) target_sources(usermod_pico_display INTERFACE ${CMAKE_CURRENT_LIST_DIR}/hub75.c ${CMAKE_CURRENT_LIST_DIR}/hub75.cpp - ${CMAKE_CURRENT_LIST_DIR}/lib/hub75.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/hub75/hub75.cpp ) target_include_directories(usermod_hub75 INTERFACE ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/hub75/ ) target_compile_definitions(usermod_hub75 INTERFACE @@ -22,4 +23,4 @@ set_source_files_properties( "-Wno-discarded-qualifiers -Wno-implicit-int" ) -pico_generate_pio_header(usermod_hub75 ${CMAKE_CURRENT_LIST_DIR}/lib/hub75.pio) \ No newline at end of file +pico_generate_pio_header(usermod_hub75 ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/hub75/hub75.pio) \ No newline at end of file