Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Stm32SpiPixelStrip.hxx
Go to the documentation of this file.
1
35#ifndef _FREERTOS_DRIVERS_ST_STM32PIXELSTRIP_HXX_
36#define _FREERTOS_DRIVERS_ST_STM32PIXELSTRIP_HXX_
37
38#include <cstdint>
39
40
41#include "stm32f_hal_conf.hxx"
42
43#include "stm32g0xx_ll_spi.h"
44
46{
47public:
55 SPI_TypeDef *spi, unsigned num_pixels, uint8_t *backing_data)
56 : spi_(spi)
57 , numPixels_(num_pixels)
58 , data_(backing_data)
59 {
60 memset(&spiHandle_, 0, sizeof(spiHandle_));
61 }
62
66 void hw_init(uint32_t spi_prescaler)
67 {
68 // Deinit if needed.
69 if (spiHandle_.State != HAL_SPI_STATE_RESET)
70 {
71 HAL_SPI_DeInit(&spiHandle_);
72 }
73 spiHandle_.Instance = spi_;
74
75 spiHandle_.Init.BaudRatePrescaler = spi_prescaler;
76 spiHandle_.Init.Direction = SPI_DIRECTION_1LINE;
77 spiHandle_.Init.CLKPolarity = SPI_POLARITY_LOW;
78 spiHandle_.Init.CLKPhase = SPI_PHASE_2EDGE;
79 spiHandle_.Init.DataSize = SPI_DATASIZE_15BIT;
80 spiHandle_.Init.FirstBit = SPI_FIRSTBIT_LSB;
81 spiHandle_.Init.NSS = SPI_NSS_SOFT;
82 spiHandle_.Init.TIMode = SPI_TIMODE_DISABLE;
83 spiHandle_.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
84 spiHandle_.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
85 spiHandle_.Init.CRCPolynomial = 7;
86 spiHandle_.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
87 spiHandle_.Init.Mode = SPI_MODE_MASTER;
88 HASSERT(HAL_SPI_Init(&spiHandle_) == HAL_OK);
89 LL_SPI_SetTransferDirection(spi_, LL_SPI_HALF_DUPLEX_TX);
90 }
91
96 {
97 LL_SPI_Enable(spi_);
100 portENTER_CRITICAL();
101 while (!eof())
102 {
103 uint16_t next_word = 0;
104 uint16_t ofs = 1u;
105 // Computes 16 SPI bits with 5 pulses.
106 while (!eof() && ofs < (1u << 13))
107 {
108 // Appends an 110 or 100 depending opn what the next bit should
109 // be.
110 next_word |= ofs;
111 ofs <<= 1;
112 if (next_bit())
113 next_word |= ofs;
114 ofs <<= 2;
115 }
116 // We leave an extra bit as zero at the end of the word. We hope
117 // that this will not confuse the pixel. They care mostly about the
118 // length of the HIGH pulse.
119
120 // Waits for space in tx buffer.
121 while (!LL_SPI_IsActiveFlag_TXE(spi_)) { }
122 LL_SPI_TransmitData16(spi_, next_word ^ 0xffff);
123 // Note that there is no wait here for the transfer to complete.
124 // This is super important, because we want to be computing the
125 // next word while the previous word is emitted by SPI.
126 }
127 // The last bit output is a zero, and leaving the line there is
128 // reasonable, because it matches the latch level.
129 portEXIT_CRITICAL();
130 }
131
132private:
136 {
137 currentByte_ = 0;
138 nextBit_ = 0x80;
139 }
141 bool next_bit()
142 {
143 bool ret = data_[currentByte_] & nextBit_;
144 nextBit_ >>= 1;
145 if (!nextBit_)
146 {
147 nextBit_ = 0x80;
148 currentByte_++;
149 }
150 return ret;
151 }
153 bool eof()
154 {
155 return currentByte_ >= numPixels_ * 3;
156 }
157
159 SPI_TypeDef *spi_;
161 SPI_HandleTypeDef spiHandle_;
163 unsigned numPixels_;
165 uint8_t *data_;
166
169 unsigned currentByte_;
172 uint8_t nextBit_;
173};
174
175#endif // _FREERTOS_DRIVERS_ST_STM32PIXELSTRIP_HXX_
unsigned numPixels_
Number of pixels to drive.
uint8_t * data_
Backing framebuffer to use.
void hw_init(uint32_t spi_prescaler)
Opens and initializes the SPI hardware.
SPI_HandleTypeDef spiHandle_
Stm32 HAL device structure.
unsigned currentByte_
Controls iteration over the data sequence when producing the output.
SPI_TypeDef * spi_
SPI peripheral pointer.
void clear_iteration()
Starts a new iteration over the strip.
Stm32SpiPixelStrip(SPI_TypeDef *spi, unsigned num_pixels, uint8_t *backing_data)
Initializes the SPI peripheral.
void update_sync()
Updates the hardware from the backing data.
uint8_t nextBit_
Controls iteration over the data sequence when producing the output.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138