aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJoel Challis <git@zvecr.com>2021-08-17 23:43:09 +0100
committerGitHub <noreply@github.com>2021-08-17 23:43:09 +0100
commit1bb7af4d446174b7181c9bb22dbd14c93642ea10 (patch)
tree894eceeb29cc2c00f6b0f08a4ca177da7f172424 /drivers
parent483691dd73e5260fac958c524e0a12e705db43f6 (diff)
downloadqmk_firmware-1bb7af4d446174b7181c9bb22dbd14c93642ea10.tar.gz
qmk_firmware-1bb7af4d446174b7181c9bb22dbd14c93642ea10.zip
Relocate platform specific drivers (#13894)
* Relocate platform specific drivers * Move stm eeprom * Tidy up slightly
Diffstat (limited to 'drivers')
-rw-r--r--drivers/avr/analog.c138
-rw-r--r--drivers/avr/analog.h53
-rw-r--r--drivers/avr/glcdfont.c23
-rw-r--r--drivers/avr/hd44780.c536
-rw-r--r--drivers/avr/hd44780.h348
-rw-r--r--drivers/avr/i2c_master.c241
-rw-r--r--drivers/avr/i2c_master.h43
-rw-r--r--drivers/avr/i2c_slave.c111
-rw-r--r--drivers/avr/i2c_slave.h41
-rw-r--r--drivers/avr/serial.c529
-rw-r--r--drivers/avr/spi_master.c180
-rw-r--r--drivers/avr/spi_master.h59
-rw-r--r--drivers/avr/ssd1306.c319
-rw-r--r--drivers/avr/ssd1306.h87
-rw-r--r--drivers/avr/uart.c170
-rw-r--r--drivers/avr/uart.h35
-rw-r--r--drivers/avr/ws2812.c176
-rw-r--r--drivers/avr/ws2812_i2c.c27
-rw-r--r--drivers/chibios/analog.c321
-rw-r--r--drivers/chibios/analog.h41
-rw-r--r--drivers/chibios/i2c_master.c121
-rw-r--r--drivers/chibios/i2c_master.h113
-rw-r--r--drivers/chibios/serial.c278
-rw-r--r--drivers/chibios/serial_usart.c318
-rw-r--r--drivers/chibios/serial_usart.h116
-rw-r--r--drivers/chibios/spi_master.c202
-rw-r--r--drivers/chibios/spi_master.h93
-rw-r--r--drivers/chibios/uart.c50
-rw-r--r--drivers/chibios/uart.h77
-rw-r--r--drivers/chibios/usbpd_stm32g4.c76
-rw-r--r--drivers/chibios/ws2812.c114
-rw-r--r--drivers/chibios/ws2812_pwm.c311
-rw-r--r--drivers/chibios/ws2812_spi.c159
-rw-r--r--drivers/eeprom/eeprom_stm32_L0_L1.c96
-rw-r--r--drivers/eeprom/eeprom_stm32_L0_L1.h33
35 files changed, 0 insertions, 5635 deletions
diff --git a/drivers/avr/analog.c b/drivers/avr/analog.c
deleted file mode 100644
index 8d299ffdb..000000000
--- a/drivers/avr/analog.c
+++ /dev/null
@@ -1,138 +0,0 @@
1/* Copyright 2015 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <avr/io.h>
18#include <avr/pgmspace.h>
19#include <stdint.h>
20#include "analog.h"
21
22static uint8_t aref = ADC_REF_POWER;
23
24void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); }
25
26// Arduino compatible pin input
27int16_t analogRead(uint8_t pin) {
28#if defined(__AVR_ATmega32U4__)
29 // clang-format off
30 static const uint8_t PROGMEM pin_to_mux[] = {
31 //A0 A1 A2 A3 A4 A5
32 //F7 F6 F5 F4 F1 F0
33 0x07, 0x06, 0x05, 0x04, 0x01, 0x00,
34 //A6 A7 A8 A9 A10 A11
35 //D4 D7 B4 B5 B6 D6
36 0x20, 0x22, 0x23, 0x24, 0x25, 0x21
37 };
38 // clang-format on
39 if (pin >= 12) return 0;
40 return adc_read(pgm_read_byte(pin_to_mux + pin));
41#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
42 if (pin >= 8) return 0;
43 return adc_read(pin);
44#else
45 return 0;
46#endif
47}
48
49int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); }
50
51uint8_t pinToMux(pin_t pin) {
52 switch (pin) {
53 // clang-format off
54#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
55 case F0: return 0; // ADC0
56 case F1: return _BV(MUX0); // ADC1
57 case F2: return _BV(MUX1); // ADC2
58 case F3: return _BV(MUX1) | _BV(MUX0); // ADC3
59 case F4: return _BV(MUX2); // ADC4
60 case F5: return _BV(MUX2) | _BV(MUX0); // ADC5
61 case F6: return _BV(MUX2) | _BV(MUX1); // ADC6
62 case F7: return _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // ADC7
63 default: return _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
64#elif defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
65 case F0: return 0; // ADC0
66 case F1: return _BV(MUX0); // ADC1
67 case F4: return _BV(MUX2); // ADC4
68 case F5: return _BV(MUX2) | _BV(MUX0); // ADC5
69 case F6: return _BV(MUX2) | _BV(MUX1); // ADC6
70 case F7: return _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // ADC7
71 case D4: return _BV(MUX5); // ADC8
72 case D6: return _BV(MUX5) | _BV(MUX0); // ADC9
73 case D7: return _BV(MUX5) | _BV(MUX1); // ADC10
74 case B4: return _BV(MUX5) | _BV(MUX1) | _BV(MUX0); // ADC11
75 case B5: return _BV(MUX5) | _BV(MUX2); // ADC12
76 case B6: return _BV(MUX5) | _BV(MUX2) | _BV(MUX0); // ADC13
77 default: return _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
78#elif defined(__AVR_ATmega32A__)
79 case A0: return 0; // ADC0
80 case A1: return _BV(MUX0); // ADC1
81 case A2: return _BV(MUX1); // ADC2
82 case A3: return _BV(MUX1) | _BV(MUX0); // ADC3
83 case A4: return _BV(MUX2); // ADC4
84 case A5: return _BV(MUX2) | _BV(MUX0); // ADC5
85 case A6: return _BV(MUX2) | _BV(MUX1); // ADC6
86 case A7: return _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // ADC7
87 default: return _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
88#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
89 case C0: return 0; // ADC0
90 case C1: return _BV(MUX0); // ADC1
91 case C2: return _BV(MUX1); // ADC2
92 case C3: return _BV(MUX1) | _BV(MUX0); // ADC3
93 case C4: return _BV(MUX2); // ADC4
94 case C5: return _BV(MUX2) | _BV(MUX0); // ADC5
95 // ADC7:6 not present in DIP package and not shared by GPIO pins
96 default: return _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
97#endif
98 // clang-format on
99 }
100 return 0;
101}
102
103int16_t adc_read(uint8_t mux) {
104 uint16_t low;
105
106 // Enable ADC and configure prescaler
107 ADCSRA = _BV(ADEN) | ADC_PRESCALER;
108
109#if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
110 // High speed mode and ADC8-13
111 ADCSRB = _BV(ADHSM) | (mux & _BV(MUX5));
112#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
113 // High speed mode only
114 ADCSRB = _BV(ADHSM);
115#endif
116
117 // Configure mux input
118#if defined(MUX4)
119 ADMUX = aref | (mux & (_BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0)));
120#else
121 ADMUX = aref | (mux & (_BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0)));
122#endif
123
124 // Start the conversion
125 ADCSRA |= _BV(ADSC);
126 // Wait for result
127 while (ADCSRA & _BV(ADSC))
128 ;
129 // Must read LSB first
130 low = ADCL;
131 // Must read MSB only once!
132 low |= (ADCH << 8);
133
134 // turn off the ADC
135 ADCSRA &= ~(1 << ADEN);
136
137 return low;
138}
diff --git a/drivers/avr/analog.h b/drivers/avr/analog.h
deleted file mode 100644
index 058882450..000000000
--- a/drivers/avr/analog.h
+++ /dev/null
@@ -1,53 +0,0 @@
1/* Copyright 2015 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <stdint.h>
20#include "quantum.h"
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25void analogReference(uint8_t mode);
26int16_t analogRead(uint8_t pin);
27
28int16_t analogReadPin(pin_t pin);
29uint8_t pinToMux(pin_t pin);
30
31int16_t adc_read(uint8_t mux);
32#ifdef __cplusplus
33}
34#endif
35
36#define ADC_REF_EXTERNAL 0 // AREF, Internal Vref turned off
37#define ADC_REF_POWER _BV(REFS0) // AVCC with external capacitor on AREF pin
38#define ADC_REF_INTERNAL (_BV(REFS1) | _BV(REFS0)) // Internal 2.56V Voltage Reference with external capacitor on AREF pin (1.1V for 328P)
39
40// These prescaler values are for high speed mode, ADHSM = 1
41#if F_CPU == 16000000L || F_CPU == 12000000L
42# define ADC_PRESCALER (_BV(ADPS2) | _BV(ADPS1)) // /64
43#elif F_CPU == 8000000L
44# define ADC_PRESCALER (_BV(ADPS2) | _BV(ADPS0)) // /32
45#elif F_CPU == 4000000L
46# define ADC_PRESCALER (_BV(ADPS2)) // /16
47#elif F_CPU == 2000000L
48# define ADC_PRESCALER (_BV(ADPS1) | _BV(ADPS0)) // /8
49#elif F_CPU == 1000000L
50# define ADC_PRESCALER _BV(ADPS1) // /4
51#else
52# define ADC_PRESCALER _BV(ADPS0) // /2
53#endif
diff --git a/drivers/avr/glcdfont.c b/drivers/avr/glcdfont.c
deleted file mode 100644
index 5e763b054..000000000
--- a/drivers/avr/glcdfont.c
+++ /dev/null
@@ -1,23 +0,0 @@
1// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
2// See gfxfont.h for newer custom bitmap font info.
3
4#include "progmem.h"
5
6// Standard ASCII 5x7 font
7
8static const unsigned char font[] PROGMEM = {
9 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, 0x18, 0x3C, 0x18, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x18, 0x24, 0x18, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x30, 0x48, 0x3A, 0x06, 0x0E, 0x26, 0x29, 0x79, 0x29, 0x26, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x40, 0x7F, 0x05, 0x25, 0x3F, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x66, 0x89, 0x95, 0x6A, 0x60, 0x60, 0x60, 0x60, 0x60, 0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x08, 0x04, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
10 0x30, 0x38, 0x3E, 0x38, 0x30, 0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00,
11 0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41, 0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, 0x03, 0x04, 0x78, 0x04, 0x03,
12 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41, 0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28, 0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08, 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48, 0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C,
13 0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C, 0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40, 0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41, 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
14 0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E, 0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54, 0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00, 0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
15 0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54, 0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49, 0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
16 0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42, 0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
17 0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E, 0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6, 0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00, 0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40, 0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D, 0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48, 0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A, 0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
18 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
19 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
20 0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17, 0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17, 0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F,
21 0x14, 0x14, 0x14, 0xF4, 0x14, 0x10, 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44, 0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
22 0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55, 0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E, 0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D, 0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D, 0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44, 0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0, 0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36, 0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
23};
diff --git a/drivers/avr/hd44780.c b/drivers/avr/hd44780.c
deleted file mode 100644
index f71069dec..000000000
--- a/drivers/avr/hd44780.c
+++ /dev/null
@@ -1,536 +0,0 @@
1/****************************************************************************
2 Title: HD44780U LCD library
3 Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury
4 License: GNU General Public License Version 3
5 File: $Id: lcd.c,v 1.15.2.2 2015/01/17 12:16:05 peter Exp $
6 Software: AVR-GCC 3.3
7 Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega
8
9 DESCRIPTION
10 Basic routines for interfacing a HD44780U-based text lcd display
11
12 Originally based on Volker Oth's lcd library,
13 changed lcd_init(), added additional constants for lcd_command(),
14 added 4-bit I/O mode, improved and optimized code.
15
16 Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in
17 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.
18
19 Memory mapped mode compatible with Kanda STK200, but supports also
20 generation of R/W signal through A8 address line.
21
22 USAGE
23 See the C include lcd.h file for a description of each function
24
25*****************************************************************************/
26#include <inttypes.h>
27#include <avr/io.h>
28#include <avr/pgmspace.h>
29#include <util/delay.h>
30#include "hd44780.h"
31
32/*
33** constants/macros
34*/
35#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */
36#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
37/* on ATmega64/128 PINF is on port 0x00 and not 0x60 */
38# define PIN(x) (&PORTF == &(x) ? _SFR_IO8(0x00) : (*(&x - 2)))
39#else
40# define PIN(x) (*(&x - 2)) /* address of input register of port x */
41#endif
42
43#if LCD_IO_MODE
44# define lcd_e_delay() _delay_us(LCD_DELAY_ENABLE_PULSE)
45# define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN);
46# define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN);
47# define lcd_e_toggle() toggle_e()
48# define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN)
49# define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN)
50# define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN)
51# define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN)
52#endif
53
54#if LCD_IO_MODE
55# if LCD_LINES == 1
56# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
57# else
58# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
59# endif
60#else
61# if LCD_LINES == 1
62# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE
63# else
64# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES
65# endif
66#endif
67
68#if LCD_CONTROLLER_KS0073
69# if LCD_LINES == 4
70
71# define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x2C /* |0|010|1100 4-bit mode, extension-bit RE = 1 */
72# define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x28 /* |0|010|1000 4-bit mode, extension-bit RE = 0 */
73# define KS0073_4LINES_MODE 0x09 /* |0|000|1001 4 lines mode */
74
75# endif
76#endif
77
78/*
79** function prototypes
80*/
81#if LCD_IO_MODE
82static void toggle_e(void);
83#endif
84
85/*
86** local functions
87*/
88
89/*************************************************************************
90delay for a minimum of <us> microseconds
91the number of loops is calculated at compile-time from MCU clock frequency
92*************************************************************************/
93#define delay(us) _delay_us(us)
94
95#if LCD_IO_MODE
96/* toggle Enable Pin to initiate write */
97static void toggle_e(void) {
98 lcd_e_high();
99 lcd_e_delay();
100 lcd_e_low();
101}
102#endif
103
104/*************************************************************************
105Low-level function to write byte to LCD controller
106Input: data byte to write to LCD
107 rs 1: write data
108 0: write instruction
109Returns: none
110*************************************************************************/
111#if LCD_IO_MODE
112static void lcd_write(uint8_t data, uint8_t rs) {
113 unsigned char dataBits;
114
115 if (rs) { /* write data (RS=1, RW=0) */
116 lcd_rs_high();
117 } else { /* write instruction (RS=0, RW=0) */
118 lcd_rs_low();
119 }
120 lcd_rw_low(); /* RW=0 write mode */
121
122 if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)) {
123 /* configure data pins as output */
124 DDR(LCD_DATA0_PORT) |= 0x0F;
125
126 /* output high nibble first */
127 dataBits = LCD_DATA0_PORT & 0xF0;
128 LCD_DATA0_PORT = dataBits | ((data >> 4) & 0x0F);
129 lcd_e_toggle();
130
131 /* output low nibble */
132 LCD_DATA0_PORT = dataBits | (data & 0x0F);
133 lcd_e_toggle();
134
135 /* all data pins high (inactive) */
136 LCD_DATA0_PORT = dataBits | 0x0F;
137 } else {
138 /* configure data pins as output */
139 DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
140 DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
141 DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
142 DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
143
144 /* output high nibble first */
145 LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
146 LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
147 LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
148 LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
149 if (data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
150 if (data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
151 if (data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
152 if (data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
153 lcd_e_toggle();
154
155 /* output low nibble */
156 LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
157 LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
158 LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
159 LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
160 if (data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
161 if (data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
162 if (data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
163 if (data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
164 lcd_e_toggle();
165
166 /* all data pins high (inactive) */
167 LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
168 LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
169 LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
170 LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
171 }
172}
173#else
174# define lcd_write(d, rs) \
175 if (rs) \
176 *(volatile uint8_t *)(LCD_IO_DATA) = d; \
177 else \
178 *(volatile uint8_t *)(LCD_IO_FUNCTION) = d;
179/* rs==0 -> write instruction to LCD_IO_FUNCTION */
180/* rs==1 -> write data to LCD_IO_DATA */
181#endif
182
183/*************************************************************************
184Low-level function to read byte from LCD controller
185Input: rs 1: read data
186 0: read busy flag / address counter
187Returns: byte read from LCD controller
188*************************************************************************/
189#if LCD_IO_MODE
190static uint8_t lcd_read(uint8_t rs) {
191 uint8_t data;
192
193 if (rs)
194 lcd_rs_high(); /* RS=1: read data */
195 else
196 lcd_rs_low(); /* RS=0: read busy flag */
197 lcd_rw_high(); /* RW=1 read mode */
198
199 if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)) {
200 DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */
201
202 lcd_e_high();
203 lcd_e_delay();
204 data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */
205 lcd_e_low();
206
207 lcd_e_delay(); /* Enable 500ns low */
208
209 lcd_e_high();
210 lcd_e_delay();
211 data |= PIN(LCD_DATA0_PORT) & 0x0F; /* read low nibble */
212 lcd_e_low();
213 } else {
214 /* configure data pins as input */
215 DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);
216 DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);
217 DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);
218 DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);
219
220 /* read high nibble first */
221 lcd_e_high();
222 lcd_e_delay();
223 data = 0;
224 if (PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN)) data |= 0x10;
225 if (PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN)) data |= 0x20;
226 if (PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN)) data |= 0x40;
227 if (PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN)) data |= 0x80;
228 lcd_e_low();
229
230 lcd_e_delay(); /* Enable 500ns low */
231
232 /* read low nibble */
233 lcd_e_high();
234 lcd_e_delay();
235 if (PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN)) data |= 0x01;
236 if (PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN)) data |= 0x02;
237 if (PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN)) data |= 0x04;
238 if (PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN)) data |= 0x08;
239 lcd_e_low();
240 }
241 return data;
242}
243#else
244# define lcd_read(rs) (rs) ? *(volatile uint8_t *)(LCD_IO_DATA + LCD_IO_READ) : *(volatile uint8_t *)(LCD_IO_FUNCTION + LCD_IO_READ)
245/* rs==0 -> read instruction from LCD_IO_FUNCTION */
246/* rs==1 -> read data from LCD_IO_DATA */
247#endif
248
249/*************************************************************************
250loops while lcd is busy, returns address counter
251*************************************************************************/
252static uint8_t lcd_waitbusy(void)
253
254{
255 register uint8_t c;
256
257 /* wait until busy flag is cleared */
258 while ((c = lcd_read(0)) & (1 << LCD_BUSY)) {
259 }
260
261 /* the address counter is updated 4us after the busy flag is cleared */
262 delay(LCD_DELAY_BUSY_FLAG);
263
264 /* now read the address counter */
265 return (lcd_read(0)); // return address counter
266
267} /* lcd_waitbusy */
268
269/*************************************************************************
270Move cursor to the start of next line or to the first line if the cursor
271is already on the last line.
272*************************************************************************/
273static inline void lcd_newline(uint8_t pos) {
274 register uint8_t addressCounter;
275
276#if LCD_LINES == 1
277 addressCounter = 0;
278#endif
279#if LCD_LINES == 2
280 if (pos < (LCD_START_LINE2))
281 addressCounter = LCD_START_LINE2;
282 else
283 addressCounter = LCD_START_LINE1;
284#endif
285#if LCD_LINES == 4
286# if KS0073_4LINES_MODE
287 if (pos < LCD_START_LINE2)
288 addressCounter = LCD_START_LINE2;
289 else if ((pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3))
290 addressCounter = LCD_START_LINE3;
291 else if ((pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4))
292 addressCounter = LCD_START_LINE4;
293 else
294 addressCounter = LCD_START_LINE1;
295# else
296 if (pos < LCD_START_LINE3)
297 addressCounter = LCD_START_LINE2;
298 else if ((pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4))
299 addressCounter = LCD_START_LINE3;
300 else if ((pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2))
301 addressCounter = LCD_START_LINE4;
302 else
303 addressCounter = LCD_START_LINE1;
304# endif
305#endif
306 lcd_command((1 << LCD_DDRAM) + addressCounter);
307
308} /* lcd_newline */
309
310/*
311** PUBLIC FUNCTIONS
312*/
313
314/*************************************************************************
315Send LCD controller instruction command
316Input: instruction to send to LCD controller, see HD44780 data sheet
317Returns: none
318*************************************************************************/
319void lcd_command(uint8_t cmd) {
320 lcd_waitbusy();
321 lcd_write(cmd, 0);
322}
323
324/*************************************************************************
325Send data byte to LCD controller
326Input: data to send to LCD controller, see HD44780 data sheet
327Returns: none
328*************************************************************************/
329void lcd_data(uint8_t data) {
330 lcd_waitbusy();
331 lcd_write(data, 1);
332}
333
334/*************************************************************************
335Set cursor to specified position
336Input: x horizontal position (0: left most position)
337 y vertical position (0: first line)
338Returns: none
339*************************************************************************/
340void lcd_gotoxy(uint8_t x, uint8_t y) {
341#if LCD_LINES == 1
342 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
343#endif
344#if LCD_LINES == 2
345 if (y == 0)
346 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
347 else
348 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
349#endif
350#if LCD_LINES == 4
351 if (y == 0)
352 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
353 else if (y == 1)
354 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
355 else if (y == 2)
356 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
357 else /* y==3 */
358 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x);
359#endif
360
361} /* lcd_gotoxy */
362
363/*************************************************************************
364*************************************************************************/
365int lcd_getxy(void) { return lcd_waitbusy(); }
366
367/*************************************************************************
368Clear display and set cursor to home position
369*************************************************************************/
370void lcd_clrscr(void) { lcd_command(1 << LCD_CLR); }
371
372/*************************************************************************
373Set cursor to home position
374*************************************************************************/
375void lcd_home(void) { lcd_command(1 << LCD_HOME); }
376
377/*************************************************************************
378Display character at current cursor position
379Input: character to be displayed
380Returns: none
381*************************************************************************/
382void lcd_putc(char c) {
383 uint8_t pos;
384
385 pos = lcd_waitbusy(); // read busy-flag and address counter
386 if (c == '\n') {
387 lcd_newline(pos);
388 } else {
389#if LCD_WRAP_LINES == 1
390# if LCD_LINES == 1
391 if (pos == LCD_START_LINE1 + LCD_DISP_LENGTH) {
392 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1, 0);
393 }
394# elif LCD_LINES == 2
395 if (pos == LCD_START_LINE1 + LCD_DISP_LENGTH) {
396 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2, 0);
397 } else if (pos == LCD_START_LINE2 + LCD_DISP_LENGTH) {
398 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1, 0);
399 }
400# elif LCD_LINES == 4
401 if (pos == LCD_START_LINE1 + LCD_DISP_LENGTH) {
402 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2, 0);
403 } else if (pos == LCD_START_LINE2 + LCD_DISP_LENGTH) {
404 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE3, 0);
405 } else if (pos == LCD_START_LINE3 + LCD_DISP_LENGTH) {
406 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE4, 0);
407 } else if (pos == LCD_START_LINE4 + LCD_DISP_LENGTH) {
408 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1, 0);
409 }
410# endif
411 lcd_waitbusy();
412#endif
413 lcd_write(c, 1);
414 }
415
416} /* lcd_putc */
417
418/*************************************************************************
419Display string without auto linefeed
420Input: string to be displayed
421Returns: none
422*************************************************************************/
423void lcd_puts(const char *s)
424/* print string on lcd (no auto linefeed) */
425{
426 register char c;
427
428 while ((c = *s++)) {
429 lcd_putc(c);
430 }
431
432} /* lcd_puts */
433
434/*************************************************************************
435Display string from program memory without auto linefeed
436Input: string from program memory be be displayed
437Returns: none
438*************************************************************************/
439void lcd_puts_p(const char *progmem_s)
440/* print string from program memory on lcd (no auto linefeed) */
441{
442 register char c;
443
444 while ((c = pgm_read_byte(progmem_s++))) {
445 lcd_putc(c);
446 }
447
448} /* lcd_puts_p */
449
450/*************************************************************************
451Initialize display and select type of cursor
452Input: dispAttr LCD_DISP_OFF display off
453 LCD_DISP_ON display on, cursor off
454 LCD_DISP_ON_CURSOR display on, cursor on
455 LCD_DISP_CURSOR_BLINK display on, cursor on flashing
456Returns: none
457*************************************************************************/
458void lcd_init(uint8_t dispAttr) {
459#if LCD_IO_MODE
460 /*
461 * Initialize LCD to 4 bit I/O mode
462 */
463
464 if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (&LCD_RS_PORT == &LCD_DATA0_PORT) && (&LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) && (LCD_RS_PIN == 4) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6)) {
465 /* configure all port bits as output (all LCD lines on same port) */
466 DDR(LCD_DATA0_PORT) |= 0x7F;
467 } else if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)) {
468 /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */
469 DDR(LCD_DATA0_PORT) |= 0x0F;
470 DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
471 DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
472 DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
473 } else {
474 /* configure all port bits as output (LCD data and control lines on different ports */
475 DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
476 DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
477 DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
478 DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
479 DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
480 DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
481 DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
482 }
483 delay(LCD_DELAY_BOOTUP); /* wait 16ms or more after power-on */
484
485 /* initial write to lcd is 8bit */
486 LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // LCD_FUNCTION>>4;
487 LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // LCD_FUNCTION_8BIT>>4;
488 lcd_e_toggle();
489 delay(LCD_DELAY_INIT); /* delay, busy flag can't be checked here */
490
491 /* repeat last command */
492 lcd_e_toggle();
493 delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */
494
495 /* repeat last command a third time */
496 lcd_e_toggle();
497 delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */
498
499 /* now configure for 4bit mode */
500 LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4
501 lcd_e_toggle();
502 delay(LCD_DELAY_INIT_4BIT); /* some displays need this additional delay */
503
504 /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */
505#else
506 /*
507 * Initialize LCD to 8 bit memory mapped mode
508 */
509
510 /* enable external SRAM (memory mapped lcd) and one wait state */
511 MCUCR = _BV(SRE) | _BV(SRW);
512
513 /* reset LCD */
514 delay(LCD_DELAY_BOOTUP); /* wait 16ms after power-on */
515 lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */
516 delay(LCD_DELAY_INIT); /* wait 5ms */
517 lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */
518 delay(LCD_DELAY_INIT_REP); /* wait 64us */
519 lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */
520 delay(LCD_DELAY_INIT_REP); /* wait 64us */
521#endif
522
523#if KS0073_4LINES_MODE
524 /* Display with KS0073 controller requires special commands for enabling 4 line mode */
525 lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);
526 lcd_command(KS0073_4LINES_MODE);
527 lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);
528#else
529 lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
530#endif
531 lcd_command(LCD_DISP_OFF); /* display off */
532 lcd_clrscr(); /* display clear */
533 lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
534 lcd_command(dispAttr); /* display/cursor control */
535
536} /* lcd_init */
diff --git a/drivers/avr/hd44780.h b/drivers/avr/hd44780.h
deleted file mode 100644
index 08e60f8a4..000000000
--- a/drivers/avr/hd44780.h
+++ /dev/null
@@ -1,348 +0,0 @@
1/*************************************************************************
2 Title : C include file for the HD44780U LCD library (lcd.c)
3 Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury
4 License: GNU General Public License Version 3
5 File: $Id: lcd.h,v 1.14.2.4 2015/01/20 17:16:07 peter Exp $
6 Software: AVR-GCC 4.x
7 Hardware: any AVR device, memory mapped mode only for AVR with
8 memory mapped interface (AT90S8515/ATmega8515/ATmega128)
9***************************************************************************/
10
11/**
12 @mainpage
13 Collection of libraries for AVR-GCC
14 @author Peter Fleury pfleury@gmx.ch http://tinyurl.com/peterfleury
15 @copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
16
17 @file
18 @defgroup pfleury_lcd LCD library <lcd.h>
19 @code #include <lcd.h> @endcode
20
21 @brief Basic routines for interfacing a HD44780U-based character LCD display
22
23 LCD character displays can be found in many devices, like espresso machines, laser printers.
24 The Hitachi HD44780 controller and its compatible controllers like Samsung KS0066U have become an industry standard for these types of displays.
25
26 This library allows easy interfacing with a HD44780 compatible display and can be
27 operated in memory mapped mode (LCD_IO_MODE defined as 0 in the include file lcd.h.) or in
28 4-bit IO port mode (LCD_IO_MODE defined as 1). 8-bit IO port mode is not supported.
29
30 Memory mapped mode is compatible with old Kanda STK200 starter kit, but also supports
31 generation of R/W signal through A8 address line.
32
33 @see The chapter <a href=" http://homepage.hispeed.ch/peterfleury/avr-lcd44780.html" target="_blank">Interfacing a HD44780 Based LCD to an AVR</a>
34 on my home page, which shows example circuits how to connect an LCD to an AVR controller.
35
36 @author Peter Fleury pfleury@gmx.ch http://tinyurl.com/peterfleury
37
38 @version 2.0
39
40 @copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
41
42*/
43
44#pragma once
45
46#include <inttypes.h>
47#include <avr/pgmspace.h>
48
49#if (__GNUC__ * 100 + __GNUC_MINOR__) < 405
50# error "This library requires AVR-GCC 4.5 or later, update to newer AVR-GCC compiler !"
51#endif
52
53/**@{*/
54
55/*
56 * LCD and target specific definitions below can be defined in a separate include file with name lcd_definitions.h instead modifying this file
57 * by adding -D_LCD_DEFINITIONS_FILE to the CDEFS section in the Makefile
58 * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h
59 */
60#ifdef _LCD_DEFINITIONS_FILE
61# include "lcd_definitions.h"
62#endif
63
64/**
65 * @name Definition for LCD controller type
66 * Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller.
67 */
68#ifndef LCD_CONTROLLER_KS0073
69# define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */
70#endif
71
72/**
73 * @name Definitions for Display Size
74 * Change these definitions to adapt setting to your display
75 *
76 * These definitions can be defined in a separate include file \b lcd_definitions.h instead modifying this file by
77 * adding -D_LCD_DEFINITIONS_FILE to the CDEFS section in the Makefile.
78 * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h
79 *
80 */
81#ifndef LCD_LINES
82# define LCD_LINES 2 /**< number of visible lines of the display */
83#endif
84#ifndef LCD_DISP_LENGTH
85# define LCD_DISP_LENGTH 16 /**< visibles characters per line of the display */
86#endif
87#ifndef LCD_LINE_LENGTH
88# define LCD_LINE_LENGTH 0x40 /**< internal line length of the display */
89#endif
90#ifndef LCD_START_LINE1
91# define LCD_START_LINE1 0x00 /**< DDRAM address of first char of line 1 */
92#endif
93#ifndef LCD_START_LINE2
94# define LCD_START_LINE2 0x40 /**< DDRAM address of first char of line 2 */
95#endif
96#ifndef LCD_START_LINE3
97# define LCD_START_LINE3 0x14 /**< DDRAM address of first char of line 3 */
98#endif
99#ifndef LCD_START_LINE4
100# define LCD_START_LINE4 0x54 /**< DDRAM address of first char of line 4 */
101#endif
102#ifndef LCD_WRAP_LINES
103# define LCD_WRAP_LINES 0 /**< 0: no wrap, 1: wrap at end of visibile line */
104#endif
105
106/**
107 * @name Definitions for 4-bit IO mode
108 *
109 * The four LCD data lines and the three control lines RS, RW, E can be on the
110 * same port or on different ports.
111 * Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on
112 * different ports.
113 *
114 * Normally the four data lines should be mapped to bit 0..3 on one port, but it
115 * is possible to connect these data lines in different order or even on different
116 * ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions.
117 *
118 * Adjust these definitions to your target.\n
119 * These definitions can be defined in a separate include file \b lcd_definitions.h instead modifying this file by
120 * adding \b -D_LCD_DEFINITIONS_FILE to the \b CDEFS section in the Makefile.
121 * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h
122 *
123 */
124#define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */
125
126#if LCD_IO_MODE
127
128# ifndef LCD_PORT
129# define LCD_PORT PORTA /**< port for the LCD lines */
130# endif
131# ifndef LCD_DATA0_PORT
132# define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */
133# endif
134# ifndef LCD_DATA1_PORT
135# define LCD_DATA1_PORT LCD_PORT /**< port for 4bit data bit 1 */
136# endif
137# ifndef LCD_DATA2_PORT
138# define LCD_DATA2_PORT LCD_PORT /**< port for 4bit data bit 2 */
139# endif
140# ifndef LCD_DATA3_PORT
141# define LCD_DATA3_PORT LCD_PORT /**< port for 4bit data bit 3 */
142# endif
143# ifndef LCD_DATA0_PIN
144# define LCD_DATA0_PIN 4 /**< pin for 4bit data bit 0 */
145# endif
146# ifndef LCD_DATA1_PIN
147# define LCD_DATA1_PIN 5 /**< pin for 4bit data bit 1 */
148# endif
149# ifndef LCD_DATA2_PIN
150# define LCD_DATA2_PIN 6 /**< pin for 4bit data bit 2 */
151# endif
152# ifndef LCD_DATA3_PIN
153# define LCD_DATA3_PIN 7 /**< pin for 4bit data bit 3 */
154# endif
155# ifndef LCD_RS_PORT
156# define LCD_RS_PORT LCD_PORT /**< port for RS line */
157# endif
158# ifndef LCD_RS_PIN
159# define LCD_RS_PIN 3 /**< pin for RS line */
160# endif
161# ifndef LCD_RW_PORT
162# define LCD_RW_PORT LCD_PORT /**< port for RW line */
163# endif
164# ifndef LCD_RW_PIN
165# define LCD_RW_PIN 2 /**< pin for RW line */
166# endif
167# ifndef LCD_E_PORT
168# define LCD_E_PORT LCD_PORT /**< port for Enable line */
169# endif
170# ifndef LCD_E_PIN
171# define LCD_E_PIN 1 /**< pin for Enable line */
172# endif
173
174#elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || defined(__AVR_ATmega64__) || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__)
175/*
176 * memory mapped mode is only supported when the device has an external data memory interface
177 */
178# define LCD_IO_DATA 0xC000 /* A15=E=1, A14=RS=1 */
179# define LCD_IO_FUNCTION 0x8000 /* A15=E=1, A14=RS=0 */
180# define LCD_IO_READ 0x0100 /* A8 =R/W=1 (R/W: 1=Read, 0=Write */
181
182#else
183# error "external data memory interface not available for this device, use 4-bit IO port mode"
184
185#endif
186
187/**
188 * @name Definitions of delays
189 * Used to calculate delay timers.
190 * Adapt the F_CPU define in the Makefile to the clock frequency in Hz of your target
191 *
192 * These delay times can be adjusted, if some displays require different delays.\n
193 * These definitions can be defined in a separate include file \b lcd_definitions.h instead modifying this file by
194 * adding \b -D_LCD_DEFINITIONS_FILE to the \b CDEFS section in the Makefile.
195 * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h
196 */
197#ifndef LCD_DELAY_BOOTUP
198# define LCD_DELAY_BOOTUP 16000 /**< delay in micro seconds after power-on */
199#endif
200#ifndef LCD_DELAY_INIT
201# define LCD_DELAY_INIT 5000 /**< delay in micro seconds after initialization command sent */
202#endif
203#ifndef LCD_DELAY_INIT_REP
204# define LCD_DELAY_INIT_REP 64 /**< delay in micro seconds after initialization command repeated */
205#endif
206#ifndef LCD_DELAY_INIT_4BIT
207# define LCD_DELAY_INIT_4BIT 64 /**< delay in micro seconds after setting 4-bit mode */
208#endif
209#ifndef LCD_DELAY_BUSY_FLAG
210# define LCD_DELAY_BUSY_FLAG 4 /**< time in micro seconds the address counter is updated after busy flag is cleared */
211#endif
212#ifndef LCD_DELAY_ENABLE_PULSE
213# define LCD_DELAY_ENABLE_PULSE 1 /**< enable signal pulse width in micro seconds */
214#endif
215
216/**
217 * @name Definitions for LCD command instructions
218 * The constants define the various LCD controller instructions which can be passed to the
219 * function lcd_command(), see HD44780 data sheet for a complete description.
220 */
221
222/* instruction register bit positions, see HD44780U data sheet */
223#define LCD_CLR 0 /* DB0: clear display */
224#define LCD_HOME 1 /* DB1: return to home position */
225#define LCD_ENTRY_MODE 2 /* DB2: set entry mode */
226#define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */
227#define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */
228#define LCD_ON 3 /* DB3: turn lcd/cursor on */
229#define LCD_ON_DISPLAY 2 /* DB2: turn display on */
230#define LCD_ON_CURSOR 1 /* DB1: turn cursor on */
231#define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */
232#define LCD_MOVE 4 /* DB4: move cursor/display */
233#define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */
234#define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */
235#define LCD_FUNCTION 5 /* DB5: function set */
236#define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */
237#define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */
238#define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */
239#define LCD_CGRAM 6 /* DB6: set CG RAM address */
240#define LCD_DDRAM 7 /* DB7: set DD RAM address */
241#define LCD_BUSY 7 /* DB7: LCD is busy */
242
243/* set entry mode: display shift on/off, dec/inc cursor move direction */
244#define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */
245#define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */
246#define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */
247#define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */
248
249/* display on/off, cursor on/off, blinking char at cursor position */
250#define LCD_DISP_OFF 0x08 /* display off */
251#define LCD_DISP_ON 0x0C /* display on, cursor off */
252#define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */
253#define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */
254#define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */
255
256/* move cursor/shift display */
257#define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */
258#define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */
259#define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */
260#define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */
261
262/* function set: set interface data length and number of display lines */
263#define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */
264#define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */
265#define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */
266#define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */
267
268#define LCD_MODE_DEFAULT ((1 << LCD_ENTRY_MODE) | (1 << LCD_ENTRY_INC))
269
270/**
271 * @name Functions
272 */
273
274/**
275 @brief Initialize display and select type of cursor
276 @param dispAttr \b LCD_DISP_OFF display off\n
277 \b LCD_DISP_ON display on, cursor off\n
278 \b LCD_DISP_ON_CURSOR display on, cursor on\n
279 \b LCD_DISP_ON_CURSOR_BLINK display on, cursor on flashing
280 @return none
281*/
282extern void lcd_init(uint8_t dispAttr);
283
284/**
285 @brief Clear display and set cursor to home position
286 @return none
287*/
288extern void lcd_clrscr(void);
289
290/**
291 @brief Set cursor to home position
292 @return none
293*/
294extern void lcd_home(void);
295
296/**
297 @brief Set cursor to specified position
298
299 @param x horizontal position\n (0: left most position)
300 @param y vertical position\n (0: first line)
301 @return none
302*/
303extern void lcd_gotoxy(uint8_t x, uint8_t y);
304
305/**
306 @brief Display character at current cursor position
307 @param c character to be displayed
308 @return none
309*/
310extern void lcd_putc(char c);
311
312/**
313 @brief Display string without auto linefeed
314 @param s string to be displayed
315 @return none
316*/
317extern void lcd_puts(const char *s);
318
319/**
320 @brief Display string from program memory without auto linefeed
321 @param progmem_s string from program memory be be displayed
322 @return none
323 @see lcd_puts_P
324*/
325extern void lcd_puts_p(const char *progmem_s);
326
327/**
328 @brief Send LCD controller instruction command
329 @param cmd instruction to send to LCD controller, see HD44780 data sheet
330 @return none
331*/
332extern void lcd_command(uint8_t cmd);
333
334/**
335 @brief Send data byte to LCD controller
336
337 Similar to lcd_putc(), but without interpreting LF
338 @param data byte to send to LCD controller, see HD44780 data sheet
339 @return none
340*/
341extern void lcd_data(uint8_t data);
342
343/**
344 @brief macros for automatically storing string constant in program memory
345*/
346#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))
347
348/**@}*/
diff --git a/drivers/avr/i2c_master.c b/drivers/avr/i2c_master.c
deleted file mode 100644
index 2773e0077..000000000
--- a/drivers/avr/i2c_master.c
+++ /dev/null
@@ -1,241 +0,0 @@
1/* Copyright (C) 2019 Elia Ritterbusch
2 +
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16/* Library made by: g4lvanix
17 * GitHub repository: https://github.com/g4lvanix/I2C-master-lib
18 */
19
20#include <avr/io.h>
21#include <util/twi.h>
22
23#include "i2c_master.h"
24#include "timer.h"
25#include "wait.h"
26
27#ifndef F_SCL
28# define F_SCL 400000UL // SCL frequency
29#endif
30
31#ifndef I2C_START_RETRY_COUNT
32# define I2C_START_RETRY_COUNT 20
33#endif // I2C_START_RETRY_COUNT
34
35#define TWBR_val (((F_CPU / F_SCL) - 16) / 2)
36
37#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
38
39void i2c_init(void) {
40 TWSR = 0; /* no prescaler */
41 TWBR = (uint8_t)TWBR_val;
42
43#ifdef __AVR_ATmega32A__
44 // set pull-up resistors on I2C bus pins
45 PORTC |= 0b11;
46
47 // enable TWI (two-wire interface)
48 TWCR |= (1 << TWEN);
49
50 // enable TWI interrupt and slave address ACK
51 TWCR |= (1 << TWIE);
52 TWCR |= (1 << TWEA);
53#endif
54}
55
56static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
57 // reset TWI control register
58 TWCR = 0;
59 // transmit START condition
60 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
61
62 uint16_t timeout_timer = timer_read();
63 while (!(TWCR & (1 << TWINT))) {
64 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
65 return I2C_STATUS_TIMEOUT;
66 }
67 }
68
69 // check if the start condition was successfully transmitted
70 if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) {
71 return I2C_STATUS_ERROR;
72 }
73
74 // load slave address into data register
75 TWDR = address;
76 // start transmission of address
77 TWCR = (1 << TWINT) | (1 << TWEN);
78
79 timeout_timer = timer_read();
80 while (!(TWCR & (1 << TWINT))) {
81 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
82 return I2C_STATUS_TIMEOUT;
83 }
84 }
85
86 // check if the device has acknowledged the READ / WRITE mode
87 uint8_t twst = TW_STATUS & 0xF8;
88 if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
89 return I2C_STATUS_ERROR;
90 }
91
92 return I2C_STATUS_SUCCESS;
93}
94
95i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
96 // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
97 uint16_t timeout_timer = timer_read();
98 uint16_t time_slice = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
99 i2c_status_t status;
100 do {
101 status = i2c_start_impl(address, time_slice);
102 } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) < timeout)));
103 return status;
104}
105
106i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
107 // load data into data register
108 TWDR = data;
109 // start transmission of data
110 TWCR = (1 << TWINT) | (1 << TWEN);
111
112 uint16_t timeout_timer = timer_read();
113 while (!(TWCR & (1 << TWINT))) {
114 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
115 return I2C_STATUS_TIMEOUT;
116 }
117 }
118
119 if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) {
120 return I2C_STATUS_ERROR;
121 }
122
123 return I2C_STATUS_SUCCESS;
124}
125
126int16_t i2c_read_ack(uint16_t timeout) {
127 // start TWI module and acknowledge data after reception
128 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
129
130 uint16_t timeout_timer = timer_read();
131 while (!(TWCR & (1 << TWINT))) {
132 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
133 return I2C_STATUS_TIMEOUT;
134 }
135 }
136
137 // return received data from TWDR
138 return TWDR;
139}
140
141int16_t i2c_read_nack(uint16_t timeout) {
142 // start receiving without acknowledging reception
143 TWCR = (1 << TWINT) | (1 << TWEN);
144
145 uint16_t timeout_timer = timer_read();
146 while (!(TWCR & (1 << TWINT))) {
147 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
148 return I2C_STATUS_TIMEOUT;
149 }
150 }
151
152 // return received data from TWDR
153 return TWDR;
154}
155
156i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
157 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
158
159 for (uint16_t i = 0; i < length && status >= 0; i++) {
160 status = i2c_write(data[i], timeout);
161 }
162
163 i2c_stop();
164
165 return status;
166}
167
168i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
169 i2c_status_t status = i2c_start(address | I2C_READ, timeout);
170
171 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
172 status = i2c_read_ack(timeout);
173 if (status >= 0) {
174 data[i] = status;
175 }
176 }
177
178 if (status >= 0) {
179 status = i2c_read_nack(timeout);
180 if (status >= 0) {
181 data[(length - 1)] = status;
182 }
183 }
184
185 i2c_stop();
186
187 return (status < 0) ? status : I2C_STATUS_SUCCESS;
188}
189
190i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
191 i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
192 if (status >= 0) {
193 status = i2c_write(regaddr, timeout);
194
195 for (uint16_t i = 0; i < length && status >= 0; i++) {
196 status = i2c_write(data[i], timeout);
197 }
198 }
199
200 i2c_stop();
201
202 return status;
203}
204
205i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
206 i2c_status_t status = i2c_start(devaddr, timeout);
207 if (status < 0) {
208 goto error;
209 }
210
211 status = i2c_write(regaddr, timeout);
212 if (status < 0) {
213 goto error;
214 }
215
216 status = i2c_start(devaddr | 0x01, timeout);
217
218 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
219 status = i2c_read_ack(timeout);
220 if (status >= 0) {
221 data[i] = status;
222 }
223 }
224
225 if (status >= 0) {
226 status = i2c_read_nack(timeout);
227 if (status >= 0) {
228 data[(length - 1)] = status;
229 }
230 }
231
232error:
233 i2c_stop();
234
235 return (status < 0) ? status : I2C_STATUS_SUCCESS;
236}
237
238void i2c_stop(void) {
239 // transmit STOP condition
240 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
241}
diff --git a/drivers/avr/i2c_master.h b/drivers/avr/i2c_master.h
deleted file mode 100644
index e5af73364..000000000
--- a/drivers/avr/i2c_master.h
+++ /dev/null
@@ -1,43 +0,0 @@
1/* Copyright (C) 2019 Elia Ritterbusch
2 +
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16/* Library made by: g4lvanix
17 * GitHub repository: https://github.com/g4lvanix/I2C-master-lib
18 */
19
20#pragma once
21
22#define I2C_READ 0x01
23#define I2C_WRITE 0x00
24
25typedef int16_t i2c_status_t;
26
27#define I2C_STATUS_SUCCESS (0)
28#define I2C_STATUS_ERROR (-1)
29#define I2C_STATUS_TIMEOUT (-2)
30
31#define I2C_TIMEOUT_IMMEDIATE (0)
32#define I2C_TIMEOUT_INFINITE (0xFFFF)
33
34void i2c_init(void);
35i2c_status_t i2c_start(uint8_t address, uint16_t timeout);
36i2c_status_t i2c_write(uint8_t data, uint16_t timeout);
37int16_t i2c_read_ack(uint16_t timeout);
38int16_t i2c_read_nack(uint16_t timeout);
39i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
40i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
41i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
42i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
43void i2c_stop(void);
diff --git a/drivers/avr/i2c_slave.c b/drivers/avr/i2c_slave.c
deleted file mode 100644
index 2907f164c..000000000
--- a/drivers/avr/i2c_slave.c
+++ /dev/null
@@ -1,111 +0,0 @@
1/* Copyright (C) 2019 Elia Ritterbusch
2 +
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16/* Library made by: g4lvanix
17 * GitHub repository: https://github.com/g4lvanix/I2C-slave-lib
18 */
19
20#include <stddef.h>
21#include <avr/io.h>
22#include <util/twi.h>
23#include <avr/interrupt.h>
24#include <stdbool.h>
25
26#include "i2c_slave.h"
27
28#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
29# include "transactions.h"
30
31static volatile bool is_callback_executor = false;
32#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
33
34volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
35
36static volatile uint8_t buffer_address;
37static volatile bool slave_has_register_set = false;
38
39void i2c_slave_init(uint8_t address) {
40 // load address into TWI address register
41 TWAR = address;
42 // set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
43 TWCR = (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
44}
45
46void i2c_slave_stop(void) {
47 // clear acknowledge and enable bits
48 TWCR &= ~((1 << TWEA) | (1 << TWEN));
49}
50
51ISR(TWI_vect) {
52 uint8_t ack = 1;
53
54 switch (TW_STATUS) {
55 case TW_SR_SLA_ACK:
56 // The device is now a slave receiver
57 slave_has_register_set = false;
58#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
59 is_callback_executor = false;
60#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
61 break;
62
63 case TW_SR_DATA_ACK:
64 // This device is a slave receiver and has received data
65 // First byte is the location then the bytes will be writen in buffer with auto-increment
66 if (!slave_has_register_set) {
67 buffer_address = TWDR;
68
69 if (buffer_address >= I2C_SLAVE_REG_COUNT) { // address out of bounds dont ack
70 ack = 0;
71 buffer_address = 0;
72 }
73 slave_has_register_set = true; // address has been received now fill in buffer
74
75#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
76 // Work out if we're attempting to execute a callback
77 is_callback_executor = buffer_address == split_transaction_table[I2C_EXECUTE_CALLBACK].initiator2target_offset;
78#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
79 } else {
80 i2c_slave_reg[buffer_address] = TWDR;
81 buffer_address++;
82
83#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
84 // If we're intending to execute a transaction callback, do so, as we've just received the transaction ID
85 if (is_callback_executor) {
86 split_transaction_desc_t *trans = &split_transaction_table[split_shmem->transaction_id];
87 if (trans->slave_callback) {
88 trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
89 }
90 }
91#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
92 }
93 break;
94
95 case TW_ST_SLA_ACK:
96 case TW_ST_DATA_ACK:
97 // This device is a slave transmitter and master has requested data
98 TWDR = i2c_slave_reg[buffer_address];
99 buffer_address++;
100 break;
101
102 case TW_BUS_ERROR:
103 // We got an error, reset i2c
104 TWCR = 0;
105 default:
106 break;
107 }
108
109 // Reset i2c state machine to be ready for next interrupt
110 TWCR |= (1 << TWIE) | (1 << TWINT) | (ack << TWEA) | (1 << TWEN);
111}
diff --git a/drivers/avr/i2c_slave.h b/drivers/avr/i2c_slave.h
deleted file mode 100644
index a8647c9da..000000000
--- a/drivers/avr/i2c_slave.h
+++ /dev/null
@@ -1,41 +0,0 @@
1/* Copyright (C) 2019 Elia Ritterbusch
2 +
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16/* Library made by: g4lvanix
17 * GitHub repository: https://github.com/g4lvanix/I2C-slave-lib
18
19 Info: Inititate the library by giving the required address.
20 Read or write to the necessary buffer according to the opperation.
21 */
22
23#pragma once
24
25#ifndef I2C_SLAVE_REG_COUNT
26
27# if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
28# include "transport.h"
29# define I2C_SLAVE_REG_COUNT sizeof(split_shared_memory_t)
30# else // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
31# define I2C_SLAVE_REG_COUNT 30
32# endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
33
34#endif // I2C_SLAVE_REG_COUNT
35
36_Static_assert(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte");
37
38extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
39
40void i2c_slave_init(uint8_t address);
41void i2c_slave_stop(void);
diff --git a/drivers/avr/serial.c b/drivers/avr/serial.c
deleted file mode 100644
index 9a7345a53..000000000
--- a/drivers/avr/serial.c
+++ /dev/null
@@ -1,529 +0,0 @@
1/*
2 * WARNING: be careful changing this code, it is very timing dependent
3 *
4 * 2018-10-28 checked
5 * avr-gcc 4.9.2
6 * avr-gcc 5.4.0
7 * avr-gcc 7.3.0
8 */
9
10#ifndef F_CPU
11# define F_CPU 16000000
12#endif
13
14#include <avr/io.h>
15#include <avr/interrupt.h>
16#include <util/delay.h>
17#include <stddef.h>
18#include <stdbool.h>
19#include "serial.h"
20
21#ifdef SOFT_SERIAL_PIN
22
23# 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__))
24# error serial.c is not supported for the currently selected MCU
25# endif
26// if using ATmega32U4/2, AT90USBxxx I2C, can not use PD0 and PD1 in soft serial.
27# if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
28# if defined(USE_AVR_I2C) && (SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1)
29# error Using I2C, so can not use PD0, PD1
30# endif
31# endif
32// PD0..PD3, common config
33# if SOFT_SERIAL_PIN == D0
34# define EIMSK_BIT _BV(INT0)
35# define EICRx_BIT (~(_BV(ISC00) | _BV(ISC01)))
36# define SERIAL_PIN_INTERRUPT INT0_vect
37# define EICRx EICRA
38# elif SOFT_SERIAL_PIN == D1
39# define EIMSK_BIT _BV(INT1)
40# define EICRx_BIT (~(_BV(ISC10) | _BV(ISC11)))
41# define SERIAL_PIN_INTERRUPT INT1_vect
42# define EICRx EICRA
43# elif SOFT_SERIAL_PIN == D2
44# define EIMSK_BIT _BV(INT2)
45# define EICRx_BIT (~(_BV(ISC20) | _BV(ISC21)))
46# define SERIAL_PIN_INTERRUPT INT2_vect
47# define EICRx EICRA
48# elif SOFT_SERIAL_PIN == D3
49# define EIMSK_BIT _BV(INT3)
50# define EICRx_BIT (~(_BV(ISC30) | _BV(ISC31)))
51# define SERIAL_PIN_INTERRUPT INT3_vect
52# define EICRx EICRA
53# endif
54
55// ATmegaxxU2/AT90USB162 specific config
56# if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB162__)
57// PD4(INT5), PD6(INT6), PD7(INT7), PC7(INT4)
58# if SOFT_SERIAL_PIN == D4
59# define EIMSK_BIT _BV(INT5)
60# define EICRx_BIT (~(_BV(ISC50) | _BV(ISC51)))
61# define SERIAL_PIN_INTERRUPT INT5_vect
62# define EICRx EICRB
63# elif SOFT_SERIAL_PIN == D6
64# define EIMSK_BIT _BV(INT6)
65# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
66# define SERIAL_PIN_INTERRUPT INT6_vect
67# define EICRx EICRB
68# elif SOFT_SERIAL_PIN == D7
69# define EIMSK_BIT _BV(INT7)
70# define EICRx_BIT (~(_BV(ISC70) | _BV(ISC71)))
71# define SERIAL_PIN_INTERRUPT INT7_vect
72# define EICRx EICRB
73# elif SOFT_SERIAL_PIN == C7
74# define EIMSK_BIT _BV(INT4)
75# define EICRx_BIT (~(_BV(ISC40) | _BV(ISC41)))
76# define SERIAL_PIN_INTERRUPT INT4_vect
77# define EICRx EICRB
78# endif
79# endif
80
81// ATmegaxxU4 specific config
82# if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
83// PE6(INT6)
84# if SOFT_SERIAL_PIN == E6
85# define EIMSK_BIT _BV(INT6)
86# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
87# define SERIAL_PIN_INTERRUPT INT6_vect
88# define EICRx EICRB
89# endif
90# endif
91
92// AT90USBxxx specific config
93# if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
94// PE4..PE7(INT4..INT7)
95# if SOFT_SERIAL_PIN == E4
96# define EIMSK_BIT _BV(INT4)
97# define EICRx_BIT (~(_BV(ISC40) | _BV(ISC41)))
98# define SERIAL_PIN_INTERRUPT INT4_vect
99# define EICRx EICRB
100# elif SOFT_SERIAL_PIN == E5
101# define EIMSK_BIT _BV(INT5)
102# define EICRx_BIT (~(_BV(ISC50) | _BV(ISC51)))
103# define SERIAL_PIN_INTERRUPT INT5_vect
104# define EICRx EICRB
105# elif SOFT_SERIAL_PIN == E6
106# define EIMSK_BIT _BV(INT6)
107# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
108# define SERIAL_PIN_INTERRUPT INT6_vect
109# define EICRx EICRB
110# elif SOFT_SERIAL_PIN == E7
111# define EIMSK_BIT _BV(INT7)
112# define EICRx_BIT (~(_BV(ISC70) | _BV(ISC71)))
113# define SERIAL_PIN_INTERRUPT INT7_vect
114# define EICRx EICRB
115# endif
116# endif
117
118# ifndef SERIAL_PIN_INTERRUPT
119# error invalid SOFT_SERIAL_PIN value
120# endif
121
122# define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
123# define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
124# define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
125# define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
126# define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
127
128# define ALWAYS_INLINE __attribute__((always_inline))
129# define NO_INLINE __attribute__((noinline))
130# define _delay_sub_us(x) __builtin_avr_delay_cycles(x)
131
132// parity check
133# define ODD_PARITY 1
134# define EVEN_PARITY 0
135# define PARITY EVEN_PARITY
136
137# ifdef SERIAL_DELAY
138// custom setup in config.h
139// #define TID_SEND_ADJUST 2
140// #define SERIAL_DELAY 6 // micro sec
141// #define READ_WRITE_START_ADJUST 30 // cycles
142// #define READ_WRITE_WIDTH_ADJUST 8 // cycles
143# else
144// ============ Standard setups ============
145
146# ifndef SELECT_SOFT_SERIAL_SPEED
147# define SELECT_SOFT_SERIAL_SPEED 1
148// 0: about 189kbps (Experimental only)
149// 1: about 137kbps (default)
150// 2: about 75kbps
151// 3: about 39kbps
152// 4: about 26kbps
153// 5: about 20kbps
154# endif
155
156# if __GNUC__ < 6
157# define TID_SEND_ADJUST 14
158# else
159# define TID_SEND_ADJUST 2
160# endif
161
162# if SELECT_SOFT_SERIAL_SPEED == 0
163// Very High speed
164# define SERIAL_DELAY 4 // micro sec
165# if __GNUC__ < 6
166# define READ_WRITE_START_ADJUST 33 // cycles
167# define READ_WRITE_WIDTH_ADJUST 3 // cycles
168# else
169# define READ_WRITE_START_ADJUST 34 // cycles
170# define READ_WRITE_WIDTH_ADJUST 7 // cycles
171# endif
172# elif SELECT_SOFT_SERIAL_SPEED == 1
173// High speed
174# define SERIAL_DELAY 6 // micro sec
175# if __GNUC__ < 6
176# define READ_WRITE_START_ADJUST 30 // cycles
177# define READ_WRITE_WIDTH_ADJUST 3 // cycles
178# else
179# define READ_WRITE_START_ADJUST 33 // cycles
180# define READ_WRITE_WIDTH_ADJUST 7 // cycles
181# endif
182# elif SELECT_SOFT_SERIAL_SPEED == 2
183// Middle speed
184# define SERIAL_DELAY 12 // micro sec
185# define READ_WRITE_START_ADJUST 30 // cycles
186# if __GNUC__ < 6
187# define READ_WRITE_WIDTH_ADJUST 3 // cycles
188# else
189# define READ_WRITE_WIDTH_ADJUST 7 // cycles
190# endif
191# elif SELECT_SOFT_SERIAL_SPEED == 3
192// Low speed
193# define SERIAL_DELAY 24 // micro sec
194# define READ_WRITE_START_ADJUST 30 // cycles
195# if __GNUC__ < 6
196# define READ_WRITE_WIDTH_ADJUST 3 // cycles
197# else
198# define READ_WRITE_WIDTH_ADJUST 7 // cycles
199# endif
200# elif SELECT_SOFT_SERIAL_SPEED == 4
201// Very Low speed
202# define SERIAL_DELAY 36 // micro sec
203# define READ_WRITE_START_ADJUST 30 // cycles
204# if __GNUC__ < 6
205# define READ_WRITE_WIDTH_ADJUST 3 // cycles
206# else
207# define READ_WRITE_WIDTH_ADJUST 7 // cycles
208# endif
209# elif SELECT_SOFT_SERIAL_SPEED == 5
210// Ultra Low speed
211# define SERIAL_DELAY 48 // micro sec
212# define READ_WRITE_START_ADJUST 30 // cycles
213# if __GNUC__ < 6
214# define READ_WRITE_WIDTH_ADJUST 3 // cycles
215# else
216# define READ_WRITE_WIDTH_ADJUST 7 // cycles
217# endif
218# else
219# error invalid SELECT_SOFT_SERIAL_SPEED value
220# endif /* SELECT_SOFT_SERIAL_SPEED */
221# endif /* SERIAL_DELAY */
222
223# define SERIAL_DELAY_HALF1 (SERIAL_DELAY / 2)
224# define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY / 2)
225
226# define SLAVE_INT_WIDTH_US 1
227# define SLAVE_INT_ACK_WIDTH_UNIT 2
228# define SLAVE_INT_ACK_WIDTH 4
229
230inline static void serial_delay(void) ALWAYS_INLINE;
231inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); }
232
233inline static void serial_delay_half1(void) ALWAYS_INLINE;
234inline static void serial_delay_half1(void) { _delay_us(SERIAL_DELAY_HALF1); }
235
236inline static void serial_delay_half2(void) ALWAYS_INLINE;
237inline static void serial_delay_half2(void) { _delay_us(SERIAL_DELAY_HALF2); }
238
239inline static void serial_output(void) ALWAYS_INLINE;
240inline static void serial_output(void) { setPinOutput(SOFT_SERIAL_PIN); }
241
242// make the serial pin an input with pull-up resistor
243inline static void serial_input_with_pullup(void) ALWAYS_INLINE;
244inline static void serial_input_with_pullup(void) { setPinInputHigh(SOFT_SERIAL_PIN); }
245
246inline static uint8_t serial_read_pin(void) ALWAYS_INLINE;
247inline static uint8_t serial_read_pin(void) { return !!readPin(SOFT_SERIAL_PIN); }
248
249inline static void serial_low(void) ALWAYS_INLINE;
250inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
251
252inline static void serial_high(void) ALWAYS_INLINE;
253inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
254
255void soft_serial_initiator_init(void) {
256 serial_output();
257 serial_high();
258}
259
260void soft_serial_target_init(void) {
261 serial_input_with_pullup();
262
263 // Enable INT0-INT7
264 EIMSK |= EIMSK_BIT;
265 EICRx &= EICRx_BIT;
266}
267
268// Used by the sender to synchronize timing with the reciver.
269static void sync_recv(void) NO_INLINE;
270static void sync_recv(void) {
271 for (uint8_t i = 0; i < SERIAL_DELAY * 5 && serial_read_pin(); i++) {
272 }
273 // This shouldn't hang if the target disconnects because the
274 // serial line will float to high if the target does disconnect.
275 while (!serial_read_pin())
276 ;
277}
278
279// Used by the reciver to send a synchronization signal to the sender.
280static void sync_send(void) NO_INLINE;
281static void sync_send(void) {
282 serial_low();
283 serial_delay();
284 serial_high();
285}
286
287// Reads a byte from the serial line
288static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) NO_INLINE;
289static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) {
290 uint8_t byte, i, p, pb;
291
292 _delay_sub_us(READ_WRITE_START_ADJUST);
293 for (i = 0, byte = 0, p = PARITY; i < bit; i++) {
294 serial_delay_half1(); // read the middle of pulses
295 if (serial_read_pin()) {
296 byte = (byte << 1) | 1;
297 p ^= 1;
298 } else {
299 byte = (byte << 1) | 0;
300 p ^= 0;
301 }
302 _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
303 serial_delay_half2();
304 }
305 /* recive parity bit */
306 serial_delay_half1(); // read the middle of pulses
307 pb = serial_read_pin();
308 _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
309 serial_delay_half2();
310
311 *pterrcount += (p != pb) ? 1 : 0;
312
313 return byte;
314}
315
316// Sends a byte with MSB ordering
317void serial_write_chunk(uint8_t data, uint8_t bit) NO_INLINE;
318void serial_write_chunk(uint8_t data, uint8_t bit) {
319 uint8_t b, p;
320 for (p = PARITY, b = 1 << (bit - 1); b; b >>= 1) {
321 if (data & b) {
322 serial_high();
323 p ^= 1;
324 } else {
325 serial_low();
326 p ^= 0;
327 }
328 serial_delay();
329 }
330 /* send parity bit */
331 if (p & 1) {
332 serial_high();
333 } else {
334 serial_low();
335 }
336 serial_delay();
337
338 serial_low(); // sync_send() / senc_recv() need raise edge
339}
340
341static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE;
342static void serial_send_packet(uint8_t *buffer, uint8_t size) {
343 for (uint8_t i = 0; i < size; ++i) {
344 uint8_t data;
345 data = buffer[i];
346 sync_send();
347 serial_write_chunk(data, 8);
348 }
349}
350
351static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) NO_INLINE;
352static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) {
353 uint8_t pecount = 0;
354 for (uint8_t i = 0; i < size; ++i) {
355 uint8_t data;
356 sync_recv();
357 data = serial_read_chunk(&pecount, 8);
358 buffer[i] = data;
359 }
360 return pecount == 0;
361}
362
363inline static void change_sender2reciver(void) {
364 sync_send(); // 0
365 serial_delay_half1(); // 1
366 serial_low(); // 2
367 serial_input_with_pullup(); // 2
368 serial_delay_half1(); // 3
369}
370
371inline static void change_reciver2sender(void) {
372 sync_recv(); // 0
373 serial_delay(); // 1
374 serial_low(); // 3
375 serial_output(); // 3
376 serial_delay_half1(); // 4
377}
378
379static inline uint8_t nibble_bits_count(uint8_t bits) {
380 bits = (bits & 0x5) + (bits >> 1 & 0x5);
381 bits = (bits & 0x3) + (bits >> 2 & 0x3);
382 return bits;
383}
384
385// interrupt handle to be used by the target device
386ISR(SERIAL_PIN_INTERRUPT) {
387 // recive transaction table index
388 uint8_t tid, bits;
389 uint8_t pecount = 0;
390 sync_recv();
391 bits = serial_read_chunk(&pecount, 8);
392 tid = bits >> 3;
393 bits = (bits & 7) != (nibble_bits_count(tid) & 7);
394 if (bits || pecount > 0 || tid > NUM_TOTAL_TRANSACTIONS) {
395 return;
396 }
397 serial_delay_half1();
398
399 serial_high(); // response step1 low->high
400 serial_output();
401 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH);
402 split_transaction_desc_t *trans = &split_transaction_table[tid];
403 serial_low(); // response step2 ack high->low
404
405 // If the transaction has a callback, we can execute it now
406 if (trans->slave_callback) {
407 trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
408 }
409
410 // target send phase
411 if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size);
412 // target switch to input
413 change_sender2reciver();
414
415 // target recive phase
416 if (trans->initiator2target_buffer_size > 0) {
417 if (serial_recive_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) {
418 *trans->status = TRANSACTION_ACCEPTED;
419 } else {
420 *trans->status = TRANSACTION_DATA_ERROR;
421 }
422 } else {
423 *trans->status = TRANSACTION_ACCEPTED;
424 }
425
426 sync_recv(); // weit initiator output to high
427}
428
429/////////
430// start transaction by initiator
431//
432// int soft_serial_transaction(int sstd_index)
433//
434// Returns:
435// TRANSACTION_END
436// TRANSACTION_NO_RESPONSE
437// TRANSACTION_DATA_ERROR
438// this code is very time dependent, so we need to disable interrupts
439int soft_serial_transaction(int sstd_index) {
440 if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
441 split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
442
443 if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
444
445 cli();
446
447 // signal to the target that we want to start a transaction
448 serial_output();
449 serial_low();
450 _delay_us(SLAVE_INT_WIDTH_US);
451
452 // send transaction table index
453 int tid = (sstd_index << 3) | (7 & nibble_bits_count(sstd_index));
454 sync_send();
455 _delay_sub_us(TID_SEND_ADJUST);
456 serial_write_chunk(tid, 8);
457 serial_delay_half1();
458
459 // wait for the target response (step1 low->high)
460 serial_input_with_pullup();
461 while (!serial_read_pin()) {
462 _delay_sub_us(2);
463 }
464
465 // check if the target is present (step2 high->low)
466 for (int i = 0; serial_read_pin(); i++) {
467 if (i > SLAVE_INT_ACK_WIDTH + 1) {
468 // slave failed to pull the line low, assume not present
469 serial_output();
470 serial_high();
471 *trans->status = TRANSACTION_NO_RESPONSE;
472 sei();
473 return TRANSACTION_NO_RESPONSE;
474 }
475 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT);
476 }
477
478 // initiator recive phase
479 // if the target is present syncronize with it
480 if (trans->target2initiator_buffer_size > 0) {
481 if (!serial_recive_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) {
482 serial_output();
483 serial_high();
484 *trans->status = TRANSACTION_DATA_ERROR;
485 sei();
486 return TRANSACTION_DATA_ERROR;
487 }
488 }
489
490 // initiator switch to output
491 change_reciver2sender();
492
493 // initiator send phase
494 if (trans->initiator2target_buffer_size > 0) {
495 serial_send_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
496 }
497
498 // always, release the line when not in use
499 sync_send();
500
501 *trans->status = TRANSACTION_END;
502 sei();
503 return TRANSACTION_END;
504}
505
506int soft_serial_get_and_clean_status(int sstd_index) {
507 split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
508 cli();
509 int retval = *trans->status;
510 *trans->status = 0;
511 ;
512 sei();
513 return retval;
514}
515#endif
516
517// Helix serial.c history
518// 2018-1-29 fork from let's split and add PD2, modify sync_recv() (#2308, bceffdefc)
519// 2018-6-28 bug fix master to slave comm and speed up (#3255, 1038bbef4)
520// (adjusted with avr-gcc 4.9.2)
521// 2018-7-13 remove USE_SERIAL_PD2 macro (#3374, f30d6dd78)
522// (adjusted with avr-gcc 4.9.2)
523// 2018-8-11 add support multi-type transaction (#3608, feb5e4aae)
524// (adjusted with avr-gcc 4.9.2)
525// 2018-10-21 fix serial and RGB animation conflict (#4191, 4665e4fff)
526// (adjusted with avr-gcc 7.3.0)
527// 2018-10-28 re-adjust compiler depend value of delay (#4269, 8517f8a66)
528// (adjusted with avr-gcc 5.4.0, 7.3.0)
529// 2018-12-17 copy to TOP/quantum/split_common/ and remove backward compatibility code (#4669)
diff --git a/drivers/avr/spi_master.c b/drivers/avr/spi_master.c
deleted file mode 100644
index 4e8fd3bcd..000000000
--- a/drivers/avr/spi_master.c
+++ /dev/null
@@ -1,180 +0,0 @@
1/* Copyright 2020
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#include "spi_master.h"
18
19#include "timer.h"
20
21#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__)
22# define SPI_SCK_PIN B1
23# define SPI_MOSI_PIN B2
24# define SPI_MISO_PIN B3
25#elif defined(__AVR_ATmega32A__)
26# define SPI_SCK_PIN B7
27# define SPI_MOSI_PIN B5
28# define SPI_MISO_PIN B6
29#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
30# define SPI_SCK_PIN B5
31# define SPI_MOSI_PIN B3
32# define SPI_MISO_PIN B4
33#endif
34
35#ifndef SPI_TIMEOUT
36# define SPI_TIMEOUT 100
37#endif
38
39static pin_t currentSlavePin = NO_PIN;
40static uint8_t currentSlaveConfig = 0;
41static bool currentSlave2X = false;
42
43void spi_init(void) {
44 writePinHigh(SPI_SS_PIN);
45 setPinOutput(SPI_SCK_PIN);
46 setPinOutput(SPI_MOSI_PIN);
47 setPinInput(SPI_MISO_PIN);
48
49 SPCR = (_BV(SPE) | _BV(MSTR));
50}
51
52bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
53 if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
54 return false;
55 }
56
57 currentSlaveConfig = 0;
58
59 if (lsbFirst) {
60 currentSlaveConfig |= _BV(DORD);
61 }
62
63 switch (mode) {
64 case 1:
65 currentSlaveConfig |= _BV(CPHA);
66 break;
67 case 2:
68 currentSlaveConfig |= _BV(CPOL);
69 break;
70 case 3:
71 currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA));
72 break;
73 }
74
75 uint16_t roundedDivisor = 1;
76 while (roundedDivisor < divisor) {
77 roundedDivisor <<= 1;
78 }
79
80 switch (roundedDivisor) {
81 case 16:
82 currentSlaveConfig |= _BV(SPR0);
83 break;
84 case 64:
85 currentSlaveConfig |= _BV(SPR1);
86 break;
87 case 128:
88 currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0));
89 break;
90 case 2:
91 currentSlave2X = true;
92 break;
93 case 8:
94 currentSlave2X = true;
95 currentSlaveConfig |= _BV(SPR0);
96 break;
97 case 32:
98 currentSlave2X = true;
99 currentSlaveConfig |= _BV(SPR1);
100 break;
101 }
102
103 SPCR |= currentSlaveConfig;
104 if (currentSlave2X) {
105 SPSR |= _BV(SPI2X);
106 }
107 currentSlavePin = slavePin;
108 setPinOutput(currentSlavePin);
109 writePinLow(currentSlavePin);
110
111 return true;
112}
113
114spi_status_t spi_write(uint8_t data) {
115 SPDR = data;
116
117 uint16_t timeout_timer = timer_read();
118 while (!(SPSR & _BV(SPIF))) {
119 if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
120 return SPI_STATUS_TIMEOUT;
121 }
122 }
123
124 return SPDR;
125}
126
127spi_status_t spi_read() {
128 SPDR = 0x00; // Dummy
129
130 uint16_t timeout_timer = timer_read();
131 while (!(SPSR & _BV(SPIF))) {
132 if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
133 return SPI_STATUS_TIMEOUT;
134 }
135 }
136
137 return SPDR;
138}
139
140spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
141 spi_status_t status;
142
143 for (uint16_t i = 0; i < length; i++) {
144 status = spi_write(data[i]);
145
146 if (status < 0) {
147 return status;
148 }
149 }
150
151 return SPI_STATUS_SUCCESS;
152}
153
154spi_status_t spi_receive(uint8_t *data, uint16_t length) {
155 spi_status_t status;
156
157 for (uint16_t i = 0; i < length; i++) {
158 status = spi_read();
159
160 if (status >= 0) {
161 data[i] = status;
162 } else {
163 return status;
164 }
165 }
166
167 return SPI_STATUS_SUCCESS;
168}
169
170void spi_stop(void) {
171 if (currentSlavePin != NO_PIN) {
172 setPinOutput(currentSlavePin);
173 writePinHigh(currentSlavePin);
174 currentSlavePin = NO_PIN;
175 SPSR &= ~(_BV(SPI2X));
176 SPCR &= ~(currentSlaveConfig);
177 currentSlaveConfig = 0;
178 currentSlave2X = false;
179 }
180}
diff --git a/drivers/avr/spi_master.h b/drivers/avr/spi_master.h
deleted file mode 100644
index 8a30f47ae..000000000
--- a/drivers/avr/spi_master.h
+++ /dev/null
@@ -1,59 +0,0 @@
1/* Copyright 2020
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <stdbool.h>
20
21#include "gpio.h"
22
23typedef int16_t spi_status_t;
24
25// Hardware SS pin is defined in the header so that user code can refer to it
26#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__)
27# define SPI_SS_PIN B0
28#elif defined(__AVR_ATmega32A__)
29# define SPI_SS_PIN B4
30#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
31# define SPI_SS_PIN B2
32#endif
33
34#define SPI_STATUS_SUCCESS (0)
35#define SPI_STATUS_ERROR (-1)
36#define SPI_STATUS_TIMEOUT (-2)
37
38#define SPI_TIMEOUT_IMMEDIATE (0)
39#define SPI_TIMEOUT_INFINITE (0xFFFF)
40
41#ifdef __cplusplus
42extern "C" {
43#endif
44void spi_init(void);
45
46bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
47
48spi_status_t spi_write(uint8_t data);
49
50spi_status_t spi_read(void);
51
52spi_status_t spi_transmit(const uint8_t *data, uint16_t length);
53
54spi_status_t spi_receive(uint8_t *data, uint16_t length);
55
56void spi_stop(void);
57#ifdef __cplusplus
58}
59#endif
diff --git a/drivers/avr/ssd1306.c b/drivers/avr/ssd1306.c
deleted file mode 100644
index 1a09a2bcb..000000000
--- a/drivers/avr/ssd1306.c
+++ /dev/null
@@ -1,319 +0,0 @@
1#ifdef SSD1306OLED
2
3# include "ssd1306.h"
4# include "i2c.h"
5# include <string.h>
6# include "print.h"
7# include "glcdfont.c"
8# ifdef PROTOCOL_LUFA
9# include "lufa.h"
10# endif
11# include "sendchar.h"
12# include "timer.h"
13
14struct CharacterMatrix display;
15
16// Set this to 1 to help diagnose early startup problems
17// when testing power-on with ble. Turn it off otherwise,
18// as the latency of printing most of the debug info messes
19// with the matrix scan, causing keys to drop.
20# define DEBUG_TO_SCREEN 0
21
22// static uint16_t last_battery_update;
23// static uint32_t vbat;
24//#define BatteryUpdateInterval 10000 /* milliseconds */
25# define ScreenOffInterval 300000 /* milliseconds */
26# if DEBUG_TO_SCREEN
27static uint8_t displaying;
28# endif
29static uint16_t last_flush;
30
31// Write command sequence.
32// Returns true on success.
33static inline bool _send_cmd1(uint8_t cmd) {
34 bool res = false;
35
36 if (i2c_start_write(SSD1306_ADDRESS)) {
37 xprintf("failed to start write to %d\n", SSD1306_ADDRESS);
38 goto done;
39 }
40
41 if (i2c_master_write(0x0 /* command byte follows */)) {
42 print("failed to write control byte\n");
43
44 goto done;
45 }
46
47 if (i2c_master_write(cmd)) {
48 xprintf("failed to write command %d\n", cmd);
49 goto done;
50 }
51 res = true;
52done:
53 i2c_master_stop();
54 return res;
55}
56
57// Write 2-byte command sequence.
58// Returns true on success
59static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) {
60 if (!_send_cmd1(cmd)) {
61 return false;
62 }
63 return _send_cmd1(opr);
64}
65
66// Write 3-byte command sequence.
67// Returns true on success
68static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) {
69 if (!_send_cmd1(cmd)) {
70 return false;
71 }
72 if (!_send_cmd1(opr1)) {
73 return false;
74 }
75 return _send_cmd1(opr2);
76}
77
78# define send_cmd1(c) \
79 if (!_send_cmd1(c)) { \
80 goto done; \
81 }
82# define send_cmd2(c, o) \
83 if (!_send_cmd2(c, o)) { \
84 goto done; \
85 }
86# define send_cmd3(c, o1, o2) \
87 if (!_send_cmd3(c, o1, o2)) { \
88 goto done; \
89 }
90
91static void clear_display(void) {
92 matrix_clear(&display);
93
94 // Clear all of the display bits (there can be random noise
95 // in the RAM on startup)
96 send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1);
97 send_cmd3(ColumnAddr, 0, DisplayWidth - 1);
98
99 if (i2c_start_write(SSD1306_ADDRESS)) {
100 goto done;
101 }
102 if (i2c_master_write(0x40)) {
103 // Data mode
104 goto done;
105 }
106 for (uint8_t row = 0; row < MatrixRows; ++row) {
107 for (uint8_t col = 0; col < DisplayWidth; ++col) {
108 i2c_master_write(0);
109 }
110 }
111
112 display.dirty = false;
113
114done:
115 i2c_master_stop();
116}
117
118# if DEBUG_TO_SCREEN
119# undef sendchar
120static int8_t capture_sendchar(uint8_t c) {
121 sendchar(c);
122 iota_gfx_write_char(c);
123
124 if (!displaying) {
125 iota_gfx_flush();
126 }
127 return 0;
128}
129# endif
130
131bool iota_gfx_init(void) {
132 bool success = false;
133
134 send_cmd1(DisplayOff);
135 send_cmd2(SetDisplayClockDiv, 0x80);
136 send_cmd2(SetMultiPlex, DisplayHeight - 1);
137
138 send_cmd2(SetDisplayOffset, 0);
139
140 send_cmd1(SetStartLine | 0x0);
141 send_cmd2(SetChargePump, 0x14 /* Enable */);
142 send_cmd2(SetMemoryMode, 0 /* horizontal addressing */);
143
144# ifdef OLED_ROTATE180
145 // the following Flip the display orientation 180 degrees
146 send_cmd1(SegRemap);
147 send_cmd1(ComScanInc);
148# endif
149# ifndef OLED_ROTATE180
150 // Flips the display orientation 0 degrees
151 send_cmd1(SegRemap | 0x1);
152 send_cmd1(ComScanDec);
153# endif
154
155 send_cmd2(SetComPins, 0x2);
156 send_cmd2(SetContrast, 0x8f);
157 send_cmd2(SetPreCharge, 0xf1);
158 send_cmd2(SetVComDetect, 0x40);
159 send_cmd1(DisplayAllOnResume);
160 send_cmd1(NormalDisplay);
161 send_cmd1(DeActivateScroll);
162 send_cmd1(DisplayOn);
163
164 send_cmd2(SetContrast, 0); // Dim
165
166 clear_display();
167
168 success = true;
169
170 iota_gfx_flush();
171
172# if DEBUG_TO_SCREEN
173 print_set_sendchar(capture_sendchar);
174# endif
175
176done:
177 return success;
178}
179
180bool iota_gfx_off(void) {
181 bool success = false;
182
183 send_cmd1(DisplayOff);
184 success = true;
185
186done:
187 return success;
188}
189
190bool iota_gfx_on(void) {
191 bool success = false;
192
193 send_cmd1(DisplayOn);
194 success = true;
195
196done:
197 return success;
198}
199
200void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) {
201 *matrix->cursor = c;
202 ++matrix->cursor;
203
204 if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) {
205 // We went off the end; scroll the display upwards by one line
206 memmove(&matrix->display[0], &matrix->display[1], MatrixCols * (MatrixRows - 1));
207 matrix->cursor = &matrix->display[MatrixRows - 1][0];
208 memset(matrix->cursor, ' ', MatrixCols);
209 }
210}
211
212void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) {
213 matrix->dirty = true;
214
215 if (c == '\n') {
216 // Clear to end of line from the cursor and then move to the
217 // start of the next line
218 uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols;
219
220 while (cursor_col++ < MatrixCols) {
221 matrix_write_char_inner(matrix, ' ');
222 }
223 return;
224 }
225
226 matrix_write_char_inner(matrix, c);
227}
228
229void iota_gfx_write_char(uint8_t c) { matrix_write_char(&display, c); }
230
231void matrix_write(struct CharacterMatrix *matrix, const char *data) {
232 const char *end = data + strlen(data);
233 while (data < end) {
234 matrix_write_char(matrix, *data);
235 ++data;
236 }
237}
238
239void iota_gfx_write(const char *data) { matrix_write(&display, data); }
240
241void matrix_write_P(struct CharacterMatrix *matrix, const char *data) {
242 while (true) {
243 uint8_t c = pgm_read_byte(data);
244 if (c == 0) {
245 return;
246 }
247 matrix_write_char(matrix, c);
248 ++data;
249 }
250}
251
252void iota_gfx_write_P(const char *data) { matrix_write_P(&display, data); }
253
254void matrix_clear(struct CharacterMatrix *matrix) {
255 memset(matrix->display, ' ', sizeof(matrix->display));
256 matrix->cursor = &matrix->display[0][0];
257 matrix->dirty = true;
258}
259
260void iota_gfx_clear_screen(void) { matrix_clear(&display); }
261
262void matrix_render(struct CharacterMatrix *matrix) {
263 last_flush = timer_read();
264 iota_gfx_on();
265# if DEBUG_TO_SCREEN
266 ++displaying;
267# endif
268
269 // Move to the home position
270 send_cmd3(PageAddr, 0, MatrixRows - 1);
271 send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1);
272
273 if (i2c_start_write(SSD1306_ADDRESS)) {
274 goto done;
275 }
276 if (i2c_master_write(0x40)) {
277 // Data mode
278 goto done;
279 }
280
281 for (uint8_t row = 0; row < MatrixRows; ++row) {
282 for (uint8_t col = 0; col < MatrixCols; ++col) {
283 const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1));
284
285 for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) {
286 uint8_t colBits = pgm_read_byte(glyph + glyphCol);
287 i2c_master_write(colBits);
288 }
289
290 // 1 column of space between chars (it's not included in the glyph)
291 i2c_master_write(0);
292 }
293 }
294
295 matrix->dirty = false;
296
297done:
298 i2c_master_stop();
299# if DEBUG_TO_SCREEN
300 --displaying;
301# endif
302}
303
304void iota_gfx_flush(void) { matrix_render(&display); }
305
306__attribute__((weak)) void iota_gfx_task_user(void) {}
307
308void iota_gfx_task(void) {
309 iota_gfx_task_user();
310
311 if (display.dirty) {
312 iota_gfx_flush();
313 }
314
315 if (timer_elapsed(last_flush) > ScreenOffInterval) {
316 iota_gfx_off();
317 }
318}
319#endif
diff --git a/drivers/avr/ssd1306.h b/drivers/avr/ssd1306.h
deleted file mode 100644
index 6eecdcfaa..000000000
--- a/drivers/avr/ssd1306.h
+++ /dev/null
@@ -1,87 +0,0 @@
1#pragma once
2
3#include <stdbool.h>
4#include <stdio.h>
5#include "config.h"
6
7enum ssd1306_cmds {
8 DisplayOff = 0xAE,
9 DisplayOn = 0xAF,
10
11 SetContrast = 0x81,
12 DisplayAllOnResume = 0xA4,
13
14 DisplayAllOn = 0xA5,
15 NormalDisplay = 0xA6,
16 InvertDisplay = 0xA7,
17 SetDisplayOffset = 0xD3,
18 SetComPins = 0xda,
19 SetVComDetect = 0xdb,
20 SetDisplayClockDiv = 0xD5,
21 SetPreCharge = 0xd9,
22 SetMultiPlex = 0xa8,
23 SetLowColumn = 0x00,
24 SetHighColumn = 0x10,
25 SetStartLine = 0x40,
26
27 SetMemoryMode = 0x20,
28 ColumnAddr = 0x21,
29 PageAddr = 0x22,
30
31 ComScanInc = 0xc0,
32 ComScanDec = 0xc8,
33 SegRemap = 0xa0,
34 SetChargePump = 0x8d,
35 ExternalVcc = 0x01,
36 SwitchCapVcc = 0x02,
37
38 ActivateScroll = 0x2f,
39 DeActivateScroll = 0x2e,
40 SetVerticalScrollArea = 0xa3,
41 RightHorizontalScroll = 0x26,
42 LeftHorizontalScroll = 0x27,
43 VerticalAndRightHorizontalScroll = 0x29,
44 VerticalAndLeftHorizontalScroll = 0x2a,
45};
46
47// Controls the SSD1306 128x32 OLED display via i2c
48
49#ifndef SSD1306_ADDRESS
50# define SSD1306_ADDRESS 0x3C
51#endif
52
53#define DisplayHeight 32
54#define DisplayWidth 128
55
56#define FontHeight 8
57#define FontWidth 6
58
59#define MatrixRows (DisplayHeight / FontHeight)
60#define MatrixCols (DisplayWidth / FontWidth)
61
62struct CharacterMatrix {
63 uint8_t display[MatrixRows][MatrixCols];
64 uint8_t *cursor;
65 bool dirty;
66};
67
68extern struct CharacterMatrix display;
69
70bool iota_gfx_init(void);
71void iota_gfx_task(void);
72bool iota_gfx_off(void);
73bool iota_gfx_on(void);
74void iota_gfx_flush(void);
75void iota_gfx_write_char(uint8_t c);
76void iota_gfx_write(const char *data);
77void iota_gfx_write_P(const char *data);
78void iota_gfx_clear_screen(void);
79
80void iota_gfx_task_user(void);
81
82void matrix_clear(struct CharacterMatrix *matrix);
83void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c);
84void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c);
85void matrix_write(struct CharacterMatrix *matrix, const char *data);
86void matrix_write_P(struct CharacterMatrix *matrix, const char *data);
87void matrix_render(struct CharacterMatrix *matrix);
diff --git a/drivers/avr/uart.c b/drivers/avr/uart.c
deleted file mode 100644
index c6abcb6fe..000000000
--- a/drivers/avr/uart.c
+++ /dev/null
@@ -1,170 +0,0 @@
1/* UART Example for Teensy USB Development Board
2 * http://www.pjrc.com/teensy/
3 * Copyright (c) 2009 PJRC.COM, LLC
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24// Version 1.0: Initial Release
25// Version 1.1: Add support for Teensy 2.0, minor optimizations
26
27#include <avr/io.h>
28#include <avr/interrupt.h>
29
30#include "uart.h"
31
32#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__)
33# define UDRn UDR1
34# define UBRRnL UBRR1L
35# define UCSRnA UCSR1A
36# define UCSRnB UCSR1B
37# define UCSRnC UCSR1C
38# define U2Xn U2X1
39# define RXENn RXEN1
40# define TXENn TXEN1
41# define RXCIEn RXCIE1
42# define UCSZn1 UCSZ11
43# define UCSZn0 UCSZ10
44# define UDRIEn UDRIE1
45# define USARTn_UDRE_vect USART1_UDRE_vect
46# define USARTn_RX_vect USART1_RX_vect
47#elif defined(__AVR_ATmega32A__)
48# define UDRn UDR
49# define UBRRnL UBRRL
50# define UCSRnA UCSRA
51# define UCSRnB UCSRB
52# define UCSRnC UCSRC
53# define U2Xn U2X
54# define RXENn RXEN
55# define TXENn TXEN
56# define RXCIEn RXCIE
57# define UCSZn1 UCSZ1
58# define UCSZn0 UCSZ0
59# define UDRIEn UDRIE
60# define USARTn_UDRE_vect USART_UDRE_vect
61# define USARTn_RX_vect USART_RX_vect
62#elif defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
63# define UDRn UDR0
64# define UBRRnL UBRR0L
65# define UCSRnA UCSR0A
66# define UCSRnB UCSR0B
67# define UCSRnC UCSR0C
68# define U2Xn U2X0
69# define RXENn RXEN0
70# define TXENn TXEN0
71# define RXCIEn RXCIE0
72# define UCSZn1 UCSZ01
73# define UCSZn0 UCSZ00
74# define UDRIEn UDRIE0
75# define USARTn_UDRE_vect USART_UDRE_vect
76# define USARTn_RX_vect USART_RX_vect
77#endif
78
79// These buffers may be any size from 2 to 256 bytes.
80#define RX_BUFFER_SIZE 64
81#define TX_BUFFER_SIZE 256
82
83static volatile uint8_t tx_buffer[TX_BUFFER_SIZE];
84static volatile uint8_t tx_buffer_head;
85static volatile uint8_t tx_buffer_tail;
86static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
87static volatile uint8_t rx_buffer_head;
88static volatile uint8_t rx_buffer_tail;
89
90// Initialize the UART
91void uart_init(uint32_t baud) {
92 cli();
93 UBRRnL = (F_CPU / 4 / baud - 1) / 2;
94 UCSRnA = (1 << U2Xn);
95 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn);
96 UCSRnC = (1 << UCSZn1) | (1 << UCSZn0);
97 tx_buffer_head = tx_buffer_tail = 0;
98 rx_buffer_head = rx_buffer_tail = 0;
99 sei();
100}
101
102// Transmit a byte
103void uart_putchar(uint8_t c) {
104 uint8_t i;
105
106 i = tx_buffer_head + 1;
107 if (i >= TX_BUFFER_SIZE) i = 0;
108 // return immediately to avoid deadlock when interrupt is disabled(called from ISR)
109 if (tx_buffer_tail == i && (SREG & (1 << SREG_I)) == 0) return;
110 while (tx_buffer_tail == i)
111 ; // wait until space in buffer
112 // cli();
113 tx_buffer[i] = c;
114 tx_buffer_head = i;
115 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn);
116 // sei();
117}
118
119// Receive a byte
120uint8_t uart_getchar(void) {
121 uint8_t c, i;
122
123 while (rx_buffer_head == rx_buffer_tail)
124 ; // wait for character
125 i = rx_buffer_tail + 1;
126 if (i >= RX_BUFFER_SIZE) i = 0;
127 c = rx_buffer[i];
128 rx_buffer_tail = i;
129 return c;
130}
131
132// Return whether the number of bytes waiting in the receive buffer is nonzero.
133// Call this before uart_getchar() to check if it will need
134// to wait for a byte to arrive.
135bool uart_available(void) {
136 uint8_t head, tail;
137
138 head = rx_buffer_head;
139 tail = rx_buffer_tail;
140 if (head >= tail) return (head - tail) > 0;
141 return (RX_BUFFER_SIZE + head - tail) > 0;
142}
143
144// Transmit Interrupt
145ISR(USARTn_UDRE_vect) {
146 uint8_t i;
147
148 if (tx_buffer_head == tx_buffer_tail) {
149 // buffer is empty, disable transmit interrupt
150 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn);
151 } else {
152 i = tx_buffer_tail + 1;
153 if (i >= TX_BUFFER_SIZE) i = 0;
154 UDRn = tx_buffer[i];
155 tx_buffer_tail = i;
156 }
157}
158
159// Receive Interrupt
160ISR(USARTn_RX_vect) {
161 uint8_t c, i;
162
163 c = UDRn;
164 i = rx_buffer_head + 1;
165 if (i >= RX_BUFFER_SIZE) i = 0;
166 if (i != rx_buffer_tail) {
167 rx_buffer[i] = c;
168 rx_buffer_head = i;
169 }
170}
diff --git a/drivers/avr/uart.h b/drivers/avr/uart.h
deleted file mode 100644
index 602eb3d8b..000000000
--- a/drivers/avr/uart.h
+++ /dev/null
@@ -1,35 +0,0 @@
1/* UART Example for Teensy USB Development Board
2 * http://www.pjrc.com/teensy/
3 * Copyright (c) 2009 PJRC.COM, LLC
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#pragma once
25
26#include <stdint.h>
27#include <stdbool.h>
28
29void uart_init(uint32_t baud);
30
31void uart_putchar(uint8_t c);
32
33uint8_t uart_getchar(void);
34
35bool uart_available(void);
diff --git a/drivers/avr/ws2812.c b/drivers/avr/ws2812.c
deleted file mode 100644
index 77c492cd4..000000000
--- a/drivers/avr/ws2812.c
+++ /dev/null
@@ -1,176 +0,0 @@
1/*
2 * light weight WS2812 lib V2.0b
3 *
4 * Controls WS2811/WS2812/WS2812B RGB-LEDs
5 * Author: Tim (cpldcpu@gmail.com)
6 *
7 * Jan 18th, 2014 v2.0b Initial Version
8 * Nov 29th, 2015 v2.3 Added SK6812RGBW support
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23#include "ws2812.h"
24#include <avr/interrupt.h>
25#include <avr/io.h>
26#include <util/delay.h>
27
28#define pinmask(pin) (_BV((pin)&0xF))
29
30/*
31 * Forward declare internal functions
32 *
33 * The functions take a byte-array and send to the data output as WS2812 bitstream.
34 * The length is the number of bytes to send - three per LED.
35 */
36
37static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t masklo, uint8_t maskhi);
38
39void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds) {
40 DDRx_ADDRESS(RGB_DI_PIN) |= pinmask(RGB_DI_PIN);
41
42 uint8_t masklo = ~(pinmask(RGB_DI_PIN)) & PORTx_ADDRESS(RGB_DI_PIN);
43 uint8_t maskhi = pinmask(RGB_DI_PIN) | PORTx_ADDRESS(RGB_DI_PIN);
44
45 ws2812_sendarray_mask((uint8_t *)ledarray, number_of_leds * sizeof(LED_TYPE), masklo, maskhi);
46
47 _delay_us(WS2812_TRST_US);
48}
49
50/*
51 This routine writes an array of bytes with RGB values to the Dataout pin
52 using the fast 800kHz clockless WS2811/2812 protocol.
53*/
54
55// Timing in ns
56#define w_zeropulse 350
57#define w_onepulse 900
58#define w_totalperiod 1250
59
60// Fixed cycles used by the inner loop
61#define w_fixedlow 2
62#define w_fixedhigh 4
63#define w_fixedtotal 8
64
65// Insert NOPs to match the timing, if possible
66#define w_zerocycles (((F_CPU / 1000) * w_zeropulse) / 1000000)
67#define w_onecycles (((F_CPU / 1000) * w_onepulse + 500000) / 1000000)
68#define w_totalcycles (((F_CPU / 1000) * w_totalperiod + 500000) / 1000000)
69
70// w1_nops - nops between rising edge and falling edge - low
71#if w_zerocycles >= w_fixedlow
72# define w1_nops (w_zerocycles - w_fixedlow)
73#else
74# define w1_nops 0
75#endif
76
77// w2_nops - nops between fe low and fe high
78#if w_onecycles >= (w_fixedhigh + w1_nops)
79# define w2_nops (w_onecycles - w_fixedhigh - w1_nops)
80#else
81# define w2_nops 0
82#endif
83
84// w3_nops - nops to complete loop
85#if w_totalcycles >= (w_fixedtotal + w1_nops + w2_nops)
86# define w3_nops (w_totalcycles - w_fixedtotal - w1_nops - w2_nops)
87#else
88# define w3_nops 0
89#endif
90
91// The only critical timing parameter is the minimum pulse length of the "0"
92// Warn or throw error if this timing can not be met with current F_CPU settings.
93#define w_lowtime ((w1_nops + w_fixedlow) * 1000000) / (F_CPU / 1000)
94#if w_lowtime > 550
95# error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
96#elif w_lowtime > 450
97# warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
98# warning "Please consider a higher clockspeed, if possible"
99#endif
100
101#define w_nop1 "nop \n\t"
102#define w_nop2 "rjmp .+0 \n\t"
103#define w_nop4 w_nop2 w_nop2
104#define w_nop8 w_nop4 w_nop4
105#define w_nop16 w_nop8 w_nop8
106
107static inline void ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t masklo, uint8_t maskhi) {
108 uint8_t curbyte, ctr, sreg_prev;
109
110 sreg_prev = SREG;
111 cli();
112
113 while (datlen--) {
114 curbyte = (*data++);
115
116 asm volatile(" ldi %0,8 \n\t"
117 "loop%=: \n\t"
118 " out %2,%3 \n\t" // '1' [01] '0' [01] - re
119#if (w1_nops & 1)
120 w_nop1
121#endif
122#if (w1_nops & 2)
123 w_nop2
124#endif
125#if (w1_nops & 4)
126 w_nop4
127#endif
128#if (w1_nops & 8)
129 w_nop8
130#endif
131#if (w1_nops & 16)
132 w_nop16
133#endif
134 " sbrs %1,7 \n\t" // '1' [03] '0' [02]
135 " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
136 " lsl %1 \n\t" // '1' [04] '0' [04]
137#if (w2_nops & 1)
138 w_nop1
139#endif
140#if (w2_nops & 2)
141 w_nop2
142#endif
143#if (w2_nops & 4)
144 w_nop4
145#endif
146#if (w2_nops & 8)
147 w_nop8
148#endif
149#if (w2_nops & 16)
150 w_nop16
151#endif
152 " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
153#if (w3_nops & 1)
154 w_nop1
155#endif
156#if (w3_nops & 2)
157 w_nop2
158#endif
159#if (w3_nops & 4)
160 w_nop4
161#endif
162#if (w3_nops & 8)
163 w_nop8
164#endif
165#if (w3_nops & 16)
166 w_nop16
167#endif
168
169 " dec %0 \n\t" // '1' [+2] '0' [+2]
170 " brne loop%=\n\t" // '1' [+3] '0' [+4]
171 : "=&d"(ctr)
172 : "r"(curbyte), "I"(_SFR_IO_ADDR(PORTx_ADDRESS(RGB_DI_PIN))), "r"(maskhi), "r"(masklo));
173 }
174
175 SREG = sreg_prev;
176}
diff --git a/drivers/avr/ws2812_i2c.c b/drivers/avr/ws2812_i2c.c
deleted file mode 100644
index 1c332e24b..000000000
--- a/drivers/avr/ws2812_i2c.c
+++ /dev/null
@@ -1,27 +0,0 @@
1#include "ws2812.h"
2#include "i2c_master.h"
3
4#ifdef RGBW
5# error "RGBW not supported"
6#endif
7
8#ifndef WS2812_ADDRESS
9# define WS2812_ADDRESS 0xb0
10#endif
11
12#ifndef WS2812_TIMEOUT
13# define WS2812_TIMEOUT 100
14#endif
15
16void ws2812_init(void) { i2c_init(); }
17
18// Setleds for standard RGB
19void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
20 static bool s_init = false;
21 if (!s_init) {
22 ws2812_init();
23 s_init = true;
24 }
25
26 i2c_transmit(WS2812_ADDRESS, (uint8_t *)ledarray, sizeof(LED_TYPE) * leds, WS2812_TIMEOUT);
27}
diff --git a/drivers/chibios/analog.c b/drivers/chibios/analog.c
deleted file mode 100644
index 8c476fcac..000000000
--- a/drivers/chibios/analog.c
+++ /dev/null
@@ -1,321 +0,0 @@
1/* Copyright 2019 Drew Mills
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "quantum.h"
18#include "analog.h"
19#include <ch.h>
20#include <hal.h>
21
22#if !HAL_USE_ADC
23# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
24#endif
25
26#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4
27# error "You need to set one of the 'STM32_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
28#endif
29
30#if STM32_ADC_DUAL_MODE
31# error "STM32 ADC Dual Mode is not supported at this time."
32#endif
33
34#if STM32_ADCV3_OVERSAMPLING
35# error "STM32 ADCV3 Oversampling is not supported at this time."
36#endif
37
38// Otherwise assume V3
39#if defined(STM32F0XX) || defined(STM32L0XX)
40# define USE_ADCV1
41#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX)
42# define USE_ADCV2
43#endif
44
45// BODGE to make v2 look like v1,3 and 4
46#ifdef USE_ADCV2
47# if !defined(ADC_SMPR_SMP_1P5) && defined(ADC_SAMPLE_3)
48# define ADC_SMPR_SMP_1P5 ADC_SAMPLE_3
49# define ADC_SMPR_SMP_7P5 ADC_SAMPLE_15
50# define ADC_SMPR_SMP_13P5 ADC_SAMPLE_28
51# define ADC_SMPR_SMP_28P5 ADC_SAMPLE_56
52# define ADC_SMPR_SMP_41P5 ADC_SAMPLE_84
53# define ADC_SMPR_SMP_55P5 ADC_SAMPLE_112
54# define ADC_SMPR_SMP_71P5 ADC_SAMPLE_144
55# define ADC_SMPR_SMP_239P5 ADC_SAMPLE_480
56# endif
57
58# if !defined(ADC_SMPR_SMP_1P5) && defined(ADC_SAMPLE_1P5)
59# define ADC_SMPR_SMP_1P5 ADC_SAMPLE_1P5
60# define ADC_SMPR_SMP_7P5 ADC_SAMPLE_7P5
61# define ADC_SMPR_SMP_13P5 ADC_SAMPLE_13P5
62# define ADC_SMPR_SMP_28P5 ADC_SAMPLE_28P5
63# define ADC_SMPR_SMP_41P5 ADC_SAMPLE_41P5
64# define ADC_SMPR_SMP_55P5 ADC_SAMPLE_55P5
65# define ADC_SMPR_SMP_71P5 ADC_SAMPLE_71P5
66# define ADC_SMPR_SMP_239P5 ADC_SAMPLE_239P5
67# endif
68
69// we still sample at 12bit, but scale down to the requested bit range
70# define ADC_CFGR1_RES_12BIT 12
71# define ADC_CFGR1_RES_10BIT 10
72# define ADC_CFGR1_RES_8BIT 8
73# define ADC_CFGR1_RES_6BIT 6
74#endif
75
76/* User configurable ADC options */
77#ifndef ADC_COUNT
78# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX)
79# define ADC_COUNT 1
80# elif defined(STM32F3XX)
81# define ADC_COUNT 4
82# else
83# error "ADC_COUNT has not been set for this ARM microcontroller."
84# endif
85#endif
86
87#ifndef ADC_NUM_CHANNELS
88# define ADC_NUM_CHANNELS 1
89#elif ADC_NUM_CHANNELS != 1
90# error "The ARM ADC implementation currently only supports reading one channel at a time."
91#endif
92
93#ifndef ADC_BUFFER_DEPTH
94# define ADC_BUFFER_DEPTH 1
95#endif
96
97// For more sampling rate options, look at hal_adc_lld.h in ChibiOS
98#ifndef ADC_SAMPLING_RATE
99# define ADC_SAMPLING_RATE ADC_SMPR_SMP_1P5
100#endif
101
102// Options are 12, 10, 8, and 6 bit.
103#ifndef ADC_RESOLUTION
104# ifdef ADC_CFGR_RES_10BITS // ADCv3, ADCv4
105# define ADC_RESOLUTION ADC_CFGR_RES_10BITS
106# else // ADCv1, ADCv5, or the bodge for ADCv2 above
107# define ADC_RESOLUTION ADC_CFGR1_RES_10BIT
108# endif
109#endif
110
111static ADCConfig adcCfg = {};
112static adcsample_t sampleBuffer[ADC_NUM_CHANNELS * ADC_BUFFER_DEPTH];
113
114// Initialize to max number of ADCs, set to empty object to initialize all to false.
115static bool adcInitialized[ADC_COUNT] = {};
116
117// TODO: add back TR handling???
118static ADCConversionGroup adcConversionGroup = {
119 .circular = FALSE,
120 .num_channels = (uint16_t)(ADC_NUM_CHANNELS),
121#if defined(USE_ADCV1)
122 .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
123 .smpr = ADC_SAMPLING_RATE,
124#elif defined(USE_ADCV2)
125# if !defined(STM32F1XX)
126 .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
127# endif
128 .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
129 .smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
130#else
131 .cfgr = ADC_CFGR_CONT | ADC_RESOLUTION,
132 .smpr = {ADC_SMPR1_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN9(ADC_SAMPLING_RATE), ADC_SMPR2_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN15(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN16(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN17(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN18(ADC_SAMPLING_RATE)},
133#endif
134};
135
136// clang-format off
137__attribute__((weak)) adc_mux pinToMux(pin_t pin) {
138 switch (pin) {
139#if defined(STM32F0XX)
140 case A0: return TO_MUX( ADC_CHSELR_CHSEL0, 0 );
141 case A1: return TO_MUX( ADC_CHSELR_CHSEL1, 0 );
142 case A2: return TO_MUX( ADC_CHSELR_CHSEL2, 0 );
143 case A3: return TO_MUX( ADC_CHSELR_CHSEL3, 0 );
144 case A4: return TO_MUX( ADC_CHSELR_CHSEL4, 0 );
145 case A5: return TO_MUX( ADC_CHSELR_CHSEL5, 0 );
146 case A6: return TO_MUX( ADC_CHSELR_CHSEL6, 0 );
147 case A7: return TO_MUX( ADC_CHSELR_CHSEL7, 0 );
148 case B0: return TO_MUX( ADC_CHSELR_CHSEL8, 0 );
149 case B1: return TO_MUX( ADC_CHSELR_CHSEL9, 0 );
150 case C0: return TO_MUX( ADC_CHSELR_CHSEL10, 0 );
151 case C1: return TO_MUX( ADC_CHSELR_CHSEL11, 0 );
152 case C2: return TO_MUX( ADC_CHSELR_CHSEL12, 0 );
153 case C3: return TO_MUX( ADC_CHSELR_CHSEL13, 0 );
154 case C4: return TO_MUX( ADC_CHSELR_CHSEL14, 0 );
155 case C5: return TO_MUX( ADC_CHSELR_CHSEL15, 0 );
156#elif defined(STM32F3XX)
157 case A0: return TO_MUX( ADC_CHANNEL_IN1, 0 );
158 case A1: return TO_MUX( ADC_CHANNEL_IN2, 0 );
159 case A2: return TO_MUX( ADC_CHANNEL_IN3, 0 );
160 case A3: return TO_MUX( ADC_CHANNEL_IN4, 0 );
161 case A4: return TO_MUX( ADC_CHANNEL_IN1, 1 );
162 case A5: return TO_MUX( ADC_CHANNEL_IN2, 1 );
163 case A6: return TO_MUX( ADC_CHANNEL_IN3, 1 );
164 case A7: return TO_MUX( ADC_CHANNEL_IN4, 1 );
165 case B0: return TO_MUX( ADC_CHANNEL_IN12, 2 );
166 case B1: return TO_MUX( ADC_CHANNEL_IN1, 2 );
167 case B2: return TO_MUX( ADC_CHANNEL_IN12, 1 );
168 case B12: return TO_MUX( ADC_CHANNEL_IN3, 3 );
169 case B13: return TO_MUX( ADC_CHANNEL_IN5, 2 );
170 case B14: return TO_MUX( ADC_CHANNEL_IN4, 3 );
171 case B15: return TO_MUX( ADC_CHANNEL_IN5, 3 );
172 case C0: return TO_MUX( ADC_CHANNEL_IN6, 0 ); // Can also be ADC2
173 case C1: return TO_MUX( ADC_CHANNEL_IN7, 0 ); // Can also be ADC2
174 case C2: return TO_MUX( ADC_CHANNEL_IN8, 0 ); // Can also be ADC2
175 case C3: return TO_MUX( ADC_CHANNEL_IN9, 0 ); // Can also be ADC2
176 case C4: return TO_MUX( ADC_CHANNEL_IN5, 1 );
177 case C5: return TO_MUX( ADC_CHANNEL_IN11, 1 );
178 case D8: return TO_MUX( ADC_CHANNEL_IN12, 3 );
179 case D9: return TO_MUX( ADC_CHANNEL_IN13, 3 );
180 case D10: return TO_MUX( ADC_CHANNEL_IN7, 2 ); // Can also be ADC4
181 case D11: return TO_MUX( ADC_CHANNEL_IN8, 2 ); // Can also be ADC4
182 case D12: return TO_MUX( ADC_CHANNEL_IN9, 2 ); // Can also be ADC4
183 case D13: return TO_MUX( ADC_CHANNEL_IN10, 2 ); // Can also be ADC4
184 case D14: return TO_MUX( ADC_CHANNEL_IN11, 2 ); // Can also be ADC4
185 case E7: return TO_MUX( ADC_CHANNEL_IN13, 2 );
186 case E8: return TO_MUX( ADC_CHANNEL_IN6, 2 ); // Can also be ADC4
187 case E9: return TO_MUX( ADC_CHANNEL_IN2, 2 );
188 case E10: return TO_MUX( ADC_CHANNEL_IN14, 2 );
189 case E11: return TO_MUX( ADC_CHANNEL_IN15, 2 );
190 case E12: return TO_MUX( ADC_CHANNEL_IN16, 2 );
191 case E13: return TO_MUX( ADC_CHANNEL_IN3, 2 );
192 case E14: return TO_MUX( ADC_CHANNEL_IN1, 3 );
193 case E15: return TO_MUX( ADC_CHANNEL_IN2, 3 );
194 case F2: return TO_MUX( ADC_CHANNEL_IN10, 0 ); // Can also be ADC2
195 case F4: return TO_MUX( ADC_CHANNEL_IN5, 0 );
196#elif defined(STM32F4XX)
197 case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
198 case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
199 case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 );
200 case A3: return TO_MUX( ADC_CHANNEL_IN3, 0 );
201 case A4: return TO_MUX( ADC_CHANNEL_IN4, 0 );
202 case A5: return TO_MUX( ADC_CHANNEL_IN5, 0 );
203 case A6: return TO_MUX( ADC_CHANNEL_IN6, 0 );
204 case A7: return TO_MUX( ADC_CHANNEL_IN7, 0 );
205 case B0: return TO_MUX( ADC_CHANNEL_IN8, 0 );
206 case B1: return TO_MUX( ADC_CHANNEL_IN9, 0 );
207 case C0: return TO_MUX( ADC_CHANNEL_IN10, 0 );
208 case C1: return TO_MUX( ADC_CHANNEL_IN11, 0 );
209 case C2: return TO_MUX( ADC_CHANNEL_IN12, 0 );
210 case C3: return TO_MUX( ADC_CHANNEL_IN13, 0 );
211 case C4: return TO_MUX( ADC_CHANNEL_IN14, 0 );
212 case C5: return TO_MUX( ADC_CHANNEL_IN15, 0 );
213# if STM32_ADC_USE_ADC3
214 case F3: return TO_MUX( ADC_CHANNEL_IN9, 2 );
215 case F4: return TO_MUX( ADC_CHANNEL_IN14, 2 );
216 case F5: return TO_MUX( ADC_CHANNEL_IN15, 2 );
217 case F6: return TO_MUX( ADC_CHANNEL_IN4, 2 );
218 case F7: return TO_MUX( ADC_CHANNEL_IN5, 2 );
219 case F8: return TO_MUX( ADC_CHANNEL_IN6, 2 );
220 case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 );
221 case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 );
222# endif
223#elif defined(STM32F1XX)
224 case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
225 case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
226 case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 );
227 case A3: return TO_MUX( ADC_CHANNEL_IN3, 0 );
228 case A4: return TO_MUX( ADC_CHANNEL_IN4, 0 );
229 case A5: return TO_MUX( ADC_CHANNEL_IN5, 0 );
230 case A6: return TO_MUX( ADC_CHANNEL_IN6, 0 );
231 case A7: return TO_MUX( ADC_CHANNEL_IN7, 0 );
232 case B0: return TO_MUX( ADC_CHANNEL_IN8, 0 );
233 case B1: return TO_MUX( ADC_CHANNEL_IN9, 0 );
234 case C0: return TO_MUX( ADC_CHANNEL_IN10, 0 );
235 case C1: return TO_MUX( ADC_CHANNEL_IN11, 0 );
236 case C2: return TO_MUX( ADC_CHANNEL_IN12, 0 );
237 case C3: return TO_MUX( ADC_CHANNEL_IN13, 0 );
238 case C4: return TO_MUX( ADC_CHANNEL_IN14, 0 );
239 case C5: return TO_MUX( ADC_CHANNEL_IN15, 0 );
240 // STM32F103x[C-G] in 144-pin packages also have analog inputs on F6...F10, but they are on ADC3, and the
241 // ChibiOS ADC driver for STM32F1xx currently supports only ADC1, therefore these pins are not usable.
242#endif
243 }
244
245 // return an adc that would never be used so intToADCDriver will bail out
246 return TO_MUX(0, 0xFF);
247}
248// clang-format on
249
250static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
251 switch (adcInt) {
252#if STM32_ADC_USE_ADC1
253 case 0:
254 return &ADCD1;
255#endif
256#if STM32_ADC_USE_ADC2
257 case 1:
258 return &ADCD2;
259#endif
260#if STM32_ADC_USE_ADC3
261 case 2:
262 return &ADCD3;
263#endif
264#if STM32_ADC_USE_ADC4
265 case 3:
266 return &ADCD4;
267#endif
268 }
269
270 return NULL;
271}
272
273static inline void manageAdcInitializationDriver(uint8_t adc, ADCDriver* adcDriver) {
274 if (!adcInitialized[adc]) {
275 adcStart(adcDriver, &adcCfg);
276 adcInitialized[adc] = true;
277 }
278}
279
280int16_t analogReadPin(pin_t pin) {
281 palSetLineMode(pin, PAL_MODE_INPUT_ANALOG);
282
283 return adc_read(pinToMux(pin));
284}
285
286int16_t analogReadPinAdc(pin_t pin, uint8_t adc) {
287 palSetLineMode(pin, PAL_MODE_INPUT_ANALOG);
288
289 adc_mux target = pinToMux(pin);
290 target.adc = adc;
291 return adc_read(target);
292}
293
294int16_t adc_read(adc_mux mux) {
295#if defined(USE_ADCV1)
296 // TODO: fix previous assumption of only 1 input...
297 adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
298#elif defined(USE_ADCV2)
299 adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
300#else
301 adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.input);
302#endif
303
304 ADCDriver* targetDriver = intToADCDriver(mux.adc);
305 if (!targetDriver) {
306 return 0;
307 }
308
309 manageAdcInitializationDriver(mux.adc, targetDriver);
310 if (adcConvert(targetDriver, &adcConversionGroup, &sampleBuffer[0], ADC_BUFFER_DEPTH) != MSG_OK) {
311 return 0;
312 }
313
314#ifdef USE_ADCV2
315 // fake 12-bit -> N-bit scale
316 return (*sampleBuffer) >> (12 - ADC_RESOLUTION);
317#else
318 // already handled as part of adcConvert
319 return *sampleBuffer;
320#endif
321}
diff --git a/drivers/chibios/analog.h b/drivers/chibios/analog.h
deleted file mode 100644
index e61c39426..000000000
--- a/drivers/chibios/analog.h
+++ /dev/null
@@ -1,41 +0,0 @@
1/* Copyright 2019 Drew Mills
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <stdint.h>
20#include "quantum.h"
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
26typedef struct {
27 uint16_t input;
28 uint8_t adc;
29} adc_mux;
30#define TO_MUX(i, a) \
31 (adc_mux) { i, a }
32
33int16_t analogReadPin(pin_t pin);
34int16_t analogReadPinAdc(pin_t pin, uint8_t adc);
35adc_mux pinToMux(pin_t pin);
36
37int16_t adc_read(adc_mux mux);
38
39#ifdef __cplusplus
40}
41#endif
diff --git a/drivers/chibios/i2c_master.c b/drivers/chibios/i2c_master.c
deleted file mode 100644
index fc4bb2ab3..000000000
--- a/drivers/chibios/i2c_master.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/* Copyright 2018 Jack Humbert
2 * Copyright 2018 Yiancar
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/* This library is only valid for STM32 processors.
19 * This library follows the convention of the AVR i2c_master library.
20 * As a result addresses are expected to be already shifted (addr << 1).
21 * I2CD1 is the default driver which corresponds to pins B6 and B7. This
22 * can be changed.
23 * Please ensure that HAL_USE_I2C is TRUE in the halconf.h file and that
24 * STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file. Pins B6 and B7 are used
25 * but using any other I2C pins should be trivial.
26 */
27#include "quantum.h"
28#include "i2c_master.h"
29#include <string.h>
30#include <hal.h>
31
32static uint8_t i2c_address;
33
34static const I2CConfig i2cconfig = {
35#if defined(USE_I2CV1_CONTRIB)
36 I2C1_CLOCK_SPEED,
37#elif defined(USE_I2CV1)
38 I2C1_OPMODE,
39 I2C1_CLOCK_SPEED,
40 I2C1_DUTY_CYCLE,
41#else
42 // This configures the I2C clock to 400khz assuming a 72Mhz clock
43 // For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html
44 STM32_TIMINGR_PRESC(I2C1_TIMINGR_PRESC) | STM32_TIMINGR_SCLDEL(I2C1_TIMINGR_SCLDEL) | STM32_TIMINGR_SDADEL(I2C1_TIMINGR_SDADEL) | STM32_TIMINGR_SCLH(I2C1_TIMINGR_SCLH) | STM32_TIMINGR_SCLL(I2C1_TIMINGR_SCLL), 0, 0
45#endif
46};
47
48static i2c_status_t chibios_to_qmk(const msg_t* status) {
49 switch (*status) {
50 case I2C_NO_ERROR:
51 return I2C_STATUS_SUCCESS;
52 case I2C_TIMEOUT:
53 return I2C_STATUS_TIMEOUT;
54 // I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
55 default:
56 return I2C_STATUS_ERROR;
57 }
58}
59
60__attribute__((weak)) void i2c_init(void) {
61 static bool is_initialised = false;
62 if (!is_initialised) {
63 is_initialised = true;
64
65 // Try releasing special pins for a short time
66 palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT);
67 palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT);
68
69 chThdSleepMilliseconds(10);
70#if defined(USE_GPIOV1)
71 palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, I2C1_SCL_PAL_MODE);
72 palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, I2C1_SDA_PAL_MODE);
73#else
74 palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
75 palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
76#endif
77 }
78}
79
80i2c_status_t i2c_start(uint8_t address) {
81 i2c_address = address;
82 i2cStart(&I2C_DRIVER, &i2cconfig);
83 return I2C_STATUS_SUCCESS;
84}
85
86i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
87 i2c_address = address;
88 i2cStart(&I2C_DRIVER, &i2cconfig);
89 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout));
90 return chibios_to_qmk(&status);
91}
92
93i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
94 i2c_address = address;
95 i2cStart(&I2C_DRIVER, &i2cconfig);
96 msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, TIME_MS2I(timeout));
97 return chibios_to_qmk(&status);
98}
99
100i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
101 i2c_address = devaddr;
102 i2cStart(&I2C_DRIVER, &i2cconfig);
103
104 uint8_t complete_packet[length + 1];
105 for (uint8_t i = 0; i < length; i++) {
106 complete_packet[i + 1] = data[i];
107 }
108 complete_packet[0] = regaddr;
109
110 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout));
111 return chibios_to_qmk(&status);
112}
113
114i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
115 i2c_address = devaddr;
116 i2cStart(&I2C_DRIVER, &i2cconfig);
117 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), &regaddr, 1, data, length, TIME_MS2I(timeout));
118 return chibios_to_qmk(&status);
119}
120
121void i2c_stop(void) { i2cStop(&I2C_DRIVER); }
diff --git a/drivers/chibios/i2c_master.h b/drivers/chibios/i2c_master.h
deleted file mode 100644
index c68109acb..000000000
--- a/drivers/chibios/i2c_master.h
+++ /dev/null
@@ -1,113 +0,0 @@
1/* Copyright 2018 Jack Humbert
2 * Copyright 2018 Yiancar
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/* This library follows the convention of the AVR i2c_master library.
19 * As a result addresses are expected to be already shifted (addr << 1).
20 * I2CD1 is the default driver which corresponds to pins B6 and B7. This
21 * can be changed.
22 * Please ensure that HAL_USE_I2C is TRUE in the halconf.h file and that
23 * STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file.
24 */
25#pragma once
26
27#include <ch.h>
28#include <hal.h>
29
30#ifdef I2C1_BANK
31# define I2C1_SCL_BANK I2C1_BANK
32# define I2C1_SDA_BANK I2C1_BANK
33#endif
34
35#ifndef I2C1_SCL_BANK
36# define I2C1_SCL_BANK GPIOB
37#endif
38
39#ifndef I2C1_SDA_BANK
40# define I2C1_SDA_BANK GPIOB
41#endif
42
43#ifndef I2C1_SCL
44# define I2C1_SCL 6
45#endif
46#ifndef I2C1_SDA
47# define I2C1_SDA 7
48#endif
49
50#ifdef USE_I2CV1
51# ifndef I2C1_OPMODE
52# define I2C1_OPMODE OPMODE_I2C
53# endif
54# ifndef I2C1_CLOCK_SPEED
55# define I2C1_CLOCK_SPEED 100000 /* 400000 */
56# endif
57# ifndef I2C1_DUTY_CYCLE
58# define I2C1_DUTY_CYCLE STD_DUTY_CYCLE /* FAST_DUTY_CYCLE_2 */
59# endif
60#else
61// The default timing values below configures the I2C clock to 400khz assuming a 72Mhz clock
62// For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html
63# ifndef I2C1_TIMINGR_PRESC
64# define I2C1_TIMINGR_PRESC 0U
65# endif
66# ifndef I2C1_TIMINGR_SCLDEL
67# define I2C1_TIMINGR_SCLDEL 7U
68# endif
69# ifndef I2C1_TIMINGR_SDADEL
70# define I2C1_TIMINGR_SDADEL 0U
71# endif
72# ifndef I2C1_TIMINGR_SCLH
73# define I2C1_TIMINGR_SCLH 38U
74# endif
75# ifndef I2C1_TIMINGR_SCLL
76# define I2C1_TIMINGR_SCLL 129U
77# endif
78#endif
79
80#ifndef I2C_DRIVER
81# define I2C_DRIVER I2CD1
82#endif
83
84#ifdef USE_GPIOV1
85# ifndef I2C1_SCL_PAL_MODE
86# define I2C1_SCL_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN
87# endif
88# ifndef I2C1_SDA_PAL_MODE
89# define I2C1_SDA_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN
90# endif
91#else
92// The default PAL alternate modes are used to signal that the pins are used for I2C
93# ifndef I2C1_SCL_PAL_MODE
94# define I2C1_SCL_PAL_MODE 4
95# endif
96# ifndef I2C1_SDA_PAL_MODE
97# define I2C1_SDA_PAL_MODE 4
98# endif
99#endif
100
101typedef int16_t i2c_status_t;
102
103#define I2C_STATUS_SUCCESS (0)
104#define I2C_STATUS_ERROR (-1)
105#define I2C_STATUS_TIMEOUT (-2)
106
107void i2c_init(void);
108i2c_status_t i2c_start(uint8_t address);
109i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
110i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
111i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
112i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
113void i2c_stop(void);
diff --git a/drivers/chibios/serial.c b/drivers/chibios/serial.c
deleted file mode 100644
index f54fbcee4..000000000
--- a/drivers/chibios/serial.c
+++ /dev/null
@@ -1,278 +0,0 @@
1/*
2 * WARNING: be careful changing this code, it is very timing dependent
3 */
4
5#include "quantum.h"
6#include "serial.h"
7#include "wait.h"
8
9#include <hal.h>
10
11// TODO: resolve/remove build warnings
12#if defined(RGBLIGHT_ENABLE) && defined(RGBLED_SPLIT) && defined(PROTOCOL_CHIBIOS) && defined(WS2812_DRIVER_BITBANG)
13# warning "RGBLED_SPLIT not supported with bitbang WS2812 driver"
14#endif
15
16// default wait implementation cannot be called within interrupt
17// this method seems to be more accurate than GPT timers
18#if PORT_SUPPORTS_RT == FALSE
19# error "chSysPolledDelayX method not supported on this platform"
20#else
21# undef wait_us
22# define wait_us(x) chSysPolledDelayX(US2RTC(STM32_SYSCLK, x))
23#endif
24
25#ifndef SELECT_SOFT_SERIAL_SPEED
26# define SELECT_SOFT_SERIAL_SPEED 1
27// TODO: correct speeds...
28// 0: about 189kbps (Experimental only)
29// 1: about 137kbps (default)
30// 2: about 75kbps
31// 3: about 39kbps
32// 4: about 26kbps
33// 5: about 20kbps
34#endif
35
36// Serial pulse period in microseconds. At the moment, going lower than 12 causes communication failure
37#if SELECT_SOFT_SERIAL_SPEED == 0
38# define SERIAL_DELAY 12
39#elif SELECT_SOFT_SERIAL_SPEED == 1
40# define SERIAL_DELAY 16
41#elif SELECT_SOFT_SERIAL_SPEED == 2
42# define SERIAL_DELAY 24
43#elif SELECT_SOFT_SERIAL_SPEED == 3
44# define SERIAL_DELAY 32
45#elif SELECT_SOFT_SERIAL_SPEED == 4
46# define SERIAL_DELAY 48
47#elif SELECT_SOFT_SERIAL_SPEED == 5
48# define SERIAL_DELAY 64
49#else
50# error invalid SELECT_SOFT_SERIAL_SPEED value
51#endif
52
53inline static void serial_delay(void) { wait_us(SERIAL_DELAY); }
54inline static void serial_delay_half(void) { wait_us(SERIAL_DELAY / 2); }
55inline static void serial_delay_blip(void) { wait_us(1); }
56inline static void serial_output(void) { setPinOutput(SOFT_SERIAL_PIN); }
57inline static void serial_input(void) { setPinInputHigh(SOFT_SERIAL_PIN); }
58inline static bool serial_read_pin(void) { return !!readPin(SOFT_SERIAL_PIN); }
59inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
60inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
61
62void interrupt_handler(void *arg);
63
64// Use thread + palWaitLineTimeout instead of palSetLineCallback
65// - Methods like setPinOutput and palEnableLineEvent/palDisableLineEvent
66// cause the interrupt to lock up, which would limit to only receiving data...
67static THD_WORKING_AREA(waThread1, 128);
68static THD_FUNCTION(Thread1, arg) {
69 (void)arg;
70 chRegSetThreadName("blinker");
71 while (true) {
72 palWaitLineTimeout(SOFT_SERIAL_PIN, TIME_INFINITE);
73 interrupt_handler(NULL);
74 }
75}
76
77void soft_serial_initiator_init(void) {
78 serial_output();
79 serial_high();
80}
81
82void soft_serial_target_init(void) {
83 serial_input();
84
85 palEnablePadEvent(PAL_PORT(SOFT_SERIAL_PIN), PAL_PAD(SOFT_SERIAL_PIN), PAL_EVENT_MODE_FALLING_EDGE);
86 chThdCreateStatic(waThread1, sizeof(waThread1), HIGHPRIO, Thread1, NULL);
87}
88
89// Used by the master to synchronize timing with the slave.
90static void __attribute__((noinline)) sync_recv(void) {
91 serial_input();
92 // This shouldn't hang if the slave disconnects because the
93 // serial line will float to high if the slave does disconnect.
94 while (!serial_read_pin()) {
95 }
96
97 serial_delay();
98}
99
100// Used by the slave to send a synchronization signal to the master.
101static void __attribute__((noinline)) sync_send(void) {
102 serial_output();
103
104 serial_low();
105 serial_delay();
106
107 serial_high();
108}
109
110// Reads a byte from the serial line
111static uint8_t __attribute__((noinline)) serial_read_byte(void) {
112 uint8_t byte = 0;
113 serial_input();
114 for (uint8_t i = 0; i < 8; ++i) {
115 byte = (byte << 1) | serial_read_pin();
116 serial_delay();
117 }
118
119 return byte;
120}
121
122// Sends a byte with MSB ordering
123static void __attribute__((noinline)) serial_write_byte(uint8_t data) {
124 uint8_t b = 8;
125 serial_output();
126 while (b--) {
127 if (data & (1 << b)) {
128 serial_high();
129 } else {
130 serial_low();
131 }
132 serial_delay();
133 }
134}
135
136// interrupt handle to be used by the slave device
137void interrupt_handler(void *arg) {
138 chSysLockFromISR();
139
140 sync_send();
141
142 // read mid pulses
143 serial_delay_blip();
144
145 uint8_t checksum_computed = 0;
146 int sstd_index = 0;
147
148 sstd_index = serial_read_byte();
149 sync_send();
150
151 split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
152 for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {
153 split_trans_initiator2target_buffer(trans)[i] = serial_read_byte();
154 sync_send();
155 checksum_computed += split_trans_initiator2target_buffer(trans)[i];
156 }
157 checksum_computed ^= 7;
158 uint8_t checksum_received = serial_read_byte();
159 sync_send();
160
161 // wait for the sync to finish sending
162 serial_delay();
163
164 // Allow any slave processing to occur
165 if (trans->slave_callback) {
166 trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
167 }
168
169 uint8_t checksum = 0;
170 for (int i = 0; i < trans->target2initiator_buffer_size; ++i) {
171 serial_write_byte(split_trans_target2initiator_buffer(trans)[i]);
172 sync_send();
173 serial_delay_half();
174 checksum += split_trans_target2initiator_buffer(trans)[i];
175 }
176 serial_write_byte(checksum ^ 7);
177 sync_send();
178
179 // wait for the sync to finish sending
180 serial_delay();
181
182 *trans->status = (checksum_computed == checksum_received) ? TRANSACTION_ACCEPTED : TRANSACTION_DATA_ERROR;
183
184 // end transaction
185 serial_input();
186
187 // TODO: remove extra delay between transactions
188 serial_delay();
189
190 chSysUnlockFromISR();
191}
192
193/////////
194// start transaction by initiator
195//
196// int soft_serial_transaction(int sstd_index)
197//
198// Returns:
199// TRANSACTION_END
200// TRANSACTION_NO_RESPONSE
201// TRANSACTION_DATA_ERROR
202// this code is very time dependent, so we need to disable interrupts
203int soft_serial_transaction(int sstd_index) {
204 if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
205 split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
206 if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
207
208 // TODO: remove extra delay between transactions
209 serial_delay();
210
211 // this code is very time dependent, so we need to disable interrupts
212 chSysLock();
213
214 // signal to the slave that we want to start a transaction
215 serial_output();
216 serial_low();
217 serial_delay_blip();
218
219 // wait for the slaves response
220 serial_input();
221 serial_high();
222 serial_delay();
223
224 // check if the slave is present
225 if (serial_read_pin()) {
226 // slave failed to pull the line low, assume not present
227 dprintf("serial::NO_RESPONSE\n");
228 chSysUnlock();
229 return TRANSACTION_NO_RESPONSE;
230 }
231
232 // if the slave is present syncronize with it
233
234 uint8_t checksum = 0;
235 // send data to the slave
236 serial_write_byte(sstd_index); // first chunk is transaction id
237 sync_recv();
238
239 for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {
240 serial_write_byte(split_trans_initiator2target_buffer(trans)[i]);
241 sync_recv();
242 checksum += split_trans_initiator2target_buffer(trans)[i];
243 }
244 serial_write_byte(checksum ^ 7);
245 sync_recv();
246
247 serial_delay();
248 serial_delay(); // read mid pulses
249
250 // receive data from the slave
251 uint8_t checksum_computed = 0;
252 for (int i = 0; i < trans->target2initiator_buffer_size; ++i) {
253 split_trans_target2initiator_buffer(trans)[i] = serial_read_byte();
254 sync_recv();
255 checksum_computed += split_trans_target2initiator_buffer(trans)[i];
256 }
257 checksum_computed ^= 7;
258 uint8_t checksum_received = serial_read_byte();
259
260 sync_recv();
261 serial_delay();
262
263 if ((checksum_computed) != (checksum_received)) {
264 dprintf("serial::FAIL[%u,%u,%u]\n", checksum_computed, checksum_received, sstd_index);
265 serial_output();
266 serial_high();
267
268 chSysUnlock();
269 return TRANSACTION_DATA_ERROR;
270 }
271
272 // always, release the line when not in use
273 serial_high();
274 serial_output();
275
276 chSysUnlock();
277 return TRANSACTION_END;
278}
diff --git a/drivers/chibios/serial_usart.c b/drivers/chibios/serial_usart.c
deleted file mode 100644
index ea4473791..000000000
--- a/drivers/chibios/serial_usart.c
+++ /dev/null
@@ -1,318 +0,0 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "serial_usart.h"
18
19#if defined(SERIAL_USART_CONFIG)
20static SerialConfig serial_config = SERIAL_USART_CONFIG;
21#else
22static SerialConfig serial_config = {
23 .speed = (SERIAL_USART_SPEED), /* speed - mandatory */
24 .cr1 = (SERIAL_USART_CR1),
25 .cr2 = (SERIAL_USART_CR2),
26# if !defined(SERIAL_USART_FULL_DUPLEX)
27 .cr3 = ((SERIAL_USART_CR3) | USART_CR3_HDSEL) /* activate half-duplex mode */
28# else
29 .cr3 = (SERIAL_USART_CR3)
30# endif
31};
32#endif
33
34static SerialDriver* serial_driver = &SERIAL_USART_DRIVER;
35
36static inline bool react_to_transactions(void);
37static inline bool __attribute__((nonnull)) receive(uint8_t* destination, const size_t size);
38static inline bool __attribute__((nonnull)) send(const uint8_t* source, const size_t size);
39static inline int initiate_transaction(uint8_t sstd_index);
40static inline void usart_clear(void);
41
42/**
43 * @brief Clear the receive input queue.
44 */
45static inline void usart_clear(void) {
46 osalSysLock();
47 bool volatile queue_not_empty = !iqIsEmptyI(&serial_driver->iqueue);
48 osalSysUnlock();
49
50 while (queue_not_empty) {
51 osalSysLock();
52 /* Hard reset the input queue. */
53 iqResetI(&serial_driver->iqueue);
54 osalSysUnlock();
55 /* Allow pending interrupts to preempt.
56 * Do not merge the lock/unlock blocks into one
57 * or the code will not work properly.
58 * The empty read adds a tiny amount of delay. */
59 (void)queue_not_empty;
60 osalSysLock();
61 queue_not_empty = !iqIsEmptyI(&serial_driver->iqueue);
62 osalSysUnlock();
63 }
64}
65
66/**
67 * @brief Blocking send of buffer with timeout.
68 *
69 * @return true Send success.
70 * @return false Send failed.
71 */
72static inline bool send(const uint8_t* source, const size_t size) {
73 bool success = (size_t)sdWriteTimeout(serial_driver, source, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size;
74
75#if !defined(SERIAL_USART_FULL_DUPLEX)
76 if (success) {
77 /* Half duplex fills the input queue with the data we wrote - just throw it away.
78 Under the right circumstances (e.g. bad cables paired with high baud rates)
79 less bytes can be present in the input queue, therefore a timeout is needed. */
80 uint8_t dump[size];
81 return receive(dump, size);
82 }
83#endif
84
85 return success;
86}
87
88/**
89 * @brief Blocking receive of size * bytes with timeout.
90 *
91 * @return true Receive success.
92 * @return false Receive failed.
93 */
94static inline bool receive(uint8_t* destination, const size_t size) {
95 bool success = (size_t)sdReadTimeout(serial_driver, destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size;
96 return success;
97}
98
99#if !defined(SERIAL_USART_FULL_DUPLEX)
100
101/**
102 * @brief Initiate pins for USART peripheral. Half-duplex configuration.
103 */
104__attribute__((weak)) void usart_init(void) {
105# if defined(MCU_STM32)
106# if defined(USE_GPIOV1)
107 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
108# else
109 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
110# endif
111
112# if defined(USART_REMAP)
113 USART_REMAP;
114# endif
115# else
116# pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files."
117# endif
118}
119
120#else
121
122/**
123 * @brief Initiate pins for USART peripheral. Full-duplex configuration.
124 */
125__attribute__((weak)) void usart_init(void) {
126# if defined(MCU_STM32)
127# if defined(USE_GPIOV1)
128 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
129 palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
130# else
131 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
132 palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
133# endif
134
135# if defined(USART_REMAP)
136 USART_REMAP;
137# endif
138# else
139# pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files."
140# endif
141}
142
143#endif
144
145/**
146 * @brief Overridable master specific initializations.
147 */
148__attribute__((weak, nonnull)) void usart_master_init(SerialDriver** driver) {
149 (void)driver;
150 usart_init();
151}
152
153/**
154 * @brief Overridable slave specific initializations.
155 */
156__attribute__((weak, nonnull)) void usart_slave_init(SerialDriver** driver) {
157 (void)driver;
158 usart_init();
159}
160
161/**
162 * @brief This thread runs on the slave and responds to transactions initiated
163 * by the master.
164 */
165static THD_WORKING_AREA(waSlaveThread, 1024);
166static THD_FUNCTION(SlaveThread, arg) {
167 (void)arg;
168 chRegSetThreadName("usart_tx_rx");
169
170 while (true) {
171 if (!react_to_transactions()) {
172 /* Clear the receive queue, to start with a clean slate.
173 * Parts of failed transactions or spurious bytes could still be in it. */
174 usart_clear();
175 }
176 }
177}
178
179/**
180 * @brief Slave specific initializations.
181 */
182void soft_serial_target_init(void) {
183 usart_slave_init(&serial_driver);
184
185 sdStart(serial_driver, &serial_config);
186
187 /* Start transport thread. */
188 chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL);
189}
190
191/**
192 * @brief React to transactions started by the master.
193 */
194static inline bool react_to_transactions(void) {
195 /* Wait until there is a transaction for us. */
196 uint8_t sstd_index = (uint8_t)sdGet(serial_driver);
197
198 /* Sanity check that we are actually responding to a valid transaction. */
199 if (sstd_index >= NUM_TOTAL_TRANSACTIONS) {
200 return false;
201 }
202
203 split_transaction_desc_t* trans = &split_transaction_table[sstd_index];
204
205 /* Send back the handshake which is XORed as a simple checksum,
206 to signal that the slave is ready to receive possible transaction buffers */
207 sstd_index ^= HANDSHAKE_MAGIC;
208 if (!send(&sstd_index, sizeof(sstd_index))) {
209 *trans->status = TRANSACTION_DATA_ERROR;
210 return false;
211 }
212
213 /* Receive transaction buffer from the master. If this transaction requires it.*/
214 if (trans->initiator2target_buffer_size) {
215 if (!receive(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) {
216 *trans->status = TRANSACTION_DATA_ERROR;
217 return false;
218 }
219 }
220
221 /* Allow any slave processing to occur. */
222 if (trans->slave_callback) {
223 trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, split_trans_target2initiator_buffer(trans));
224 }
225
226 /* Send transaction buffer to the master. If this transaction requires it. */
227 if (trans->target2initiator_buffer_size) {
228 if (!send(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) {
229 *trans->status = TRANSACTION_DATA_ERROR;
230 return false;
231 }
232 }
233
234 *trans->status = TRANSACTION_ACCEPTED;
235 return true;
236}
237
238/**
239 * @brief Master specific initializations.
240 */
241void soft_serial_initiator_init(void) {
242 usart_master_init(&serial_driver);
243
244#if defined(MCU_STM32) && defined(SERIAL_USART_PIN_SWAP)
245 serial_config.cr2 |= USART_CR2_SWAP; // master has swapped TX/RX pins
246#endif
247
248 sdStart(serial_driver, &serial_config);
249}
250
251/**
252 * @brief Start transaction from the master half to the slave half.
253 *
254 * @param index Transaction Table index of the transaction to start.
255 * @return int TRANSACTION_NO_RESPONSE in case of Timeout.
256 * TRANSACTION_TYPE_ERROR in case of invalid transaction index.
257 * TRANSACTION_END in case of success.
258 */
259int soft_serial_transaction(int index) {
260 /* Clear the receive queue, to start with a clean slate.
261 * Parts of failed transactions or spurious bytes could still be in it. */
262 usart_clear();
263 return initiate_transaction((uint8_t)index);
264}
265
266/**
267 * @brief Initiate transaction to slave half.
268 */
269static inline int initiate_transaction(uint8_t sstd_index) {
270 /* Sanity check that we are actually starting a valid transaction. */
271 if (sstd_index >= NUM_TOTAL_TRANSACTIONS) {
272 dprintln("USART: Illegal transaction Id.");
273 return TRANSACTION_TYPE_ERROR;
274 }
275
276 split_transaction_desc_t* trans = &split_transaction_table[sstd_index];
277
278 /* Transaction is not registered. Abort. */
279 if (!trans->status) {
280 dprintln("USART: Transaction not registered.");
281 return TRANSACTION_TYPE_ERROR;
282 }
283
284 /* Send transaction table index to the slave, which doubles as basic handshake token. */
285 if (!send(&sstd_index, sizeof(sstd_index))) {
286 dprintln("USART: Send Handshake failed.");
287 return TRANSACTION_TYPE_ERROR;
288 }
289
290 uint8_t sstd_index_shake = 0xFF;
291
292 /* Which we always read back first so that we can error out correctly.
293 * - due to the half duplex limitations on return codes, we always have to read *something*.
294 * - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready.
295 */
296 if (!receive(&sstd_index_shake, sizeof(sstd_index_shake)) || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) {
297 dprintln("USART: Handshake failed.");
298 return TRANSACTION_NO_RESPONSE;
299 }
300
301 /* Send transaction buffer to the slave. If this transaction requires it. */
302 if (trans->initiator2target_buffer_size) {
303 if (!send(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) {
304 dprintln("USART: Send failed.");
305 return TRANSACTION_NO_RESPONSE;
306 }
307 }
308
309 /* Receive transaction buffer from the slave. If this transaction requires it. */
310 if (trans->target2initiator_buffer_size) {
311 if (!receive(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) {
312 dprintln("USART: Receive failed.");
313 return TRANSACTION_NO_RESPONSE;
314 }
315 }
316
317 return TRANSACTION_END;
318}
diff --git a/drivers/chibios/serial_usart.h b/drivers/chibios/serial_usart.h
deleted file mode 100644
index c64e15566..000000000
--- a/drivers/chibios/serial_usart.h
+++ /dev/null
@@ -1,116 +0,0 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "quantum.h"
20#include "serial.h"
21#include "printf.h"
22
23#include <ch.h>
24#include <hal.h>
25
26#if !defined(SERIAL_USART_DRIVER)
27# define SERIAL_USART_DRIVER SD1
28#endif
29
30#if !defined(USE_GPIOV1)
31/* The default PAL alternate modes are used to signal that the pins are used for USART. */
32# if !defined(SERIAL_USART_TX_PAL_MODE)
33# define SERIAL_USART_TX_PAL_MODE 7
34# endif
35# if !defined(SERIAL_USART_RX_PAL_MODE)
36# define SERIAL_USART_RX_PAL_MODE 7
37# endif
38#endif
39
40#if defined(SOFT_SERIAL_PIN)
41# define SERIAL_USART_TX_PIN SOFT_SERIAL_PIN
42#endif
43
44#if !defined(SERIAL_USART_TX_PIN)
45# define SERIAL_USART_TX_PIN A9
46#endif
47
48#if !defined(SERIAL_USART_RX_PIN)
49# define SERIAL_USART_RX_PIN A10
50#endif
51
52#if !defined(USART_CR1_M0)
53# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
54#endif
55
56#if !defined(SERIAL_USART_CR1)
57# define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
58#endif
59
60#if !defined(SERIAL_USART_CR2)
61# define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
62#endif
63
64#if !defined(SERIAL_USART_CR3)
65# define SERIAL_USART_CR3 0
66#endif
67
68#if defined(USART1_REMAP)
69# define USART_REMAP \
70 do { \
71 (AFIO->MAPR |= AFIO_MAPR_USART1_REMAP); \
72 } while (0)
73#elif defined(USART2_REMAP)
74# define USART_REMAP \
75 do { \
76 (AFIO->MAPR |= AFIO_MAPR_USART2_REMAP); \
77 } while (0)
78#elif defined(USART3_PARTIALREMAP)
79# define USART_REMAP \
80 do { \
81 (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP); \
82 } while (0)
83#elif defined(USART3_FULLREMAP)
84# define USART_REMAP \
85 do { \
86 (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \
87 } while (0)
88#endif
89
90#if !defined(SELECT_SOFT_SERIAL_SPEED)
91# define SELECT_SOFT_SERIAL_SPEED 1
92#endif
93
94#if defined(SERIAL_USART_SPEED)
95// Allow advanced users to directly set SERIAL_USART_SPEED
96#elif SELECT_SOFT_SERIAL_SPEED == 0
97# define SERIAL_USART_SPEED 460800
98#elif SELECT_SOFT_SERIAL_SPEED == 1
99# define SERIAL_USART_SPEED 230400
100#elif SELECT_SOFT_SERIAL_SPEED == 2
101# define SERIAL_USART_SPEED 115200
102#elif SELECT_SOFT_SERIAL_SPEED == 3
103# define SERIAL_USART_SPEED 57600
104#elif SELECT_SOFT_SERIAL_SPEED == 4
105# define SERIAL_USART_SPEED 38400
106#elif SELECT_SOFT_SERIAL_SPEED == 5
107# define SERIAL_USART_SPEED 19200
108#else
109# error invalid SELECT_SOFT_SERIAL_SPEED value
110#endif
111
112#if !defined(SERIAL_USART_TIMEOUT)
113# define SERIAL_USART_TIMEOUT 100
114#endif
115
116#define HANDSHAKE_MAGIC 7
diff --git a/drivers/chibios/spi_master.c b/drivers/chibios/spi_master.c
deleted file mode 100644
index 28ddcbb2b..000000000
--- a/drivers/chibios/spi_master.c
+++ /dev/null
@@ -1,202 +0,0 @@
1/* Copyright 2020 Nick Brassel (tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#include "spi_master.h"
18
19#include "timer.h"
20
21static pin_t currentSlavePin = NO_PIN;
22
23#if defined(K20x) || defined(KL2x)
24static SPIConfig spiConfig = {NULL, 0, 0, 0};
25#else
26static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
27#endif
28
29__attribute__((weak)) void spi_init(void) {
30 static bool is_initialised = false;
31 if (!is_initialised) {
32 is_initialised = true;
33
34 // Try releasing special pins for a short time
35 setPinInput(SPI_SCK_PIN);
36 setPinInput(SPI_MOSI_PIN);
37 setPinInput(SPI_MISO_PIN);
38
39 chThdSleepMilliseconds(10);
40#if defined(USE_GPIOV1)
41 palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_PAL_MODE);
42 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);
43 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);
44#else
45 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);
46 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);
47 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);
48#endif
49 }
50}
51
52bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
53 if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
54 return false;
55 }
56
57 uint16_t roundedDivisor = 2;
58 while (roundedDivisor < divisor) {
59 roundedDivisor <<= 1;
60 }
61
62 if (roundedDivisor < 2 || roundedDivisor > 256) {
63 return false;
64 }
65
66#if defined(K20x) || defined(KL2x)
67 spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
68
69 if (lsbFirst) {
70 spiConfig.tar0 |= SPIx_CTARn_LSBFE;
71 }
72
73 switch (mode) {
74 case 0:
75 break;
76 case 1:
77 spiConfig.tar0 |= SPIx_CTARn_CPHA;
78 break;
79 case 2:
80 spiConfig.tar0 |= SPIx_CTARn_CPOL;
81 break;
82 case 3:
83 spiConfig.tar0 |= SPIx_CTARn_CPHA | SPIx_CTARn_CPOL;
84 break;
85 }
86
87 switch (roundedDivisor) {
88 case 2:
89 spiConfig.tar0 |= SPIx_CTARn_BR(0);
90 break;
91 case 4:
92 spiConfig.tar0 |= SPIx_CTARn_BR(1);
93 break;
94 case 8:
95 spiConfig.tar0 |= SPIx_CTARn_BR(3);
96 break;
97 case 16:
98 spiConfig.tar0 |= SPIx_CTARn_BR(4);
99 break;
100 case 32:
101 spiConfig.tar0 |= SPIx_CTARn_BR(5);
102 break;
103 case 64:
104 spiConfig.tar0 |= SPIx_CTARn_BR(6);
105 break;
106 case 128:
107 spiConfig.tar0 |= SPIx_CTARn_BR(7);
108 break;
109 case 256:
110 spiConfig.tar0 |= SPIx_CTARn_BR(8);
111 break;
112 }
113#else
114 spiConfig.cr1 = 0;
115
116 if (lsbFirst) {
117 spiConfig.cr1 |= SPI_CR1_LSBFIRST;
118 }
119
120 switch (mode) {
121 case 0:
122 break;
123 case 1:
124 spiConfig.cr1 |= SPI_CR1_CPHA;
125 break;
126 case 2:
127 spiConfig.cr1 |= SPI_CR1_CPOL;
128 break;
129 case 3:
130 spiConfig.cr1 |= SPI_CR1_CPHA | SPI_CR1_CPOL;
131 break;
132 }
133
134 switch (roundedDivisor) {
135 case 2:
136 break;
137 case 4:
138 spiConfig.cr1 |= SPI_CR1_BR_0;
139 break;
140 case 8:
141 spiConfig.cr1 |= SPI_CR1_BR_1;
142 break;
143 case 16:
144 spiConfig.cr1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
145 break;
146 case 32:
147 spiConfig.cr1 |= SPI_CR1_BR_2;
148 break;
149 case 64:
150 spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
151 break;
152 case 128:
153 spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
154 break;
155 case 256:
156 spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0;
157 break;
158 }
159#endif
160
161 currentSlavePin = slavePin;
162 spiConfig.ssport = PAL_PORT(slavePin);
163 spiConfig.sspad = PAL_PAD(slavePin);
164
165 setPinOutput(slavePin);
166 spiStart(&SPI_DRIVER, &spiConfig);
167 spiSelect(&SPI_DRIVER);
168
169 return true;
170}
171
172spi_status_t spi_write(uint8_t data) {
173 uint8_t rxData;
174 spiExchange(&SPI_DRIVER, 1, &data, &rxData);
175
176 return rxData;
177}
178
179spi_status_t spi_read(void) {
180 uint8_t data = 0;
181 spiReceive(&SPI_DRIVER, 1, &data);
182
183 return data;
184}
185
186spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
187 spiSend(&SPI_DRIVER, length, data);
188 return SPI_STATUS_SUCCESS;
189}
190
191spi_status_t spi_receive(uint8_t *data, uint16_t length) {
192 spiReceive(&SPI_DRIVER, length, data);
193 return SPI_STATUS_SUCCESS;
194}
195
196void spi_stop(void) {
197 if (currentSlavePin != NO_PIN) {
198 spiUnselect(&SPI_DRIVER);
199 spiStop(&SPI_DRIVER);
200 currentSlavePin = NO_PIN;
201 }
202}
diff --git a/drivers/chibios/spi_master.h b/drivers/chibios/spi_master.h
deleted file mode 100644
index b5a6ef143..000000000
--- a/drivers/chibios/spi_master.h
+++ /dev/null
@@ -1,93 +0,0 @@
1/* Copyright 2020 Nick Brassel (tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <ch.h>
20#include <hal.h>
21#include <stdbool.h>
22
23#include "gpio.h"
24#include "chibios_config.h"
25
26#ifndef SPI_DRIVER
27# define SPI_DRIVER SPID2
28#endif
29
30#ifndef SPI_SCK_PIN
31# define SPI_SCK_PIN B13
32#endif
33
34#ifndef SPI_SCK_PAL_MODE
35# if defined(USE_GPIOV1)
36# define SPI_SCK_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
37# else
38# define SPI_SCK_PAL_MODE 5
39# endif
40#endif
41
42#ifndef SPI_MOSI_PIN
43# define SPI_MOSI_PIN B15
44#endif
45
46#ifndef SPI_MOSI_PAL_MODE
47# if defined(USE_GPIOV1)
48# define SPI_MOSI_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
49# else
50# define SPI_MOSI_PAL_MODE 5
51# endif
52#endif
53
54#ifndef SPI_MISO_PIN
55# define SPI_MISO_PIN B14
56#endif
57
58#ifndef SPI_MISO_PAL_MODE
59# if defined(USE_GPIOV1)
60# define SPI_MISO_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
61# else
62# define SPI_MISO_PAL_MODE 5
63# endif
64#endif
65
66typedef int16_t spi_status_t;
67
68#define SPI_STATUS_SUCCESS (0)
69#define SPI_STATUS_ERROR (-1)
70#define SPI_STATUS_TIMEOUT (-2)
71
72#define SPI_TIMEOUT_IMMEDIATE (0)
73#define SPI_TIMEOUT_INFINITE (0xFFFF)
74
75#ifdef __cplusplus
76extern "C" {
77#endif
78void spi_init(void);
79
80bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
81
82spi_status_t spi_write(uint8_t data);
83
84spi_status_t spi_read(void);
85
86spi_status_t spi_transmit(const uint8_t *data, uint16_t length);
87
88spi_status_t spi_receive(uint8_t *data, uint16_t length);
89
90void spi_stop(void);
91#ifdef __cplusplus
92}
93#endif
diff --git a/drivers/chibios/uart.c b/drivers/chibios/uart.c
deleted file mode 100644
index 030335b34..000000000
--- a/drivers/chibios/uart.c
+++ /dev/null
@@ -1,50 +0,0 @@
1/* Copyright 2021
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#include "uart.h"
18
19#include "quantum.h"
20
21static SerialConfig serialConfig = {SERIAL_DEFAULT_BITRATE, SD1_CR1, SD1_CR2, SD1_CR3};
22
23void uart_init(uint32_t baud) {
24 static bool is_initialised = false;
25
26 if (!is_initialised) {
27 is_initialised = true;
28
29 serialConfig.speed = baud;
30
31#if defined(USE_GPIOV1)
32 palSetLineMode(SD1_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
33 palSetLineMode(SD1_RX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
34#else
35 palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
36 palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
37#endif
38 sdStart(&SERIAL_DRIVER, &serialConfig);
39 }
40}
41
42void uart_putchar(uint8_t c) { sdPut(&SERIAL_DRIVER, c); }
43
44uint8_t uart_getchar(void) {
45 msg_t res = sdGet(&SERIAL_DRIVER);
46
47 return (uint8_t)res;
48}
49
50bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); }
diff --git a/drivers/chibios/uart.h b/drivers/chibios/uart.h
deleted file mode 100644
index b4e20e9fd..000000000
--- a/drivers/chibios/uart.h
+++ /dev/null
@@ -1,77 +0,0 @@
1/* Copyright 2021
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <stdint.h>
20
21#include <hal.h>
22
23#ifndef SERIAL_DRIVER
24# define SERIAL_DRIVER SD1
25#endif
26
27#ifndef SD1_TX_PIN
28# define SD1_TX_PIN A9
29#endif
30
31#ifndef SD1_TX_PAL_MODE
32# define SD1_TX_PAL_MODE 7
33#endif
34
35#ifndef SD1_RX_PIN
36# define SD1_RX_PIN A10
37#endif
38
39#ifndef SD1_RX_PAL_MODE
40# define SD1_RX_PAL_MODE 7
41#endif
42
43#ifndef SD1_CTS_PIN
44# define SD1_CTS_PIN A11
45#endif
46
47#ifndef SD1_CTS_PAL_MODE
48# define SD1_CTS_PAL_MODE 7
49#endif
50
51#ifndef SD1_RTS_PIN
52# define SD1_RTS_PIN A12
53#endif
54
55#ifndef SD1_RTS_PAL_MODE
56# define SD1_RTS_PAL_MODE 7
57#endif
58
59#ifndef SD1_CR1
60# define SD1_CR1 0
61#endif
62
63#ifndef SD1_CR2
64# define SD1_CR2 0
65#endif
66
67#ifndef SD1_CR3
68# define SD1_CR3 0
69#endif
70
71void uart_init(uint32_t baud);
72
73void uart_putchar(uint8_t c);
74
75uint8_t uart_getchar(void);
76
77bool uart_available(void);
diff --git a/drivers/chibios/usbpd_stm32g4.c b/drivers/chibios/usbpd_stm32g4.c
deleted file mode 100644
index f16ca8aea..000000000
--- a/drivers/chibios/usbpd_stm32g4.c
+++ /dev/null
@@ -1,76 +0,0 @@
1/* Copyright 2021 Nick Brassel (@tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <quantum.h>
18
19#ifndef USBPD_UCPD1_CFG1
20# define USBPD_UCPD1_CFG1 (UCPD_CFG1_PSC_UCPDCLK_0 | UCPD_CFG1_TRANSWIN_3 | UCPD_CFG1_IFRGAP_4 | UCPD_CFG1_HBITCLKDIV_4)
21#endif // USBPD_UCPD1_CFG1
22
23// Initialises the USBPD subsystem
24__attribute__((weak)) void usbpd_init(void) {
25 // Disable dead-battery signals
26 PWR->CR3 |= PWR_CR3_UCPD_DBDIS;
27 // Enable the clock for the UCPD1 peripheral
28 RCC->APB1ENR2 |= RCC_APB1ENR2_UCPD1EN;
29
30 // Copy the existing value
31 uint32_t CFG1 = UCPD1->CFG1;
32 // Force-disable UCPD1 before configuring
33 CFG1 &= ~UCPD_CFG1_UCPDEN;
34 // Configure UCPD1
35 CFG1 = USBPD_UCPD1_CFG1;
36 // Apply the changes
37 UCPD1->CFG1 = CFG1;
38 // Enable UCPD1
39 UCPD1->CFG1 |= UCPD_CFG1_UCPDEN;
40
41 // Copy the existing value
42 uint32_t CR = UCPD1->CR;
43 // Clear out ANASUBMODE (irrelevant as a sink device)
44 CR &= ~UCPD_CR_ANASUBMODE_Msk;
45 // Advertise our capabilities as a sink, with both CC lines enabled
46 CR |= UCPD_CR_ANAMODE | UCPD_CR_CCENABLE_Msk;
47 // Apply the changes
48 UCPD1->CR = CR;
49}
50
51// Gets the current state of the USBPD allowance
52__attribute__((weak)) usbpd_allowance_t usbpd_get_allowance(void) {
53 uint32_t CR = UCPD1->CR;
54
55 int ucpd_enabled = (UCPD1->CFG1 & UCPD_CFG1_UCPDEN_Msk) >> UCPD_CFG1_UCPDEN_Pos;
56 int anamode = (CR & UCPD_CR_ANAMODE_Msk) >> UCPD_CR_ANAMODE_Pos;
57 int cc_enabled = (CR & UCPD_CR_CCENABLE_Msk) >> UCPD_CR_CCENABLE_Pos;
58
59 if (ucpd_enabled && anamode && cc_enabled) {
60 uint32_t SR = UCPD1->SR;
61 int vstate_cc1 = (SR & UCPD_SR_TYPEC_VSTATE_CC1_Msk) >> UCPD_SR_TYPEC_VSTATE_CC1_Pos;
62 int vstate_cc2 = (SR & UCPD_SR_TYPEC_VSTATE_CC2_Msk) >> UCPD_SR_TYPEC_VSTATE_CC2_Pos;
63 int vstate_max = vstate_cc1 > vstate_cc2 ? vstate_cc1 : vstate_cc2;
64 switch (vstate_max) {
65 case 0:
66 case 1:
67 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.
68 case 2:
69 return USBPD_1500MA;
70 case 3:
71 return USBPD_3000MA;
72 }
73 }
74
75 return USBPD_500MA;
76} \ No newline at end of file
diff --git a/drivers/chibios/ws2812.c b/drivers/chibios/ws2812.c
deleted file mode 100644
index 0d12e2fb7..000000000
--- a/drivers/chibios/ws2812.c
+++ /dev/null
@@ -1,114 +0,0 @@
1#include "quantum.h"
2#include "ws2812.h"
3#include <ch.h>
4#include <hal.h>
5
6/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
7
8#ifndef NOP_FUDGE
9# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX)
10# define NOP_FUDGE 0.4
11# else
12# error("NOP_FUDGE configuration required")
13# define NOP_FUDGE 1 // this just pleases the compile so the above error is easier to spot
14# endif
15#endif
16
17// Push Pull or Open Drain Configuration
18// Default Push Pull
19#ifndef WS2812_EXTERNAL_PULLUP
20# define WS2812_OUTPUT_MODE PAL_MODE_OUTPUT_PUSHPULL
21#else
22# define WS2812_OUTPUT_MODE PAL_MODE_OUTPUT_OPENDRAIN
23#endif
24
25#define NUMBER_NOPS 6
26#define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE)
27#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
28#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
29#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)
30
31#define wait_ns(x) \
32 do { \
33 for (int i = 0; i < NS_TO_CYCLES(x); i++) { \
34 __asm__ volatile("nop\n\t" \
35 "nop\n\t" \
36 "nop\n\t" \
37 "nop\n\t" \
38 "nop\n\t" \
39 "nop\n\t"); \
40 } \
41 } while (0)
42
43// These are the timing constraints taken mostly from the WS2812 datasheets
44// These are chosen to be conservative and avoid problems rather than for maximum throughput
45
46#define T1H 900 // Width of a 1 bit in ns
47#define T1L (1250 - T1H) // Width of a 1 bit in ns
48
49#define T0H 350 // Width of a 0 bit in ns
50#define T0L (1250 - T0H) // Width of a 0 bit in ns
51
52// The reset gap can be 6000 ns, but depending on the LED strip it may have to be increased
53// to values like 600000 ns. If it is too small, the pixels will show nothing most of the time.
54#define RES (1000 * WS2812_TRST_US) // Width of the low gap between bits to cause a frame to latch
55
56void sendByte(uint8_t byte) {
57 // WS2812 protocol wants most significant bits first
58 for (unsigned char bit = 0; bit < 8; bit++) {
59 bool is_one = byte & (1 << (7 - bit));
60 // using something like wait_ns(is_one ? T1L : T0L) here throws off timings
61 if (is_one) {
62 // 1
63 writePinHigh(RGB_DI_PIN);
64 wait_ns(T1H);
65 writePinLow(RGB_DI_PIN);
66 wait_ns(T1L);
67 } else {
68 // 0
69 writePinHigh(RGB_DI_PIN);
70 wait_ns(T0H);
71 writePinLow(RGB_DI_PIN);
72 wait_ns(T0L);
73 }
74 }
75}
76
77void ws2812_init(void) { palSetLineMode(RGB_DI_PIN, WS2812_OUTPUT_MODE); }
78
79// Setleds for standard RGB
80void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
81 static bool s_init = false;
82 if (!s_init) {
83 ws2812_init();
84 s_init = true;
85 }
86
87 // this code is very time dependent, so we need to disable interrupts
88 chSysLock();
89
90 for (uint8_t i = 0; i < leds; i++) {
91 // WS2812 protocol dictates grb order
92#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
93 sendByte(ledarray[i].g);
94 sendByte(ledarray[i].r);
95 sendByte(ledarray[i].b);
96#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
97 sendByte(ledarray[i].r);
98 sendByte(ledarray[i].g);
99 sendByte(ledarray[i].b);
100#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
101 sendByte(ledarray[i].b);
102 sendByte(ledarray[i].g);
103 sendByte(ledarray[i].r);
104#endif
105
106#ifdef RGBW
107 sendByte(ledarray[i].w);
108#endif
109 }
110
111 wait_ns(RES);
112
113 chSysUnlock();
114}
diff --git a/drivers/chibios/ws2812_pwm.c b/drivers/chibios/ws2812_pwm.c
deleted file mode 100644
index e6af55b6b..000000000
--- a/drivers/chibios/ws2812_pwm.c
+++ /dev/null
@@ -1,311 +0,0 @@
1#include "ws2812.h"
2#include "quantum.h"
3#include <hal.h>
4
5/* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */
6
7#ifdef RGBW
8# error "RGBW not supported"
9#endif
10
11#ifndef WS2812_PWM_DRIVER
12# define WS2812_PWM_DRIVER PWMD2 // TIMx
13#endif
14#ifndef WS2812_PWM_CHANNEL
15# define WS2812_PWM_CHANNEL 2 // Channel
16#endif
17#ifndef WS2812_PWM_PAL_MODE
18# define WS2812_PWM_PAL_MODE 2 // DI Pin's alternate function value
19#endif
20#ifndef WS2812_DMA_STREAM
21# define WS2812_DMA_STREAM STM32_DMA1_STREAM2 // DMA Stream for TIMx_UP
22#endif
23#ifndef WS2812_DMA_CHANNEL
24# define WS2812_DMA_CHANNEL 2 // DMA Channel for TIMx_UP
25#endif
26#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_DMAMUX_ID)
27# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM?_UP"
28#endif
29
30#ifndef WS2812_PWM_COMPLEMENTARY_OUTPUT
31# define WS2812_PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_HIGH
32#else
33# if !STM32_PWM_USE_ADVANCED
34# error "WS2812_PWM_COMPLEMENTARY_OUTPUT requires STM32_PWM_USE_ADVANCED == TRUE"
35# endif
36# define WS2812_PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH
37#endif
38
39// Push Pull or Open Drain Configuration
40// Default Push Pull
41#ifndef WS2812_EXTERNAL_PULLUP
42# if defined(USE_GPIOV1)
43# define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
44# else
45# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING
46# endif
47#else
48# if defined(USE_GPIOV1)
49# define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN
50# else
51# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING
52# endif
53#endif
54
55#ifndef WS2812_PWM_TARGET_PERIOD
56//# define WS2812_PWM_TARGET_PERIOD 800000 // Original code is 800k...?
57# define WS2812_PWM_TARGET_PERIOD 80000 // TODO: work out why 10x less on f303/f4x1
58#endif
59
60/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
61
62#define WS2812_PWM_FREQUENCY (STM32_SYSCLK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */
63#define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */
64
65/**
66 * @brief Number of bit-periods to hold the data line low at the end of a frame
67 *
68 * The reset period for each frame is defined in WS2812_TRST_US.
69 * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit:
70 */
71#define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250)
72#define WS2812_COLOR_BIT_N (RGBLED_NUM * 24) /**< Number of data bits */
73#define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */
74
75/**
76 * @brief High period for a zero, in ticks
77 *
78 * Per the datasheet:
79 * WS2812:
80 * - T0H: 200 nS to 500 nS, inclusive
81 * - T0L: 650 nS to 950 nS, inclusive
82 * WS2812B:
83 * - T0H: 200 nS to 500 nS, inclusive
84 * - T0L: 750 nS to 1050 nS, inclusive
85 *
86 * The duty cycle is calculated for a high period of 350 nS.
87 */
88#define WS2812_DUTYCYCLE_0 (WS2812_PWM_FREQUENCY / (1000000000 / 350))
89
90/**
91 * @brief High period for a one, in ticks
92 *
93 * Per the datasheet:
94 * WS2812:
95 * - T1H: 550 nS to 850 nS, inclusive
96 * - T1L: 450 nS to 750 nS, inclusive
97 * WS2812B:
98 * - T1H: 750 nS to 1050 nS, inclusive
99 * - T1L: 200 nS to 500 nS, inclusive
100 *
101 * The duty cycle is calculated for a high period of 800 nS.
102 * This is in the middle of the specifications of the WS2812 and WS2812B.
103 */
104#define WS2812_DUTYCYCLE_1 (WS2812_PWM_FREQUENCY / (1000000000 / 800))
105
106/* --- PRIVATE MACROS ------------------------------------------------------- */
107
108/**
109 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given bit
110 *
111 * @param[in] led: The led index [0, @ref RGBLED_NUM)
112 * @param[in] byte: The byte number [0, 2]
113 * @param[in] bit: The bit number [0, 7]
114 *
115 * @return The bit index
116 */
117#define WS2812_BIT(led, byte, bit) (24 * (led) + 8 * (byte) + (7 - (bit)))
118
119#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
120/**
121 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given red bit
122 *
123 * @note The red byte is the middle byte in the color packet
124 *
125 * @param[in] led: The led index [0, @ref RGBLED_NUM)
126 * @param[in] bit: The bit number [0, 7]
127 *
128 * @return The bit index
129 */
130# define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 1, (bit))
131
132/**
133 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given green bit
134 *
135 * @note The red byte is the first byte in the color packet
136 *
137 * @param[in] led: The led index [0, @ref RGBLED_NUM)
138 * @param[in] bit: The bit number [0, 7]
139 *
140 * @return The bit index
141 */
142# define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 0, (bit))
143
144/**
145 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given blue bit
146 *
147 * @note The red byte is the last byte in the color packet
148 *
149 * @param[in] led: The led index [0, @ref RGBLED_NUM)
150 * @param[in] bit: The bit index [0, 7]
151 *
152 * @return The bit index
153 */
154# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit))
155
156#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
157/**
158 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given red bit
159 *
160 * @note The red byte is the middle byte in the color packet
161 *
162 * @param[in] led: The led index [0, @ref RGBLED_NUM)
163 * @param[in] bit: The bit number [0, 7]
164 *
165 * @return The bit index
166 */
167# define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 0, (bit))
168
169/**
170 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given green bit
171 *
172 * @note The red byte is the first byte in the color packet
173 *
174 * @param[in] led: The led index [0, @ref RGBLED_NUM)
175 * @param[in] bit: The bit number [0, 7]
176 *
177 * @return The bit index
178 */
179# define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 1, (bit))
180
181/**
182 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given blue bit
183 *
184 * @note The red byte is the last byte in the color packet
185 *
186 * @param[in] led: The led index [0, @ref RGBLED_NUM)
187 * @param[in] bit: The bit index [0, 7]
188 *
189 * @return The bit index
190 */
191# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit))
192
193#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
194/**
195 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given red bit
196 *
197 * @note The red byte is the middle byte in the color packet
198 *
199 * @param[in] led: The led index [0, @ref RGBLED_NUM)
200 * @param[in] bit: The bit number [0, 7]
201 *
202 * @return The bit index
203 */
204# define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 2, (bit))
205
206/**
207 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given green bit
208 *
209 * @note The red byte is the first byte in the color packet
210 *
211 * @param[in] led: The led index [0, @ref RGBLED_NUM)
212 * @param[in] bit: The bit number [0, 7]
213 *
214 * @return The bit index
215 */
216# define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 1, (bit))
217
218/**
219 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given blue bit
220 *
221 * @note The red byte is the last byte in the color packet
222 *
223 * @param[in] led: The led index [0, @ref RGBLED_NUM)
224 * @param[in] bit: The bit index [0, 7]
225 *
226 * @return The bit index
227 */
228# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit))
229#endif
230
231/* --- PRIVATE VARIABLES ---------------------------------------------------- */
232
233static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */
234
235/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
236/*
237 * Gedanke: Double-buffer type transactions: double buffer transfers using two memory pointers for
238the memory (while the DMA is reading/writing from/to a buffer, the application can
239write/read to/from the other buffer).
240 */
241
242void ws2812_init(void) {
243 // Initialize led frame buffer
244 uint32_t i;
245 for (i = 0; i < WS2812_COLOR_BIT_N; i++) ws2812_frame_buffer[i] = WS2812_DUTYCYCLE_0; // All color bits are zero duty cycle
246 for (i = 0; i < WS2812_RESET_BIT_N; i++) ws2812_frame_buffer[i + WS2812_COLOR_BIT_N] = 0; // All reset bits are zero
247
248 palSetLineMode(RGB_DI_PIN, WS2812_OUTPUT_MODE);
249
250 // PWM Configuration
251 //#pragma GCC diagnostic ignored "-Woverride-init" // Turn off override-init warning for this struct. We use the overriding ability to set a "default" channel config
252 static const PWMConfig ws2812_pwm_config = {
253 .frequency = WS2812_PWM_FREQUENCY,
254 .period = WS2812_PWM_PERIOD, // Mit dieser Periode wird UDE-Event erzeugt und ein neuer Wert (Länge WS2812_BIT_N) vom DMA ins CCR geschrieben
255 .callback = NULL,
256 .channels =
257 {
258 [0 ... 3] = {.mode = PWM_OUTPUT_DISABLED, .callback = NULL}, // Channels default to disabled
259 [WS2812_PWM_CHANNEL - 1] = {.mode = WS2812_PWM_OUTPUT_MODE, .callback = NULL}, // Turn on the channel we care about
260 },
261 .cr2 = 0,
262 .dier = TIM_DIER_UDE, // DMA on update event for next period
263 };
264 //#pragma GCC diagnostic pop // Restore command-line warning options
265
266 // Configure DMA
267 // dmaInit(); // Joe added this
268 dmaStreamAlloc(WS2812_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL);
269 dmaStreamSetPeripheral(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
270 dmaStreamSetMemory0(WS2812_DMA_STREAM, ws2812_frame_buffer);
271 dmaStreamSetTransactionSize(WS2812_DMA_STREAM, WS2812_BIT_N);
272 dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3));
273 // M2P: Memory 2 Periph; PL: Priority Level
274
275#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE)
276 // If the MCU has a DMAMUX we need to assign the correct resource
277 dmaSetRequestSource(WS2812_DMA_STREAM, WS2812_DMAMUX_ID);
278#endif
279
280 // Start DMA
281 dmaStreamEnable(WS2812_DMA_STREAM);
282
283 // Configure PWM
284 // NOTE: It's required that preload be enabled on the timer channel CCR register. This is currently enabled in the
285 // ChibiOS driver code, so we don't have to do anything special to the timer. If we did, we'd have to start the timer,
286 // disable counting, enable the channel, and then make whatever configuration changes we need.
287 pwmStart(&WS2812_PWM_DRIVER, &ws2812_pwm_config);
288 pwmEnableChannel(&WS2812_PWM_DRIVER, WS2812_PWM_CHANNEL - 1, 0); // Initial period is 0; output will be low until first duty cycle is DMA'd in
289}
290
291void ws2812_write_led(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b) {
292 // Write color to frame buffer
293 for (uint8_t bit = 0; bit < 8; bit++) {
294 ws2812_frame_buffer[WS2812_RED_BIT(led_number, bit)] = ((r >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
295 ws2812_frame_buffer[WS2812_GREEN_BIT(led_number, bit)] = ((g >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
296 ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
297 }
298}
299
300// Setleds for standard RGB
301void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
302 static bool s_init = false;
303 if (!s_init) {
304 ws2812_init();
305 s_init = true;
306 }
307
308 for (uint16_t i = 0; i < leds; i++) {
309 ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b);
310 }
311}
diff --git a/drivers/chibios/ws2812_spi.c b/drivers/chibios/ws2812_spi.c
deleted file mode 100644
index 377a929b9..000000000
--- a/drivers/chibios/ws2812_spi.c
+++ /dev/null
@@ -1,159 +0,0 @@
1#include "quantum.h"
2#include "ws2812.h"
3
4/* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */
5
6#ifdef RGBW
7# error "RGBW not supported"
8#endif
9
10// Define the spi your LEDs are plugged to here
11#ifndef WS2812_SPI
12# define WS2812_SPI SPID1
13#endif
14
15#ifndef WS2812_SPI_MOSI_PAL_MODE
16# define WS2812_SPI_MOSI_PAL_MODE 5
17#endif
18
19#ifndef WS2812_SPI_SCK_PAL_MODE
20# define WS2812_SPI_SCK_PAL_MODE 5
21#endif
22
23// Push Pull or Open Drain Configuration
24// Default Push Pull
25#ifndef WS2812_EXTERNAL_PULLUP
26# if defined(USE_GPIOV1)
27# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
28# else
29# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL
30# endif
31#else
32# if defined(USE_GPIOV1)
33# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN
34# else
35# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN
36# endif
37#endif
38
39// Define SPI config speed
40// baudrate should target 3.2MHz
41// F072 fpclk = 48MHz
42// 48/16 = 3Mhz
43#if WS2812_SPI_DIVISOR == 2
44# define WS2812_SPI_DIVISOR (0)
45#elif WS2812_SPI_DIVISOR == 4
46# define WS2812_SPI_DIVISOR (SPI_CR1_BR_0)
47#elif WS2812_SPI_DIVISOR == 8
48# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1)
49#elif WS2812_SPI_DIVISOR == 16 // same as default
50# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0)
51#elif WS2812_SPI_DIVISOR == 32
52# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2)
53#elif WS2812_SPI_DIVISOR == 64
54# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_0)
55#elif WS2812_SPI_DIVISOR == 128
56# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1)
57#elif WS2812_SPI_DIVISOR == 256
58# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
59#else
60# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0) // default
61#endif
62
63// Use SPI circular buffer
64#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
65# define WS2812_SPI_BUFFER_MODE 1 // circular buffer
66#else
67# define WS2812_SPI_BUFFER_MODE 0 // normal buffer
68#endif
69
70#if defined(USE_GPIOV1)
71# define WS2812_SCK_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
72#else
73# define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL
74#endif
75
76#define BYTES_FOR_LED_BYTE 4
77#define NB_COLORS 3
78#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
79#define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM)
80#define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250))
81#define PREAMBLE_SIZE 4
82
83static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE] = {0};
84
85/*
86 * As the trick here is to use the SPI to send a huge pattern of 0 and 1 to
87 * the ws2812b protocol, we use this helper function to translate bytes into
88 * 0s and 1s for the LED (with the appropriate timing).
89 */
90static uint8_t get_protocol_eq(uint8_t data, int pos) {
91 uint8_t eq = 0;
92 if (data & (1 << (2 * (3 - pos))))
93 eq = 0b1110;
94 else
95 eq = 0b1000;
96 if (data & (2 << (2 * (3 - pos))))
97 eq += 0b11100000;
98 else
99 eq += 0b10000000;
100 return eq;
101}
102
103static void set_led_color_rgb(LED_TYPE color, int pos) {
104 uint8_t* tx_start = &txbuf[PREAMBLE_SIZE];
105
106#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
107 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j);
108 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j);
109 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);
110#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
111 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.r, j);
112 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
113 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);
114#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
115 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.b, j);
116 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
117 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j);
118#endif
119}
120
121void ws2812_init(void) {
122 palSetLineMode(RGB_DI_PIN, WS2812_MOSI_OUTPUT_MODE);
123
124#ifdef WS2812_SPI_SCK_PIN
125 palSetLineMode(WS2812_SPI_SCK_PIN, WS2812_SCK_OUTPUT_MODE);
126#endif // WS2812_SPI_SCK_PIN
127
128 // TODO: more dynamic baudrate
129 static const SPIConfig spicfg = {WS2812_SPI_BUFFER_MODE, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN), WS2812_SPI_DIVISOR};
130
131 spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
132 spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
133 spiSelect(&WS2812_SPI); /* Slave Select assertion. */
134#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
135 spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
136#endif
137}
138
139void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
140 static bool s_init = false;
141 if (!s_init) {
142 ws2812_init();
143 s_init = true;
144 }
145
146 for (uint8_t i = 0; i < leds; i++) {
147 set_led_color_rgb(ledarray[i], i);
148 }
149
150 // Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
151 // Instead spiSend can be used to send synchronously (or the thread logic can be added back).
152#ifndef WS2812_SPI_USE_CIRCULAR_BUFFER
153# ifdef WS2812_SPI_SYNC
154 spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
155# else
156 spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
157# endif
158#endif
159}
diff --git a/drivers/eeprom/eeprom_stm32_L0_L1.c b/drivers/eeprom/eeprom_stm32_L0_L1.c
deleted file mode 100644
index ed26cc714..000000000
--- a/drivers/eeprom/eeprom_stm32_L0_L1.c
+++ /dev/null
@@ -1,96 +0,0 @@
1/* Copyright 2020 Nick Brassel (tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <stdint.h>
18#include <string.h>
19
20#include <hal.h>
21#include "eeprom_driver.h"
22#include "eeprom_stm32_L0_L1.h"
23
24#define EEPROM_BASE_ADDR 0x08080000
25#define EEPROM_ADDR(offset) (EEPROM_BASE_ADDR + (offset))
26#define EEPROM_PTR(offset) ((__IO uint8_t *)EEPROM_ADDR(offset))
27#define EEPROM_BYTE(location, offset) (*(EEPROM_PTR(((uint32_t)location) + ((uint32_t)offset))))
28
29#define BUFFER_BYTE(buffer, offset) (*(((uint8_t *)buffer) + offset))
30
31#define FLASH_PEKEY1 0x89ABCDEF
32#define FLASH_PEKEY2 0x02030405
33
34static inline void STM32_L0_L1_EEPROM_WaitNotBusy(void) {
35 while (FLASH->SR & FLASH_SR_BSY) {
36 __WFI();
37 }
38}
39
40static inline void STM32_L0_L1_EEPROM_Unlock(void) {
41 STM32_L0_L1_EEPROM_WaitNotBusy();
42 if (FLASH->PECR & FLASH_PECR_PELOCK) {
43 FLASH->PEKEYR = FLASH_PEKEY1;
44 FLASH->PEKEYR = FLASH_PEKEY2;
45 }
46}
47
48static inline void STM32_L0_L1_EEPROM_Lock(void) {
49 STM32_L0_L1_EEPROM_WaitNotBusy();
50 FLASH->PECR |= FLASH_PECR_PELOCK;
51}
52
53void eeprom_driver_init(void) {}
54
55void eeprom_driver_erase(void) {
56 STM32_L0_L1_EEPROM_Unlock();
57
58 for (size_t offset = 0; offset < STM32_ONBOARD_EEPROM_SIZE; offset += sizeof(uint32_t)) {
59 FLASH->PECR |= FLASH_PECR_ERASE | FLASH_PECR_DATA;
60
61 *(__IO uint32_t *)EEPROM_ADDR(offset) = (uint32_t)0;
62
63 STM32_L0_L1_EEPROM_WaitNotBusy();
64 FLASH->PECR &= ~(FLASH_PECR_ERASE | FLASH_PECR_DATA);
65 }
66
67 STM32_L0_L1_EEPROM_Lock();
68}
69
70void eeprom_read_block(void *buf, const void *addr, size_t len) {
71 for (size_t offset = 0; offset < len; ++offset) {
72 // Drop out if we've hit the limit of the EEPROM
73 if ((((uint32_t)addr) + offset) >= STM32_ONBOARD_EEPROM_SIZE) {
74 break;
75 }
76
77 STM32_L0_L1_EEPROM_WaitNotBusy();
78 BUFFER_BYTE(buf, offset) = EEPROM_BYTE(addr, offset);
79 }
80}
81
82void eeprom_write_block(const void *buf, void *addr, size_t len) {
83 STM32_L0_L1_EEPROM_Unlock();
84
85 for (size_t offset = 0; offset < len; ++offset) {
86 // Drop out if we've hit the limit of the EEPROM
87 if ((((uint32_t)addr) + offset) >= STM32_ONBOARD_EEPROM_SIZE) {
88 break;
89 }
90
91 STM32_L0_L1_EEPROM_WaitNotBusy();
92 EEPROM_BYTE(addr, offset) = BUFFER_BYTE(buf, offset);
93 }
94
95 STM32_L0_L1_EEPROM_Lock();
96}
diff --git a/drivers/eeprom/eeprom_stm32_L0_L1.h b/drivers/eeprom/eeprom_stm32_L0_L1.h
deleted file mode 100644
index a35defca8..000000000
--- a/drivers/eeprom/eeprom_stm32_L0_L1.h
+++ /dev/null
@@ -1,33 +0,0 @@
1/* Copyright 2020 Nick Brassel (tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19/*
20 The size used by the STM32 L0/L1 EEPROM driver.
21*/
22#ifndef STM32_ONBOARD_EEPROM_SIZE
23# ifdef VIA_ENABLE
24# define STM32_ONBOARD_EEPROM_SIZE 1024
25# else
26# include "eeconfig.h"
27# define STM32_ONBOARD_EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO and EEPROM page sizing
28# endif
29#endif
30
31#if STM32_ONBOARD_EEPROM_SIZE > 128
32# pragma message("Please note: resetting EEPROM using an STM32L0/L1 device takes up to 1 second for every 1kB of internal EEPROM used.")
33#endif