|
25 | 25 |
|
26 | 26 | #if defined(CONFIG_IDF_TARGET_ESP32S3)
|
27 | 27 |
|
| 28 | +#define GPIO_DRIVE_STRENGTH GPIO_DRIVE_CAP_3 |
| 29 | +#define LCD_CLK_PRESCALE 9 // 8, 9, 10 allowed. Bit clock = 160 MHz / this. |
| 30 | + |
28 | 31 | #if defined(CIRCUITPY) // COMPILING FOR CIRCUITPYTHON --------------------
|
29 | 32 | #include "components/esp_rom/include/esp_rom_sys.h"
|
30 | 33 | #include "components/heap/include/esp_heap_caps.h"
|
|
62 | 65 | // dmaSetupTime (measured in blast_byte()) measures the number of timer
|
63 | 66 | // cycles to set up and trigger the DMA transfer...
|
64 | 67 | static uint32_t dmaSetupTime = 100;
|
65 |
| -// ...then, the version of _PM_timerGetCount() here uses that figure as a |
66 |
| -// starting point, plus the known constant DMA transfer speed (20 MHz) and |
67 |
| -// timer frequency (40 MHz), i.e. 2 cycles/column, to return a fair estimate |
68 |
| -// of the one-scanline transfer time, from which everything is extrapolated: |
| 68 | +// ...then, the version of _PM_timerGetCount() here uses that as a starting |
| 69 | +// point, plus the known constant DMA xfer speed (160/LCD_CLK_PRESCALE MHz) |
| 70 | +// and timer frequency (40 MHz), to return an estimate of the one-scanline |
| 71 | +// transfer time, from which everything is extrapolated: |
69 | 72 | IRAM_ATTR inline uint32_t _PM_timerGetCount(Protomatter_core *core) {
|
70 | 73 | // Time estimate seems to come in a little high, so the -10 here is an
|
71 | 74 | // empirically-derived fudge factor that may yield ever-so-slightly better
|
72 | 75 | // refresh in some edge cases. If visual glitches are encountered, might
|
73 | 76 | // need to dial back this number a bit or remove it.
|
74 |
| - return dmaSetupTime + core->chainBits * 2 - 10; |
| 77 | + return dmaSetupTime + core->chainBits * 40 * LCD_CLK_PRESCALE / 160 - 10; |
75 | 78 | }
|
76 | 79 | // Note that dmaSetupTime can vary from line to line, potentially influenced
|
77 | 80 | // by interrupts, nondeterministic DMA channel clearing times, etc., which is
|
78 | 81 | // why we don't just use a constant value. Each scanline might show for a
|
79 | 82 | // slightly different length of time, but duty cycle scales with this so it's
|
80 | 83 | // perceptually consistent; don't see bright or dark rows.
|
81 | 84 |
|
82 |
| -#define _PM_minMinPeriod (200 + (uint32_t)core->chainBits * 2) |
| 85 | +#define _PM_minMinPeriod \ |
| 86 | + (200 + (uint32_t)core->chainBits * 40 * LCD_CLK_PRESCALE / 160) |
83 | 87 |
|
84 | 88 | #if (ESP_IDF_VERSION_MAJOR == 5)
|
85 | 89 | #include <esp_private/periph_ctrl.h>
|
@@ -125,10 +129,11 @@ IRAM_ATTR static void blast_long(Protomatter_core *core, uint32_t *data) {}
|
125 | 129 | static void pinmux(int8_t pin, uint8_t signal) {
|
126 | 130 | esp_rom_gpio_connect_out_signal(pin, signal, false, false);
|
127 | 131 | gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO);
|
128 |
| - gpio_set_drive_capability((gpio_num_t)pin, GPIO_DRIVE_CAP_MAX); |
| 132 | + gpio_set_drive_capability((gpio_num_t)pin, GPIO_DRIVE_STRENGTH); |
129 | 133 | }
|
130 | 134 |
|
131 | 135 | #if defined(ARDUINO) // COMPILING FOR ARDUINO ------------------------------
|
| 136 | + |
132 | 137 | // LCD_CAM requires a complete replacement of the "blast" functions in order
|
133 | 138 | // to use the DMA-based peripheral.
|
134 | 139 | #define _PM_CUSTOM_BLAST // Disable blast_*() functions in core.c
|
@@ -172,11 +177,17 @@ void _PM_timerInit(Protomatter_core *core) {
|
172 | 177 | esp_rom_delay_us(100);
|
173 | 178 |
|
174 | 179 | // Configure LCD clock
|
175 |
| - LCD_CAM.lcd_clock.clk_en = 1; // Enable clock |
176 |
| - LCD_CAM.lcd_clock.lcd_clk_sel = 3; // PLL160M source |
177 |
| - LCD_CAM.lcd_clock.lcd_clkm_div_a = 1; // 1/1 fractional divide, |
178 |
| - LCD_CAM.lcd_clock.lcd_clkm_div_b = 1; // plus '7' below yields... |
179 |
| - LCD_CAM.lcd_clock.lcd_clkm_div_num = 7; // 1:8 prescale (20 MHz CLK) |
| 180 | + LCD_CAM.lcd_clock.clk_en = 1; // Enable clock |
| 181 | + LCD_CAM.lcd_clock.lcd_clk_sel = 3; // PLL160M source |
| 182 | + LCD_CAM.lcd_clock.lcd_clkm_div_a = 1; // 1/1 fractional divide, |
| 183 | + LCD_CAM.lcd_clock.lcd_clkm_div_b = 1; // plus prescale below yields... |
| 184 | +#if LCD_CLK_PRESCALE == 8 |
| 185 | + LCD_CAM.lcd_clock.lcd_clkm_div_num = 7; // 1:8 prescale (20 MHz CLK) |
| 186 | +#elif LCD_CLK_PRESCALE == 9 |
| 187 | + LCD_CAM.lcd_clock.lcd_clkm_div_num = 8; // 1:9 prescale (17.8 MHz CLK) |
| 188 | +#else |
| 189 | + LCD_CAM.lcd_clock.lcd_clkm_div_num = 9; // 1:10 prescale (16 MHz CLK) |
| 190 | +#endif |
180 | 191 | LCD_CAM.lcd_clock.lcd_ck_out_edge = 0; // PCLK low in first half of cycle
|
181 | 192 | LCD_CAM.lcd_clock.lcd_ck_idle_edge = 0; // PCLK low idle
|
182 | 193 | LCD_CAM.lcd_clock.lcd_clk_equ_sysclk = 1; // PCLK = CLK (ignore CLKCNT_N)
|
@@ -212,10 +223,10 @@ void _PM_timerInit(Protomatter_core *core) {
|
212 | 223 | for (int i = 0; i < 6; i++)
|
213 | 224 | pinmux(core->rgbPins[i], signal[i]);
|
214 | 225 | pinmux(core->clockPin, LCD_PCLK_IDX);
|
215 |
| - gpio_set_drive_capability(core->latch.pin, GPIO_DRIVE_CAP_MAX); |
216 |
| - gpio_set_drive_capability(core->oe.pin, GPIO_DRIVE_CAP_MAX); |
| 226 | + gpio_set_drive_capability(core->latch.pin, GPIO_DRIVE_STRENGTH); |
| 227 | + gpio_set_drive_capability(core->oe.pin, GPIO_DRIVE_STRENGTH); |
217 | 228 | for (uint8_t i = 0; i < core->numAddressLines; i++) {
|
218 |
| - gpio_set_drive_capability(core->addr[i].pin, GPIO_DRIVE_CAP_MAX); |
| 229 | + gpio_set_drive_capability(core->addr[i].pin, GPIO_DRIVE_STRENGTH); |
219 | 230 | }
|
220 | 231 |
|
221 | 232 | // Disable LCD_CAM interrupts, clear any pending interrupt
|
@@ -256,6 +267,7 @@ void _PM_timerInit(Protomatter_core *core) {
|
256 | 267 | }
|
257 | 268 |
|
258 | 269 | #elif defined(CIRCUITPY) // COMPILING FOR CIRCUITPYTHON --------------------
|
| 270 | + |
259 | 271 | // LCD_CAM requires a complete replacement of the "blast" functions in order
|
260 | 272 | // to use the DMA-based peripheral.
|
261 | 273 | #define _PM_CUSTOM_BLAST // Disable blast_*() functions in core.c
|
@@ -312,8 +324,14 @@ static void _PM_timerInit(Protomatter_core *core) {
|
312 | 324 | LCD_CAM.lcd_clock.clk_en = 1; // Enable clock
|
313 | 325 | LCD_CAM.lcd_clock.lcd_clk_sel = 3; // PLL160M source
|
314 | 326 | LCD_CAM.lcd_clock.lcd_clkm_div_a = 1; // 1/1 fractional divide,
|
315 |
| - LCD_CAM.lcd_clock.lcd_clkm_div_b = 1; // plus '7' below yields... |
| 327 | + LCD_CAM.lcd_clock.lcd_clkm_div_b = 1; // plus prescale below yields... |
| 328 | +#if LCD_CLK_PRESCALE == 8 |
316 | 329 | LCD_CAM.lcd_clock.lcd_clkm_div_num = 7; // 1:8 prescale (20 MHz CLK)
|
| 330 | +#elif LCD_CLK_PRESCALE == 9 |
| 331 | + LCD_CAM.lcd_clock.lcd_clkm_div_num = 8; // 1:9 prescale (17.8 MHz CLK) |
| 332 | +#else |
| 333 | + LCD_CAM.lcd_clock.lcd_clkm_div_num = 9; // 1:10 prescale (16 MHz CLK) |
| 334 | +#endif |
317 | 335 | LCD_CAM.lcd_clock.lcd_ck_out_edge = 0; // PCLK low in first half of cycle
|
318 | 336 | LCD_CAM.lcd_clock.lcd_ck_idle_edge = 0; // PCLK low idle
|
319 | 337 | LCD_CAM.lcd_clock.lcd_clk_equ_sysclk = 1; // PCLK = CLK (ignore CLKCNT_N)
|
@@ -349,10 +367,10 @@ static void _PM_timerInit(Protomatter_core *core) {
|
349 | 367 | for (int i = 0; i < 6; i++)
|
350 | 368 | pinmux(core->rgbPins[i], signal[i]);
|
351 | 369 | pinmux(core->clockPin, LCD_PCLK_IDX);
|
352 |
| - gpio_set_drive_capability(core->latch.pin, GPIO_DRIVE_CAP_MAX); |
353 |
| - gpio_set_drive_capability(core->oe.pin, GPIO_DRIVE_CAP_MAX); |
| 370 | + gpio_set_drive_capability(core->latch.pin, GPIO_DRIVE_STRENGTH); |
| 371 | + gpio_set_drive_capability(core->oe.pin, GPIO_DRIVE_STRENGTH); |
354 | 372 | for (uint8_t i = 0; i < core->numAddressLines; i++) {
|
355 |
| - gpio_set_drive_capability(core->addr[i].pin, GPIO_DRIVE_CAP_MAX); |
| 373 | + gpio_set_drive_capability(core->addr[i].pin, GPIO_DRIVE_STRENGTH); |
356 | 374 | }
|
357 | 375 |
|
358 | 376 | // Disable LCD_CAM interrupts, clear any pending interrupt
|
|
0 commit comments