aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/apa102/apa102.c151
-rw-r--r--drivers/apa102/apa102.h (renamed from drivers/avr/apa102.h)32
-rw-r--r--drivers/avr/apa102.c96
-rw-r--r--drivers/chibios/serial_usart.c13
-rw-r--r--drivers/qwiic/qwiic.mk9
5 files changed, 178 insertions, 123 deletions
diff --git a/drivers/apa102/apa102.c b/drivers/apa102/apa102.c
new file mode 100644
index 000000000..7396dc3c5
--- /dev/null
+++ b/drivers/apa102/apa102.c
@@ -0,0 +1,151 @@
1/* Copyright 2020 Aldehir Rojas
2 * Copyright 2017 Mikkel (Duckle29)
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#include "apa102.h"
19#include "quantum.h"
20
21#ifndef APA102_NOPS
22# if defined(__AVR__)
23# define APA102_NOPS 0 // AVR at 16 MHz already spends 62.5 ns per clock, so no extra delay is needed
24# elif defined(PROTOCOL_CHIBIOS)
25
26# include "hal.h"
27# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX)
28# define APA102_NOPS (100 / (1000000000L / (STM32_SYSCLK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns
29# else
30# error("APA102_NOPS configuration required")
31# define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot
32# endif
33# endif
34#endif
35
36#define io_wait \
37 do { \
38 for (int i = 0; i < APA102_NOPS; i++) { \
39 __asm__ volatile("nop\n\t" \
40 "nop\n\t" \
41 "nop\n\t" \
42 "nop\n\t"); \
43 } \
44 } while (0)
45
46#define APA102_SEND_BIT(byte, bit) \
47 do { \
48 writePin(RGB_DI_PIN, (byte >> bit) & 1); \
49 io_wait; \
50 writePinHigh(RGB_CI_PIN); \
51 io_wait; \
52 writePinLow(RGB_CI_PIN); \
53 io_wait; \
54 } while (0)
55
56uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS;
57
58void static apa102_start_frame(void);
59void static apa102_end_frame(uint16_t num_leds);
60
61void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness);
62void static apa102_send_byte(uint8_t byte);
63
64void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds) {
65 LED_TYPE *end = start_led + num_leds;
66
67 apa102_start_frame();
68 for (LED_TYPE *led = start_led; led < end; led++) {
69 apa102_send_frame(led->r, led->g, led->b, apa102_led_brightness);
70 }
71 apa102_end_frame(num_leds);
72}
73
74// Overwrite the default rgblight_call_driver to use apa102 driver
75void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { apa102_setleds(start_led, num_leds); }
76
77void static apa102_init(void) {
78 setPinOutput(RGB_DI_PIN);
79 setPinOutput(RGB_CI_PIN);
80
81 writePinLow(RGB_DI_PIN);
82 writePinLow(RGB_CI_PIN);
83}
84
85void apa102_set_brightness(uint8_t brightness) {
86 if (brightness > APA102_MAX_BRIGHTNESS) {
87 apa102_led_brightness = APA102_MAX_BRIGHTNESS;
88 } else if (brightness < 0) {
89 apa102_led_brightness = 0;
90 } else {
91 apa102_led_brightness = brightness;
92 }
93}
94
95void static apa102_send_frame(uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness) {
96 apa102_send_byte(0b11100000 | brightness);
97 apa102_send_byte(blue);
98 apa102_send_byte(green);
99 apa102_send_byte(red);
100}
101
102void static apa102_start_frame(void) {
103 apa102_init();
104 for (uint16_t i = 0; i < 4; i++) {
105 apa102_send_byte(0);
106 }
107}
108
109void static apa102_end_frame(uint16_t num_leds) {
110 // This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h
111 // and adapted. The code is MIT licensed. I think thats compatible?
112 //
113 // The data stream seen by the last LED in the chain will be delayed by
114 // (count - 1) clock edges, because each LED before it inverts the clock
115 // line and delays the data by one clock edge. Therefore, to make sure
116 // the last LED actually receives the data we wrote, the number of extra
117 // edges we send at the end of the frame must be at least (count - 1).
118 //
119 // Assuming we only want to send these edges in groups of size K, the
120 // C/C++ expression for the minimum number of groups to send is:
121 //
122 // ((count - 1) + (K - 1)) / K
123 //
124 // The C/C++ expression above is just (count - 1) divided by K,
125 // rounded up to the nearest whole number if there is a remainder.
126 //
127 // We set K to 16 and use the formula above as the number of frame-end
128 // bytes to transfer. Each byte has 16 clock edges.
129 //
130 // We are ignoring the specification for the end frame in the APA102
131 // datasheet, which says to send 0xFF four times, because it does not work
132 // when you have 66 LEDs or more, and also it results in unwanted white
133 // pixels if you try to update fewer LEDs than are on your LED strip.
134 uint16_t iterations = (num_leds + 14) / 16;
135 for (uint16_t i = 0; i < iterations; i++) {
136 apa102_send_byte(0);
137 }
138
139 apa102_init();
140}
141
142void static apa102_send_byte(uint8_t byte) {
143 APA102_SEND_BIT(byte, 7);
144 APA102_SEND_BIT(byte, 6);
145 APA102_SEND_BIT(byte, 5);
146 APA102_SEND_BIT(byte, 4);
147 APA102_SEND_BIT(byte, 3);
148 APA102_SEND_BIT(byte, 2);
149 APA102_SEND_BIT(byte, 1);
150 APA102_SEND_BIT(byte, 0);
151}
diff --git a/drivers/avr/apa102.h b/drivers/apa102/apa102.h
index d4c1e18ee..58cf020c1 100644
--- a/drivers/avr/apa102.h
+++ b/drivers/apa102/apa102.h
@@ -1,10 +1,5 @@
1/* 1/* Copyright 2020 Aldehir Rojas
2 * light weight WS2812 lib include 2 * Copyright 2017 Mikkel (Duckle29)
3 *
4 * Version 2.3 - Nev 29th 2015
5 * Author: Tim (cpldcpu@gmail.com)
6 *
7 * Please do not change this file! All configuration is handled in "ws2812_config.h"
8 * 3 *
9 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -22,24 +17,25 @@
22 17
23#pragma once 18#pragma once
24 19
25#include <avr/io.h>
26#include <avr/interrupt.h>
27
28#include "color.h" 20#include "color.h"
29 21
22#ifndef APA102_DEFAULT_BRIGHTNESS
23# define APA102_DEFAULT_BRIGHTNESS 31
24#endif
25
26#define APA102_MAX_BRIGHTNESS 31
27
28extern uint8_t apa102_led_brightness;
29
30/* User Interface 30/* User Interface
31 * 31 *
32 * Input: 32 * Input:
33 * ledarray: An array of GRB data describing the LED colors 33 * start_led: An array of GRB data describing the LED colors
34 * number_of_leds: The number of LEDs to write 34 * num_leds: The number of LEDs to write
35 * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
36 * 35 *
37 * The functions will perform the following actions: 36 * The functions will perform the following actions:
38 * - Set the data-out pin as output 37 * - Set the data-out pin as output
39 * - Send out the LED data 38 * - Send out the LED data
40 * - Wait 50�s to reset the LEDs
41 */ 39 */
42 40void apa102_setleds(LED_TYPE *start_led, uint16_t num_leds);
43void apa102_setleds(LED_TYPE *ledarray, uint16_t number_of_leds); 41void apa102_set_brightness(uint8_t brightness);
44void apa102_setleds_pin(LED_TYPE *ledarray, uint16_t number_of_leds, uint8_t pinmask);
45void apa102_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);
diff --git a/drivers/avr/apa102.c b/drivers/avr/apa102.c
deleted file mode 100644
index 740acb573..000000000
--- a/drivers/avr/apa102.c
+++ /dev/null
@@ -1,96 +0,0 @@
1/*
2 * APA102 lib V1.0a
3 *
4 * Controls APA102 RGB-LEDs
5 * Author: Mikkel (Duckle29 on GitHub)
6 *
7 * Dec 22th, 2017 v1.0a Initial Version
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "apa102.h"
24#include <avr/interrupt.h>
25#include <avr/io.h>
26#include <util/delay.h>
27#include "debug.h"
28
29// Setleds for standard RGB
30void inline apa102_setleds(LED_TYPE *ledarray, uint16_t leds) { apa102_setleds_pin(ledarray, leds, _BV(RGB_DI_PIN & 0xF), _BV(RGB_CLK_PIN & 0xF)); }
31
32void static inline apa102_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask_DI, uint8_t pinmask_CLK) {
33 setPinOutput(RGB_DI_PIN);
34 setPinOutput(RGB_CLK_PIN);
35
36 apa102_send_array((uint8_t *)ledarray, leds)
37}
38
39void apa102_send_array(uint8_t *data, uint16_t leds) { // Data is struct of 3 bytes. RGB - leds is number of leds in data
40 apa102_start_frame();
41 while (leds--) {
42 apa102_send_frame(0xFF000000 | (data->b << 16) | (data->g << 8) | data->r);
43 data++;
44 }
45 apa102_end_frame(leds);
46}
47
48void apa102_send_frame(uint32_t frame) {
49 for (uint32_t i = 0xFF; i > 0;) {
50 apa102_send_byte(frame & i);
51 i = i << 8;
52 }
53}
54
55void apa102_start_frame() { apa102_send_frame(0); }
56
57void apa102_end_frame(uint16_t leds) {
58 // This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h
59 // and adapted. The code is MIT licensed. I think thats compatible?
60
61 // We need to send some more bytes to ensure that all the LEDs in the
62 // chain see their new color and start displaying it.
63 //
64 // The data stream seen by the last LED in the chain will be delayed by
65 // (count - 1) clock edges, because each LED before it inverts the clock
66 // line and delays the data by one clock edge. Therefore, to make sure
67 // the last LED actually receives the data we wrote, the number of extra
68 // edges we send at the end of the frame must be at least (count - 1).
69 // For the APA102C, that is sufficient.
70 //
71 // The SK9822 only updates after it sees 32 zero bits followed by one more
72 // rising edge. To avoid having the update time depend on the color of
73 // the last LED, we send a dummy 0xFF byte. (Unfortunately, this means
74 // that partial updates of the beginning of an LED strip are not possible;
75 // the LED after the last one you are trying to update will be black.)
76 // After that, to ensure that the last LED in the chain sees 32 zero bits
77 // and a rising edge, we need to send at least 65 + (count - 1) edges. It
78 // is sufficent and simpler to just send (5 + count/16) bytes of zeros.
79 //
80 // We are ignoring the specification for the end frame in the APA102/SK9822
81 // datasheets because it does not actually ensure that all the LEDs will
82 // start displaying their new colors right away.
83
84 apa102_send_byte(0xFF);
85 for (uint16_t i = 0; i < 5 + leds / 16; i++) {
86 apa102_send_byte(0);
87 }
88}
89
90void apa102_send_byte(uint8_t byte) {
91 uint8_t i;
92 for (i = 0; i < 8; i++) {
93 writePin(RGB_DI_PIN, !!(byte & (1 << (7 - i))));
94 writePinHigh(RGB_CLK_PIN);
95 }
96}
diff --git a/drivers/chibios/serial_usart.c b/drivers/chibios/serial_usart.c
index a3e21f90b..7c81b1646 100644
--- a/drivers/chibios/serial_usart.c
+++ b/drivers/chibios/serial_usart.c
@@ -58,7 +58,10 @@
58# error invalid SELECT_SOFT_SERIAL_SPEED value 58# error invalid SELECT_SOFT_SERIAL_SPEED value
59#endif 59#endif
60 60
61#define TIMEOUT 100 61#ifndef SERIAL_USART_TIMEOUT
62# define SERIAL_USART_TIMEOUT 100
63#endif
64
62#define HANDSHAKE_MAGIC 7 65#define HANDSHAKE_MAGIC 7
63 66
64static inline msg_t sdWriteHalfDuplex(SerialDriver* driver, uint8_t* data, uint8_t size) { 67static inline msg_t sdWriteHalfDuplex(SerialDriver* driver, uint8_t* data, uint8_t size) {
@@ -201,21 +204,21 @@ int soft_serial_transaction(int index) {
201 sdClear(&SERIAL_USART_DRIVER); 204 sdClear(&SERIAL_USART_DRIVER);
202 205
203 // First chunk is always transaction id 206 // First chunk is always transaction id
204 sdWriteTimeout(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index), TIME_MS2I(TIMEOUT)); 207 sdWriteTimeout(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index), TIME_MS2I(SERIAL_USART_TIMEOUT));
205 208
206 uint8_t sstd_index_shake = 0xFF; 209 uint8_t sstd_index_shake = 0xFF;
207 210
208 // Which we always read back first so that we can error out correctly 211 // Which we always read back first so that we can error out correctly
209 // - due to the half duplex limitations on return codes, we always have to read *something* 212 // - due to the half duplex limitations on return codes, we always have to read *something*
210 // - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready 213 // - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready
211 res = sdReadTimeout(&SERIAL_USART_DRIVER, &sstd_index_shake, sizeof(sstd_index_shake), TIME_MS2I(TIMEOUT)); 214 res = sdReadTimeout(&SERIAL_USART_DRIVER, &sstd_index_shake, sizeof(sstd_index_shake), TIME_MS2I(SERIAL_USART_TIMEOUT));
212 if (res < 0 || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) { 215 if (res < 0 || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) {
213 dprintf("serial::usart_shake NO_RESPONSE\n"); 216 dprintf("serial::usart_shake NO_RESPONSE\n");
214 return TRANSACTION_NO_RESPONSE; 217 return TRANSACTION_NO_RESPONSE;
215 } 218 }
216 219
217 if (trans->initiator2target_buffer_size) { 220 if (trans->initiator2target_buffer_size) {
218 res = sdWriteTimeout(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size, TIME_MS2I(TIMEOUT)); 221 res = sdWriteTimeout(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
219 if (res < 0) { 222 if (res < 0) {
220 dprintf("serial::usart_transmit NO_RESPONSE\n"); 223 dprintf("serial::usart_transmit NO_RESPONSE\n");
221 return TRANSACTION_NO_RESPONSE; 224 return TRANSACTION_NO_RESPONSE;
@@ -223,7 +226,7 @@ int soft_serial_transaction(int index) {
223 } 226 }
224 227
225 if (trans->target2initiator_buffer_size) { 228 if (trans->target2initiator_buffer_size) {
226 res = sdReadTimeout(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size, TIME_MS2I(TIMEOUT)); 229 res = sdReadTimeout(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
227 if (res < 0) { 230 if (res < 0) {
228 dprintf("serial::usart_receive NO_RESPONSE\n"); 231 dprintf("serial::usart_receive NO_RESPONSE\n");
229 return TRANSACTION_NO_RESPONSE; 232 return TRANSACTION_NO_RESPONSE;
diff --git a/drivers/qwiic/qwiic.mk b/drivers/qwiic/qwiic.mk
index b23c25657..164bd7210 100644
--- a/drivers/qwiic/qwiic.mk
+++ b/drivers/qwiic/qwiic.mk
@@ -1,16 +1,17 @@
1ifneq ($(strip $(QWIIC_ENABLE)),) 1ifeq ($(strip $(QWIIC_ENABLE)),yes)
2 COMMON_VPATH += $(DRIVER_PATH)/qwiic 2 COMMON_VPATH += $(DRIVER_PATH)/qwiic
3 OPT_DEFS += -DQWIIC_ENABLE 3 OPT_DEFS += -DQWIIC_ENABLE
4 SRC += qwiic.c 4 SRC += qwiic.c
5 QUANTUM_LIB_SRC += i2c_master.c 5 QUANTUM_LIB_SRC += i2c_master.c
6endif
7 6
8ifneq ($(filter JOYSTIIC, $(QWIIC_ENABLE)),) 7ifneq ($(filter JOYSTIIC, $(QWIIC_DRIVERS)),)
9 OPT_DEFS += -DQWIIC_JOYSTIIC_ENABLE 8 OPT_DEFS += -DQWIIC_JOYSTIIC_ENABLE
10 SRC += joystiic.c 9 SRC += joystiic.c
11endif 10endif
12 11
13ifneq ($(filter MICRO_OLED, $(QWIIC_ENABLE)),) 12ifneq ($(filter MICRO_OLED, $(QWIIC_DRIVERS)),)
14 OPT_DEFS += -DQWIIC_MICRO_OLED_ENABLE 13 OPT_DEFS += -DQWIIC_MICRO_OLED_ENABLE
15 SRC += micro_oled.c 14 SRC += micro_oled.c
16endif 15endif
16
17endif