diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/avr/apa102.c | 8 | ||||
-rw-r--r-- | drivers/avr/ssd1306.h | 1 | ||||
-rw-r--r-- | drivers/chibios/spi_master.c | 137 | ||||
-rw-r--r-- | drivers/chibios/spi_master.h | 78 | ||||
-rw-r--r-- | drivers/oled/oled_driver.c | 2 |
5 files changed, 220 insertions, 6 deletions
diff --git a/drivers/avr/apa102.c b/drivers/avr/apa102.c index f4d97a1589..b174b39b8f 100644 --- a/drivers/avr/apa102.c +++ b/drivers/avr/apa102.c @@ -30,8 +30,8 @@ void inline apa102_setleds(LED_TYPE *ledarray, uint16_t leds) { apa102_setleds_pin(ledarray, leds, _BV(RGB_DI_PIN & 0xF), _BV(RGB_CLK_PIN & 0xF)); } void static inline apa102_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask_DI, uint8_t pinmask_CLK) { - pinMode(RGB_DI_PIN, PinDirectionOutput); - pinMode(RGB_CLK_PIN, PinDirectionOutput); + setPinOutput(RGB_DI_PIN); + setPinOutput(RGB_CLK_PIN); apa102_send_array((uint8_t *)ledarray, leds) } @@ -90,7 +90,7 @@ void apa102_end_frame(uint16_t leds) { void apa102_send_byte(uint8_t byte) { uint8_t i; for (i = 0; i < 8; i++) { - digitalWrite(RGB_DI_PIN, !!(byte & (1 << (7-i))); - digitalWrite(RGB_CLK_PIN, PinLevelHigh); + writePin(RGB_DI_PIN, !!(byte & (1 << (7 - i)))); + writePinHigh(RGB_CLK_PIN); } } diff --git a/drivers/avr/ssd1306.h b/drivers/avr/ssd1306.h index 825b0d7d5b..9669d1b7e7 100644 --- a/drivers/avr/ssd1306.h +++ b/drivers/avr/ssd1306.h @@ -3,7 +3,6 @@ #include <stdbool.h> #include <stdio.h> -#include "pincontrol.h" #include "config.h" enum ssd1306_cmds { diff --git a/drivers/chibios/spi_master.c b/drivers/chibios/spi_master.c new file mode 100644 index 0000000000..552ac663c1 --- /dev/null +++ b/drivers/chibios/spi_master.c @@ -0,0 +1,137 @@ +/* Copyright 2020 Nick Brassel (tzarc) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "spi_master.h" +#include "quantum.h" +#include "timer.h" + +static pin_t currentSlavePin = NO_PIN; +static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0}; + +__attribute__((weak)) void spi_init(void) { + // Try releasing special pins for a short time + palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_INPUT); + palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_INPUT); + palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_INPUT); + + chThdSleepMilliseconds(10); +#if defined(USE_GPIOV1) + palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); + palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); + palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); +#else + palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); +#endif +} + +bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { + if (currentSlavePin != NO_PIN || slavePin == NO_PIN) { + return false; + } + + uint16_t roundedDivisor = 2; + while (roundedDivisor < divisor) { + roundedDivisor <<= 1; + } + + if (roundedDivisor < 2 || roundedDivisor > 256) { + return false; + } + + spiConfig.cr1 = 0; + + if (lsbFirst) { + spiConfig.cr1 |= SPI_CR1_LSBFIRST; + } + + switch (mode) { + case 0: + break; + case 1: + spiConfig.cr1 |= SPI_CR1_CPHA; + break; + case 2: + spiConfig.cr1 |= SPI_CR1_CPOL; + break; + case 3: + spiConfig.cr1 |= SPI_CR1_CPHA | SPI_CR1_CPOL; + break; + } + + switch (roundedDivisor) { + case 2: + break; + case 4: + spiConfig.cr1 |= SPI_CR1_BR_0; + break; + case 8: + spiConfig.cr1 |= SPI_CR1_BR_1; + break; + case 16: + spiConfig.cr1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0; + break; + case 32: + spiConfig.cr1 |= SPI_CR1_BR_2; + break; + case 64: + spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0; + break; + case 128: + spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1; + break; + case 256: + spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0; + break; + } + + currentSlavePin = slavePin; + spiConfig.ssport = PAL_PORT(slavePin); + spiConfig.sspad = PAL_PAD(slavePin); + + setPinOutput(slavePin); + spiStart(&SPI_DRIVER, &spiConfig); + spiSelect(&SPI_DRIVER); + + return true; +} + +spi_status_t spi_write(uint8_t data) { return spi_transmit(&data, 1); } + +spi_status_t spi_read(void) { + uint8_t data = 0; + spi_receive(&data, 1); + return data; +} + +spi_status_t spi_transmit(const uint8_t *data, uint16_t length) { + spiSend(&SPI_DRIVER, length, data); + return SPI_STATUS_SUCCESS; +} + +spi_status_t spi_receive(uint8_t *data, uint16_t length) { + spiReceive(&SPI_DRIVER, length, data); + return SPI_STATUS_SUCCESS; +} + +void spi_stop(void) { + if (currentSlavePin != NO_PIN) { + spiUnselect(&SPI_DRIVER); + spiStop(&SPI_DRIVER); + currentSlavePin = NO_PIN; + } +} diff --git a/drivers/chibios/spi_master.h b/drivers/chibios/spi_master.h new file mode 100644 index 0000000000..0c18587c95 --- /dev/null +++ b/drivers/chibios/spi_master.h @@ -0,0 +1,78 @@ +/* Copyright 2020 Nick Brassel (tzarc) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <ch.h> +#include <hal.h> +#include <quantum.h> + +#ifndef SPI_DRIVER +# define SPI_DRIVER SPID2 +#endif + +#ifndef SPI_SCK_PIN +# define SPI_SCK_PIN B13 +#endif + +#ifndef SPI_SCK_PAL_MODE +# define SPI_SCK_PAL_MODE 5 +#endif + +#ifndef SPI_MOSI_PIN +# define SPI_MOSI_PIN B15 +#endif + +#ifndef SPI_MOSI_PAL_MODE +# define SPI_MOSI_PAL_MODE 5 +#endif + +#ifndef SPI_MISO_PIN +# define SPI_MISO_PIN B14 +#endif + +#ifndef SPI_MISO_PAL_MODE +# define SPI_MISO_PAL_MODE 5 +#endif + +typedef int16_t spi_status_t; + +#define SPI_STATUS_SUCCESS (0) +#define SPI_STATUS_ERROR (-1) +#define SPI_STATUS_TIMEOUT (-2) + +#define SPI_TIMEOUT_IMMEDIATE (0) +#define SPI_TIMEOUT_INFINITE (0xFFFF) + +#ifdef __cplusplus +extern "C" { +#endif +void spi_init(void); + +bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor); + +spi_status_t spi_write(uint8_t data); + +spi_status_t spi_read(void); + +spi_status_t spi_transmit(const uint8_t *data, uint16_t length); + +spi_status_t spi_receive(uint8_t *data, uint16_t length); + +void spi_stop(void); +#ifdef __cplusplus +} +#endif diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c index ce5c23cc40..eedaedcd36 100644 --- a/drivers/oled/oled_driver.c +++ b/drivers/oled/oled_driver.c @@ -479,7 +479,7 @@ void oled_write_ln_P(const char *data, bool invert) { void oled_write_raw_P(const char *data, uint16_t size) { if (size > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE; for (uint16_t i = 0; i < size; i++) { - uint8_t c = pgm_read_byte(++data); + uint8_t c = pgm_read_byte(data++); if (oled_buffer[i] == c) continue; oled_buffer[i] = c; oled_dirty |= (1 << (i / OLED_BLOCK_SIZE)); |