More LED fixes (#3368)

* apa102: remove dead code

We can't store strings of hundreds of thousands of characters in RAM, so
this can't possibly have fired, historically.  Pixbufs are still RAM
objects, so that's still out.  With LFS, it would take a pathological
example to hit the required 400KB TSTRING.

* Add IRQ management functions

* ws2812: fill UART FIFOs with IRQs off

Refactor code to make the use of two fill loops less gross.
This commit is contained in:
Nathaniel Wesley Filardo 2021-01-10 17:19:10 +00:00 committed by GitHub
parent 4023df7e60
commit 109f500be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 28 deletions

View File

@ -102,10 +102,6 @@ static int apa102_write(lua_State* L) {
return luaL_argerror(L, 3, "String or pixbuf expected");
}
if (nbr_frames > 100000) {
return luaL_error(L, "The supplied buffer is too long, and might cause the callback watchdog to bark.");
}
// Initialize the output pins
platform_gpio_mode(data_pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
GPIO_OUTPUT_SET(alt_data_pin, PLATFORM_GPIO_HIGH); // Set pin high

View File

@ -8,6 +8,7 @@
#include "user_interface.h"
#include "driver/uart.h"
#include "osapi.h"
#include "cpu_esp8266_irq.h"
#include "pixbuf.h"
@ -51,12 +52,18 @@ static int ws2812_init(lua_State* L) {
return 0;
}
// Stream data using UART1 routed to GPIO2
// ws2812.init() should be called first
//
// NODE_DEBUG should not be activated because it also uses UART1
void ICACHE_RAM_ATTR ws2812_write_data(const uint8_t *pixels, uint32_t length, const uint8_t *pixels2, uint32_t length2) {
static bool
ws2812_can_write(int uart)
{
// If something to send for first buffer and enough room
// in FIFO buffer (we wants to write 4 bytes, so less than
// 124 in the buffer)
return (((READ_PERI_REG(UART_STATUS(uart)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT) <= 124);
}
static void
ws2812_write_byte(int uart, uint8_t value)
{
// Data are sent LSB first, with a start bit at 0, an end bit at 1 and all inverted
// 0b00110111 => 110111 => [0]111011[1] => 10001000 => 00
// 0b00000111 => 000111 => [0]111000[1] => 10001110 => 01
@ -66,31 +73,37 @@ void ICACHE_RAM_ATTR ws2812_write_data(const uint8_t *pixels, uint32_t length, c
// But declared in ".data" section to avoid read penalty from FLASH
static const __attribute__((section(".data._uartData"))) uint8_t _uartData[4] = { 0b00110111, 0b00000111, 0b00110100, 0b00000100 };
WRITE_PERI_REG(UART_FIFO(uart), _uartData[(value >> 6) & 3]);
WRITE_PERI_REG(UART_FIFO(uart), _uartData[(value >> 4) & 3]);
WRITE_PERI_REG(UART_FIFO(uart), _uartData[(value >> 2) & 3]);
WRITE_PERI_REG(UART_FIFO(uart), _uartData[(value >> 0) & 3]);
}
// Stream data using UART1 routed to GPIO2
// ws2812.init() should be called first
//
// NODE_DEBUG should not be activated because it also uses UART1
void ICACHE_RAM_ATTR ws2812_write_data(const uint8_t *pixels, uint32_t length, const uint8_t *pixels2, uint32_t length2) {
const uint8_t *end = pixels + length;
const uint8_t *end2 = pixels2 + length2;
do {
// If something to send for first buffer and enough room
// in FIFO buffer (we wants to write 4 bytes, so less than
// 124 in the buffer)
if (pixels < end && (((READ_PERI_REG(UART_STATUS(1)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT) <= 124)) {
uint8_t value = *pixels++;
/* Fill the UART fifos with IRQs disabled */
uint32_t irq_state = esp8266_defer_irqs();
while ((pixels < end) && ws2812_can_write(1)) {
ws2812_write_byte(1, *pixels++);
}
while ((pixels2 < end2) && ws2812_can_write(0)) {
ws2812_write_byte(0, *pixels2++);
}
esp8266_restore_irqs(irq_state);
// Fill the buffer
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 6) & 3]);
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 4) & 3]);
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 2) & 3]);
WRITE_PERI_REG(UART_FIFO(1), _uartData[(value >> 0) & 3]);
do {
if (pixels < end && ws2812_can_write(1)) {
ws2812_write_byte(1, *pixels++);
}
// Same for the second buffer
if (pixels2 < end2 && (((READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT) <= 124)) {
uint8_t value = *pixels2++;
// Fill the buffer
WRITE_PERI_REG(UART_FIFO(0), _uartData[(value >> 6) & 3]);
WRITE_PERI_REG(UART_FIFO(0), _uartData[(value >> 4) & 3]);
WRITE_PERI_REG(UART_FIFO(0), _uartData[(value >> 2) & 3]);
WRITE_PERI_REG(UART_FIFO(0), _uartData[(value >> 0) & 3]);
if (pixels2 < end2 && ws2812_can_write(0)) {
ws2812_write_byte(0, *pixels2++);
}
} while(pixels < end || pixels2 < end2); // Until there is still something to send
}

View File

@ -0,0 +1,15 @@
#pragma once
static inline uint32_t
esp8266_defer_irqs(void)
{
uint32_t state;
__asm__ __volatile__ ("rsil %0, 15" : "=a"(state) : : "memory");
return state;
}
static inline void
esp8266_restore_irqs(uint32_t state)
{
__asm__ __volatile__ ("wsr %0, ps" : : "a"(state) : "memory");
}