diff options
Diffstat (limited to 'drivers/arm')
-rw-r--r-- | drivers/arm/i2c_master.c | 5 | ||||
-rw-r--r-- | drivers/arm/i2c_master.h | 23 | ||||
-rw-r--r-- | drivers/arm/ws2812.c | 2 | ||||
-rw-r--r-- | drivers/arm/ws2812_spi.c | 91 |
4 files changed, 103 insertions, 18 deletions
diff --git a/drivers/arm/i2c_master.c b/drivers/arm/i2c_master.c index 2a43ba239..21aefd497 100644 --- a/drivers/arm/i2c_master.c +++ b/drivers/arm/i2c_master.c @@ -24,9 +24,8 @@ * STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file. Pins B6 and B7 are used * but using any other I2C pins should be trivial. */ - -#include "i2c_master.h" #include "quantum.h" +#include "i2c_master.h" #include <string.h> #include <hal.h> @@ -62,7 +61,7 @@ __attribute__((weak)) void i2c_init(void) { palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT); chThdSleepMilliseconds(10); -#ifdef USE_I2CV1 +#if defined(USE_GPIOV1) palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); #else diff --git a/drivers/arm/i2c_master.h b/drivers/arm/i2c_master.h index efe3909a6..3d3891289 100644 --- a/drivers/arm/i2c_master.h +++ b/drivers/arm/i2c_master.h @@ -27,10 +27,6 @@ #include "ch.h" #include <hal.h> -#if defined(STM32F1XX) || defined(STM32F1xx) || defined(STM32F2xx) || defined(STM32F4xx) || defined(STM32L0xx) || defined(STM32L1xx) -# define USE_I2CV1 -#endif - #ifdef I2C1_BANK # define I2C1_SCL_BANK I2C1_BANK # define I2C1_SDA_BANK I2C1_BANK @@ -62,14 +58,6 @@ # define I2C1_DUTY_CYCLE STD_DUTY_CYCLE /* FAST_DUTY_CYCLE_2 */ # endif #else -// The default PAL alternate modes are used to signal that the pins are used for I2C -# ifndef I2C1_SCL_PAL_MODE -# define I2C1_SCL_PAL_MODE 4 -# endif -# ifndef I2C1_SDA_PAL_MODE -# define I2C1_SDA_PAL_MODE 4 -# endif - // The default timing values below configures the I2C clock to 400khz assuming a 72Mhz clock // For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html # ifndef I2C1_TIMINGR_PRESC @@ -93,6 +81,16 @@ # define I2C_DRIVER I2CD1 #endif +#ifndef USE_GPIOV1 +// The default PAL alternate modes are used to signal that the pins are used for I2C +# ifndef I2C1_SCL_PAL_MODE +# define I2C1_SCL_PAL_MODE 4 +# endif +# ifndef I2C1_SDA_PAL_MODE +# define I2C1_SDA_PAL_MODE 4 +# endif +#endif + typedef int16_t i2c_status_t; #define I2C_STATUS_SUCCESS (0) @@ -103,7 +101,6 @@ void i2c_init(void); i2c_status_t i2c_start(uint8_t address); i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); -i2c_status_t i2c_transmit_receive(uint8_t address, uint8_t* tx_body, uint16_t tx_length, uint8_t* rx_body, uint16_t rx_length); i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); void i2c_stop(void); diff --git a/drivers/arm/ws2812.c b/drivers/arm/ws2812.c index fa702fca9..bdca565d8 100644 --- a/drivers/arm/ws2812.c +++ b/drivers/arm/ws2812.c @@ -6,7 +6,7 @@ /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ #ifndef NOP_FUDGE -# if defined(STM32F1XX) || defined(STM32F1xx) || defined(STM32F0XX) || defined(STM32F0xx) || defined(STM32F3XX) || defined(STM32F3xx) || defined(STM32L0XX) || defined(STM32L0xx) +# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) # define NOP_FUDGE 0.4 # else # error("NOP_FUDGE configuration required") diff --git a/drivers/arm/ws2812_spi.c b/drivers/arm/ws2812_spi.c index 2094e5009..0e954ec50 100644 --- a/drivers/arm/ws2812_spi.c +++ b/drivers/arm/ws2812_spi.c @@ -1 +1,90 @@ -#error("NOT SUPPORTED")
\ No newline at end of file +#include "quantum.h" +#include "ws2812.h" + +/* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ + +#ifdef RGBW +# error "RGBW not supported" +#endif + +// Define the spi your LEDs are plugged to here +#ifndef WS2812_SPI +# define WS2812_SPI SPID1 +#endif + +#ifndef WS2812_SPI_MOSI_PAL_MODE +# define WS2812_SPI_MOSI_PAL_MODE 5 +#endif + +#define BYTES_FOR_LED_BYTE 4 +#define NB_COLORS 3 +#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS) +#define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM) +#define RESET_SIZE 200 +#define PREAMBLE_SIZE 4 + +static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE] = {0}; + +/* + * As the trick here is to use the SPI to send a huge pattern of 0 and 1 to + * the ws2812b protocol, we use this helper function to translate bytes into + * 0s and 1s for the LED (with the appropriate timing). + */ +static uint8_t get_protocol_eq(uint8_t data, int pos) { + uint8_t eq = 0; + if (data & (1 << (2 * (3 - pos)))) + eq = 0b1110; + else + eq = 0b1000; + if (data & (2 << (2 * (3 - pos)))) + eq += 0b11100000; + else + eq += 0b10000000; + return eq; +} + +static void set_led_color_rgb(LED_TYPE color, int pos) { + uint8_t* tx_start = &txbuf[PREAMBLE_SIZE]; + + for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j); + for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j); + for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j); +} + +void ws2812_init(void) { +#if defined(USE_GPIOV1) + palSetLineMode(RGB_DI_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL); +#else + palSetLineMode(RGB_DI_PIN, PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL); +#endif + + // TODO: more dynamic baudrate + static const SPIConfig spicfg = { + 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) + }; + + spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */ + spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */ + spiSelect(&WS2812_SPI); /* Slave Select assertion. */ +} + +void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { + static bool s_init = false; + if (!s_init) { + ws2812_init(); + s_init = true; + } + + for (uint8_t i = 0; i < leds; i++) { + set_led_color_rgb(ledarray[i], i); + } + + // 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). +#ifdef WS2812_SPI_SYNC + spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf); +#else + spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf); +#endif +} |