32static constexpr uint32_t APB0_HZ = 40000000;
34static constexpr uint8_t SPI_BITS_PER_LED_BIT = 8;
36static constexpr uint32_t LED_STRIP_DMA_CH = DMA_CH_4;
38static uint8_t spi_pattern(uint8_t high_bits) {
return uint8_t(0xFF00 >> high_bits); }
40static void spi_dma_init(uint8_t pin, uint8_t prescaler) {
43 const uint32_t gpio_base = (pin >> 4) ? GPIOB_BASE : GPIOA_BASE;
44 const auto gpio_pin =
static_cast<gpio_pin_t
>(1U << (pin & 0xF));
45 hal_gpio_pin_afio_select(gpio_base, gpio_pin, SPI0_MOSI);
46 hal_gpio_pin_afio_en(gpio_base, gpio_pin, HAL_ENABLE);
49 spi_init_type_def spi_init{};
50 spi_init.spi_direction = SPI_DIRECTION_2LINES_FULLDUPLEX;
51 spi_init.spi_mode = SPI_MODE_MASTER;
52 spi_init.spi_data_size = SPI_DATASIZE_8B;
53 spi_init.spi_cpol = SPI_CPOL_LOW;
54 spi_init.spi_cpha = SPI_CPHA_1EDGE;
55 spi_init.spi_nss_mode = SPI_NSS_HARD;
56 spi_init.spi_baud_rate_prescaler =
static_cast<spi_baud_rate_precaler_t
>(prescaler);
57 spi_init.spi_first_bit = SPI_FIRST_BIT_MSB;
58 hal_spi_init(SPI0_BASE, &spi_init);
59 hal_spi_en(SPI0_BASE, HAL_ENABLE);
60 hal_spi_ssoe_en(SPI0_BASE, HAL_DISABLE);
62 dma_init_t_def dma_init{};
63 dma_init.dma_mem_to_mem_en = DMA_MEM_TO_MEM_DIS;
64 dma_init.dma_pri_lev = DMA_PRI_LEV_HIGH;
65 dma_init.dma_mem_size = DMA_MEM_SIZE_8_BIT;
66 dma_init.dma_p_size = DMA_P_SIZE_8_BIT;
67 dma_init.dma_mem_inc_en = DMA_MEM_INC_EN;
68 dma_init.dma_p_inc_en = DMA_P_INC_DIS;
69 dma_init.dma_circ_mode_en = DMA_CIRC_MODE_DIS;
70 dma_init.dma_dir = DMA_READ_FORM_MEM;
71 dma_init.dma_p_addr = SPI0_DATA_REG;
72 hal_dma_init(LED_STRIP_DMA_CH, &dma_init);
73 hal_dma_en(LED_STRIP_DMA_CH, HAL_DISABLE);
76static void spi_dma_transmit(
const uint8_t *data, uint16_t
len) {
77 hal_dma_en(LED_STRIP_DMA_CH, HAL_DISABLE);
78 hal_spi_dma_en(SPI0_BASE, SPI_DMA_TX_EN, HAL_DISABLE);
79 hal_dma_set_mem_addr(LED_STRIP_DMA_CH,
reinterpret_cast<uint32_t>(data));
80 hal_dma_set_data_num(LED_STRIP_DMA_CH,
len);
81 hal_spi_dma_en(SPI0_BASE, SPI_DMA_TX_EN, HAL_ENABLE);
82 hal_dma_en(LED_STRIP_DMA_CH, HAL_ENABLE);
87static bool spi_dma_busy() {
return hal_dma_get_data_num(LED_STRIP_DMA_CH) != 0; }
91 uint8_t bit0_high_bits, uint8_t bit1_high_bits,
93 : color_data_bytes_(num_leds * channel_colors.bytes_per_led()),
95 dma_data_bytes_(color_data_bytes_ * SPI_BITS_PER_LED_BIT + reset_bytes),
96 channel_colors_(channel_colors),
99 prescaler_(prescaler),
100 bit0_high_bits_(bit0_high_bits),
101 bit1_high_bits_(bit1_high_bits) {}
104 const uint32_t apb0_hz = hal_clock_get_apb0_clk();
105 if (apb0_hz != APB0_HZ) {
106 ESP_LOGE(TAG,
"APB0 clock is %" PRIu32
" Hz", apb0_hz);
107 this->
mark_failed(LOG_STR(
"APB0 clock is not 40 MHz"));
114 if (buffer ==
nullptr) {
128 char channel_colors[5];
130 "LN882x SPI LED Strip:\n"
132 " Channel colors: %s\n"
133 " Number of LEDs: %" PRIu16
"\n"
134 " Max refresh rate: %" PRIu32
" us\n"
135 " SPI frequency: %" PRIu32
" Hz\n"
136 " Bit 0 / bit 1 high: %" PRIu32
" / %" PRIu32
" ns of %" PRIu32
" ns",
138 APB0_HZ >> this->prescaler_, this->bit0_high_bits_ * spi_bit_ns, this->bit1_high_bits_ * spi_bit_ns,
139 SPI_BITS_PER_LED_BIT * spi_bit_ns);
152 if (spi_dma_busy()) {
166 const uint8_t color_byte = *(color_data++);
167 for (uint8_t mask = 0x80; mask != 0; mask >>= 1) {
168 *(dma_data++) = (color_byte & mask) ? bit1 : bit0;
LN882xSPILEDStripLightOutput(uint8_t pin, uint16_t num_leds, light::ChannelColors channel_colors, uint8_t prescaler, uint8_t bit0_high_bits, uint8_t bit1_high_bits, uint16_t reset_bytes)
The SPI encoding comes from light.py: SPI clock APB0 / 2^prescaler, the number of high SPI bits for a...