From 990d5189d19341cb768ea39a5510f381f1522e20 Mon Sep 17 00:00:00 2001 From: XScorpion2 Date: Sun, 29 Nov 2020 10:28:03 -0600 Subject: Configurable serial usart timeout (#11057) --- drivers/chibios/serial_usart.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/chibios/serial_usart.c b/drivers/chibios/serial_usart.c index 62b4913cbf..72fcaed0c7 100644 --- a/drivers/chibios/serial_usart.c +++ b/drivers/chibios/serial_usart.c @@ -58,7 +58,10 @@ # error invalid SELECT_SOFT_SERIAL_SPEED value #endif -#define TIMEOUT 100 +#ifndef SERIAL_USART_TIMEOUT +# define SERIAL_USART_TIMEOUT 100 +#endif + #define HANDSHAKE_MAGIC 7 static inline msg_t sdWriteHalfDuplex(SerialDriver* driver, uint8_t* data, uint8_t size) { @@ -201,21 +204,21 @@ int soft_serial_transaction(int index) { sdClear(&SERIAL_USART_DRIVER); // First chunk is always transaction id - sdWriteTimeout(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index), TIME_MS2I(TIMEOUT)); + sdWriteTimeout(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index), TIME_MS2I(SERIAL_USART_TIMEOUT)); uint8_t sstd_index_shake = 0xFF; // Which we always read back first so that we can error out correctly // - due to the half duplex limitations on return codes, we always have to read *something* // - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready - res = sdReadTimeout(&SERIAL_USART_DRIVER, &sstd_index_shake, sizeof(sstd_index_shake), TIME_MS2I(TIMEOUT)); + res = sdReadTimeout(&SERIAL_USART_DRIVER, &sstd_index_shake, sizeof(sstd_index_shake), TIME_MS2I(SERIAL_USART_TIMEOUT)); if (res < 0 || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) { dprintf("serial::usart_shake NO_RESPONSE\n"); return TRANSACTION_NO_RESPONSE; } if (trans->initiator2target_buffer_size) { - res = sdWriteTimeout(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size, TIME_MS2I(TIMEOUT)); + res = sdWriteTimeout(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT)); if (res < 0) { dprintf("serial::usart_transmit NO_RESPONSE\n"); return TRANSACTION_NO_RESPONSE; @@ -223,7 +226,7 @@ int soft_serial_transaction(int index) { } if (trans->target2initiator_buffer_size) { - res = sdReadTimeout(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size, TIME_MS2I(TIMEOUT)); + res = sdReadTimeout(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT)); if (res < 0) { dprintf("serial::usart_receive NO_RESPONSE\n"); return TRANSACTION_NO_RESPONSE; -- cgit v1.2.3 From 4f2f21dc05c70451593ba83ed7a0956c771850c2 Mon Sep 17 00:00:00 2001 From: Aldehir Rojas Date: Tue, 29 Dec 2020 18:28:49 -0600 Subject: Rewrite APA102 support (#10894) * Rewrite APA102 support The APA102 source was broken by commit 16a15c1cfcbfd0feb2c2cf1383676747e2f97d73 as it did not include the quantum header. This commit addresses that, as well as other issues with transferring bytes over the SPI interface, i.e. it was not setting the clock pin back to low after sending a bit. The deviation when sending the end frame is kept, but updated to the latest from the referenced project. Finally, these changes expose the global LED brightness parameter of the APA102. Brightness values are configurable through `APA102_DEFAULT_BRIGHTNESS` and `APA102_MAX_BRIGHTNESS`. * Fix typo in led brightness extern * Move driver out of AVR directory and add delay for ARM * Experimental APA102 support on AVR and ARM Co-authored-by: Alde Rojas * Refactor apa102_send_byte() calls to a loop * Implement io_wait function for ARM * Move APA102 drivers to own directory, fix copyright notice * Add APA102 keymap to handwired/onekey * Simplify RGBLIGHT_ENABLE/DRIVER option handling Co-authored-by: Mikkel Jeppesen <2756925+Duckle29@users.noreply.github.com> --- drivers/apa102/apa102.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/apa102/apa102.h | 41 +++++++++++++ drivers/avr/apa102.c | 96 ------------------------------ drivers/avr/apa102.h | 45 --------------- 4 files changed, 192 insertions(+), 141 deletions(-) create mode 100644 drivers/apa102/apa102.c create mode 100644 drivers/apa102/apa102.h delete mode 100644 drivers/avr/apa102.c delete mode 100644 drivers/avr/apa102.h (limited to 'drivers') diff --git a/drivers/apa102/apa102.c b/drivers/apa102/apa102.c new file mode 100644 index 0000000000..7396dc3c55 --- /dev/null +++ b/drivers/apa102/apa102.c @@ -0,0 +1,151 @@ +/* Copyright 2020 Aldehir Rojas + * Copyright 2017 Mikkel (Duckle29) + * + * 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 2 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 . + */ + +#include "apa102.h" +#include "quantum.h" + +#ifndef APA102_NOPS +# if defined(__AVR__) +# define APA102_NOPS 0 // AVR at 16 MHz already spends 62.5 ns per clock, so no extra delay is needed +# elif defined(PROTOCOL_CHIBIOS) + +# include "hal.h" +# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) +# define APA102_NOPS (100 / (1000000000L / (STM32_SYSCLK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns +# else +# error("APA102_NOPS configuration required") +# define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot +# endif +# endif +#endif + +#define io_wait \ + do { \ + for (int i = 0; i < APA102_NOPS; i++) { \ + __asm__ volatile("nop\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + "nop\n\t"); \ + } \ + } while (0) + +#define APA102_SEND_BIT(byte, bit) \ + do { \ + writePin(RGB_DI_PIN, (byte >> bit) & 1); \ + io_wait; \ + writePinHigh(RGB_CI_PIN); \ + io_wait; \ + writePinLow(RGB_CI_PIN); \ + io_wait; \ + } while (0) + +uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS; + +void static apa102_start_frame(void); +void static apa102_end_frame(uint16_t num_leds); + +void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness); +void static apa102_send_byte(uint8_t byte); + +void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds) { + LED_TYPE *end = start_led + num_leds; + + apa102_start_frame(); + for (LED_TYPE *led = start_led; led < end; led++) { + apa102_send_frame(led->r, led->g, led->b, apa102_led_brightness); + } + apa102_end_frame(num_leds); +} + +// Overwrite the default rgblight_call_driver to use apa102 driver +void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { apa102_setleds(start_led, num_leds); } + +void static apa102_init(void) { + setPinOutput(RGB_DI_PIN); + setPinOutput(RGB_CI_PIN); + + writePinLow(RGB_DI_PIN); + writePinLow(RGB_CI_PIN); +} + +void apa102_set_brightness(uint8_t brightness) { + if (brightness > APA102_MAX_BRIGHTNESS) { + apa102_led_brightness = APA102_MAX_BRIGHTNESS; + } else if (brightness < 0) { + apa102_led_brightness = 0; + } else { + apa102_led_brightness = brightness; + } +} + +void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness) { + apa102_send_byte(0b11100000 | brightness); + apa102_send_byte(blue); + apa102_send_byte(green); + apa102_send_byte(red); +} + +void static apa102_start_frame(void) { + apa102_init(); + for (uint16_t i = 0; i < 4; i++) { + apa102_send_byte(0); + } +} + +void static apa102_end_frame(uint16_t num_leds) { + // This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h + // and adapted. The code is MIT licensed. I think thats compatible? + // + // The data stream seen by the last LED in the chain will be delayed by + // (count - 1) clock edges, because each LED before it inverts the clock + // line and delays the data by one clock edge. Therefore, to make sure + // the last LED actually receives the data we wrote, the number of extra + // edges we send at the end of the frame must be at least (count - 1). + // + // Assuming we only want to send these edges in groups of size K, the + // C/C++ expression for the minimum number of groups to send is: + // + // ((count - 1) + (K - 1)) / K + // + // The C/C++ expression above is just (count - 1) divided by K, + // rounded up to the nearest whole number if there is a remainder. + // + // We set K to 16 and use the formula above as the number of frame-end + // bytes to transfer. Each byte has 16 clock edges. + // + // We are ignoring the specification for the end frame in the APA102 + // datasheet, which says to send 0xFF four times, because it does not work + // when you have 66 LEDs or more, and also it results in unwanted white + // pixels if you try to update fewer LEDs than are on your LED strip. + uint16_t iterations = (num_leds + 14) / 16; + for (uint16_t i = 0; i < iterations; i++) { + apa102_send_byte(0); + } + + apa102_init(); +} + +void static apa102_send_byte(uint8_t byte) { + APA102_SEND_BIT(byte, 7); + APA102_SEND_BIT(byte, 6); + APA102_SEND_BIT(byte, 5); + APA102_SEND_BIT(byte, 4); + APA102_SEND_BIT(byte, 3); + APA102_SEND_BIT(byte, 2); + APA102_SEND_BIT(byte, 1); + APA102_SEND_BIT(byte, 0); +} diff --git a/drivers/apa102/apa102.h b/drivers/apa102/apa102.h new file mode 100644 index 0000000000..58cf020c1e --- /dev/null +++ b/drivers/apa102/apa102.h @@ -0,0 +1,41 @@ +/* Copyright 2020 Aldehir Rojas + * Copyright 2017 Mikkel (Duckle29) + * + * 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 2 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 . + */ + +#pragma once + +#include "color.h" + +#ifndef APA102_DEFAULT_BRIGHTNESS +# define APA102_DEFAULT_BRIGHTNESS 31 +#endif + +#define APA102_MAX_BRIGHTNESS 31 + +extern uint8_t apa102_led_brightness; + +/* User Interface + * + * Input: + * start_led: An array of GRB data describing the LED colors + * num_leds: The number of LEDs to write + * + * The functions will perform the following actions: + * - Set the data-out pin as output + * - Send out the LED data + */ +void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds); +void apa102_set_brightness(uint8_t brightness); diff --git a/drivers/avr/apa102.c b/drivers/avr/apa102.c deleted file mode 100644 index 740acb5739..0000000000 --- a/drivers/avr/apa102.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * APA102 lib V1.0a - * - * Controls APA102 RGB-LEDs - * Author: Mikkel (Duckle29 on GitHub) - * - * Dec 22th, 2017 v1.0a Initial Version - * - * 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 2 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 . - */ - -#include "apa102.h" -#include -#include -#include -#include "debug.h" - -// Setleds for standard RGB -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) { - setPinOutput(RGB_DI_PIN); - setPinOutput(RGB_CLK_PIN); - - apa102_send_array((uint8_t *)ledarray, leds) -} - -void apa102_send_array(uint8_t *data, uint16_t leds) { // Data is struct of 3 bytes. RGB - leds is number of leds in data - apa102_start_frame(); - while (leds--) { - apa102_send_frame(0xFF000000 | (data->b << 16) | (data->g << 8) | data->r); - data++; - } - apa102_end_frame(leds); -} - -void apa102_send_frame(uint32_t frame) { - for (uint32_t i = 0xFF; i > 0;) { - apa102_send_byte(frame & i); - i = i << 8; - } -} - -void apa102_start_frame() { apa102_send_frame(0); } - -void apa102_end_frame(uint16_t leds) { - // This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h - // and adapted. The code is MIT licensed. I think thats compatible? - - // We need to send some more bytes to ensure that all the LEDs in the - // chain see their new color and start displaying it. - // - // The data stream seen by the last LED in the chain will be delayed by - // (count - 1) clock edges, because each LED before it inverts the clock - // line and delays the data by one clock edge. Therefore, to make sure - // the last LED actually receives the data we wrote, the number of extra - // edges we send at the end of the frame must be at least (count - 1). - // For the APA102C, that is sufficient. - // - // The SK9822 only updates after it sees 32 zero bits followed by one more - // rising edge. To avoid having the update time depend on the color of - // the last LED, we send a dummy 0xFF byte. (Unfortunately, this means - // that partial updates of the beginning of an LED strip are not possible; - // the LED after the last one you are trying to update will be black.) - // After that, to ensure that the last LED in the chain sees 32 zero bits - // and a rising edge, we need to send at least 65 + (count - 1) edges. It - // is sufficent and simpler to just send (5 + count/16) bytes of zeros. - // - // We are ignoring the specification for the end frame in the APA102/SK9822 - // datasheets because it does not actually ensure that all the LEDs will - // start displaying their new colors right away. - - apa102_send_byte(0xFF); - for (uint16_t i = 0; i < 5 + leds / 16; i++) { - apa102_send_byte(0); - } -} - -void apa102_send_byte(uint8_t byte) { - uint8_t i; - for (i = 0; i < 8; i++) { - writePin(RGB_DI_PIN, !!(byte & (1 << (7 - i)))); - writePinHigh(RGB_CLK_PIN); - } -} diff --git a/drivers/avr/apa102.h b/drivers/avr/apa102.h deleted file mode 100644 index d4c1e18ee1..0000000000 --- a/drivers/avr/apa102.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * light weight WS2812 lib include - * - * Version 2.3 - Nev 29th 2015 - * Author: Tim (cpldcpu@gmail.com) - * - * Please do not change this file! All configuration is handled in "ws2812_config.h" - * - * 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 2 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 . - */ - -#pragma once - -#include -#include - -#include "color.h" - -/* User Interface - * - * Input: - * ledarray: An array of GRB data describing the LED colors - * number_of_leds: The number of LEDs to write - * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0) - * - * The functions will perform the following actions: - * - Set the data-out pin as output - * - Send out the LED data - * - Wait 50�s to reset the LEDs - */ - -void apa102_setleds(LED_TYPE *ledarray, uint16_t number_of_leds); -void apa102_setleds_pin(LED_TYPE *ledarray, uint16_t number_of_leds, uint8_t pinmask); -void apa102_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds); -- cgit v1.2.3 From 34446b79d7a17ba6e753d39956ebb5e871618d84 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Mon, 4 Jan 2021 08:45:43 +1100 Subject: Split up QWIIC_ENABLE to use QWIIC_DRIVERS as well, with yes/no for enable flag. (#11426) --- drivers/qwiic/qwiic.mk | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/qwiic/qwiic.mk b/drivers/qwiic/qwiic.mk index b23c25657d..164bd72108 100644 --- a/drivers/qwiic/qwiic.mk +++ b/drivers/qwiic/qwiic.mk @@ -1,16 +1,17 @@ -ifneq ($(strip $(QWIIC_ENABLE)),) +ifeq ($(strip $(QWIIC_ENABLE)),yes) COMMON_VPATH += $(DRIVER_PATH)/qwiic OPT_DEFS += -DQWIIC_ENABLE SRC += qwiic.c QUANTUM_LIB_SRC += i2c_master.c -endif -ifneq ($(filter JOYSTIIC, $(QWIIC_ENABLE)),) +ifneq ($(filter JOYSTIIC, $(QWIIC_DRIVERS)),) OPT_DEFS += -DQWIIC_JOYSTIIC_ENABLE SRC += joystiic.c endif -ifneq ($(filter MICRO_OLED, $(QWIIC_ENABLE)),) +ifneq ($(filter MICRO_OLED, $(QWIIC_DRIVERS)),) OPT_DEFS += -DQWIIC_MICRO_OLED_ENABLE SRC += micro_oled.c endif + +endif -- cgit v1.2.3 From 30b46fad5764b54ab4d47e9c4024f8030e1bf1a7 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 27 Jan 2021 17:42:49 +1100 Subject: UART driver refactor (#11637) --- drivers/avr/uart.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/avr/uart.h | 34 ++++++++++ drivers/chibios/uart.c | 59 +++++++++++++++++ drivers/chibios/uart.h | 77 ++++++++++++++++++++++ 4 files changed, 340 insertions(+) create mode 100644 drivers/avr/uart.c create mode 100644 drivers/avr/uart.h create mode 100644 drivers/chibios/uart.c create mode 100644 drivers/chibios/uart.h (limited to 'drivers') diff --git a/drivers/avr/uart.c b/drivers/avr/uart.c new file mode 100644 index 0000000000..e866a9e4f8 --- /dev/null +++ b/drivers/avr/uart.c @@ -0,0 +1,170 @@ +/* UART Example for Teensy USB Development Board + * http://www.pjrc.com/teensy/ + * Copyright (c) 2009 PJRC.COM, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Version 1.0: Initial Release +// Version 1.1: Add support for Teensy 2.0, minor optimizations + +#include +#include + +#include "uart.h" + +#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) +# define UDRn UDR1 +# define UBRRnL UBRR1L +# define UCSRnA UCSR1A +# define UCSRnB UCSR1B +# define UCSRnC UCSR1C +# define U2Xn U2X1 +# define RXENn RXEN1 +# define TXENn TXEN1 +# define RXCIEn RXCIE1 +# define UCSZn1 UCSZ11 +# define UCSZn0 UCSZ10 +# define UDRIEn UDRIE1 +# define USARTn_UDRE_vect USART1_UDRE_vect +# define USARTn_RX_vect USART1_RX_vect +#elif defined(__AVR_ATmega32A__) +# define UDRn UDR +# define UBRRnL UBRRL +# define UCSRnA UCSRA +# define UCSRnB UCSRB +# define UCSRnC UCSRC +# define U2Xn U2X +# define RXENn RXEN +# define TXENn TXEN +# define RXCIEn RXCIE +# define UCSZn1 UCSZ1 +# define UCSZn0 UCSZ0 +# define UDRIEn UDRIE +# define USARTn_UDRE_vect USART_UDRE_vect +# define USARTn_RX_vect USART_RX_vect +#elif defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) +# define UDRn UDR0 +# define UBRRnL UBRR0L +# define UCSRnA UCSR0A +# define UCSRnB UCSR0B +# define UCSRnC UCSR0C +# define U2Xn U2X0 +# define RXENn RXEN0 +# define TXENn TXEN0 +# define RXCIEn RXCIE0 +# define UCSZn1 UCSZ01 +# define UCSZn0 UCSZ00 +# define UDRIEn UDRIE0 +# define USARTn_UDRE_vect USART_UDRE_vect +# define USARTn_RX_vect USART_RX_vect +#endif + +// These buffers may be any size from 2 to 256 bytes. +#define RX_BUFFER_SIZE 64 +#define TX_BUFFER_SIZE 256 + +static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; +static volatile uint8_t tx_buffer_head; +static volatile uint8_t tx_buffer_tail; +static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; +static volatile uint8_t rx_buffer_head; +static volatile uint8_t rx_buffer_tail; + +// Initialize the UART +void uart_init(uint32_t baud) { + cli(); + UBRRnL = (F_CPU / 4 / baud - 1) / 2; + UCSRnA = (1 << U2Xn); + UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn); + UCSRnC = (1 << UCSZn1) | (1 << UCSZn0); + tx_buffer_head = tx_buffer_tail = 0; + rx_buffer_head = rx_buffer_tail = 0; + sei(); +} + +// Transmit a byte +void uart_putchar(uint8_t c) { + uint8_t i; + + i = tx_buffer_head + 1; + if (i >= TX_BUFFER_SIZE) i = 0; + // return immediately to avoid deadlock when interrupt is disabled(called from ISR) + if (tx_buffer_tail == i && (SREG & (1 << SREG_I)) == 0) return; + while (tx_buffer_tail == i) + ; // wait until space in buffer + // cli(); + tx_buffer[i] = c; + tx_buffer_head = i; + UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn); + // sei(); +} + +// Receive a byte +uint8_t uart_getchar(void) { + uint8_t c, i; + + while (rx_buffer_head == rx_buffer_tail) + ; // wait for character + i = rx_buffer_tail + 1; + if (i >= RX_BUFFER_SIZE) i = 0; + c = rx_buffer[i]; + rx_buffer_tail = i; + return c; +} + +// Return whether the number of bytes waiting in the receive buffer is nonzero. +// Call this before uart_getchar() to check if it will need +// to wait for a byte to arrive. +bool uart_available(void) { + uint8_t head, tail; + + head = rx_buffer_head; + tail = rx_buffer_tail; + if (head >= tail) return (head - tail) > 0; + return (RX_BUFFER_SIZE + head - tail) > 0; +} + +// Transmit Interrupt +ISR(USARTn_UDRE_vect) { + uint8_t i; + + if (tx_buffer_head == tx_buffer_tail) { + // buffer is empty, disable transmit interrupt + UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn); + } else { + i = tx_buffer_tail + 1; + if (i >= TX_BUFFER_SIZE) i = 0; + UDRn = tx_buffer[i]; + tx_buffer_tail = i; + } +} + +// Receive Interrupt +ISR(USARTn_RX_vect) { + uint8_t c, i; + + c = UDRn; + i = rx_buffer_head + 1; + if (i >= RX_BUFFER_SIZE) i = 0; + if (i != rx_buffer_tail) { + rx_buffer[i] = c; + rx_buffer_head = i; + } +} diff --git a/drivers/avr/uart.h b/drivers/avr/uart.h new file mode 100644 index 0000000000..d5ec563db2 --- /dev/null +++ b/drivers/avr/uart.h @@ -0,0 +1,34 @@ +/* UART Example for Teensy USB Development Board + * http://www.pjrc.com/teensy/ + * Copyright (c) 2009 PJRC.COM, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include + +void uart_init(uint32_t baud); + +void uart_putchar(uint8_t c); + +uint8_t uart_getchar(void); + +bool uart_available(void); diff --git a/drivers/chibios/uart.c b/drivers/chibios/uart.c new file mode 100644 index 0000000000..6e94899b9d --- /dev/null +++ b/drivers/chibios/uart.c @@ -0,0 +1,59 @@ +/* Copyright 2021 + * + * 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 . + */ + +#include "uart.h" + +#include "quantum.h" + +static SerialConfig serialConfig = { + SERIAL_DEFAULT_BITRATE, + SD1_CR1, + SD1_CR2, + SD1_CR3 +}; + +void uart_init(uint32_t baud) { + static bool is_initialised = false; + + if (!is_initialised) { + is_initialised = true; + + serialConfig.speed = baud; + +#if defined(USE_GPIOV1) + palSetLineMode(SD1_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); + palSetLineMode(SD1_RX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); +#else + palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); + palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); +#endif + sdStart(&SERIAL_DRIVER, &serialConfig); + } +} + +void uart_putchar(uint8_t c) { + sdPut(&SERIAL_DRIVER, c); +} + +uint8_t uart_getchar(void) { + msg_t res = sdGet(&SERIAL_DRIVER); + + return (uint8_t)res; +} + +bool uart_available(void) { + return !sdGetWouldBlock(&SERIAL_DRIVER); +} diff --git a/drivers/chibios/uart.h b/drivers/chibios/uart.h new file mode 100644 index 0000000000..b4e20e9fd3 --- /dev/null +++ b/drivers/chibios/uart.h @@ -0,0 +1,77 @@ +/* Copyright 2021 + * + * 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 . + */ + +#pragma once + +#include + +#include + +#ifndef SERIAL_DRIVER +# define SERIAL_DRIVER SD1 +#endif + +#ifndef SD1_TX_PIN +# define SD1_TX_PIN A9 +#endif + +#ifndef SD1_TX_PAL_MODE +# define SD1_TX_PAL_MODE 7 +#endif + +#ifndef SD1_RX_PIN +# define SD1_RX_PIN A10 +#endif + +#ifndef SD1_RX_PAL_MODE +# define SD1_RX_PAL_MODE 7 +#endif + +#ifndef SD1_CTS_PIN +# define SD1_CTS_PIN A11 +#endif + +#ifndef SD1_CTS_PAL_MODE +# define SD1_CTS_PAL_MODE 7 +#endif + +#ifndef SD1_RTS_PIN +# define SD1_RTS_PIN A12 +#endif + +#ifndef SD1_RTS_PAL_MODE +# define SD1_RTS_PAL_MODE 7 +#endif + +#ifndef SD1_CR1 +# define SD1_CR1 0 +#endif + +#ifndef SD1_CR2 +# define SD1_CR2 0 +#endif + +#ifndef SD1_CR3 +# define SD1_CR3 0 +#endif + +void uart_init(uint32_t baud); + +void uart_putchar(uint8_t c); + +uint8_t uart_getchar(void); + +bool uart_available(void); -- cgit v1.2.3 From d92ffd1157e3ecc4ae2dbf8548c45c8b0269f664 Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Sat, 30 Jan 2021 03:53:56 +0000 Subject: Adds AT90USB162 support (#11570) * at90usb162 support * fix missing bracket * Apply suggestions from code review Co-authored-by: Ryan Co-authored-by: Ryan --- drivers/avr/serial.c | 6 +++--- drivers/avr/spi_master.c | 2 +- drivers/avr/spi_master.h | 2 +- drivers/avr/uart.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/avr/serial.c b/drivers/avr/serial.c index 526a0946b2..3647bee0d3 100644 --- a/drivers/avr/serial.c +++ b/drivers/avr/serial.c @@ -20,7 +20,7 @@ #ifdef SOFT_SERIAL_PIN -# if !(defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) +# if !(defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) # error serial.c is not supported for the currently selected MCU # endif // if using ATmega32U4/2, AT90USBxxx I2C, can not use PD0 and PD1 in soft serial. @@ -52,8 +52,8 @@ # define EICRx EICRA # endif -// ATmegaxxU2 specific config -# if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) +// ATmegaxxU2/AT90USB162 specific config +# if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB162__) // PD4(INT5), PD6(INT6), PD7(INT7), PC7(INT4) # if SOFT_SERIAL_PIN == D4 # define EIMSK_BIT _BV(INT5) diff --git a/drivers/avr/spi_master.c b/drivers/avr/spi_master.c index cbec9f36e1..19ca0ced44 100644 --- a/drivers/avr/spi_master.c +++ b/drivers/avr/spi_master.c @@ -20,7 +20,7 @@ #include "quantum.h" #include "timer.h" -#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) +#if defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) # define SPI_SCK_PIN B1 # define SPI_MOSI_PIN B2 # define SPI_MISO_PIN B3 diff --git a/drivers/avr/spi_master.h b/drivers/avr/spi_master.h index e36a7c21c0..9203698dd5 100644 --- a/drivers/avr/spi_master.h +++ b/drivers/avr/spi_master.h @@ -21,7 +21,7 @@ typedef int16_t spi_status_t; // Hardware SS pin is defined in the header so that user code can refer to it -#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) +#if defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) # define SPI_SS_PIN B0 #elif defined(__AVR_ATmega32A__) # define SPI_SS_PIN B4 diff --git a/drivers/avr/uart.c b/drivers/avr/uart.c index e866a9e4f8..c6abcb6fe0 100644 --- a/drivers/avr/uart.c +++ b/drivers/avr/uart.c @@ -29,7 +29,7 @@ #include "uart.h" -#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) +#if defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) # define UDRn UDR1 # define UBRRnL UBRR1L # define UCSRnA UCSR1A -- cgit v1.2.3 From 6b9a7e21e953d68d6ae093c2d727f1f3ac2798c0 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Fri, 29 Jan 2021 23:35:16 -0800 Subject: Include stdbool.h in uart.h (#11728) --- drivers/avr/uart.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/avr/uart.h b/drivers/avr/uart.h index d5ec563db2..602eb3d8b0 100644 --- a/drivers/avr/uart.h +++ b/drivers/avr/uart.h @@ -24,6 +24,7 @@ #pragma once #include +#include void uart_init(uint32_t baud); -- cgit v1.2.3 From c27a778281824423a324d04276d291f06b49b1ae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 06:55:43 +1100 Subject: Format code according to conventions (#11905) Co-authored-by: QMK Bot --- drivers/chibios/uart.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/chibios/uart.c b/drivers/chibios/uart.c index 6e94899b9d..030335b342 100644 --- a/drivers/chibios/uart.c +++ b/drivers/chibios/uart.c @@ -18,12 +18,7 @@ #include "quantum.h" -static SerialConfig serialConfig = { - SERIAL_DEFAULT_BITRATE, - SD1_CR1, - SD1_CR2, - SD1_CR3 -}; +static SerialConfig serialConfig = {SERIAL_DEFAULT_BITRATE, SD1_CR1, SD1_CR2, SD1_CR3}; void uart_init(uint32_t baud) { static bool is_initialised = false; @@ -44,9 +39,7 @@ void uart_init(uint32_t baud) { } } -void uart_putchar(uint8_t c) { - sdPut(&SERIAL_DRIVER, c); -} +void uart_putchar(uint8_t c) { sdPut(&SERIAL_DRIVER, c); } uint8_t uart_getchar(void) { msg_t res = sdGet(&SERIAL_DRIVER); @@ -54,6 +47,4 @@ uint8_t uart_getchar(void) { return (uint8_t)res; } -bool uart_available(void) { - return !sdGetWouldBlock(&SERIAL_DRIVER); -} +bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); } -- cgit v1.2.3 From f53e41ac81662a560a299a23c7863dd2f618a1f8 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Mon, 15 Feb 2021 08:56:13 +1100 Subject: Add support for analog USBPD on STM32G4xx. (#11824) * Add support for analog USBPD on STM32G4xx. * Split up to a list of driver types, allow for custom. --- drivers/chibios/usbpd_stm32g4.c | 76 +++++++++++++++++++++++++++++++++++++++++ drivers/usbpd.h | 29 ++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 drivers/chibios/usbpd_stm32g4.c create mode 100644 drivers/usbpd.h (limited to 'drivers') diff --git a/drivers/chibios/usbpd_stm32g4.c b/drivers/chibios/usbpd_stm32g4.c new file mode 100644 index 0000000000..54c1e1fb3d --- /dev/null +++ b/drivers/chibios/usbpd_stm32g4.c @@ -0,0 +1,76 @@ +/* Copyright 2021 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 2 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 . + */ + +#include + +#ifndef USBPD_UCPD1_CFG1 +# define USBPD_UCPD1_CFG1 (UCPD_CFG1_PSC_UCPDCLK_0 | UCPD_CFG1_TRANSWIN_3 | UCPD_CFG1_IFRGAP_4 | UCPD_CFG1_HBITCLKDIV_4) +#endif // USBPD_UCPD1_CFG1 + +// Initialises the USBPD subsystem +__attribute__((weak)) void usbpd_init(void) { + // Disable dead-battery signals + PWR->CR3 |= PWR_CR3_UCPD_DBDIS; + // Enable the clock for the UCPD1 peripheral + RCC->APB1ENR2 |= RCC_APB1ENR2_UCPD1EN; + + // Copy the existing value + uint32_t CFG1 = UCPD1->CFG1; + // Force-disable UCPD1 before configuring + CFG1 &= ~UCPD_CFG1_UCPDEN; + // Configure UCPD1 + CFG1 = USBPD_UCPD1_CFG1; + // Apply the changes + UCPD1->CFG1 = CFG1; + // Enable UCPD1 + UCPD1->CFG1 |= UCPD_CFG1_UCPDEN; + + // Copy the existing value + uint32_t CR = UCPD1->CR; + // Clear out ANASUBMODE (irrelevant as a sink device) + CR &= ~UCPD_CR_ANASUBMODE_Msk; + // Advertise our capabilities as a sink, with both CC lines enabled + CR |= UCPD_CR_ANAMODE | UCPD_CR_CCENABLE_Msk; + // Apply the changes + UCPD1->CR = CR; +} + +// Gets the current state of the USBPD allowance +__attribute__((weak)) usbpd_allowance_t usbpd_get_allowance(void) { + uint32_t CR = UCPD1->CR; + + int ucpd_enabled = (UCPD1->CFG1 & UCPD_CFG1_UCPDEN_Msk) >> UCPD_CFG1_UCPDEN_Pos; + int anamode = (CR & UCPD_CR_ANAMODE_Msk) >> UCPD_CR_ANAMODE_Pos; + int cc_enabled = (CR & UCPD_CR_CCENABLE_Msk) >> UCPD_CR_CCENABLE_Pos; + + if (ucpd_enabled && anamode && cc_enabled) { + uint32_t SR = UCPD1->SR; + int vstate_cc1 = (SR & UCPD_SR_TYPEC_VSTATE_CC1_Msk) >> UCPD_SR_TYPEC_VSTATE_CC1_Pos; + int vstate_cc2 = (SR & UCPD_SR_TYPEC_VSTATE_CC2_Msk) >> UCPD_SR_TYPEC_VSTATE_CC2_Pos; + int vstate_max = vstate_cc1 > vstate_cc2 ? vstate_cc1 : vstate_cc2; + switch (vstate_max) { + case 0: + case 1: + return USBPD_500MA; // Note that this is 500mA (i.e. max USB 2.0), not 900mA, as we're not using USB 3.1 as a sink device. + case 2: + return USBPD_1500MA; + case 3: + return USBPD_3000MA; + } + } + + return USBPD_500MA; +} \ No newline at end of file diff --git a/drivers/usbpd.h b/drivers/usbpd.h new file mode 100644 index 0000000000..df4f29bb9d --- /dev/null +++ b/drivers/usbpd.h @@ -0,0 +1,29 @@ +/* Copyright 2021 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 2 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 . + */ + +#pragma once + +typedef enum { + USBPD_500MA, + USBPD_1500MA, + USBPD_3000MA, +} usbpd_allowance_t; + +// Initialises the USBPD subsystem +void usbpd_init(void); + +// Gets the current state of the USBPD allowance +usbpd_allowance_t usbpd_get_allowance(void); \ No newline at end of file -- cgit v1.2.3 From 8e8b7113dcf1ec8be0bdac75ed4a1d2b256a5965 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 11:53:15 +1100 Subject: Format code according to conventions (#11907) Co-authored-by: QMK Bot --- drivers/chibios/usbpd_stm32g4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/chibios/usbpd_stm32g4.c b/drivers/chibios/usbpd_stm32g4.c index 54c1e1fb3d..f16ca8aeae 100644 --- a/drivers/chibios/usbpd_stm32g4.c +++ b/drivers/chibios/usbpd_stm32g4.c @@ -64,7 +64,7 @@ __attribute__((weak)) usbpd_allowance_t usbpd_get_allowance(void) { switch (vstate_max) { case 0: case 1: - return USBPD_500MA; // Note that this is 500mA (i.e. max USB 2.0), not 900mA, as we're not using USB 3.1 as a sink device. + return USBPD_500MA; // Note that this is 500mA (i.e. max USB 2.0), not 900mA, as we're not using USB 3.1 as a sink device. case 2: return USBPD_1500MA; case 3: -- cgit v1.2.3