aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/arm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/arm')
-rw-r--r--drivers/arm/i2c_master.c5
-rw-r--r--drivers/arm/i2c_master.h23
-rw-r--r--drivers/arm/ws2812.c2
-rw-r--r--drivers/arm/ws2812_spi.c91
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
+}