diff --git a/esp-firmware/lib/ledtl/Esp32DriverRGBW.cpp b/esp-firmware/lib/ledtl/Esp32DriverRGBW.cpp index cb86513..4d9ce1c 100644 --- a/esp-firmware/lib/ledtl/Esp32DriverRGBW.cpp +++ b/esp-firmware/lib/ledtl/Esp32DriverRGBW.cpp @@ -2,93 +2,72 @@ #include "drivers/Esp32DriverRGBW.h" -#include -#include +#include +#include -// Timing constants -static constexpr uint16_t DIVIDER = 4; -static constexpr double RMT_DURATION_NS = 12.5; // Minimum time of a single RMT duration based on clock ns +// Timing constants, in ns +static constexpr uint32_t RESOLUTION_HZ = 20 * 1000 * 1000; // one RMT tick = 50 ns +static constexpr uint32_t TICK_NS = 1000 * 1000 * 1000 / RESOLUTION_HZ; static constexpr uint32_t T0H = 300; static constexpr uint32_t T0L = 900; static constexpr uint32_t T1H = 600; static constexpr uint32_t T1L = 600; -static constexpr uint32_t TRS = 80000; -static constexpr rmt_item32_t bit0Data = {uint32_t(T0H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T0L / (RMT_DURATION_NS * DIVIDER)), 0}; -static constexpr rmt_item32_t bit1Data = {uint32_t(T1H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T1L / (RMT_DURATION_NS * DIVIDER)), 0}; -// Function registered at the RMT driver that converts regular uint8_t values containing r,g,b,w values -// to rmt_item32_t for each bit. (8 bit -> 32 * 8 bit) -static void IRAM_ATTR uint8ToRmtAdaptor(const void *src, rmt_item32_t *dest, size_t srcSize, - size_t wantedNum, size_t *translatedSize, size_t *itemNum) +static rmt_symbol_word_t symbol(uint32_t highNs, uint32_t lowNs) { - if (src == NULL || dest == NULL) - { - *translatedSize = 0; - *itemNum = 0; - return; - } - - size_t size = 0; - size_t num = 0; - uint8_t *psrc = (uint8_t *)src; - rmt_item32_t *pdest = dest; - while (size < srcSize && num < wantedNum) - { - for (int i = 0; i < 8; i++) - { - // MSB first - const bool isBitSet = *psrc & (1 << (7 - i)); - pdest->val = isBitSet ? bit1Data.val : bit0Data.val; - num++; - pdest++; - } - size++; - psrc++; - } - *translatedSize = size; - *itemNum = num; + rmt_symbol_word_t s = {}; + s.duration0 = highNs / TICK_NS; + s.level0 = 1; + s.duration1 = lowNs / TICK_NS; + s.level1 = 0; + return s; } -void Esp32DriverRGBW::begin(int gpio, int rmtChannel) +void Esp32DriverRGBW::begin(int gpio) { - rmtChannel_ = rmtChannel; transmitting_ = false; - rmt_config_t rmt_tx; - rmt_tx.channel = static_cast(rmtChannel); - rmt_tx.gpio_num = static_cast(gpio); - rmt_tx.rmt_mode = RMT_MODE_TX; - rmt_tx.mem_block_num = 1; - rmt_tx.clk_div = DIVIDER; - rmt_tx.tx_config.loop_en = false; - rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; - rmt_tx.tx_config.carrier_en = false; - rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; - rmt_tx.tx_config.idle_output_en = true; + rmt_tx_channel_config_t channelConfig = {}; + channelConfig.gpio_num = static_cast(gpio); + channelConfig.clk_src = RMT_CLK_SRC_DEFAULT; + channelConfig.resolution_hz = RESOLUTION_HZ; + channelConfig.mem_block_symbols = 64; // one block, refilled from the interrupt + channelConfig.trans_queue_depth = 4; + ESP_ERROR_CHECK(rmt_new_tx_channel(&channelConfig, &channel_)); - ESP_ERROR_CHECK(rmt_config(&rmt_tx)); - ESP_ERROR_CHECK(rmt_driver_install(rmt_tx.channel, 0, 0)); + // Every byte goes out MSB first, one RMT symbol per bit - the strip's own byte order + // (g, r, b, w) is already how LedStripRGBW lays the data out in memory. + rmt_bytes_encoder_config_t encoderConfig = {}; + encoderConfig.bit0 = symbol(T0H, T0L); + encoderConfig.bit1 = symbol(T1H, T1L); + encoderConfig.flags.msb_first = 1; + ESP_ERROR_CHECK(rmt_new_bytes_encoder(&encoderConfig, &encoder_)); - rmt_translator_init((rmt_channel_t)rmtChannel, uint8ToRmtAdaptor); + ESP_ERROR_CHECK(rmt_enable(channel_)); } void Esp32DriverRGBW::end() { - ESP_ERROR_CHECK(rmt_driver_uninstall((rmt_channel_t)rmtChannel_)); + waitForTransmissionToFinish(); + ESP_ERROR_CHECK(rmt_disable(channel_)); + ESP_ERROR_CHECK(rmt_del_encoder(encoder_)); + ESP_ERROR_CHECK(rmt_del_channel(channel_)); + encoder_ = nullptr; + channel_ = nullptr; } void Esp32DriverRGBW::writeSync(const uint32_t *rgbwData, int numLeds) { + writeAsync(rgbwData, numLeds); waitForTransmissionToFinish(); - auto data = reinterpret_cast(rgbwData); - ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, true)); } void Esp32DriverRGBW::writeAsync(const uint32_t *rgbwData, int numLeds) { waitForTransmissionToFinish(); - auto data = reinterpret_cast(rgbwData); - ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, false)); + rmt_transmit_config_t transmitConfig = {}; + transmitConfig.loop_count = 0; + ESP_ERROR_CHECK(rmt_transmit(channel_, encoder_, rgbwData, numLeds * 4, &transmitConfig)); transmitting_ = true; } @@ -96,8 +75,7 @@ bool Esp32DriverRGBW::waitForTransmissionToFinish(int waitMs) { if (!transmitting_) return true; - auto ret = rmt_wait_tx_done((rmt_channel_t)rmtChannel_, waitMs / portTICK_PERIOD_MS); - if (ret == ESP_OK) + if (rmt_tx_wait_all_done(channel_, waitMs) == ESP_OK) { transmitting_ = false; return true; @@ -106,4 +84,4 @@ bool Esp32DriverRGBW::waitForTransmissionToFinish(int waitMs) return false; } -#endif \ No newline at end of file +#endif diff --git a/esp-firmware/lib/ledtl/drivers/Esp32DriverRGBW.h b/esp-firmware/lib/ledtl/drivers/Esp32DriverRGBW.h index dda9088..a691ba1 100644 --- a/esp-firmware/lib/ledtl/drivers/Esp32DriverRGBW.h +++ b/esp-firmware/lib/ledtl/drivers/Esp32DriverRGBW.h @@ -4,10 +4,13 @@ #include "containers/LedStripRGBW.h" +#include + class Esp32DriverRGBW { public: - void begin(int gpio, int rmtChannel); + // The RMT channel is picked by the driver; only the pin is ours to choose. + void begin(int gpio); void end(); void writeSync(const uint32_t *rgbwData, int numLeds); @@ -16,8 +19,9 @@ public: bool waitForTransmissionToFinish(int waitMs = 1000); private: - int rmtChannel_; - bool transmitting_; + rmt_channel_handle_t channel_ = nullptr; + rmt_encoder_handle_t encoder_ = nullptr; + bool transmitting_ = false; }; -#endif \ No newline at end of file +#endif diff --git a/esp-firmware/lib/rotary_encoder/rotary_encoder.c b/esp-firmware/lib/rotary_encoder/rotary_encoder.c index d9aa854..d81de14 100644 --- a/esp-firmware/lib/rotary_encoder/rotary_encoder.c +++ b/esp-firmware/lib/rotary_encoder/rotary_encoder.c @@ -220,12 +220,12 @@ esp_err_t rotary_encoder_init(rotary_encoder_info_t * info, gpio_num_t pin_a, gp info->state.direction = ROTARY_ENCODER_DIRECTION_NOT_SET; // configure GPIOs - gpio_pad_select_gpio(info->pin_a); + gpio_reset_pin(info->pin_a); gpio_set_pull_mode(info->pin_a, GPIO_PULLUP_ONLY); gpio_set_direction(info->pin_a, GPIO_MODE_INPUT); gpio_set_intr_type(info->pin_a, GPIO_INTR_ANYEDGE); - gpio_pad_select_gpio(info->pin_b); + gpio_reset_pin(info->pin_b); gpio_set_pull_mode(info->pin_b, GPIO_PULLUP_ONLY); gpio_set_direction(info->pin_b, GPIO_MODE_INPUT); gpio_set_intr_type(info->pin_b, GPIO_INTR_ANYEDGE); diff --git a/esp-firmware/platformio.ini b/esp-firmware/platformio.ini index df60b87..6e38933 100644 --- a/esp-firmware/platformio.ini +++ b/esp-firmware/platformio.ini @@ -13,7 +13,9 @@ data_dir = data default_envs = esp32 [env:esp32] -platform = espressif32 +; pioarduino's fork rather than PlatformIO's own espressif32 platform, which stays on +; Arduino core 2.x. Pinned to a release: 55.03.312-1 is Arduino core 3.3.12 on ESP-IDF 5.5. +platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.312-1/platform-espressif32.zip board = esp-wrover-kit board_upload.flash_size = "4MB" build_flags = -DPLATFORM_ESP32 @@ -21,14 +23,14 @@ framework = arduino monitor_port = /dev/ttyUSB0 upload_port = /dev/ttyUSB0 monitor_speed = 115200 -src_filter = +<*> - +build_src_filter = +<*> - lib_deps = - miguelbalboa/MFRC522 - bxparks/AceButton@^1.9.1 + miguelbalboa/MFRC522@1.4.12 + bxparks/AceButton@1.10.1 [env:native] -platform = native -src_filter = +<*> - +platform = native@1.2.1 +build_src_filter = +<*> - build_flags = -Ilib/ledtl -g -DPLATFORM_NATIVE lib_deps = - bxparks/AceButton@^1.9.1 + bxparks/AceButton@1.10.1 diff --git a/esp-firmware/src/Messages.h b/esp-firmware/src/Messages.h index d7b4f27..93d5f3a 100644 --- a/esp-firmware/src/Messages.h +++ b/esp-firmware/src/Messages.h @@ -183,7 +183,7 @@ inline bool handleLedEffect(TLedTask *ledTask, MessageHostToFw msgType, MessageH } template -inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *ledTaskMouse, LedTaskShelf *ledTaskShelf, uint8_t ledChannelLeft, uint8_t ledChannelRight) +inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *ledTaskMouse, LedTaskShelf *ledTaskShelf, uint8_t ledPinLeft, uint8_t ledPinRight) { if (Serial.available() < sizeof(MAGIC_TOKEN_FW_TO_HOST) + sizeof(MessageHostToFw) + sizeof(uint16_t)) return; @@ -238,12 +238,12 @@ inline void handleIncomingMessagesFromHost(LedTask1 *ledTaskCircle, LedTask2 *le else if (msgType == MessageHostToFw::PREV_BUTTON_LED) { float *val = reinterpret_cast(msgBuffer); - ledcWrite(ledChannelLeft, uint32_t(255 * (*val))); + ledcWrite(ledPinLeft, uint32_t(255 * (*val))); } else if (msgType == MessageHostToFw::NEXT_BUTTON_LED) { float *val = reinterpret_cast(msgBuffer); - ledcWrite(ledChannelRight, uint32_t(255 * (*val))); + ledcWrite(ledPinRight, uint32_t(255 * (*val))); } else Serial.println("Unknown message type"); diff --git a/esp-firmware/src/main.cpp b/esp-firmware/src/main.cpp index 91c7144..04ff0c6 100644 --- a/esp-firmware/src/main.cpp +++ b/esp-firmware/src/main.cpp @@ -117,11 +117,9 @@ void setupButtons() buttonRight.setEventHandler(handleButtonEvent); buttonRotary.setEventHandler(handleButtonEvent); - ledcSetup(0, PWM_FREQ, PWM_RESOLUTION); - ledcAttachPin(BUTTON_LEFT_LED_PIN, 0); - - ledcSetup(1, PWM_FREQ, PWM_RESOLUTION); - ledcAttachPin(BUTTON_RIGHT_LED_PIN, 1); + // Arduino core 3 picks the LEDC channel itself; from here on the pin is the handle. + ledcAttach(BUTTON_LEFT_LED_PIN, PWM_FREQ, PWM_RESOLUTION); + ledcAttach(BUTTON_RIGHT_LED_PIN, PWM_FREQ, PWM_RESOLUTION); } void handleButtons() @@ -139,7 +137,7 @@ LedTask ledTaskCircle; void setupLedCircle() { - ledDriverCircle.begin(22, 0); + ledDriverCircle.begin(22); ledTaskCircle.begin(ledStripCircle, ledDriverCircle); ledTaskCircle.startEffect(EffectStaticConfig(ColorRGBW{0, 0, 0, 0})); } @@ -152,7 +150,7 @@ LedTask ledTaskMouse; void setupMouseLeds() { - ledDriverMouse.begin(16, 1); + ledDriverMouse.begin(16); ledTaskMouse.begin(ledStripMouse, ledDriverMouse); ledTaskMouse.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}, 0, 0}); } @@ -165,7 +163,7 @@ LedTask ledTaskShelf; void setupShelfLeds() { - ledDriverShelf.begin(17, 2); + ledDriverShelf.begin(17); ledTaskShelf.begin(ledStripShelf, ledDriverShelf); ledTaskShelf.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}, 0, 0}); } @@ -234,7 +232,7 @@ void setup() void loop() { - handleIncomingMessagesFromHost(&ledTaskCircle, &ledTaskMouse, &ledTaskShelf, 0, 1); + handleIncomingMessagesFromHost(&ledTaskCircle, &ledTaskMouse, &ledTaskShelf, BUTTON_LEFT_LED_PIN, BUTTON_RIGHT_LED_PIN); handleTouchInputs(); handleRotaryEncoder(); handleButtons();