diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml index 7b917a8..01aeec0 100644 --- a/.github/workflows/push-master.yml +++ b/.github/workflows/push-master.yml @@ -9,7 +9,7 @@ jobs: ########################### HyperSerialPico: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v6.0.2 @@ -19,7 +19,7 @@ jobs: - name: Install GNU Arm Embedded Toolchain uses: carlosperate/arm-none-eabi-gcc-action@v1 with: - release: '12.2.Rel1' + release: '14.2.Rel1' - name: Build packages shell: bash @@ -30,101 +30,129 @@ jobs: cmake --build . --config Release - uses: actions/upload-artifact@v7.0.0 - name: Upload artifacts (commit) - if: (startsWith(github.event.ref, 'refs/tags') != true) + name: Upload artifacts (release) with: + name: firmware-release-generic-RP2040 path: | firmware/*.uf2 + - name: Build packages for generic RP2350 + shell: bash + run: | + cd build + rm -rf * + rm -rf ../firmware/* + cmake -DTARGET_BOARD=pico2 -DCMAKE_BUILD_TYPE=Release .. + cmake --build . + zip -j ../firmware/firmware_generic_RP2350.zip ../firmware/* + - uses: actions/upload-artifact@v7.0.0 - name: Upload artifacts (release) - if: startsWith(github.ref, 'refs/tags/') + name: Upload artifacts (release generic RP2350) with: - name: firmware-release-generic + name: firmware-release-generic-RP2350 + archive: false path: | - firmware/*.uf2 + firmware/*.zip - - name: Build packages for Adafruit Feather RP2040 Scorpio (release-only) - if: startsWith(github.ref, 'refs/tags/') + - name: Build packages for Adafruit Feather RP2040 Scorpio shell: bash run: | cd build - rm *.* - rm ../firmware/* - echo "Neopixel is using GPIO16(OUTPUT_DATA_PIN) on output 0." > ../firmware/Firmwares_for_Adafruit_Feather_RP2040_Scorpio.txt - echo "SPI is using spi0 interface pins: GPIO19(OUTPUT_SPI_DATA_PIN) and GPIO18(OUTPUT_SPI_CLOCK_PIN) on output 3 and 2 respectively." >> ../firmware/Firmwares_for_Adafruit_Feather_RP2040_Scorpio.txt + rm -rf * + rm -rf ../firmware/* + echo "Neopixel is using GPIO16(OUTPUT_DATA_PIN) on output 0." > ../firmware/Pinout_for_Adafruit_Feather_RP2040_Scorpio.txt + echo "SPI is using spi0 interface pins: GPIO19(OUTPUT_SPI_DATA_PIN) and GPIO18(OUTPUT_SPI_CLOCK_PIN) on output 3 and 2 respectively." >> ../firmware/Pinout_for_Adafruit_Feather_RP2040_Scorpio.txt cmake -DOVERRIDE_BOOT_WORKAROUND=ON -DOVERRIDE_DATA_PIN=16 -DOVERRIDE_SPI_DATA_PIN=19 -DOVERRIDE_SPI_CLOCK_PIN=18 -DCMAKE_BUILD_TYPE=Release .. cmake --build . zip -j ../firmware/Adafruit_Feather_RP2040_Scorpio.zip ../firmware/* - uses: actions/upload-artifact@v7.0.0 - name: Upload artifacts (release Adafruit_Feather) - if: startsWith(github.ref, 'refs/tags/') + name: Upload artifacts (release for Adafruit_Feather_RP2040) with: - name: firmware-release-adafruit-scorpio + name: firmware-release-adafruit-scorpio-RP2040 + archive: false path: | firmware/*.zip - - name: Build packages for Adafruit ItsyBitsy RP2040 (release-only) - if: startsWith(github.ref, 'refs/tags/') + - name: Build packages for Adafruit ItsyBitsy RP2040 shell: bash run: | cd build - rm *.* - rm ../firmware/* - echo "Neopixel is using GPIO14(OUTPUT_DATA_PIN) on output 5." > ../firmware/Firmwares_for_Adafruit_ItsyBitsy_2040.txt + rm -rf * + rm -rf ../firmware/* + echo "Neopixel is using GPIO14(OUTPUT_DATA_PIN) on output 5." > ../firmware/Pinout_for_Adafruit_ItsyBitsy_RP2040.txt cmake -DOVERRIDE_BOOT_WORKAROUND=ON -DOVERRIDE_DATA_PIN=14 -DCMAKE_BUILD_TYPE=Release .. cmake --build . rm ../firmware/*_Spi.uf2 - zip -j ../firmware/Adafruit_ItsyBitsy_2040.zip ../firmware/* + rm ../firmware/*_ws2801.uf2 + zip -j ../firmware/Adafruit_ItsyBitsy_RP2040.zip ../firmware/* - uses: actions/upload-artifact@v7.0.0 - name: Upload artifacts (release Adafruit_ItsyBitsy) - if: startsWith(github.ref, 'refs/tags/') + name: Upload artifacts (release for Adafruit_ItsyBitsy_RP2040) with: - name: firmware-release-adafruit-itsybitsy + name: firmware-release-adafruit-itsybitsy-RP2040 + archive: false path: | firmware/*.zip - - name: Build packages for Pimoroni Plasma Stick 2040 W (release-only) - if: startsWith(github.ref, 'refs/tags/') + - name: Build packages for Pimoroni Plasma Stick RP2040 W shell: bash run: | cd build - rm *.* - rm ../firmware/* - echo "Neopixel is using GPIO15(OUTPUT_DATA_PIN) on output PIXELS." > ../firmware/Firmwares_for_Pimoroni_Plasma_Stick_2040_W.txt + rm -rf * + rm -rf ../firmware/* + echo "Neopixel is using GPIO15(OUTPUT_DATA_PIN) on output PIXELS." > ../firmware/Pinout_for_Pimoroni_Plasma_Stick_RP2040_W.txt cmake -DOVERRIDE_DATA_PIN=15 -DCMAKE_BUILD_TYPE=Release .. cmake --build . rm ../firmware/*_Spi.uf2 - zip -j ../firmware/Pimoroni_Plasma_Stick_2040_W.zip ../firmware/* + rm ../firmware/*_ws2801.uf2 + zip -j ../firmware/Pimoroni_Plasma_Stick_RP2040_W.zip ../firmware/* - uses: actions/upload-artifact@v7.0.0 - name: Upload artifacts (release Pimoroni_Plasma_Stick_W) - if: startsWith(github.ref, 'refs/tags/') + name: Upload artifacts (release for Pimoroni_Plasma_Stick_RP2040_W) with: - name: firmware-release-pimoroni-plasma-stick + name: firmware-release-pimoroni-plasma-stick-RP2040-W + archive: false path: | firmware/*.zip - - name: Build packages for Pimoroni Plasma 2040 (release-only) - if: startsWith(github.ref, 'refs/tags/') + - name: Build packages for Pimoroni Plasma 2040 shell: bash run: | cd build - rm *.* - rm ../firmware/* - echo "Neopixel is using GPIO15(OUTPUT_DATA_PIN) on output DA." > ../firmware/Firmwares_for_Pimoroni_Plasma_2040.txt - echo "SPI is using spi1 interface pins: GPIO15(OUTPUT_SPI_DATA_PIN) and GPIO14(OUTPUT_SPI_CLOCK_PIN) on output DA and CL respectively." >> ../firmware/Firmwares_for_Pimoroni_Plasma_2040.txt + rm -rf * + rm -rf ../firmware/* + echo "Neopixel is using GPIO15(OUTPUT_DATA_PIN) on output DA." > ../firmware/Pinout_for_Pimoroni_Plasma_RP2040.txt + echo "SPI is using spi1 interface pins: GPIO15(OUTPUT_SPI_DATA_PIN) and GPIO14(OUTPUT_SPI_CLOCK_PIN) on output DA and CL respectively." >> ../firmware/Pinout_for_Pimoroni_Plasma_RP2040.txt cmake -DOVERRIDE_DATA_PIN=15 -DOVERRIDE_SPI_INTERFACE=spi1 -DOVERRIDE_SPI_DATA_PIN=15 -DOVERRIDE_SPI_CLOCK_PIN=14 -DCMAKE_BUILD_TYPE=Release .. cmake --build . - zip -j ../firmware/Pimoroni_Plasma_2040.zip ../firmware/* + zip -j ../firmware/Pimoroni_Plasma_RP2040.zip ../firmware/* + + - uses: actions/upload-artifact@v7.0.0 + name: Upload artifacts (release for Pimoroni_Plasma_RP2040) + with: + name: firmware-release-pimoroni-plasma-RP2040 + archive: false + path: | + firmware/*.zip + + - name: Build packages for Pimoroni Plasma RP2350 + shell: bash + run: | + cd build + rm -rf * + rm -rf ../firmware/* + echo "Neopixel is using GPIO15(OUTPUT_DATA_PIN) on output DA." > ../firmware/Pinout_for_Pimoroni_Plasma_RP2350.txt + echo "SPI is using spi1 interface pins: GPIO15(OUTPUT_SPI_DATA_PIN) and GPIO14(OUTPUT_SPI_CLOCK_PIN) on output DA and CL respectively." >> ../firmware/Pinout_for_Pimoroni_Plasma_RP2350.txt + cmake -DTARGET_BOARD=pimoroni_plasma2350 -DOVERRIDE_DATA_PIN=15 -DOVERRIDE_SPI_INTERFACE=spi1 -DOVERRIDE_SPI_DATA_PIN=15 -DOVERRIDE_SPI_CLOCK_PIN=14 -DCMAKE_BUILD_TYPE=Release .. + cmake --build . + zip -j ../firmware/Pimoroni_Plasma_RP2350.zip ../firmware/* - uses: actions/upload-artifact@v7.0.0 - name: Upload artifacts (release Pimoroni_Plasma) - if: startsWith(github.ref, 'refs/tags/') + name: Upload artifacts (release for Pimoroni_Plasma_RP2350) with: - name: firmware-release-pimoroni-plasma + name: firmware-release-pimoroni-plasma-RP2350 + archive: false path: | firmware/*.zip @@ -136,7 +164,7 @@ jobs: name: Publish Releases if: startsWith(github.event.ref, 'refs/tags') needs: [HyperSerialPico] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: contents: write steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index a6e0ad2..2c5c6e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,12 +33,26 @@ add_definitions ( -DPICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE=0 ) # initialize the SDK based on PICO_SDK_PATH # note: this must happen before project() set(PICO_SDK_PATH ${CMAKE_CURRENT_SOURCE_DIR}/sdk/pico) -set(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/sdk/freertos) +# FreeRTOS config +add_library(freertos_config INTERFACE) +target_include_directories(freertos_config INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/sdk/config ) +set(FREERTOS_KERNEL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sdk/freertos") + +# Target: 'pico' (RP2040) or 'pico2' (RP2350) +set(TARGET_BOARD "pico" CACHE STRING "Target board: pico or pico2") +set(PICO_BOARD ${TARGET_BOARD}) include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake) + +if (PICO_RP2350) + set(FREERTOS_PORT "GCC_ARM_CM33_NTZ" CACHE STRING "") +else() + set(FREERTOS_PORT "GCC_ARM_CM0" CACHE STRING "") +endif() + include(${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake) -project(HyperSerialPico C CXX ASM) +project("HyperSerialPico_${PICO_CHIP}" C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) @@ -53,8 +67,8 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC) pico_sdk_init() # generic HyperSerialPico settings -set(HyperSerialPicoCompanionLibs FreeRTOS-Kernel FreeRTOS-Kernel-Heap1 pico_stdlib pico_multicore hardware_pio hardware_dma hardware_spi) -set(HyperSerialPicoCompanionIncludes ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/sdk/config) +set(HyperSerialPicoCompanionIncludes ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/sdk/config ${PICO_SDK_PATH}/src/rp2_common/pico_stdio_usb/include ${PICO_SDK_PATH}/src/common/pico_usb_reset_interface_headers/include) +set(HyperSerialPicoCompanionLibs FreeRTOS-Kernel freertos_config FreeRTOS-Kernel-Heap1 tinyusb_board tinyusb_device pico_stdlib pico_multicore hardware_pio hardware_dma hardware_spi) file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/generated) file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/firmware) @@ -114,10 +128,14 @@ macro(HyperSerialPicoTarget HyperSerialPicoTargetName) if (BOOT_WORKAROUND) target_compile_definitions(${HyperSerialPicoTargetName} PUBLIC -DBOOT_WORKAROUND -DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64) endif() + + target_compile_definitions(${HyperSerialPicoTargetName} PRIVATE -DPICO_STDIO_USB_USE_DEFAULT_DESCRIPTORS=1) + target_sources(${HyperSerialPicoTargetName} PRIVATE ${PICO_SDK_PATH}/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c) + target_include_directories(${HyperSerialPicoTargetName} PRIVATE ${HyperSerialPicoCompanionIncludes}) target_link_libraries(${HyperSerialPicoTargetName} ${HyperSerialPicoCompanionLibs}) pico_add_extra_outputs(${HyperSerialPicoTargetName}) - pico_enable_stdio_usb(${HyperSerialPicoTargetName} 1) + pico_enable_stdio_usb(${HyperSerialPicoTargetName} 0) pico_enable_stdio_uart(${HyperSerialPicoTargetName} 0) pico_generate_pio_header(${HyperSerialPicoTargetName} ${CMAKE_CURRENT_SOURCE_DIR}/pio/neopixel.pio OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/generated) pico_generate_pio_header(${HyperSerialPicoTargetName} ${CMAKE_CURRENT_SOURCE_DIR}/pio/neopixel_ws2812b.pio OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/generated) diff --git a/include/base.h b/include/base.h index 9857b64..e48b41e 100644 --- a/include/base.h +++ b/include/base.h @@ -45,9 +45,6 @@ class Base // handle to tasks TaskHandle_t processDataHandle = nullptr; TaskHandle_t processSerialHandle = nullptr; - // semaphore to synchronize them - semaphore_t serialSemaphore; - semaphore_t receiverSemaphore; // current queue position volatile int queueCurrent = 0; // queue end position diff --git a/include/calibration.h b/include/calibration.h index cd7cf50..5d334c7 100644 --- a/include/calibration.h +++ b/include/calibration.h @@ -125,11 +125,11 @@ class CalibrationConfig * @brief print RGBW calibration parameters when no data is received * */ - void printCalibration() + template + void printCalibration(char (&output)[N]) { - char output[128]; - snprintf(output, sizeof(output),"RGBW => Gain: %i/255, red: %i, green: %i, blue: %i\r\n", gain, red, green, blue); - printf(output); + snprintf(output, N, "RGBW => Gain: %i/255, red: %i, green: %i, blue: %i\r\n", gain, red, green, blue); + tud_cdc_write_str(output); } } calibrationConfig; diff --git a/include/leds.h b/include/leds.h index bb58f32..3e92162 100644 --- a/include/leds.h +++ b/include/leds.h @@ -77,7 +77,7 @@ #include #include -struct ColorGrb32 +struct __attribute__((packed)) ColorGrb32 { uint8_t notUsed; uint8_t B; @@ -99,7 +99,7 @@ struct ColorGrb32 }; }; -struct ColorGrb +struct __attribute__((packed)) ColorGrb { uint8_t B; uint8_t R; @@ -116,7 +116,7 @@ struct ColorGrb }; }; -struct ColorGrbw +struct __attribute__((packed)) ColorGrbw { uint8_t W; uint8_t B; @@ -138,7 +138,7 @@ struct ColorGrbw }; }; -struct ColorDotstartBgr +struct __attribute__((packed)) ColorDotstartBgr { uint8_t Brightness; uint8_t B; @@ -155,7 +155,7 @@ struct ColorDotstartBgr }; }; -struct ColorRgb +struct __attribute__((packed)) ColorRgb { uint8_t R; uint8_t G; @@ -202,7 +202,7 @@ class LedDriver dma = reinterpret_cast(calloc(dmaSize, 1)); } - ~LedDriver() + virtual ~LedDriver() { free(buffer); free(dma); @@ -234,22 +234,27 @@ class DmaClient lastRenderTime = 0; }; - ~DmaClient() + virtual ~DmaClient() { - for(int i = 0; i < 10 && isDmaBusy; i++) + for(int i = 0; i < 100 && isDmaBusy; i++) busy_wait_us(500); dma_channel_abort(PICO_DMA_CHANNEL); dma_channel_set_irq0_enabled(PICO_DMA_CHANNEL, false); - irq_set_enabled(DMA_IRQ_0, false); + irq_remove_handler(DMA_IRQ_0, dmaFinishReceiver); dma_channel_unclaim(PICO_DMA_CHANNEL); }; - void dmaConfigure(PIO _selectedPIO, uint _sm) + void dmaConfigure() { - selectedPIO = _selectedPIO; - stateIndex = _sm; + selectedPIO = pio0; + int sm = pio_claim_unused_sm(selectedPIO, false); + if (sm < 0) { + selectedPIO = pio1; + sm = pio_claim_unused_sm(selectedPIO, true); + } + stateIndex = (uint)sm; }; void initDmaPio(uint dataLenDword32) @@ -275,7 +280,7 @@ class DmaClient void assignDmaIrq() { - irq_set_exclusive_handler(DMA_IRQ_0, dmaFinishReceiver); + irq_add_shared_handler(DMA_IRQ_0, dmaFinishReceiver, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); dma_channel_set_irq0_enabled(PICO_DMA_CHANNEL, true); irq_set_enabled(DMA_IRQ_0, true); }; @@ -284,7 +289,7 @@ class DmaClient bool isReadyBlocking() { - int wait = 200; + int wait = 2000; while(isDmaBusy && wait-- > 0) busy_wait_us(50); @@ -315,6 +320,9 @@ class Neopixel : public LedDriver, public DmaClient uint64_t resetTime; + uint programAddress; + const pio_program_t* pioProgram; + friend class NeopixelParallel; public: @@ -322,15 +330,14 @@ class Neopixel : public LedDriver, public DmaClient LedDriver(_ledsNumber, _pin, _dmaSize) { pio_sm_config smConfig; - uint programAddress; - dmaConfigure(pio0, 0); + dmaConfigure(); resetTime = _resetTime; if (lanes >= 1) { - programAddress = (timingType == NeopixelSubtype::ws2812b) ? - pio_add_program(selectedPIO, &neopixel_ws2812b_parallel_program) : pio_add_program(selectedPIO, &neopixel_parallel_program); + pioProgram = (timingType == NeopixelSubtype::ws2812b) ? &neopixel_ws2812b_parallel_program : &neopixel_parallel_program; + programAddress = pio_add_program(selectedPIO, pioProgram); for(uint i=_pin; i<_pin + lanes; i++){ pio_gpio_init(selectedPIO, i); @@ -340,12 +347,11 @@ class Neopixel : public LedDriver, public DmaClient neopixel_ws2812b_parallel_program_get_default_config(programAddress) : neopixel_parallel_program_get_default_config(programAddress); sm_config_set_out_pins(&smConfig, _pin, lanes); - sm_config_set_set_pins(&smConfig, _pin, lanes); } else { - programAddress = (timingType == NeopixelSubtype::ws2812b) ? - pio_add_program(selectedPIO, &neopixel_ws2812b_program) : pio_add_program(selectedPIO, &neopixel_program); + pioProgram = (timingType == NeopixelSubtype::ws2812b) ? &neopixel_ws2812b_program : &neopixel_program; + programAddress = pio_add_program(selectedPIO, pioProgram); pio_gpio_init(selectedPIO, _pin); @@ -366,6 +372,15 @@ class Neopixel : public LedDriver, public DmaClient initDmaPio(dmaSize / 4); } + virtual ~Neopixel() + { + pio_sm_set_enabled(selectedPIO, stateIndex, false); + pio_sm_clear_fifos(selectedPIO, stateIndex); + pio_sm_unclaim(selectedPIO, stateIndex); + + pio_remove_program(selectedPIO, pioProgram, programAddress); + } + uint8_t* getBufferMemory() { return buffer; @@ -440,7 +455,7 @@ class NeopixelParallel buffer = muxer->getBufferMemory(); } - ~NeopixelParallel() + virtual ~NeopixelParallel() { if (instances > 0) instances--; @@ -514,7 +529,7 @@ class Dotstar : public LedDriver, public DmaClient Dotstar(uint64_t _resetTime, int _ledsNumber, spi_inst_t* _spi, uint32_t _datapin, uint32_t _clockpin, int _dmaSize): LedDriver(_ledsNumber, _datapin, _clockpin, _dmaSize) { - dmaConfigure(pio0, 0); + dmaConfigure(); resetTime = _resetTime; spi_init(_spi, 10000000); @@ -583,7 +598,7 @@ class Ws2801 : public LedDriver, public DmaClient Ws2801(uint64_t _resetTime, int _ledsNumber, spi_inst_t* _spi, uint32_t _datapin, uint32_t _clockpin, int _dmaSize): LedDriver(_ledsNumber, _datapin, _clockpin, _dmaSize) { - dmaConfigure(pio0, 0); + dmaConfigure(); resetTime = _resetTime; spi_init(_spi, 1000000); diff --git a/include/main.h b/include/main.h index 3f0fca6..c18bf73 100644 --- a/include/main.h +++ b/include/main.h @@ -73,7 +73,6 @@ void processData() if (base.queueCurrent >= MAX_BUFFER) { base.queueCurrent = 0; - yield(); } switch (frameState.getState()) @@ -151,17 +150,20 @@ void processData() } else if (frameState.getCount() == 0x2aa2 && (input == 0x15 || input == 0x35)) { - statistics.print(currentTime, base.processDataHandle, base.processSerialHandle); - - if (input == 0x15) - printf(HELLO_MESSAGE); + statistics.print(currentTime, input == 0x15); frameState.setRegroup(true); - delay(10); - currentTime = millis(); - statistics.reset(currentTime); + if (input == 0x15) + { + statistics.reset(currentTime); + } + else + { + statistics.lightReset(currentTime, true); + } + frameState.setState(AwaProtocol::HEADER_A); } else @@ -297,8 +299,6 @@ void processData() currentTime = millis(); deltaTime = currentTime - statistics.getStartTime(); updateMainStatistics(currentTime, deltaTime, true); - - yield(); } frameState.setState(AwaProtocol::HEADER_A); diff --git a/include/statistics.h b/include/statistics.h index 8629179..8d756f2 100644 --- a/include/statistics.h +++ b/include/statistics.h @@ -28,6 +28,8 @@ #ifndef STATISTICS_H #define STATISTICS_H +#include + // statistics (stats sent only when there is no communication) class { @@ -35,11 +37,17 @@ class uint16_t goodFrames = 0; uint16_t showFrames = 0; uint16_t totalFrames = 0; - uint16_t finalGoodFrames = 0; - uint16_t finalShowFrames = 0; - uint16_t finalTotalFrames = 0; + + volatile struct { + uint16_t finalGoodFrames = 0; + uint16_t finalShowFrames = 0; + uint16_t finalTotalFrames = 0; + bool welcomeMessage = false; + } outputStatistics; public: + std::atomic printLogs = false; + /** * @brief Get the start time of the current period * @@ -96,9 +104,9 @@ class { if (totalFrames > 0) { - finalShowFrames = showFrames; - finalGoodFrames = std::min(goodFrames, totalFrames); - finalTotalFrames = totalFrames; + outputStatistics.finalShowFrames = showFrames; + outputStatistics.finalGoodFrames = std::min(goodFrames, totalFrames); + outputStatistics.finalTotalFrames = totalFrames; } startTime = currentTime; @@ -113,25 +121,37 @@ class * @param curTime * @param taskHandle */ - void print(unsigned long curTime, TaskHandle_t taskHandle1, TaskHandle_t taskHandle2) + void print(unsigned long curTime, bool isWelcome) { - char output[128]; - startTime = curTime; goodFrames = 0; totalFrames = 0; showFrames = 0; + + outputStatistics.welcomeMessage = isWelcome; + + printLogs.store(true); + } - snprintf(output, sizeof(output), "HyperHDR frames: %u (FPS), receiv.: %u, good: %u, incompl.: %u, mem1: %i, mem2: %i, heap: %zu\r\n", - finalShowFrames, finalTotalFrames,finalGoodFrames,(finalTotalFrames - finalGoodFrames), - (taskHandle1 != nullptr) ? uxTaskGetStackHighWaterMark(taskHandle1) : 0, - (taskHandle2 != nullptr) ? uxTaskGetStackHighWaterMark(taskHandle2) : 0, + void printToSerial(TaskHandle_t taskHandleCore0) + { + char output[128]; + + snprintf(output, sizeof(output), "HyperHDR frames: %u (FPS), receiv.: %u, good: %u, incompl.: %u, core0: %i, heap: %zu\r\n", + outputStatistics.finalShowFrames, outputStatistics.finalTotalFrames, outputStatistics.finalGoodFrames, + (outputStatistics.finalTotalFrames - outputStatistics.finalGoodFrames), + (taskHandleCore0 != nullptr) ? uxTaskGetStackHighWaterMark(taskHandleCore0) : 0, xPortGetFreeHeapSize()); - printf(output); + tud_cdc_write_str(output); #if defined(NEOPIXEL_RGBW) - calibrationConfig.printCalibration(); + calibrationConfig.printCalibration(output); #endif + + if (outputStatistics.welcomeMessage) + { + tud_cdc_write_str(HELLO_MESSAGE); + } } /** @@ -142,9 +162,9 @@ class { startTime = currentTime; - finalShowFrames = 0; - finalGoodFrames = 0; - finalTotalFrames = 0; + outputStatistics.finalShowFrames = 0; + outputStatistics.finalGoodFrames = 0; + outputStatistics.finalTotalFrames = 0; goodFrames = 0; totalFrames = 0; diff --git a/sdk/config/FreeRTOSConfig.h b/sdk/config/FreeRTOSConfig.h index 64902fc..9c7eaab 100644 --- a/sdk/config/FreeRTOSConfig.h +++ b/sdk/config/FreeRTOSConfig.h @@ -47,7 +47,20 @@ #define configUSE_TICK_HOOK 0 #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMAX_PRIORITIES 32 -#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 +#ifdef __ARM_ARCH_8M_MAIN__ + #define configMINIMAL_STACK_SIZE ( ( configSTACK_DEPTH_TYPE ) 2048 ) + #define configENABLE_FPU 0 + #define configENABLE_MPU 0 + #define configENABLE_TRUSTZONE 0 + #define configRUN_FREERTOS_SECURE_ONLY 1 + #define configPRIO_BITS 3 + #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x07 + #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x05 + #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) ) + #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) ) +#else + #define configMINIMAL_STACK_SIZE ( ( configSTACK_DEPTH_TYPE ) 512 ) +#endif #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 @@ -103,7 +116,7 @@ /* SMP port only */ #define configNUM_CORES 1 -#define configTICK_CORE 1 +#define configTICK_CORE 0 #define configRUN_MULTIPLE_PRIORITIES 1 /* RP2040 specific */ diff --git a/sdk/config/tusb_config.h b/sdk/config/tusb_config.h new file mode 100644 index 0000000..643553b --- /dev/null +++ b/sdk/config/tusb_config.h @@ -0,0 +1,47 @@ +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// COMMON CONFIGURATION +// ----------------------------------------------------------------------------- +#define CFG_TUSB_MCU OPT_MCU_RP2040 + +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) +#ifndef BOARD_TUD_RHPORT + #define BOARD_TUD_RHPORT 0 +#endif + +#define CFG_TUD_ENDPOINT0_SIZE 64 + +// ----------------------------------------------------------------------------- +// DEVICE CLASSES CONFIGURATION +// ----------------------------------------------------------------------------- +#define CFG_TUD_ENABLED 1 +#define CFG_TUD_CDC 1 +#define CFG_TUD_MSC 0 +#define CFG_TUD_HID 0 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_VENDOR 0 + +// ----------------------------------------------------------------------------- +// CDC CONFIGURATION +// ----------------------------------------------------------------------------- +#ifndef CFG_TUD_CDC_RX_BUFSIZE + #define CFG_TUD_CDC_RX_BUFSIZE 8192 +#endif +#ifndef CFG_TUD_CDC_EP_BUFSIZE + #define CFG_TUD_CDC_EP_BUFSIZE 4096 +#endif +#ifndef CFG_TUD_CDC_TX_BUFSIZE + #define CFG_TUD_CDC_TX_BUFSIZE 768 +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ \ No newline at end of file diff --git a/sdk/freertos b/sdk/freertos index 570ade4..9b777ae 160000 --- a/sdk/freertos +++ b/sdk/freertos @@ -1 +1 @@ -Subproject commit 570ade4001e50adbf06a074582ea993af562e0e1 +Subproject commit 9b777ae5c5b8e9e456065a00294d1e5f5f9facf5 diff --git a/sdk/pico b/sdk/pico index f396d05..a1438df 160000 --- a/sdk/pico +++ b/sdk/pico @@ -1 +1 @@ -Subproject commit f396d05f8252d4670d4ea05c8b7ac938ef0cd381 +Subproject commit a1438dff1d38bd9c65dbd693f0e5db4b9ae91779 diff --git a/source/main.cpp b/source/main.cpp index ada0f73..516d98b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -25,17 +25,18 @@ * SOFTWARE. */ -#define TUD_OPT_HIGH_SPEED - - #include "FreeRTOS.h" #include "task.h" +#include "tusb_config.h" +#include "tusb.h" +#include "pico/multicore.h" +#include "hardware/irq.h" +#include "semphr.h" #include #include #include "pico/stdio/driver.h" #include "pico/stdlib.h" #include "pico/stdio.h" -#include "pico/stdio_usb.h" #include "pico/multicore.h" #include "pico/sem.h" #include "leds.h" @@ -129,52 +130,49 @@ static void core1() { for( ;; ) { - if (sem_acquire_timeout_us(&base.serialSemaphore, portMAX_DELAY)) - { - processData(); - } + [[maybe_unused]] auto val = multicore_fifo_pop_blocking(); + processData(); } } -static void core0( void *pvParameters ) -{ - for( ;; ) - { - if (sem_acquire_timeout_us(&base.receiverSemaphore, portMAX_DELAY)) +void core0(void *pvParameters) { + tusb_init(); + while (1) { + tud_task(); + if (tud_cdc_connected()) { - int wanted, received; - do - { - wanted = std::min(MAX_BUFFER - base.queueEnd, MAX_BUFFER - 1); - received = stdio_usb.in_chars((char*)(&(base.buffer[base.queueEnd])), wanted); - if (received > 0) + // receive + if (tud_cdc_available()) { + int wanted, received; + do { - base.queueEnd = (base.queueEnd + received) % (MAX_BUFFER); - } - }while(wanted == received); - - sem_release(&base.serialSemaphore); - } + wanted = std::min(MAX_BUFFER - base.queueEnd, MAX_BUFFER - 1); + + if (tud_cdc_connected() && tud_cdc_available()) { + received = (int)tud_cdc_read(const_cast(&(base.buffer[base.queueEnd])), (uint32_t)wanted); + } + + if (received > 0) + { + base.queueEnd = (base.queueEnd + received) % (MAX_BUFFER); + } + }while(wanted == received); + + multicore_fifo_push_blocking(0xAA); + } + // send + else if (statistics.printLogs.exchange(false)) { + statistics.printToSerial(base.processSerialHandle); + tud_cdc_write_flush(); + } + } } } -static void serialEvent(void *) -{ - sem_release(&base.receiverSemaphore); -} - int main(void) { - stdio_init_all(); - - sem_init(&base.serialSemaphore, 0, 1); - - sem_init(&base.receiverSemaphore, 0, 1); - multicore_launch_core1(core1); - stdio_set_chars_available_callback(serialEvent, nullptr); - xTaskCreate(core0, "HyperSerialPico:core0", configMINIMAL_STACK_SIZE * 2,