|
43 | 43 | #include "py/mphal.h"
|
44 | 44 | #include "py/runtime.h"
|
45 | 45 | #include "shared-bindings/neopixel_write/__init__.h"
|
| 46 | +#include "supervisor/port.h" |
46 | 47 | #include "components/driver/include/driver/rmt.h"
|
47 | 48 | #include "peripherals/rmt.h"
|
48 | 49 |
|
49 |
| -#define WS2812_T0H_NS (350) |
50 |
| -#define WS2812_T0L_NS (1000) |
51 |
| -#define WS2812_T1H_NS (1000) |
52 |
| -#define WS2812_T1L_NS (350) |
53 |
| -#define WS2812_RESET_US (280) |
| 50 | +// 416 ns is 1/3 of the 1250ns period of a 800khz signal. |
| 51 | +#define WS2812_T0H_NS (416) |
| 52 | +#define WS2812_T0L_NS (416 * 2) |
| 53 | +#define WS2812_T1H_NS (416 * 2) |
| 54 | +#define WS2812_T1L_NS (416) |
54 | 55 |
|
55 | 56 | static uint32_t ws2812_t0h_ticks = 0;
|
56 | 57 | static uint32_t ws2812_t1h_ticks = 0;
|
57 | 58 | static uint32_t ws2812_t0l_ticks = 0;
|
58 | 59 | static uint32_t ws2812_t1l_ticks = 0;
|
59 | 60 |
|
| 61 | +static uint64_t next_start_raw_ticks = 0; |
| 62 | + |
60 | 63 | static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
|
61 | 64 | size_t wanted_num, size_t *translated_size, size_t *item_num) {
|
62 | 65 | if (src == NULL || dest == NULL) {
|
@@ -107,21 +110,29 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout,
|
107 | 110 | if (rmt_get_counter_clock(config.channel, &counter_clk_hz) != ESP_OK) {
|
108 | 111 | mp_raise_RuntimeError(translate("Could not retrieve clock"));
|
109 | 112 | }
|
110 |
| - float ratio = (float)counter_clk_hz / 1e9; |
111 |
| - ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS); |
112 |
| - ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS); |
113 |
| - ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS); |
114 |
| - ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS); |
| 113 | + size_t ns_per_tick = 1e9 / counter_clk_hz; |
| 114 | + ws2812_t0h_ticks = WS2812_T0H_NS / ns_per_tick; |
| 115 | + ws2812_t0l_ticks = WS2812_T0L_NS / ns_per_tick; |
| 116 | + ws2812_t1h_ticks = WS2812_T1H_NS / ns_per_tick; |
| 117 | + ws2812_t1l_ticks = WS2812_T1L_NS / ns_per_tick; |
115 | 118 |
|
116 | 119 | // Initialize automatic timing translator
|
117 | 120 | rmt_translator_init(config.channel, ws2812_rmt_adapter);
|
118 | 121 |
|
| 122 | + // Wait to make sure we don't append onto the last transmission. This should only be a tick or |
| 123 | + // two. |
| 124 | + while (port_get_raw_ticks(NULL) < next_start_raw_ticks) { |
| 125 | + } |
| 126 | + |
119 | 127 | // Write and wait to finish
|
120 | 128 | if (rmt_write_sample(config.channel, pixels, (size_t)numBytes, true) != ESP_OK) {
|
121 | 129 | mp_raise_RuntimeError(translate("Input/output error"));
|
122 | 130 | }
|
123 | 131 | rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(100));
|
124 | 132 |
|
| 133 | + // Update the next start to +2 ticks. It ensures that we've gone 300+ us. |
| 134 | + next_start_raw_ticks = port_get_raw_ticks(NULL) + 2; |
| 135 | + |
125 | 136 | // Free channel again
|
126 | 137 | peripherals_free_rmt(config.channel);
|
127 | 138 | // Swap pin back to GPIO mode
|
|
0 commit comments