ARM WS2812 SPI config (baudrate and circular buffer) (#12216)
* initial commit * include circular buffer command * add endif * circular buffer mode * remove untrue comment * revamp and add documentation * do not allow WS2812_SPI_SYNC & CIRCULAR_BUFFER
This commit is contained in:
		
							parent
							
								
									f2715a0593
								
							
						
					
					
						commit
						6f7466b6dd
					
				
					 2 changed files with 59 additions and 4 deletions
				
			
		| 
						 | 
					@ -77,6 +77,25 @@ Configure the hardware via your config.h:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You must also turn on the SPI feature in your halconf.h and mcuconf.h
 | 
					You must also turn on the SPI feature in your halconf.h and mcuconf.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Circular Buffer Mode
 | 
				
			||||||
 | 
					Some boards may flicker while in the normal buffer mode. To fix this issue, circular buffer mode may be used to rectify the issue. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default, the circular buffer mode is disabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To enable this alternative buffer mode, place this into your `config.h` file:
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					#define WS2812_SPI_USE_CIRCULAR_BUFFER
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Setting baudrate with divisor
 | 
				
			||||||
 | 
					To adjust the baudrate at which the SPI peripheral is configured, users will need to derive the target baudrate from the clock tree provided by STM32CubeMX.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Only divisors of 2, 4, 8, 16, 32, 64, 128 and 256 are supported by hardware.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|Define              |Default|Description                          |
 | 
				
			||||||
 | 
					|--------------------|-------|-------------------------------------|
 | 
				
			||||||
 | 
					|`WS2812_SPI_DIVISOR`|`16`   |SPI source clock peripheral divisor  |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Testing Notes
 | 
					#### Testing Notes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
While not an exhaustive list, the following table provides the scenarios that have been partially validated:
 | 
					While not an exhaustive list, the following table provides the scenarios that have been partially validated:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,37 @@
 | 
				
			||||||
#    endif
 | 
					#    endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define SPI config speed
 | 
				
			||||||
 | 
					// baudrate should target 3.2MHz
 | 
				
			||||||
 | 
					// F072 fpclk = 48MHz 
 | 
				
			||||||
 | 
					// 48/16 = 3Mhz
 | 
				
			||||||
 | 
					#if WS2812_SPI_DIVISOR == 2
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (0)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 4
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_0)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 8
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_1)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 16                                  //same as default
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 32
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_2)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 64
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_0)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 128
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1)
 | 
				
			||||||
 | 
					#elif WS2812_SPI_DIVISOR == 256
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#    define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0)    //default
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Use SPI circular buffer
 | 
				
			||||||
 | 
					#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
 | 
				
			||||||
 | 
					#    define WS2812_SPI_BUFFER_MODE 1    //circular buffer
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#    define WS2812_SPI_BUFFER_MODE 0    //normal buffer
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BYTES_FOR_LED_BYTE 4
 | 
					#define BYTES_FOR_LED_BYTE 4
 | 
				
			||||||
#define NB_COLORS 3
 | 
					#define NB_COLORS 3
 | 
				
			||||||
#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
 | 
					#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
 | 
				
			||||||
| 
						 | 
					@ -82,13 +113,16 @@ void ws2812_init(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: more dynamic baudrate
 | 
					    // TODO: more dynamic baudrate
 | 
				
			||||||
    static const SPIConfig spicfg = {
 | 
					    static const SPIConfig spicfg = {
 | 
				
			||||||
        0, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
 | 
					        WS2812_SPI_BUFFER_MODE, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
 | 
				
			||||||
        SPI_CR1_BR_1 | SPI_CR1_BR_0  // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
 | 
					        WS2812_SPI_DIVISOR
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    spiAcquireBus(&WS2812_SPI);     /* Acquire ownership of the bus.    */
 | 
					    spiAcquireBus(&WS2812_SPI);     /* Acquire ownership of the bus.    */
 | 
				
			||||||
    spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters.       */
 | 
					    spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters.       */
 | 
				
			||||||
    spiSelect(&WS2812_SPI);         /* Slave Select assertion.          */
 | 
					    spiSelect(&WS2812_SPI);         /* Slave Select assertion.          */
 | 
				
			||||||
 | 
					#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
 | 
				
			||||||
 | 
					    spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
 | 
					void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
 | 
				
			||||||
| 
						 | 
					@ -104,9 +138,11 @@ void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
 | 
					    // Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
 | 
				
			||||||
    // Instead spiSend can be used to send synchronously (or the thread logic can be added back).
 | 
					    // Instead spiSend can be used to send synchronously (or the thread logic can be added back).
 | 
				
			||||||
#ifdef WS2812_SPI_SYNC
 | 
					#ifndef WS2812_SPI_USE_CIRCULAR_BUFFER
 | 
				
			||||||
 | 
					#    ifdef WS2812_SPI_SYNC
 | 
				
			||||||
    spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
 | 
					    spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
 | 
				
			||||||
#else
 | 
					#    else
 | 
				
			||||||
    spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
 | 
					    spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
 | 
				
			||||||
 | 
					#    endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue