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:
parent
4023df7e60
commit
109f500be7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
Loading…
Reference in New Issue