From 0f6379b63fb2bb08dcbdfe666b723902234b5714 Mon Sep 17 00:00:00 2001 From: bkleiner Date: Tue, 29 Oct 2024 10:13:45 +0100 Subject: [PATCH] dma: dynamically assign streams/channels --- script/device_gen.py | 207 +++++++++-------- src/config/feature.h | 1 + src/core/main.c | 3 +- src/core/project.h | 14 +- src/core/target.c | 2 + src/core/target.h | 40 +++- src/core/tasks.c | 10 +- src/driver/dma.c | 109 +++++++++ src/driver/dma.h | 53 +++-- src/driver/mcu/at32/dma.c | 80 +++---- src/driver/mcu/at32/dma.h | 24 +- src/driver/mcu/at32/motor_dshot.c | 138 +++++++----- src/driver/mcu/at32/motor_pwm.c | 1 + src/driver/mcu/at32/rgb_led.c | 187 ++++++++++++++++ src/driver/mcu/at32/spi.c | 107 ++++----- src/driver/mcu/at32/system.h | 8 +- src/driver/mcu/at32/timer.c | 18 ++ src/driver/mcu/stm32/dma.c | 118 +++------- src/driver/mcu/stm32/dma.h | 40 +++- src/driver/mcu/stm32/motor_dshot.c | 120 ++++++---- src/driver/mcu/stm32/rgb_led.c | 193 ++++++++++++++++ src/driver/mcu/stm32/spi.c | 91 ++++---- src/driver/mcu/stm32/system.h | 7 - src/driver/mcu/stm32/timer.c | 18 ++ src/driver/mcu/system.h | 13 ++ src/driver/motor_dshot.c | 30 +-- src/driver/motor_dshot.h | 6 +- src/driver/resource.c | 78 +++++++ src/driver/resource.h | 7 +- src/driver/rgb_led.c | 347 ----------------------------- src/driver/rgb_led.h | 11 +- src/driver/timer.c | 7 - src/driver/timer.h | 2 + src/io/rgb_led.c | 184 +++------------ src/io/rgb_led.h | 4 +- 35 files changed, 1263 insertions(+), 1015 deletions(-) create mode 100644 src/driver/dma.c create mode 100644 src/driver/mcu/at32/rgb_led.c create mode 100644 src/driver/mcu/stm32/rgb_led.c create mode 100644 src/driver/mcu/system.h create mode 100644 src/driver/resource.c delete mode 100644 src/driver/rgb_led.c diff --git a/script/device_gen.py b/script/device_gen.py index 16edee41d..069286654 100644 --- a/script/device_gen.py +++ b/script/device_gen.py @@ -1,7 +1,6 @@ import glob import hashlib -import yaml -import os +import re import modm_devices @@ -106,6 +105,66 @@ def __getitem__(self, item) -> modm_devices.device.Device: return value +def map_signal(s): + if s is None: + return None + + if s["driver"] == "tim" and s["name"].startswith("ch"): + return { + "func": "timer", + "af": int(s.get("af", "-1")), + "instance": int(s["instance"]), + "name": s["name"], + } + elif s["driver"] == "spi" and ( + s["name"] == "sck" + or s["name"] == "mosi" + or s["name"] == "miso" + or s["name"] == "tx" + or s["name"] == "rx" + ): + return { + "func": "spi", + "af": int(s.get("af", "-1")), + "instance": int(s["instance"]), + "name": {"tx": "mosi", "rx": "miso"}.get(s["name"], s["name"]), + } + elif (s["driver"] == "uart" or s["driver"] == "usart") and ( + s["name"] == "rx" or s["name"] == "tx" + ): + return { + "func": "serial", + "af": int(s.get("af", "-1")), + "instance": int(s["instance"]), + "name": s["name"], + } + elif s["driver"] == "adc" and re.match(r"in\d+", s.get("name", "in0")): + return { + "func": "adc", + "af": -1, + "instance": int(s["instance"]), + "name": s.get("name", "in0xff")[2:], + } + else: + return None + + +def map_tag(f): + if f is None: + return None + + if f["func"] == "timer": + return f"TIMER_TAG(TIMER{f['instance']}, TIMER_{f['name']})".upper() + elif f["func"] == "spi": + return f"SPI_TAG(SPI_PORT{f['instance']}, RES_SPI_{f['name']})".upper() + elif f["func"] == "serial": + return f"SERIAL_TAG(SERIAL_PORT{f['instance']}, RES_SERIAL_{f['name']})".upper() + elif f["func"] == "adc": + return f"ADC_TAG(ADC_DEVICE{f['instance']}, {f['name']})".upper() + else: + return None + + devices = [ "stm32f405rg", "stm32f411re", @@ -123,100 +182,58 @@ def __getitem__(self, item) -> modm_devices.device.Device: pins = {} key = next((x for x in caches.keys() if x.startswith(device)), None) - for driver in caches[key].get_all_drivers("gpio"): - for pin in driver["gpio"]: - funcs = [] + with open(f"src/system/{device[:9]}/gpio_pins.in", "w") as file: + for driver in caches[key].get_all_drivers("gpio"): + for pin in driver["gpio"]: + file.write(f"GPIO_PIN({pin['port']}, {pin['pin']})\n".upper()) + if "signal" not in pin: + continue - if "signal" in pin: for s in pin["signal"]: - if s["driver"] == "tim" and s["name"].startswith("ch"): - funcs.append( - { - "func": "timer", - "af": int(s["af"]), - "instance": int(s["instance"]), - "name": s["name"], - } - ) - - if s["driver"] == "spi" and ( - s["name"] == "sck" or s["name"] == "mosi" or s["name"] == "miso" - ): - funcs.append( - { - "func": "spi", - "af": int(s["af"]), - "instance": int(s["instance"]), - "name": s["name"], - } - ) - - if (s["driver"] == "uart" or s["driver"] == "usart") and ( - s["name"] == "rx" or s["name"] == "tx" - ): - funcs.append( - { - "func": "serial", - "af": int(s["af"]), - "instance": int(s["instance"]), - "name": s["name"], - } - ) - - if s["driver"] == "adc" and not ( - s["name"].startswith("inp") or s["name"].startswith("inn") - ): - funcs.append( - { - "func": "adc", - "af": -1, - "instance": int(s["instance"]), - "name": s["name"][2:], - } - ) - - pins[f"P{pin['port']}{pin['pin']}".upper()] = funcs - - with open(f"src/system/{device[:9]}/gpio_pins.yaml", "w") as file: - documents = yaml.dump(pins, file, sort_keys=False) - -for filename in glob.glob("src/system/*/gpio_pins.yaml"): - dir = os.path.dirname(filename) - - with open(filename, "r") as f: - pins = yaml.load(f, Loader=yaml.Loader) - - with open(f"{dir}/gpio_pins.in", "w") as file: - for k, funcs in pins.items(): - port = k[1] - pin = k[2:] - file.write(f"GPIO_PIN({port}, {pin})\n") - - for f in funcs: - line = f"GPIO_AF(PIN_{port}{pin}, {f['af']}, " - - if f["func"] == "timer": - line = ( - line - + f"TIMER_TAG(TIMER{f['instance']}, TIMER_{f['name'].upper()}))\n" - ) - - if f["func"] == "spi": - line = ( - line - + f"SPI_TAG(SPI_PORT{f['instance']}, RES_SPI_{f['name'].upper()}))\n" - ) - - if f["func"] == "serial": - line = ( - line - + f"SERIAL_TAG(SERIAL_PORT{f['instance']}, RES_SERIAL_{f['name'].upper()}))\n" - ) - - if f["func"] == "adc": - line = ( - line - + f"ADC_TAG(ADC_DEVICE{f['instance']}, {f['name'].upper()}))\n" + f = map_signal(s) + s = map_tag(f) + if s is None: + continue + file.write( + f"GPIO_AF(PIN_{pin['port']}{pin['pin']}, {f['af']}, {s})\n".upper() ) - file.write(line) + with open(f"src/system/{device[:9]}/dma.in", "w") as file: + for driver in caches[key].get_all_drivers("dma"): + if "streams" in driver: + for dma in driver["streams"]: + for stream in dma["stream"]: + for channel in stream["channel"]: + funcs = [ + r + for s in channel["signal"] + if (r := map_tag(map_signal(s))) is not None + ] + for func in funcs: + entry = ", ".join( + [ + f".tag = {func}", + f".port_index = {dma['instance']}", + f".stream_index = {stream['position']}", + f".channel = LL_DMA_CHANNEL_{channel['position']}", + ] + ) + file.write("{ " + entry + " },\n") + if "requests" in driver: + for dma in driver["requests"]: + for request in dma["request"]: + funcs = [ + r + for s in request["signal"] + if (r := map_tag(map_signal(s))) is not None + ] + for func in funcs: + entry = ", ".join( + [ + f".tag = {func}", + f".port_index = -1", + f".stream_index = -1", + f".request = {request['position']}", + ] + ) + file.write("{ " + entry + " },\n") diff --git a/src/config/feature.h b/src/config/feature.h index 1194684bc..577dd0475 100644 --- a/src/config/feature.h +++ b/src/config/feature.h @@ -12,6 +12,7 @@ #define USE_VTX #define USE_DIGITAL_VTX #define USE_MAX7456 +#define USE_RGB_LED #define USE_MOTOR_DSHOT #define USE_MOTOR_PWM diff --git a/src/core/main.c b/src/core/main.c index 9befbcf23..295c6fb6f 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -80,7 +80,6 @@ __attribute__((__used__)) int main() { // setup filters early filter_global_init(); - timer_alloc_init(); pid_init(); // init some hardware things @@ -123,7 +122,7 @@ __attribute__((__used__)) int main() { rx_init(); vtx_init(); - rgb_init(); + rgb_led_init(); blackbox_init(); imu_init(); diff --git a/src/core/project.h b/src/core/project.h index 372482b41..6e6b91e0d 100644 --- a/src/core/project.h +++ b/src/core/project.h @@ -3,19 +3,9 @@ #include "config/config.h" #include "config/feature.h" -#include "core/target.h" - -#ifdef STM32 -#include "driver/mcu/stm32/system.h" -#endif +#include "driver/mcu/system.h" -#ifdef AT32 -#include "driver/mcu/at32/system.h" -#endif - -#ifdef SIMULATOR -#include "driver/mcu/native/system.h" -#endif +#include "core/target.h" #ifdef USE_FAST_RAM #define FAST_RAM __attribute__((section(".fast_ram"), aligned(4))) diff --git a/src/core/target.c b/src/core/target.c index f2025d352..2d714f4ad 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -41,6 +41,7 @@ target_info_t target_info = { #define INDEX_ARRAY_MEMBER CBOR_ENCODE_INDEX_ARRAY_MEMBER #define STR_ARRAY_MEMBER CBOR_ENCODE_STR_ARRAY_MEMBER +TARGET_DMA_MEMBERS TARGET_LED_MEMBERS TARGET_BUZZER_MEMBERS TARGET_SERIAL_MEMBERS @@ -69,6 +70,7 @@ TARGET_INFO_MEMBERS #define INDEX_ARRAY_MEMBER CBOR_DECODE_INDEX_ARRAY_MEMBER #define STR_ARRAY_MEMBER CBOR_DECODE_STR_ARRAY_MEMBER +TARGET_DMA_MEMBERS TARGET_LED_MEMBERS TARGET_BUZZER_MEMBERS TARGET_SERIAL_MEMBERS diff --git a/src/core/target.h b/src/core/target.h index a191d3c26..397128472 100644 --- a/src/core/target.h +++ b/src/core/target.h @@ -3,6 +3,7 @@ #include #include +#include "driver/dma.h" #include "rx/rx.h" #define LED_MAX 4 @@ -64,6 +65,32 @@ typedef enum { SERIAL_SOFT_COUNT = SERIAL_SOFT_MAX - SERIAL_SOFT_START, } __attribute__((__packed__)) serial_ports_t; +typedef struct { +#if defined(STM32H7) || defined(STM32G4) || defined(AT32) + uint32_t request; +#else + uint32_t channel; +#endif + resource_tag_t tag; + dma_stream_t dma; +} target_dma_t; + +#if defined(STM32H7) || defined(STM32G4) || defined(AT32) +#define TARGET_DMA_MEMBERS \ + START_STRUCT(target_dma_t) \ + MEMBER(request, uint32_t) \ + MEMBER(tag, resource_tag_t) \ + MEMBER(dma, dma_stream_t) \ + END_STRUCT() +#else +#define TARGET_DMA_MEMBERS \ + START_STRUCT(target_dma_t) \ + MEMBER(channel, uint32_t) \ + MEMBER(tag, resource_tag_t) \ + MEMBER(dma, dma_stream_t) \ + END_STRUCT() +#endif + typedef struct { gpio_pins_t pin; bool invert; @@ -186,6 +213,7 @@ typedef struct { gpio_pins_t fpv; gpio_pins_t vbat; gpio_pins_t ibat; + gpio_pins_t rgb_led; target_invert_pin_t sdcard_detect; target_invert_pin_t buzzer; @@ -193,6 +221,8 @@ typedef struct { uint16_t vbat_scale; uint16_t ibat_scale; + + target_dma_t dma[DMA_DEVICE_MAX]; } target_t; #define TARGET_MEMBERS \ @@ -213,11 +243,13 @@ typedef struct { MEMBER(fpv, gpio_pins_t) \ MEMBER(vbat, gpio_pins_t) \ MEMBER(ibat, gpio_pins_t) \ + MEMBER(rgb_led, gpio_pins_t) \ MEMBER(sdcard_detect, target_invert_pin_t) \ MEMBER(buzzer, target_invert_pin_t) \ ARRAY_MEMBER(motor_pins, MOTOR_PIN_MAX, gpio_pins_t) \ MEMBER(vbat_scale, uint16_t) \ MEMBER(ibat_scale, uint16_t) \ + MEMBER(dma, target_dma_array) \ END_STRUCT() typedef enum { @@ -268,4 +300,10 @@ cbor_result_t cbor_decode_gpio_pins_t(cbor_value_t *dec, gpio_pins_t *t); cbor_result_t cbor_encode_target_t(cbor_value_t *enc, const target_t *t); cbor_result_t cbor_decode_target_t(cbor_value_t *dec, target_t *t); -cbor_result_t cbor_encode_target_info_t(cbor_value_t *enc, const target_info_t *i); \ No newline at end of file +cbor_result_t cbor_encode_target_dma_t(cbor_value_t *enc, const target_dma_t *dma); +cbor_result_t cbor_decode_target_dma_t(cbor_value_t *dec, target_dma_t *dma); + +cbor_result_t cbor_encode_target_info_t(cbor_value_t *enc, const target_info_t *i); + +cbor_result_t cbor_encode_target_dma_array(cbor_value_t *dec, const target_dma_t (*dma)[DMA_DEVICE_MAX]); +cbor_result_t cbor_decode_target_dma_array(cbor_value_t *dec, target_dma_t (*dma)[DMA_DEVICE_MAX]); diff --git a/src/core/tasks.c b/src/core/tasks.c index 8e12b8c98..784db0c03 100644 --- a/src/core/tasks.c +++ b/src/core/tasks.c @@ -11,6 +11,7 @@ #include "io/blackbox.h" #include "io/buzzer.h" #include "io/led.h" +#include "io/rgb_led.h" #include "io/usb_configurator.h" #include "io/vbat.h" #include "io/vtx.h" @@ -22,14 +23,7 @@ void util_task() { // handle led commands led_update(); - -#if (RGB_LED_NUMBER > 0) - // RGB led control - rgb_led_lvc(); -#ifdef RGB_LED_DMA - rgb_dma_start(); -#endif -#endif + rgb_led_update(); buzzer_update(); } diff --git a/src/driver/dma.c b/src/driver/dma.c new file mode 100644 index 000000000..6b1a87338 --- /dev/null +++ b/src/driver/dma.c @@ -0,0 +1,109 @@ +#include "dma.h" + +#include "core/project.h" +#include "util/cbor_helper.h" +#include "util/util.h" + +dma_device_t dma_stream_map[DMA_STREAM_MAX]; + +cbor_result_t cbor_decode_dma_device_t(cbor_value_t *dec, dma_device_t *d) { + const uint8_t *name; + uint32_t name_len; + cbor_result_t res = cbor_decode_tstr(dec, &name, &name_len); + +#define DMA_DEVICE(member) \ + if (buf_equal_string(name, name_len, #member)) \ + *d = DMA_DEVICE_##member; \ + else + DMA_DEVICES +#undef DMA_DEVICE + *d = DMA_DEVICE_INVALID; + + return res; +} + +cbor_result_t cbor_encode_dma_device_t(cbor_value_t *enc, const dma_device_t *d) { + cbor_result_t res = CBOR_OK; + + switch (*d) { +#define DMA_DEVICE(_name) \ + case DMA_DEVICE_##_name: \ + CBOR_CHECK_ERROR(res = cbor_encode_str(enc, "DMA_DEVICE_##_name")); \ + break; + DMA_DEVICES +#undef DMA_DEVICE + default: + break; + } + + return res; +} + +cbor_result_t cbor_decode_dma_stream_t(cbor_value_t *dec, dma_stream_t *d) { + const uint8_t *name; + uint32_t name_len; + cbor_result_t res = cbor_decode_tstr(dec, &name, &name_len); + +#define DMA_STREAM(_port, _stream) \ + if (buf_equal_string(name, name_len, "DMA##_port##_STREAM##_stream")) \ + *d = DMA##_port##_STREAM##_stream; \ + else + DMA_STREAMS +#undef DMA_STREAM + *d = DMA_STREAM_MAX; + + return res; +} + +cbor_result_t cbor_encode_dma_stream_t(cbor_value_t *enc, const dma_stream_t *d) { + cbor_result_t res = CBOR_OK; + + switch (*d) { +#define DMA_STREAM(_port, _stream) \ + case DMA##_port##_STREAM##_stream: \ + CBOR_CHECK_ERROR(res = cbor_encode_str(enc, "DMA##_port##_STREAM##_stream")); \ + break; + DMA_STREAMS +#undef DMA_STREAM + default: + break; + } + + return res; +} + +cbor_result_t cbor_decode_target_dma_array(cbor_value_t *dec, target_dma_t (*dma)[DMA_DEVICE_MAX]) { + cbor_result_t res = CBOR_OK; + + cbor_container_t map; + CBOR_CHECK_ERROR(res = cbor_decode_map(dec, &map)); + for (uint32_t i = 0; i < cbor_decode_map_size(dec, &map); i++) { + dma_device_t dev = DMA_DEVICE_INVALID; + CBOR_CHECK_ERROR(res = cbor_decode_dma_device_t(dec, &dev)); + if (dev == DMA_DEVICE_INVALID) { + continue; + } + + target_dma_t *d = &(*dma)[dev]; + CBOR_CHECK_ERROR(res = cbor_decode_target_dma_t(dec, d)); + dma_stream_map[d->dma] = dev; + } + + return res; +} + +cbor_result_t cbor_encode_target_dma_array(cbor_value_t *enc, const target_dma_t (*dma)[DMA_DEVICE_MAX]) { + cbor_result_t res = CBOR_OK; + CBOR_CHECK_ERROR(res = cbor_encode_map_indefinite(enc)); + + for (uint32_t i = 0; i < DMA_DEVICE_MAX; i++) { + const target_dma_t *d = &(*dma)[i]; + if (d->dma == DMA_STREAM_INVALID) + continue; + + CBOR_CHECK_ERROR(res = cbor_encode_dma_device_t(enc, (const dma_device_t *)&i)); + CBOR_CHECK_ERROR(res = cbor_encode_target_dma_t(enc, d)); + } + + return cbor_encode_end_indefinite(enc); +} \ No newline at end of file diff --git a/src/driver/dma.h b/src/driver/dma.h index bb3b23c1c..ec43c7dff 100644 --- a/src/driver/dma.h +++ b/src/driver/dma.h @@ -1,31 +1,52 @@ #pragma once +#include #include -#include "core/project.h" +#include "driver/mcu/system.h" +#include "driver/resource.h" #define DMA_ALIGN_SIZE 32 #define DMA_ALIGN(offset) MEMORY_ALIGN(offset, DMA_ALIGN_SIZE) +#define DMA_DEVICES \ + DMA_DEVICE(DSHOT_CH1) \ + DMA_DEVICE(DSHOT_CH2) \ + DMA_DEVICE(DSHOT_CH3) \ + DMA_DEVICE(SPI1_RX) \ + DMA_DEVICE(SPI1_TX) \ + DMA_DEVICE(SPI2_RX) \ + DMA_DEVICE(SPI2_TX) \ + DMA_DEVICE(SPI3_RX) \ + DMA_DEVICE(SPI3_TX) \ + DMA_DEVICE(SPI4_RX) \ + DMA_DEVICE(SPI4_TX) \ + DMA_DEVICE(RGB) + typedef enum { - DMA_DEVICE_SPI1_RX, - DMA_DEVICE_SPI1_TX, - DMA_DEVICE_SPI2_RX, - DMA_DEVICE_SPI2_TX, - DMA_DEVICE_SPI3_RX, - DMA_DEVICE_SPI3_TX, - DMA_DEVICE_SPI4_RX, - DMA_DEVICE_SPI4_TX, - DMA_DEVICE_TIM1_CH1, - DMA_DEVICE_TIM1_CH3, - DMA_DEVICE_TIM1_CH4, - - DMA_DEVICE_MAX, + DMA_DEVICE_INVALID, +#define DMA_DEVICE(_name) DMA_DEVICE_##_name, + DMA_DEVICES DMA_DEVICE_MAX +#undef DMA_DEVICE } dma_device_t; -extern const dma_stream_def_t dma_stream_defs[DMA_DEVICE_MAX]; +typedef enum { + DMA_STREAM_INVALID, +#define DMA_STREAM(_port, _stream) DMA##_port##_STREAM##_stream, + DMA_STREAMS DMA_STREAM_MAX +#undef DMA_STREAM +} dma_stream_t; + +extern const dma_stream_def_t dma_stream_defs[DMA_STREAM_MAX]; +extern dma_device_t dma_stream_map[DMA_STREAM_MAX]; + +cbor_result_t cbor_decode_dma_device_t(cbor_value_t *dec, dma_device_t *d); +cbor_result_t cbor_encode_dma_device_t(cbor_value_t *enc, const dma_device_t *d); + +cbor_result_t cbor_decode_dma_stream_t(cbor_value_t *dec, dma_stream_t *d); +cbor_result_t cbor_encode_dma_stream_t(cbor_value_t *enc, const dma_stream_t *d); void dma_prepare_tx_memory(void *addr, uint32_t size); void dma_prepare_rx_memory(void *addr, uint32_t size); -void dma_enable_rcc(dma_device_t dev); +void dma_enable_rcc(const dma_stream_def_t *def); diff --git a/src/driver/mcu/at32/dma.c b/src/driver/mcu/at32/dma.c index 5c8f71808..6013833d1 100644 --- a/src/driver/mcu/at32/dma.c +++ b/src/driver/mcu/at32/dma.c @@ -1,50 +1,24 @@ #include "driver/dma.h" +#include "driver/adc.h" #include "driver/rcc.h" +#include "driver/resource.h" +#include "driver/timer.h" -#define DMAMUX_DMAREQ_ID_TIM1_CH1 DMAMUX_DMAREQ_ID_TMR1_CH1 -#define DMAMUX_DMAREQ_ID_TIM1_CH2 DMAMUX_DMAREQ_ID_TMR1_CH2 -#define DMAMUX_DMAREQ_ID_TIM1_CH3 DMAMUX_DMAREQ_ID_TMR1_CH3 -#define DMAMUX_DMAREQ_ID_TIM1_CH4 DMAMUX_DMAREQ_ID_TMR1_CH3 - -#define DMA_STREAMS \ - DMA_STREAM(1, 1, SPI1_RX) \ - DMA_STREAM(1, 2, SPI1_TX) \ - DMA_STREAM(1, 3, SPI2_RX) \ - DMA_STREAM(1, 4, SPI2_TX) \ - DMA_STREAM(1, 5, SPI3_RX) \ - DMA_STREAM(1, 6, SPI3_TX) \ - DMA_STREAM(2, 1, SPI4_RX) \ - DMA_STREAM(2, 2, SPI4_TX) \ - DMA_STREAM(2, 3, TIM1_CH1) \ - DMA_STREAM(2, 4, TIM1_CH3) \ - DMA_STREAM(2, 5, TIM1_CH4) - -#define DMA_STREAM(_port, _chan, _dev) \ - [DMA_DEVICE_##_dev] = { \ - .device = DMA_DEVICE_##_dev, \ +#define DMA_STREAM(_port, _chan) \ + { \ .port = DMA##_port, \ .port_index = _port, \ - .channel = DMA##_port##_CHANNEL##_chan, \ - .channel_index = _chan, \ - .request = DMAMUX_DMAREQ_ID_##_dev, \ + .stream = DMA##_port##_CHANNEL##_chan, \ + .stream_index = _chan, \ .mux = DMA##_port##MUX_CHANNEL##_chan, \ .irq = DMA##_port##_Channel##_chan##_IRQn, \ }, - -const dma_stream_def_t dma_stream_defs[DMA_DEVICE_MAX] = {DMA_STREAMS}; - +const dma_stream_def_t dma_stream_defs[DMA_STREAM_MAX] = {DMA_STREAMS}; #undef DMA_STREAM -void dma_prepare_tx_memory(void *addr, uint32_t size) { -} - -void dma_prepare_rx_memory(void *addr, uint32_t size) { -} - -void dma_enable_rcc(dma_device_t dev) { - const dma_stream_def_t *dma = &dma_stream_defs[dev]; - switch (dma->port_index) { +void dma_enable_rcc(const dma_stream_def_t *def) { + switch (def->port_index) { case 1: rcc_enable(RCC_ENCODE(DMA1)); dmamux_enable(DMA1, TRUE); @@ -56,37 +30,45 @@ void dma_enable_rcc(dma_device_t dev) { } } -extern void dshot_dma_isr(dma_device_t dev); -extern void spi_dma_isr(dma_device_t dev); +void dma_prepare_tx_memory(void *addr, uint32_t size) {} +void dma_prepare_rx_memory(void *addr, uint32_t size) {} + +extern void dshot_dma_isr(const dma_device_t); +extern void spi_dma_isr(const dma_device_t); +extern void rgb_dma_isr(const dma_device_t); -static void handle_dma_stream_isr(dma_device_t dev) { +static void handle_dma_stream_isr(const dma_device_t dev) { switch (dev) { case DMA_DEVICE_SPI1_RX: - case DMA_DEVICE_SPI2_RX: - case DMA_DEVICE_SPI3_RX: - case DMA_DEVICE_SPI4_RX: case DMA_DEVICE_SPI1_TX: + case DMA_DEVICE_SPI2_RX: case DMA_DEVICE_SPI2_TX: + case DMA_DEVICE_SPI3_RX: case DMA_DEVICE_SPI3_TX: + case DMA_DEVICE_SPI4_RX: case DMA_DEVICE_SPI4_TX: spi_dma_isr(dev); break; - case DMA_DEVICE_TIM1_CH1: - case DMA_DEVICE_TIM1_CH3: - case DMA_DEVICE_TIM1_CH4: + case DMA_DEVICE_DSHOT_CH1: + case DMA_DEVICE_DSHOT_CH2: + case DMA_DEVICE_DSHOT_CH3: #ifdef USE_MOTOR_DSHOT dshot_dma_isr(dev); #endif break; + case DMA_DEVICE_RGB: +#ifdef USE_RGB_LED + rgb_dma_isr(dev); +#endif + break; + case DMA_DEVICE_INVALID: case DMA_DEVICE_MAX: break; } } -#define DMA_STREAM(_port, _chan, _dev) \ - void DMA##_port##_Channel##_chan##_IRQHandler() { \ - handle_dma_stream_isr(DMA_DEVICE_##_dev); \ - } +#define DMA_STREAM(_port, _stream) \ + void DMA##_port##_Channel##_stream##_IRQHandler() { handle_dma_stream_isr(dma_stream_map[DMA##_port##_STREAM##_stream]); } DMA_STREAMS diff --git a/src/driver/mcu/at32/dma.h b/src/driver/mcu/at32/dma.h index 94e6b3c1c..191269a5a 100644 --- a/src/driver/mcu/at32/dma.h +++ b/src/driver/mcu/at32/dma.h @@ -5,8 +5,24 @@ #define DMA_HDT_FLAG ((uint32_t)0x00000004) #define DMA_DTERR_FLAG ((uint32_t)0x00000008) -// 4bits per channel -#define dma_flag_for_channel(dev, flags) ((dev->port_index == 2 ? 0x10000000 : 0x0) | ((flags) << ((dev->channel_index - 1) * 4))) +// 4bits per stream +#define dma_flag_for_stream(dev, flags) ((dev->port_index == 2 ? 0x10000000 : 0x0) | ((flags) << ((dev->stream_index - 1) * 4))) -#define dma_is_flag_active_tc(dev) (dma_flag_get(dma_flag_for_channel(dev, DMA_FDT_FLAG))) -#define dma_clear_flag_tc(dev) dma_flag_clear(dma_flag_for_channel(dev, DMA_FDT_FLAG | DMA_HDT_FLAG | DMA_DTERR_FLAG)) +#define dma_is_flag_active_tc(dev) (dma_flag_get(dma_flag_for_stream(dev, DMA_FDT_FLAG))) +#define dma_clear_flag_tc(dev) dma_flag_clear(dma_flag_for_stream(dev, DMA_FDT_FLAG | DMA_HDT_FLAG | DMA_DTERR_FLAG)) + +#define DMA_STREAMS \ + DMA_STREAM(1, 1) \ + DMA_STREAM(1, 2) \ + DMA_STREAM(1, 3) \ + DMA_STREAM(1, 4) \ + DMA_STREAM(1, 5) \ + DMA_STREAM(1, 6) \ + DMA_STREAM(1, 7) \ + DMA_STREAM(2, 1) \ + DMA_STREAM(2, 2) \ + DMA_STREAM(2, 3) \ + DMA_STREAM(2, 4) \ + DMA_STREAM(2, 5) \ + DMA_STREAM(2, 6) \ + DMA_STREAM(2, 7) diff --git a/src/driver/mcu/at32/motor_dshot.c b/src/driver/mcu/at32/motor_dshot.c index b6c613043..dd9d05d54 100644 --- a/src/driver/mcu/at32/motor_dshot.c +++ b/src/driver/mcu/at32/motor_dshot.c @@ -2,6 +2,7 @@ #include +#include "core/failloop.h" #include "core/profile.h" #include "core/project.h" #include "driver/dma.h" @@ -11,8 +12,52 @@ #ifdef USE_MOTOR_DSHOT -static void dshot_init_gpio_port(dshot_gpio_port_t *port) { - dma_enable_rcc(port->dma_device); +extern uint16_t dshot_packet[MOTOR_PIN_MAX]; +extern dshot_pin_t dshot_pins[MOTOR_PIN_MAX]; +extern volatile uint32_t dshot_dma_phase; + +extern uint8_t dshot_gpio_port_count; +extern dshot_gpio_port_t dshot_gpio_ports[DSHOT_MAX_PORT_COUNT]; + +extern volatile DMA_RAM uint32_t port_dma_buffer[DSHOT_MAX_PORT_COUNT][DSHOT_DMA_BUFFER_SIZE]; + +static const resource_tag_t timers[] = { + TIMER_TAG(TIMER8, TIMER_CH1), + TIMER_TAG(TIMER8, TIMER_CH2), + TIMER_TAG(TIMER8, TIMER_CH3), + TIMER_TAG(TIMER8, TIMER_CH4), + TIMER_TAG(TIMER1, TIMER_CH1), + TIMER_TAG(TIMER1, TIMER_CH2), + TIMER_TAG(TIMER1, TIMER_CH3), + TIMER_TAG(TIMER1, TIMER_CH4), +}; +static const uint32_t timer_count = sizeof(timers) / sizeof(resource_tag_t); + +extern const dshot_gpio_port_t *dshot_gpio_for_device(const dma_device_t dev); + +void dshot_init_gpio_port(dshot_gpio_port_t *port) { + for (uint8_t i = 0; i < timer_count; i++) { + const resource_tag_t tag = timers[i]; + if (timer_alloc_tag(TIMER_USE_MOTOR_DSHOT, tag)) { + port->timer_tag = tag; + break; + } + } + if (port->timer_tag == 0) { + failloop(FAILLOOP_DMA); + } + + const timer_channel_t ch = TIMER_TAG_CH(port->timer_tag); + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(port->timer_tag)]; + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[port->dma_device].dma]; + + rcc_enable(tim->rcc); + + // setup timer to 1/3 of the full bit time + tmr_base_init(tim->instance, DSHOT_SYMBOL_TIME, 0); + tmr_clock_source_div_set(tim->instance, TMR_CLOCK_DIV1); + tmr_cnt_dir_set(tim->instance, TMR_COUNT_UP); + tmr_period_buffer_enable(tim->instance, TRUE); tmr_output_config_type tim_oc_init; tmr_output_default_para_init(&tim_oc_init); @@ -20,13 +65,13 @@ static void dshot_init_gpio_port(dshot_gpio_port_t *port) { tim_oc_init.oc_idle_state = TRUE; tim_oc_init.oc_polarity = TMR_OUTPUT_ACTIVE_LOW; tim_oc_init.oc_output_state = TRUE; - tmr_output_channel_config(TMR1, timer_channel_val(port->timer_channel), &tim_oc_init); - tmr_output_channel_buffer_enable(TMR1, timer_channel_val(port->timer_channel), TRUE); + tmr_output_channel_config(tim->instance, timer_channel_val(ch), &tim_oc_init); + tmr_output_channel_buffer_enable(tim->instance, timer_channel_val(ch), TRUE); - const dma_stream_def_t *dma = &dma_stream_defs[port->dma_device]; + dma_enable_rcc(dma); - dma_reset(dma->channel); - dmamux_init(dma->mux, dma->request); + dma_reset(dma->stream); + dmamux_init(dma->mux, target.dma[port->dma_device].request); dma_init_type init; init.peripheral_base_addr = 0x0; // overwritten later @@ -39,75 +84,58 @@ static void dshot_init_gpio_port(dshot_gpio_port_t *port) { init.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD; init.loop_mode_enable = FALSE; init.priority = DMA_PRIORITY_VERY_HIGH; - dma_init(dma->channel, &init); - dma_interrupt_enable(dma->channel, DMA_FDT_INT, TRUE); + dma_init(dma->stream, &init); + dma_interrupt_enable(dma->stream, DMA_FDT_INT, TRUE); interrupt_enable(dma->irq, DMA_PRIORITY); -} - -void dshot_init_timer() { - rcc_enable(RCC_ENCODE(TMR1)); - // setup timer to 1/3 of the full bit time - tmr_base_init(TMR1, DSHOT_SYMBOL_TIME, 0); - tmr_clock_source_div_set(TMR1, TMR_CLOCK_DIV1); - tmr_cnt_dir_set(TMR1, TMR_COUNT_UP); - tmr_period_buffer_enable(TMR1, TRUE); - - for (uint32_t j = 0; j < dshot_gpio_port_count; j++) { - dshot_init_gpio_port(&dshot_gpio_ports[j]); - - for (uint8_t i = 0; i < DSHOT_DMA_SYMBOLS; i++) { - dshot_output_buffer[j][i * 3 + 0] = dshot_gpio_ports[j].set_mask; // start bit - dshot_output_buffer[j][i * 3 + 1] = 0; // actual bit, set below - dshot_output_buffer[j][i * 3 + 2] = dshot_gpio_ports[j].reset_mask; // return line to low - } - } - - tmr_counter_enable(TMR1, TRUE); + tmr_counter_enable(tim->instance, TRUE); } void dshot_dma_setup_output(uint32_t index) { - tmr_period_value_set(TMR1, DSHOT_SYMBOL_TIME); - const dshot_gpio_port_t *port = &dshot_gpio_ports[index]; - const dma_stream_def_t *dma = &dma_stream_defs[port->dma_device]; - dma->channel->ctrl_bit.dtd = 1; // DMA_DIR_MEMORY_TO_PERIPHERAL - dma->channel->ctrl_bit.mwidth = DMA_MEMORY_DATA_WIDTH_WORD; - dma->channel->ctrl_bit.pwidth = DMA_PERIPHERAL_DATA_WIDTH_WORD; - dma->channel->paddr = (uint32_t)(&port->gpio->scr); - dma->channel->maddr = (uint32_t)(&dshot_output_buffer[index][0]); - dma->channel->dtcnt_bit.cnt = DSHOT_DMA_BUFFER_SIZE; + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(port->timer_tag)]; + tmr_period_value_set(tim->instance, DSHOT_SYMBOL_TIME); - dma_channel_enable(dma->channel, TRUE); - timer_enable_dma_request(TIMER1, port->timer_channel, true); + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[port->dma_device].dma]; + dma->stream->ctrl_bit.dtd = 1; // DMA_DIR_MEMORY_TO_PERIPHERAL + dma->stream->ctrl_bit.mwidth = DMA_MEMORY_DATA_WIDTH_WORD; + dma->stream->ctrl_bit.pwidth = DMA_PERIPHERAL_DATA_WIDTH_WORD; + dma->stream->paddr = (uint32_t)(&port->gpio->scr); + dma->stream->maddr = (uint32_t)(&dshot_output_buffer[index][0]); + dma->stream->dtcnt_bit.cnt = DSHOT_DMA_BUFFER_SIZE; + + dma_channel_enable(dma->stream, TRUE); + timer_enable_dma_request(TIMER_TAG_TIM(port->timer_tag), TIMER_TAG_CH(port->timer_tag), true); } void dshot_dma_setup_input(uint32_t index) { - tmr_period_value_set(TMR1, GCR_SYMBOL_TIME); - const dshot_gpio_port_t *port = &dshot_gpio_ports[index]; - const dma_stream_def_t *dma = &dma_stream_defs[port->dma_device]; - dma->channel->ctrl_bit.dtd = 0; // DMA_DIR_PERIPHERAL_TO_MEMORY - dma->channel->ctrl_bit.mwidth = DMA_MEMORY_DATA_WIDTH_HALFWORD; - dma->channel->ctrl_bit.pwidth = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD; - dma->channel->paddr = (uint32_t)(&port->gpio->idt); - dma->channel->maddr = (uint32_t)(&dshot_input_buffer[index][0]); - dma->channel->dtcnt_bit.cnt = GCR_DMA_BUFFER_SIZE; + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(port->timer_tag)]; + tmr_period_value_set(tim->instance, GCR_SYMBOL_TIME); - dma_channel_enable(dma->channel, TRUE); - timer_enable_dma_request(TIMER1, port->timer_channel, true); + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[port->dma_device].dma]; + dma->stream->ctrl_bit.dtd = 0; // DMA_DIR_PERIPHERAL_TO_MEMORY + dma->stream->ctrl_bit.mwidth = DMA_MEMORY_DATA_WIDTH_HALFWORD; + dma->stream->ctrl_bit.pwidth = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD; + dma->stream->paddr = (uint32_t)(&port->gpio->idt); + dma->stream->maddr = (uint32_t)(&dshot_input_buffer[index][0]); + dma->stream->dtcnt_bit.cnt = GCR_DMA_BUFFER_SIZE; + + dma_channel_enable(dma->stream, TRUE); + timer_enable_dma_request(TIMER_TAG_TIM(port->timer_tag), TIMER_TAG_CH(port->timer_tag), true); } -void dshot_dma_isr(dma_device_t dev) { +void dshot_dma_isr(const dma_device_t dev) { const dma_stream_def_t *dma = &dma_stream_defs[dev]; + dma_clear_flag_tc(dma); - dma_channel_enable(dma->channel, FALSE); + dma_channel_enable(dma->stream, FALSE); const dshot_gpio_port_t *port = dshot_gpio_for_device(dev); - timer_enable_dma_request(TIMER1, port->timer_channel, false); + timer_enable_dma_request(TIMER_TAG_TIM(port->timer_tag), TIMER_TAG_CH(port->timer_tag), false); dshot_phase--; diff --git a/src/driver/mcu/at32/motor_pwm.c b/src/driver/mcu/at32/motor_pwm.c index 2f0c45f34..a0d653172 100644 --- a/src/driver/mcu/at32/motor_pwm.c +++ b/src/driver/mcu/at32/motor_pwm.c @@ -54,6 +54,7 @@ void motor_pwm_init() { tmr_output_channel_config(def->instance, timer_channel_val(ch), &tim_oc_init); tmr_channel_value_set(def->instance, timer_channel_val(ch), 0); tmr_output_channel_buffer_enable(def->instance, timer_channel_val(ch), TRUE); + tmr_channel_enable(def->instance, timer_channel_val(ch), TRUE); tmr_output_enable(def->instance, TRUE); tmr_counter_enable(def->instance, TRUE); diff --git a/src/driver/mcu/at32/rgb_led.c b/src/driver/mcu/at32/rgb_led.c new file mode 100644 index 000000000..4c8930511 --- /dev/null +++ b/src/driver/mcu/at32/rgb_led.c @@ -0,0 +1,187 @@ +#include "driver/rgb_led.h" + +#include +#include + +#include "core/project.h" +#include "driver/dma.h" +#include "driver/gpio.h" +#include "driver/interrupt.h" +#include "driver/timer.h" + +#if defined(USE_RGB_LED) + +#define TIMER_HZ PWM_CLOCK_FREQ_HZ +#define TIMER_DIV ((PWM_CLOCK_FREQ_HZ / TIMER_HZ) - 1) + +#define RGB_BIT_TIME ((TIMER_HZ / 800000) - 1) +#define RGB_T0H_TIME ((RGB_BIT_TIME / 3) + 1) +#define RGB_T1H_TIME ((RGB_BIT_TIME / 3) * 2 + 1) + +#define RGB_BITS_LED 24 +#define RGB_BUFFER_SIZE (RGB_BITS_LED * RGB_LED_MAX + 40) + +static resource_tag_t timer_tag = 0; + +static volatile bool rgb_dma_busy = false; +static DMA_RAM uint32_t rgb_timer_buffer[RGB_BUFFER_SIZE]; +static uint32_t rgb_timer_buffer_count = 0; + +static const gpio_af_t *rgb_led_find_af(gpio_pins_t pin) { + for (uint32_t j = 0; j < GPIO_AF_MAX; j++) { + const gpio_af_t *func = &gpio_pin_afs[j]; + if (func->pin != pin || + RESOURCE_TAG_TYPE(func->tag) != RESOURCE_TIM || + TIMER_TAG_CH(func->tag) == TIMER_CH1N || + TIMER_TAG_CH(func->tag) == TIMER_CH2N || + TIMER_TAG_CH(func->tag) == TIMER_CH3N || + TIMER_TAG_CH(func->tag) == TIMER_CH4N) { + continue; + } + + if (timer_alloc_tag(TIMER_USE_RGB_LED, func->tag)) { + return func; + } + } + + return NULL; +} + +void rgb_led_init() { + const gpio_pins_t pin = target.rgb_led; + if (pin == PIN_NONE) { + return; + } + + const gpio_af_t *func = rgb_led_find_af(pin); + if (func == NULL) { + return; + } + + timer_tag = func->tag; + + gpio_config_t gpio_init; + gpio_init.mode = GPIO_ALTERNATE; + gpio_init.drive = GPIO_DRIVE_HIGH; + gpio_init.output = GPIO_PUSHPULL; + gpio_init.pull = GPIO_DOWN_PULL; + gpio_pin_init_af(pin, gpio_init, func->af); + + const timer_channel_t ch = TIMER_TAG_CH(func->tag); + const timer_index_t tim = TIMER_TAG_TIM(func->tag); + const timer_def_t *def = &timer_defs[tim]; + + rcc_enable(def->rcc); + + tmr_counter_enable(def->instance, FALSE); + + tmr_base_init(def->instance, RGB_BIT_TIME, TIMER_DIV); + tmr_cnt_dir_set(def->instance, TMR_COUNT_UP); + tmr_clock_source_div_set(def->instance, TMR_CLOCK_DIV1); + + tmr_output_config_type tim_oc_init; + tmr_output_default_para_init(&tim_oc_init); + tim_oc_init.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A; + tim_oc_init.oc_idle_state = FALSE; + tim_oc_init.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH; + tim_oc_init.oc_output_state = TRUE; + tmr_output_channel_config(def->instance, timer_channel_val(ch), &tim_oc_init); + + tmr_channel_value_set(def->instance, timer_channel_val(ch), 0); + tmr_output_channel_buffer_enable(def->instance, timer_channel_val(ch), TRUE); + tmr_channel_enable(def->instance, timer_channel_val(ch), TRUE); + + tmr_period_buffer_enable(def->instance, TRUE); + + const dma_stream_def_t *rgb_dma = &dma_stream_defs[target.dma[DMA_DEVICE_RGB].dma]; + dma_enable_rcc(rgb_dma); + dma_reset(rgb_dma->stream); + + dma_init_type init; + init.peripheral_base_addr = timer_channel_addr(def->instance, ch); + init.memory_base_addr = (uint32_t)rgb_timer_buffer; + init.direction = DMA_DIR_MEMORY_TO_PERIPHERAL; + init.buffer_size = RGB_BUFFER_SIZE; + init.peripheral_inc_enable = FALSE; + init.memory_inc_enable = TRUE; + init.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_WORD; + init.memory_data_width = DMA_MEMORY_DATA_WIDTH_WORD; + init.loop_mode_enable = FALSE; + init.priority = DMA_PRIORITY_MEDIUM; + dma_init(rgb_dma->stream, &init); + dmamux_init(rgb_dma->mux, target.dma[DMA_DEVICE_RGB].request); + + interrupt_enable(rgb_dma->irq, DMA_PRIORITY); + + tmr_output_enable(def->instance, TRUE); +} + +bool rgb_led_busy() { + return rgb_dma_busy; +} + +void rgb_led_set_value(uint32_t value, uint32_t count) { + if (rgb_led_busy()) { + return; + } + + uint32_t offset = 0; + for (uint32_t i = 0; i < 20; i++) { + rgb_timer_buffer[offset++] = 0; + } + for (uint32_t i = 0; i < count; i++) { + // rgb_led_value contains a (32bit) int that contains the RGB values in G R B format already + // Test each bit and assign the T1H or T0H depending on whether it is 1 or 0. + for (int32_t j = RGB_BITS_LED - 1; j >= 0; j--) { + rgb_timer_buffer[offset++] = ((value >> j) & 0x1) ? RGB_T1H_TIME : RGB_T0H_TIME; + } + } + for (uint32_t i = 0; i < 20; i++) { + rgb_timer_buffer[offset++] = 0; + } + rgb_timer_buffer_count = offset; +} + +void rgb_led_send() { + if (rgb_led_busy()) { + return; + } + + rgb_dma_busy = true; + + const timer_channel_t ch = TIMER_TAG_CH(timer_tag); + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(timer_tag)]; + + const dma_stream_def_t *rgb_dma = &dma_stream_defs[target.dma[DMA_DEVICE_RGB].dma]; + + dma_clear_flag_tc(rgb_dma); + dma_prepare_tx_memory((void *)rgb_timer_buffer, sizeof(rgb_timer_buffer)); + + rgb_dma->stream->paddr = timer_channel_addr(tim->instance, ch); + rgb_dma->stream->maddr = (uint32_t)rgb_timer_buffer; + rgb_dma->stream->dtcnt = rgb_timer_buffer_count; + + dma_interrupt_enable(rgb_dma->stream, DMA_FDT_INT, TRUE); + + dma_channel_enable(rgb_dma->stream, TRUE); + timer_enable_dma_request(TIMER_TAG_TIM(timer_tag), ch, TRUE); + tmr_counter_enable(tim->instance, TRUE); +} + +void rgb_dma_isr(const dma_device_t dev) { + const dma_stream_def_t *dma = &dma_stream_defs[dev]; + + dma_clear_flag_tc(dma); + dma_channel_enable(dma->stream, FALSE); + + const uint8_t ch = TIMER_TAG_CH(timer_tag); + const uint8_t tim = TIMER_TAG_TIM(timer_tag); + const timer_def_t *def = &timer_defs[tim]; + + tmr_counter_enable(def->instance, FALSE); + timer_enable_dma_request(tim, ch, FALSE); + + rgb_dma_busy = false; +} + +#endif \ No newline at end of file diff --git a/src/driver/mcu/at32/spi.c b/src/driver/mcu/at32/spi.c index 6c57fa63f..dbe9f44cf 100644 --- a/src/driver/mcu/at32/spi.c +++ b/src/driver/mcu/at32/spi.c @@ -40,8 +40,6 @@ const spi_port_def_t spi_port_defs[SPI_PORT_MAX] = { extern FAST_RAM spi_txn_t txn_pool[SPI_TXN_MAX]; -#define PORT spi_port_defs[port] - static uint32_t spi_divider_to_ll(uint32_t divider) { switch (divider) { default: @@ -81,13 +79,13 @@ static uint32_t spi_find_divder(uint32_t clk_hz) { } static void spi_dma_init_rx(spi_ports_t port) { - const dma_stream_def_t *dma = &dma_stream_defs[PORT.dma_rx]; + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; - dma_reset(dma->channel); - dmamux_init(dma->mux, dma->request); + dma_reset(dma->stream); + dmamux_init(dma->mux, target.dma[spi_port_defs[port].dma_rx].request); dma_init_type init; - init.peripheral_base_addr = (uint32_t)(&PORT.channel->dt); + init.peripheral_base_addr = (uint32_t)(&spi_port_defs[port].channel->dt); init.memory_base_addr = 0; init.direction = DMA_DIR_PERIPHERAL_TO_MEMORY; init.buffer_size = 0; @@ -97,25 +95,17 @@ static void spi_dma_init_rx(spi_ports_t port) { init.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE; init.loop_mode_enable = FALSE; init.priority = DMA_PRIORITY_HIGH; - dma_init(dma->channel, &init); -} - -static void spi_dma_reset_rx(spi_ports_t port, uint8_t *rx_data, uint32_t rx_size) { - dma_prepare_rx_memory(rx_data, rx_size); - - const dma_stream_def_t *dma = &dma_stream_defs[PORT.dma_rx]; - dma->channel->maddr = (uint32_t)rx_data; - dma_data_number_set(dma->channel, rx_size); + dma_init(dma->stream, &init); } static void spi_dma_init_tx(spi_ports_t port) { - const dma_stream_def_t *dma = &dma_stream_defs[PORT.dma_tx]; + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; - dma_reset(dma->channel); - dmamux_init(dma->mux, dma->request); + dma_reset(dma->stream); + dmamux_init(dma->mux, target.dma[spi_port_defs[port].dma_rx].request); dma_init_type init; - init.peripheral_base_addr = (uint32_t)(&PORT.channel->dt); + init.peripheral_base_addr = (uint32_t)(&spi_port_defs[port].channel->dt); init.memory_base_addr = 0; init.direction = DMA_DIR_MEMORY_TO_PERIPHERAL; init.buffer_size = 0; @@ -125,15 +115,7 @@ static void spi_dma_init_tx(spi_ports_t port) { init.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE; init.loop_mode_enable = FALSE; init.priority = DMA_PRIORITY_HIGH; - dma_init(dma->channel, &init); -} - -static void spi_dma_reset_tx(spi_ports_t port, uint8_t *tx_data, uint32_t tx_size) { - dma_prepare_tx_memory(tx_data, tx_size); - - const dma_stream_def_t *dma = &dma_stream_defs[PORT.dma_tx]; - dma->channel->maddr = (uint32_t)tx_data; - dma_data_number_set(dma->channel, tx_size); + dma_init(dma->stream, &init); } static void spi_set_divider(spi_type *channel, spi_mclk_freq_div_type div) { @@ -186,32 +168,42 @@ void spi_reconfigure(spi_bus_device_t *bus) { } void spi_dma_transfer_begin(spi_ports_t port, uint8_t *buffer, uint32_t length) { - const dma_stream_def_t *dma_tx = &dma_stream_defs[PORT.dma_tx]; - const dma_stream_def_t *dma_rx = &dma_stream_defs[PORT.dma_rx]; + const dma_stream_def_t *dma_tx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; + const dma_stream_def_t *dma_rx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; dma_clear_flag_tc(dma_rx); dma_clear_flag_tc(dma_tx); - spi_dma_reset_rx(port, buffer, length); - spi_dma_reset_tx(port, buffer, length); + dma_prepare_rx_memory(buffer, length); + dma_prepare_tx_memory(buffer, length); + + dma_rx->stream->maddr = (uint32_t)buffer; + dma_data_number_set(dma_rx->stream, length); + + dma_tx->stream->maddr = (uint32_t)buffer; + dma_data_number_set(dma_tx->stream, length); - dma_interrupt_enable(dma_rx->channel, DMA_FDT_INT, TRUE); - dma_interrupt_enable(dma_rx->channel, DMA_DTERR_INT, TRUE); + dma_interrupt_enable(dma_rx->stream, DMA_FDT_INT, TRUE); + dma_interrupt_enable(dma_rx->stream, DMA_DTERR_INT, TRUE); - dma_channel_enable(dma_rx->channel, TRUE); - dma_channel_enable(dma_tx->channel, TRUE); + dma_channel_enable(dma_rx->stream, TRUE); + dma_channel_enable(dma_tx->stream, TRUE); - spi_i2s_dma_transmitter_enable(PORT.channel, TRUE); - spi_i2s_dma_receiver_enable(PORT.channel, TRUE); + spi_i2s_dma_transmitter_enable(spi_port_defs[port].channel, TRUE); + spi_i2s_dma_receiver_enable(spi_port_defs[port].channel, TRUE); - spi_enable(PORT.channel, TRUE); + spi_enable(spi_port_defs[port].channel, TRUE); } void spi_device_init(spi_ports_t port) { const spi_port_def_t *def = &spi_port_defs[port]; rcc_enable(def->rcc); - dma_enable_rcc(def->dma_rx); - dma_enable_rcc(def->dma_tx); + + const dma_stream_def_t *dma_rx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; + const dma_stream_def_t *dma_tx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; + + dma_enable_rcc(dma_rx); + dma_enable_rcc(dma_tx); spi_i2s_reset(def->channel); @@ -233,7 +225,6 @@ void spi_device_init(spi_ports_t port) { spi_dma_init_rx(port); spi_dma_init_tx(port); - const dma_stream_def_t *dma_rx = &dma_stream_defs[def->dma_rx]; interrupt_enable(dma_rx->irq, DMA_PRIORITY); } @@ -250,7 +241,7 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs spi_reconfigure(bus); spi_csn_enable(bus); - spi_enable(PORT.channel, TRUE); + spi_enable(spi_port_defs[port].channel, TRUE); for (uint32_t i = 0; i < count; i++) { const spi_txn_segment_t *seg = &segs[i]; @@ -267,15 +258,15 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs } for (uint32_t j = 0; j < size; j++) { - while (!spi_i2s_flag_get(PORT.channel, SPI_I2S_TDBE_FLAG)) + while (!spi_i2s_flag_get(spi_port_defs[port].channel, SPI_I2S_TDBE_FLAG)) ; - spi_i2s_data_transmit(PORT.channel, tx_data ? tx_data[j] : 0xFF); + spi_i2s_data_transmit(spi_port_defs[port].channel, tx_data ? tx_data[j] : 0xFF); - while (!spi_i2s_flag_get(PORT.channel, SPI_I2S_RDBF_FLAG)) + while (!spi_i2s_flag_get(spi_port_defs[port].channel, SPI_I2S_RDBF_FLAG)) ; - const uint8_t ret = spi_i2s_data_receive(PORT.channel); + const uint8_t ret = spi_i2s_data_receive(spi_port_defs[port].channel); if (rx_data != NULL) { rx_data[j] = ret; } @@ -283,14 +274,14 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs } spi_csn_disable(bus); - spi_enable(PORT.channel, FALSE); + spi_enable(spi_port_defs[port].channel, FALSE); spi_dev[port].dma_done = true; } static void handle_dma_rx_isr(spi_ports_t port) { - const dma_stream_def_t *dma_rx = &dma_stream_defs[PORT.dma_rx]; - const dma_stream_def_t *dma_tx = &dma_stream_defs[PORT.dma_tx]; + const dma_stream_def_t *dma_tx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; + const dma_stream_def_t *dma_rx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; if (!dma_is_flag_active_tc(dma_rx)) { return; @@ -299,21 +290,21 @@ static void handle_dma_rx_isr(spi_ports_t port) { dma_clear_flag_tc(dma_rx); dma_clear_flag_tc(dma_tx); - dma_interrupt_enable(dma_rx->channel, DMA_FDT_INT, FALSE); - dma_interrupt_enable(dma_rx->channel, DMA_DTERR_INT, FALSE); + dma_interrupt_enable(dma_rx->stream, DMA_FDT_INT, FALSE); + dma_interrupt_enable(dma_rx->stream, DMA_DTERR_INT, FALSE); - spi_i2s_dma_transmitter_enable(PORT.channel, FALSE); - spi_i2s_dma_receiver_enable(PORT.channel, FALSE); + spi_i2s_dma_transmitter_enable(spi_port_defs[port].channel, FALSE); + spi_i2s_dma_receiver_enable(spi_port_defs[port].channel, FALSE); - dma_channel_enable(dma_rx->channel, FALSE); - dma_channel_enable(dma_tx->channel, FALSE); + dma_channel_enable(dma_rx->stream, FALSE); + dma_channel_enable(dma_tx->stream, FALSE); - spi_enable(PORT.channel, FALSE); + spi_enable(spi_port_defs[port].channel, FALSE); spi_txn_finish(port); } -void spi_dma_isr(dma_device_t dev) { +void spi_dma_isr(const dma_device_t dev) { switch (dev) { case DMA_DEVICE_SPI1_RX: handle_dma_rx_isr(SPI_PORT1); diff --git a/src/driver/mcu/at32/system.h b/src/driver/mcu/at32/system.h index 8e9a65176..df760fa2a 100644 --- a/src/driver/mcu/at32/system.h +++ b/src/driver/mcu/at32/system.h @@ -20,17 +20,13 @@ typedef tmr_type timer_dev_t; typedef usart_type usart_dev_t; typedef struct { - uint32_t device; - dma_type *port; uint8_t port_index; - dma_channel_type *channel; - uint8_t channel_index; + dma_channel_type *stream; + uint8_t stream_index; - uint32_t request; dmamux_channel_type *mux; - IRQn_Type irq; } dma_stream_def_t; diff --git a/src/driver/mcu/at32/timer.c b/src/driver/mcu/at32/timer.c index fd7ab6004..c29a96e6e 100644 --- a/src/driver/mcu/at32/timer.c +++ b/src/driver/mcu/at32/timer.c @@ -108,6 +108,24 @@ uint32_t timer_channel_val(timer_channel_t chan) { } } +uint32_t timer_channel_addr(timer_dev_t *timer, timer_channel_t chan) { + switch (chan) { + case TIMER_CH1: + case TIMER_CH1N: + return (uint32_t)(&timer->c1dt); + case TIMER_CH2: + case TIMER_CH2N: + return (uint32_t)(&timer->c2dt); + case TIMER_CH3: + case TIMER_CH3N: + return (uint32_t)(&timer->c3dt); + case TIMER_CH4: + return (uint32_t)(&timer->c4dt); + default: + return 0; + } +} + void timer_enable_dma_request(timer_index_t tim, timer_channel_t chan, bool state) { const timer_def_t *def = &timer_defs[tim]; diff --git a/src/driver/mcu/stm32/dma.c b/src/driver/mcu/stm32/dma.c index 13e7af8fe..1a16bac7a 100644 --- a/src/driver/mcu/stm32/dma.c +++ b/src/driver/mcu/stm32/dma.c @@ -1,103 +1,37 @@ #include "driver/dma.h" +#include "driver/adc.h" #include "driver/rcc.h" +#include "driver/resource.h" +#include "driver/timer.h" -#if !defined(STM32G4) -// DMA1 Stream0 SPI3_RX -// DMA1 Stream1 -// DMA1 Stream2 -// DMA1 Stream3 SPI2_RX -// DMA1 Stream4 SPI2_TX -// DMA1 Stream5 -// DMA1 Stream6 -// DMA1 Stream7 SPI3_TX - -// DMA2 Stream0 SPI4_RX -// DMA2 Stream1 SPI4_TX -// DMA2 Stream2 SPI1_RX -// DMA2 Stream3 TIM1_CH1 -// DMA2 Stream4 TIM1_CH4 -// DMA2 Stream5 SPI1_TX -// DMA2 Stream6 TIM1_CH3 -// DMA2 Stream7 - -#define DMA_STREAMS \ - DMA_STREAM(2, 3, 2, SPI1_RX) \ - DMA_STREAM(2, 3, 5, SPI1_TX) \ - DMA_STREAM(1, 0, 3, SPI2_RX) \ - DMA_STREAM(1, 0, 4, SPI2_TX) \ - DMA_STREAM(1, 0, 0, SPI3_RX) \ - DMA_STREAM(1, 0, 7, SPI3_TX) \ - DMA_STREAM(2, 4, 0, SPI4_RX) \ - DMA_STREAM(2, 4, 1, SPI4_TX) \ - DMA_STREAM(2, 6, 3, TIM1_CH1) \ - DMA_STREAM(2, 6, 6, TIM1_CH3) \ - DMA_STREAM(2, 6, 4, TIM1_CH4) -#else -#define DMA_STREAMS \ - DMA_STREAM(1, 0, 1, SPI1_RX) \ - DMA_STREAM(1, 0, 2, SPI1_TX) \ - DMA_STREAM(1, 0, 3, SPI2_RX) \ - DMA_STREAM(1, 0, 4, SPI2_TX) \ - DMA_STREAM(1, 0, 5, SPI3_RX) \ - DMA_STREAM(1, 0, 6, SPI3_TX) \ - DMA_STREAM(1, 0, 7, SPI4_RX) \ - DMA_STREAM(1, 0, 8, SPI4_TX) \ - DMA_STREAM(2, 0, 1, TIM1_CH1) \ - DMA_STREAM(2, 0, 2, TIM1_CH3) \ - DMA_STREAM(2, 0, 3, TIM1_CH4) +#if defined(STM32F7) || defined(STM32H7) +#define CACHE_LINE_SIZE 32 +#define CACHE_LINE_MASK (CACHE_LINE_SIZE - 1) #endif #if defined(STM32G4) -#define DMA_STREAM(_port, _chan, _stream, _dev) \ - [DMA_DEVICE_##_dev] = { \ - .device = DMA_DEVICE_##_dev, \ +#define DMA_STREAM(_port, _stream) \ + { \ .port = DMA##_port, \ .port_index = _port, \ - .channel = 0, \ - .channel_index = 0, \ - .request = LL_DMAMUX_REQ_##_dev, \ .stream = DMA##_port##_Channel##_stream, \ .stream_index = LL_DMA_CHANNEL_##_stream, \ .irq = DMA##_port##_Channel##_stream##_IRQn, \ }, -#elif defined(STM32H7) -#define DMA_STREAM(_port, _chan, _stream, _dev) \ - [DMA_DEVICE_##_dev] = { \ - .device = DMA_DEVICE_##_dev, \ - .port = DMA##_port, \ - .port_index = _port, \ - .channel = -1, \ - .channel_index = -1, \ - .request = LL_DMAMUX1_REQ_##_dev, \ - .stream = DMA##_port##_Stream##_stream, \ - .stream_index = LL_DMA_STREAM_##_stream, \ - .irq = DMA##_port##_Stream##_stream##_IRQn, \ - }, #else -#define DMA_STREAM(_port, _chan, _stream, _dev) \ - [DMA_DEVICE_##_dev] = { \ - .device = DMA_DEVICE_##_dev, \ +#define DMA_STREAM(_port, _stream) \ + { \ .port = DMA##_port, \ .port_index = _port, \ - .channel = LL_DMA_CHANNEL_##_chan, \ - .channel_index = _chan, \ - .request = -1, \ .stream = DMA##_port##_Stream##_stream, \ .stream_index = LL_DMA_STREAM_##_stream, \ .irq = DMA##_port##_Stream##_stream##_IRQn, \ }, #endif - -const dma_stream_def_t dma_stream_defs[DMA_DEVICE_MAX] = {DMA_STREAMS}; - +const dma_stream_def_t dma_stream_defs[DMA_STREAM_MAX] = {DMA_STREAMS}; #undef DMA_STREAM -#if defined(STM32F7) || defined(STM32H7) -#define CACHE_LINE_SIZE 32 -#define CACHE_LINE_MASK (CACHE_LINE_SIZE - 1) -#endif - void dma_prepare_tx_memory(void *addr, uint32_t size) { #if defined(STM32F7) || defined(STM32H7) if (!WITHIN_DTCM_RAM(addr) && !WITHIN_DMA_RAM(addr)) { @@ -114,13 +48,12 @@ void dma_prepare_rx_memory(void *addr, uint32_t size) { #endif } -void dma_enable_rcc(dma_device_t dev) { +void dma_enable_rcc(const dma_stream_def_t *def) { #ifdef STM32G4 rcc_enable(RCC_AHB1_GRP1(DMAMUX1)); #endif - const dma_stream_def_t *dma = &dma_stream_defs[dev]; - switch (dma->port_index) { + switch (def->port_index) { case 1: rcc_enable(RCC_AHB1_GRP1(DMA1)); break; @@ -130,10 +63,11 @@ void dma_enable_rcc(dma_device_t dev) { } } -extern void dshot_dma_isr(dma_device_t dev); -extern void spi_dma_isr(dma_device_t dev); +extern void dshot_dma_isr(const dma_device_t); +extern void spi_dma_isr(const dma_device_t); +extern void rgb_dma_isr(const dma_device_t); -static void handle_dma_stream_isr(dma_device_t dev) { +static void handle_dma_stream_isr(const dma_device_t dev) { switch (dev) { case DMA_DEVICE_SPI1_RX: case DMA_DEVICE_SPI2_RX: @@ -145,21 +79,27 @@ static void handle_dma_stream_isr(dma_device_t dev) { case DMA_DEVICE_SPI4_TX: spi_dma_isr(dev); break; - case DMA_DEVICE_TIM1_CH1: - case DMA_DEVICE_TIM1_CH3: - case DMA_DEVICE_TIM1_CH4: + case DMA_DEVICE_DSHOT_CH1: + case DMA_DEVICE_DSHOT_CH2: + case DMA_DEVICE_DSHOT_CH3: #ifdef USE_MOTOR_DSHOT dshot_dma_isr(dev); #endif break; + case DMA_DEVICE_RGB: +#ifdef USE_RGB_LED + rgb_dma_isr(dev); +#endif + break; + case DMA_DEVICE_INVALID: case DMA_DEVICE_MAX: break; } } -#define DMA_STREAM(_port, _chan, _stream, _dev) \ - void DMA##_port##_Stream##_stream##_IRQHandler() { handle_dma_stream_isr(DMA_DEVICE_##_dev); } \ - void DMA##_port##_Channel##_stream##_IRQHandler() { handle_dma_stream_isr(DMA_DEVICE_##_dev); } +#define DMA_STREAM(_port, _stream) \ + void DMA##_port##_Stream##_stream##_IRQHandler() { handle_dma_stream_isr(dma_stream_map[DMA##_port##_STREAM##_stream]); } \ + void DMA##_port##_Channel##_stream##_IRQHandler() { handle_dma_stream_isr(dma_stream_map[DMA##_port##_STREAM##_stream]); } DMA_STREAMS diff --git a/src/driver/mcu/stm32/dma.h b/src/driver/mcu/stm32/dma.h index 4f6269627..c689f275c 100644 --- a/src/driver/mcu/stm32/dma.h +++ b/src/driver/mcu/stm32/dma.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifdef STM32G4 #define DMA_FLAG_TE (0x1 << 3) #define DMA_FLAG_HT (0x1 << 2) @@ -14,6 +16,24 @@ #define LL_DMA_DisableStream LL_DMA_DisableChannel #define LL_DMA_IsEnabledStream LL_DMA_IsEnabledChannel +#define DMA_STREAMS \ + DMA_STREAM(1, 1) \ + DMA_STREAM(1, 2) \ + DMA_STREAM(1, 3) \ + DMA_STREAM(1, 4) \ + DMA_STREAM(1, 5) \ + DMA_STREAM(1, 6) \ + DMA_STREAM(1, 7) \ + DMA_STREAM(1, 8) \ + DMA_STREAM(2, 1) \ + DMA_STREAM(2, 2) \ + DMA_STREAM(2, 3) \ + DMA_STREAM(2, 4) \ + DMA_STREAM(2, 5) \ + DMA_STREAM(2, 6) \ + DMA_STREAM(2, 7) \ + DMA_STREAM(2, 8) + #else #define DMA_FLAG_TC (0x1 << 5) #define DMA_FLAG_HT (0x1 << 4) @@ -35,4 +55,22 @@ static const uint32_t _dma_flag_shift[] = {0, 6, 16, 22, 0, 6, 16, 22}; WRITE_REG(dev->port->HIFCR, dma_flag_for_channel(dev, DMA_FLAG_TC | DMA_FLAG_TE | DMA_FLAG_HT | DMA_FLAG_FE)); \ } -#endif \ No newline at end of file +#define DMA_STREAMS \ + DMA_STREAM(1, 0) \ + DMA_STREAM(1, 1) \ + DMA_STREAM(1, 2) \ + DMA_STREAM(1, 3) \ + DMA_STREAM(1, 4) \ + DMA_STREAM(1, 5) \ + DMA_STREAM(1, 6) \ + DMA_STREAM(1, 7) \ + DMA_STREAM(2, 0) \ + DMA_STREAM(2, 1) \ + DMA_STREAM(2, 2) \ + DMA_STREAM(2, 3) \ + DMA_STREAM(2, 4) \ + DMA_STREAM(2, 5) \ + DMA_STREAM(2, 6) \ + DMA_STREAM(2, 7) + +#endif diff --git a/src/driver/mcu/stm32/motor_dshot.c b/src/driver/mcu/stm32/motor_dshot.c index a77860dca..04f6c532c 100644 --- a/src/driver/mcu/stm32/motor_dshot.c +++ b/src/driver/mcu/stm32/motor_dshot.c @@ -2,6 +2,7 @@ #include +#include "core/failloop.h" #include "core/profile.h" #include "core/project.h" #include "driver/dma.h" @@ -11,7 +12,60 @@ #ifdef USE_MOTOR_DSHOT -static void dshot_init_gpio_port(dshot_gpio_port_t *port) { +extern uint16_t dshot_packet[MOTOR_PIN_MAX]; +extern dshot_pin_t dshot_pins[MOTOR_PIN_MAX]; +extern volatile uint32_t dshot_dma_phase; + +extern uint8_t dshot_gpio_port_count; +extern dshot_gpio_port_t dshot_gpio_ports[DSHOT_MAX_PORT_COUNT]; + +extern volatile DMA_RAM uint32_t port_dma_buffer[DSHOT_MAX_PORT_COUNT][DSHOT_DMA_BUFFER_SIZE]; + +static const resource_tag_t timers[] = { +#ifndef STM32F411 + TIMER_TAG(TIMER8, TIMER_CH1), + TIMER_TAG(TIMER8, TIMER_CH2), + TIMER_TAG(TIMER8, TIMER_CH3), + TIMER_TAG(TIMER8, TIMER_CH4), +#endif + TIMER_TAG(TIMER1, TIMER_CH1), + TIMER_TAG(TIMER1, TIMER_CH2), + TIMER_TAG(TIMER1, TIMER_CH3), + TIMER_TAG(TIMER1, TIMER_CH4), +}; +static const uint32_t timer_count = sizeof(timers) / sizeof(resource_tag_t); + +extern const dshot_gpio_port_t *dshot_gpio_for_device(const dma_device_t dev); + +void dshot_init_gpio_port(dshot_gpio_port_t *port) { + for (uint8_t i = 0; i < timer_count; i++) { + const resource_tag_t tag = timers[i]; + if (timer_alloc_tag(TIMER_USE_MOTOR_DSHOT, tag)) { + port->timer_tag = tag; + break; + } + } + if (port->timer_tag == 0) { + failloop(FAILLOOP_DMA); + } + + const timer_channel_t ch = TIMER_TAG_CH(port->timer_tag); + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(port->timer_tag)]; + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[port->dma_device].dma]; + + rcc_enable(tim->rcc); + + // setup timer to 1/3 of the full bit time + LL_TIM_InitTypeDef tim_init; + LL_TIM_StructInit(&tim_init); + tim_init.Autoreload = DSHOT_SYMBOL_TIME; + tim_init.Prescaler = 0; + tim_init.ClockDivision = 0; + tim_init.CounterMode = LL_TIM_COUNTERMODE_UP; + LL_TIM_Init(tim->instance, &tim_init); + LL_TIM_EnableARRPreload(tim->instance); + LL_TIM_DisableMasterSlaveMode(tim->instance); + LL_TIM_OC_InitTypeDef tim_oc_init; LL_TIM_OC_StructInit(&tim_oc_init); tim_oc_init.OCMode = LL_TIM_OCMODE_PWM1; @@ -19,20 +73,18 @@ static void dshot_init_gpio_port(dshot_gpio_port_t *port) { tim_oc_init.OCState = LL_TIM_OCSTATE_ENABLE; tim_oc_init.OCPolarity = LL_TIM_OCPOLARITY_LOW; tim_oc_init.CompareValue = 10; - LL_TIM_OC_Init(TIM1, timer_channel_val(port->timer_channel), &tim_oc_init); - LL_TIM_OC_EnablePreload(TIM1, timer_channel_val(port->timer_channel)); + LL_TIM_OC_Init(tim->instance, ch, &tim_oc_init); + LL_TIM_OC_EnablePreload(tim->instance, ch); - const dma_stream_def_t *dma = &dma_stream_defs[port->dma_device]; - - dma_enable_rcc(port->dma_device); + dma_enable_rcc(dma); LL_DMA_DeInit(dma->port, dma->stream_index); LL_DMA_InitTypeDef DMA_InitStructure; LL_DMA_StructInit(&DMA_InitStructure); #if defined(STM32H7) || defined(STM32G4) - DMA_InitStructure.PeriphRequest = dma->request; + DMA_InitStructure.PeriphRequest = target.dma[port->dma_device].request; #else - DMA_InitStructure.Channel = dma->channel; + DMA_InitStructure.Channel = target.dma[port->dma_device].channel; #endif DMA_InitStructure.PeriphOrM2MSrcAddress = 0x0; // overwritten later DMA_InitStructure.MemoryOrM2MDstAddress = 0x0; // overwritten later @@ -50,44 +102,20 @@ static void dshot_init_gpio_port(dshot_gpio_port_t *port) { DMA_InitStructure.PeriphBurst = LL_DMA_PBURST_SINGLE; #endif LL_DMA_Init(dma->port, dma->stream_index, &DMA_InitStructure); - LL_DMA_EnableIT_TC(dma->port, dma->stream_index); interrupt_enable(dma->irq, DMA_PRIORITY); -} - -void dshot_init_timer() { - rcc_enable(RCC_APB2_GRP1(TIM1)); - - // setup timer to 1/3 of the full bit time - LL_TIM_InitTypeDef tim_init; - LL_TIM_StructInit(&tim_init); - tim_init.Autoreload = DSHOT_SYMBOL_TIME; - tim_init.Prescaler = 0; - tim_init.ClockDivision = 0; - tim_init.CounterMode = LL_TIM_COUNTERMODE_UP; - LL_TIM_Init(TIM1, &tim_init); - LL_TIM_EnableARRPreload(TIM1); - LL_TIM_DisableMasterSlaveMode(TIM1); - - for (uint32_t j = 0; j < dshot_gpio_port_count; j++) { - dshot_init_gpio_port(&dshot_gpio_ports[j]); - - for (uint8_t i = 0; i < DSHOT_DMA_SYMBOLS; i++) { - dshot_output_buffer[j][i * 3 + 0] = dshot_gpio_ports[j].set_mask; // start bit - dshot_output_buffer[j][i * 3 + 1] = 0; // actual bit, set below - dshot_output_buffer[j][i * 3 + 2] = dshot_gpio_ports[j].reset_mask; // return line to low - } - } + LL_DMA_EnableIT_TC(dma->port, dma->stream_index); - LL_TIM_EnableCounter(TIM1); + LL_TIM_EnableCounter(tim->instance); } void dshot_dma_setup_output(uint32_t index) { - LL_TIM_SetAutoReload(TIM1, DSHOT_SYMBOL_TIME); - const dshot_gpio_port_t *port = &dshot_gpio_ports[index]; - const dma_stream_def_t *dma = &dma_stream_defs[port->dma_device]; + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(port->timer_tag)]; + LL_TIM_SetAutoReload(tim->instance, DSHOT_SYMBOL_TIME); + + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[port->dma_device].dma]; LL_DMA_SetPeriphAddress(dma->port, dma->stream_index, (uint32_t)&port->gpio->BSRR); LL_DMA_SetMemoryAddress(dma->port, dma->stream_index, (uint32_t)&dshot_output_buffer[index][0]); LL_DMA_SetDataLength(dma->port, dma->stream_index, DSHOT_DMA_BUFFER_SIZE); @@ -96,15 +124,16 @@ void dshot_dma_setup_output(uint32_t index) { LL_DMA_SetMemorySize(dma->port, dma->stream_index, LL_DMA_MDATAALIGN_WORD); LL_DMA_EnableStream(dma->port, dma->stream_index); - timer_enable_dma_request(TIMER1, port->timer_channel, true); + timer_enable_dma_request(TIMER_TAG_TIM(port->timer_tag), TIMER_TAG_CH(port->timer_tag), true); } void dshot_dma_setup_input(uint32_t index) { - LL_TIM_SetAutoReload(TIM1, GCR_SYMBOL_TIME); - const dshot_gpio_port_t *port = &dshot_gpio_ports[index]; - const dma_stream_def_t *dma = &dma_stream_defs[port->dma_device]; + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(port->timer_tag)]; + LL_TIM_SetAutoReload(tim->instance, GCR_SYMBOL_TIME); + + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[port->dma_device].dma]; LL_DMA_SetPeriphAddress(dma->port, dma->stream_index, (uint32_t)&port->gpio->IDR); LL_DMA_SetMemoryAddress(dma->port, dma->stream_index, (uint32_t)&dshot_input_buffer[index][0]); LL_DMA_SetDataLength(dma->port, dma->stream_index, GCR_DMA_BUFFER_SIZE); @@ -113,16 +142,17 @@ void dshot_dma_setup_input(uint32_t index) { LL_DMA_SetMemorySize(dma->port, dma->stream_index, LL_DMA_MDATAALIGN_HALFWORD); LL_DMA_EnableStream(dma->port, dma->stream_index); - timer_enable_dma_request(TIMER1, port->timer_channel, true); + timer_enable_dma_request(TIMER_TAG_TIM(port->timer_tag), TIMER_TAG_CH(port->timer_tag), true); } -void dshot_dma_isr(dma_device_t dev) { +void dshot_dma_isr(const dma_device_t dev) { const dma_stream_def_t *dma = &dma_stream_defs[dev]; + dma_clear_flag_tc(dma); LL_DMA_DisableStream(dma->port, dma->stream_index); const dshot_gpio_port_t *port = dshot_gpio_for_device(dev); - timer_enable_dma_request(TIMER1, port->timer_channel, false); + timer_enable_dma_request(TIMER_TAG_TIM(port->timer_tag), TIMER_TAG_CH(port->timer_tag), false); dshot_phase--; diff --git a/src/driver/mcu/stm32/rgb_led.c b/src/driver/mcu/stm32/rgb_led.c new file mode 100644 index 000000000..cd28b19a3 --- /dev/null +++ b/src/driver/mcu/stm32/rgb_led.c @@ -0,0 +1,193 @@ +#include "driver/rgb_led.h" + +#include +#include + +#include "core/project.h" +#include "driver/dma.h" +#include "driver/gpio.h" +#include "driver/interrupt.h" +#include "driver/timer.h" + +#if defined(USE_RGB_LED) + +#define TIMER_HZ PWM_CLOCK_FREQ_HZ +#define TIMER_DIV ((PWM_CLOCK_FREQ_HZ / TIMER_HZ) - 1) + +#define RGB_BIT_TIME ((TIMER_HZ / 800000) - 1) +#define RGB_T0H_TIME ((RGB_BIT_TIME / 3) + 1) +#define RGB_T1H_TIME ((RGB_BIT_TIME / 3) * 2 + 1) + +#define RGB_BITS_LED 24 +#define RGB_BUFFER_SIZE (RGB_BITS_LED * RGB_LED_MAX + 40) + +static resource_tag_t timer_tag = 0; + +static volatile bool rgb_dma_busy = false; +static DMA_RAM uint32_t rgb_timer_buffer[RGB_BUFFER_SIZE]; +static uint32_t rgb_timer_buffer_count = 0; + +static const gpio_af_t *rgb_led_find_af(gpio_pins_t pin) { + for (uint32_t j = 0; j < GPIO_AF_MAX; j++) { + const gpio_af_t *func = &gpio_pin_afs[j]; + if (func->pin != pin || + RESOURCE_TAG_TYPE(func->tag) != RESOURCE_TIM || + TIMER_TAG_CH(func->tag) == TIMER_CH1N || + TIMER_TAG_CH(func->tag) == TIMER_CH2N || + TIMER_TAG_CH(func->tag) == TIMER_CH3N || + TIMER_TAG_CH(func->tag) == TIMER_CH4N) { + continue; + } + + if (timer_alloc_tag(TIMER_USE_RGB_LED, func->tag)) { + return func; + } + } + + return NULL; +} + +void rgb_led_init() { + const gpio_pins_t pin = target.rgb_led; + if (pin == PIN_NONE) { + return; + } + + const gpio_af_t *func = rgb_led_find_af(pin); + if (func == NULL) { + return; + } + + timer_tag = func->tag; + + gpio_config_t gpio_init; + gpio_init.mode = GPIO_ALTERNATE; + gpio_init.drive = GPIO_DRIVE_HIGH; + gpio_init.output = GPIO_PUSHPULL; + gpio_init.pull = GPIO_DOWN_PULL; + gpio_pin_init_af(pin, gpio_init, func->af); + + const timer_channel_t ch = TIMER_TAG_CH(func->tag); + const timer_index_t tim = TIMER_TAG_TIM(func->tag); + const timer_def_t *def = &timer_defs[tim]; + + rcc_enable(def->rcc); + + LL_TIM_InitTypeDef tim_init; + LL_TIM_StructInit(&tim_init); + tim_init.Autoreload = RGB_BIT_TIME; + tim_init.Prescaler = TIMER_DIV; + tim_init.ClockDivision = 0; + tim_init.CounterMode = LL_TIM_COUNTERMODE_UP; + LL_TIM_Init(def->instance, &tim_init); + LL_TIM_EnableARRPreload(def->instance); + LL_TIM_DisableMasterSlaveMode(def->instance); + + LL_TIM_OC_InitTypeDef tim_oc_init; + LL_TIM_OC_StructInit(&tim_oc_init); + tim_oc_init.CompareValue = 0; + tim_oc_init.OCMode = LL_TIM_OCMODE_PWM1; + tim_oc_init.OCState = LL_TIM_OCSTATE_ENABLE; + tim_oc_init.OCPolarity = LL_TIM_OCPOLARITY_HIGH; + tim_oc_init.OCIdleState = LL_TIM_OCIDLESTATE_LOW; + tim_oc_init.OCNState = LL_TIM_OCSTATE_ENABLE; + tim_oc_init.OCNPolarity = LL_TIM_OCPOLARITY_LOW; + tim_oc_init.OCNIdleState = LL_TIM_OCIDLESTATE_LOW; + LL_TIM_OC_Init(def->instance, timer_channel_val(ch), &tim_oc_init); + LL_TIM_OC_EnablePreload(def->instance, timer_channel_val(ch)); + LL_TIM_EnableAllOutputs(def->instance); + + const dma_stream_def_t *rgb_dma = &dma_stream_defs[target.dma[DMA_DEVICE_RGB].dma]; + dma_enable_rcc(rgb_dma); + LL_DMA_DeInit(rgb_dma->port, rgb_dma->stream_index); + + LL_DMA_InitTypeDef DMA_InitStructure; + LL_DMA_StructInit(&DMA_InitStructure); +#if defined(STM32H7) || defined(STM32G4) + DMA_InitStructure.PeriphRequest = target.dma[DMA_DEVICE_RGB].request; +#else + DMA_InitStructure.Channel = target.dma[DMA_DEVICE_RGB].channel; +#endif + DMA_InitStructure.PeriphOrM2MSrcAddress = timer_channel_addr(def->instance, ch); + DMA_InitStructure.MemoryOrM2MDstAddress = (uint32_t)rgb_timer_buffer; + DMA_InitStructure.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + DMA_InitStructure.NbData = RGB_BUFFER_SIZE; + DMA_InitStructure.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + DMA_InitStructure.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + DMA_InitStructure.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + DMA_InitStructure.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + DMA_InitStructure.Mode = LL_DMA_MODE_NORMAL; + DMA_InitStructure.Priority = LL_DMA_PRIORITY_VERYHIGH; +#ifndef STM32G4 + DMA_InitStructure.FIFOMode = LL_DMA_FIFOMODE_DISABLE; + DMA_InitStructure.MemBurst = LL_DMA_MBURST_SINGLE; + DMA_InitStructure.PeriphBurst = LL_DMA_PBURST_SINGLE; +#endif + LL_DMA_Init(rgb_dma->port, rgb_dma->stream_index, &DMA_InitStructure); + + LL_DMA_EnableIT_TC(rgb_dma->port, rgb_dma->stream_index); + interrupt_enable(rgb_dma->irq, DMA_PRIORITY); +} + +bool rgb_led_busy() { + return rgb_dma_busy; +} + +void rgb_led_set_value(uint32_t value, uint32_t count) { + if (rgb_led_busy()) { + return; + } + + uint32_t offset = 0; + for (uint32_t i = 0; i < 20; i++) { + rgb_timer_buffer[offset++] = 0; + } + for (uint32_t i = 0; i < count; i++) { + // rgb_led_value contains a (32bit) int that contains the RGB values in G R B format already + // Test each bit and assign the T1H or T0H depending on whether it is 1 or 0. + for (int32_t j = RGB_BITS_LED - 1; j >= 0; j--) { + rgb_timer_buffer[offset++] = ((value >> j) & 0x1) ? RGB_T1H_TIME : RGB_T0H_TIME; + } + } + for (uint32_t i = 0; i < 20; i++) { + rgb_timer_buffer[offset++] = 0; + } + rgb_timer_buffer_count = offset; +} + +void rgb_led_send() { + rgb_dma_busy = true; + + const timer_channel_t ch = TIMER_TAG_CH(timer_tag); + const timer_def_t *tim = &timer_defs[TIMER_TAG_TIM(timer_tag)]; + + const dma_stream_def_t *rgb_dma = &dma_stream_defs[target.dma[DMA_DEVICE_RGB].dma]; + + dma_clear_flag_tc(rgb_dma); + dma_prepare_tx_memory((void *)rgb_timer_buffer, sizeof(rgb_timer_buffer)); + + LL_DMA_SetMemoryAddress(rgb_dma->port, rgb_dma->stream_index, (uint32_t)rgb_timer_buffer); + LL_DMA_SetDataLength(rgb_dma->port, rgb_dma->stream_index, rgb_timer_buffer_count); + + LL_DMA_EnableStream(rgb_dma->port, rgb_dma->stream_index); + timer_enable_dma_request(TIMER_TAG_TIM(timer_tag), ch, true); + LL_TIM_EnableCounter(tim->instance); +} + +void rgb_dma_isr(const dma_device_t dev) { + const dma_stream_def_t *dma = &dma_stream_defs[dev]; + + dma_clear_flag_tc(dma); + LL_DMA_DisableStream(dma->port, dma->stream_index); + + const uint8_t ch = TIMER_TAG_CH(timer_tag); + const uint8_t tim = TIMER_TAG_TIM(timer_tag); + const timer_def_t *def = &timer_defs[tim]; + + LL_TIM_DisableCounter(def->instance); + timer_enable_dma_request(tim, ch, false); + + rgb_dma_busy = false; +} + +#endif \ No newline at end of file diff --git a/src/driver/mcu/stm32/spi.c b/src/driver/mcu/stm32/spi.c index 4aaf3f63b..2cf04e3a3 100644 --- a/src/driver/mcu/stm32/spi.c +++ b/src/driver/mcu/stm32/spi.c @@ -42,8 +42,6 @@ const spi_port_def_t spi_port_defs[SPI_PORT_MAX] = { extern FAST_RAM spi_txn_t txn_pool[SPI_TXN_MAX]; -#define PORT spi_port_defs[port] - static uint32_t spi_divider_to_ll(uint32_t divider) { switch (divider) { default: @@ -79,20 +77,20 @@ static uint32_t spi_find_divder(uint32_t clk_hz) { } static void spi_dma_init_rx(spi_ports_t port) { - const dma_stream_def_t *dma = &dma_stream_defs[PORT.dma_rx]; + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; LL_DMA_DeInit(dma->port, dma->stream_index); LL_DMA_InitTypeDef DMA_InitStructure; #if defined(STM32H7) || defined(STM32G4) - DMA_InitStructure.PeriphRequest = dma->request; + DMA_InitStructure.PeriphRequest = target.dma[spi_port_defs[port].dma_rx].request; #else - DMA_InitStructure.Channel = dma->channel; + DMA_InitStructure.Channel = target.dma[spi_port_defs[port].dma_rx].channel; #endif #if defined(STM32H7) - DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&PORT.channel->RXDR; + DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&spi_port_defs[port].channel->RXDR; #else - DMA_InitStructure.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRegAddr(PORT.channel); + DMA_InitStructure.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRegAddr(spi_port_defs[port].channel); #endif DMA_InitStructure.MemoryOrM2MDstAddress = 0; DMA_InitStructure.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; @@ -112,20 +110,20 @@ static void spi_dma_init_rx(spi_ports_t port) { } static void spi_dma_init_tx(spi_ports_t port) { - const dma_stream_def_t *dma = &dma_stream_defs[PORT.dma_tx]; + const dma_stream_def_t *dma = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; LL_DMA_DeInit(dma->port, dma->stream_index); LL_DMA_InitTypeDef DMA_InitStructure; #if defined(STM32H7) || defined(STM32G4) - DMA_InitStructure.PeriphRequest = dma->request; + DMA_InitStructure.PeriphRequest = target.dma[spi_port_defs[port].dma_rx].request; #else - DMA_InitStructure.Channel = dma->channel; + DMA_InitStructure.Channel = target.dma[spi_port_defs[port].dma_rx].channel; #endif #if defined(STM32H7) - DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&PORT.channel->TXDR; + DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&spi_port_defs[port].channel->TXDR; #else - DMA_InitStructure.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRegAddr(PORT.channel); + DMA_InitStructure.PeriphOrM2MSrcAddress = LL_SPI_DMA_GetRegAddr(spi_port_defs[port].channel); #endif DMA_InitStructure.MemoryOrM2MDstAddress = 0; DMA_InitStructure.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -180,12 +178,12 @@ void spi_reconfigure(spi_bus_device_t *bus) { void spi_dma_transfer_begin(spi_ports_t port, uint8_t *buffer, uint32_t length) { #if !defined(STM32H7) // dummy read - while (LL_SPI_IsActiveFlag_RXNE(PORT.channel)) - LL_SPI_ReceiveData8(PORT.channel); + while (LL_SPI_IsActiveFlag_RXNE(spi_port_defs[port].channel)) + LL_SPI_ReceiveData8(spi_port_defs[port].channel); #endif - const dma_stream_def_t *dma_tx = &dma_stream_defs[PORT.dma_tx]; - const dma_stream_def_t *dma_rx = &dma_stream_defs[PORT.dma_rx]; + const dma_stream_def_t *dma_tx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; + const dma_stream_def_t *dma_rx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; dma_clear_flag_tc(dma_rx); dma_clear_flag_tc(dma_tx); @@ -208,23 +206,27 @@ void spi_dma_transfer_begin(spi_ports_t port, uint8_t *buffer, uint32_t length) LL_DMA_EnableStream(dma_rx->port, dma_rx->stream_index); LL_DMA_EnableStream(dma_tx->port, dma_tx->stream_index); - LL_SPI_EnableDMAReq_TX(PORT.channel); - LL_SPI_EnableDMAReq_RX(PORT.channel); + LL_SPI_EnableDMAReq_TX(spi_port_defs[port].channel); + LL_SPI_EnableDMAReq_RX(spi_port_defs[port].channel); #ifdef STM32H7 - LL_SPI_SetTransferSize(PORT.channel, length); + LL_SPI_SetTransferSize(spi_port_defs[port].channel, length); #endif - LL_SPI_Enable(PORT.channel); + LL_SPI_Enable(spi_port_defs[port].channel); #ifdef STM32H7 - LL_SPI_StartMasterTransfer(PORT.channel); + LL_SPI_StartMasterTransfer(spi_port_defs[port].channel); #endif } void spi_device_init(spi_ports_t port) { const spi_port_def_t *def = &spi_port_defs[port]; rcc_enable(def->rcc); - dma_enable_rcc(def->dma_rx); - dma_enable_rcc(def->dma_tx); + + const dma_stream_def_t *dma_rx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; + const dma_stream_def_t *dma_tx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; + + dma_enable_rcc(dma_rx); + dma_enable_rcc(dma_tx); LL_SPI_DeInit(def->channel); @@ -258,7 +260,6 @@ void spi_device_init(spi_ports_t port) { spi_dma_init_rx(port); spi_dma_init_tx(port); - const dma_stream_def_t *dma_rx = &dma_stream_defs[def->dma_rx]; interrupt_enable(dma_rx->irq, DMA_PRIORITY); LL_DMA_EnableIT_TC(dma_rx->port, dma_rx->stream_index); @@ -283,11 +284,11 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs for (uint32_t i = 0; i < count; i++) { transfer_size += segs[i].size; } - LL_SPI_SetTransferSize(PORT.channel, transfer_size); - LL_SPI_Enable(PORT.channel); - LL_SPI_StartMasterTransfer(PORT.channel); + LL_SPI_SetTransferSize(spi_port_defs[port].channel, transfer_size); + LL_SPI_Enable(spi_port_defs[port].channel); + LL_SPI_StartMasterTransfer(spi_port_defs[port].channel); #else - LL_SPI_Enable(PORT.channel); + LL_SPI_Enable(spi_port_defs[port].channel); #endif for (uint32_t i = 0; i < count; i++) { @@ -306,21 +307,21 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs for (uint32_t j = 0; j < size; j++) { #if defined(STM32H7) - while (!LL_SPI_IsActiveFlag_TXP(PORT.channel)) + while (!LL_SPI_IsActiveFlag_TXP(spi_port_defs[port].channel)) ; #else - while (!LL_SPI_IsActiveFlag_TXE(PORT.channel)) + while (!LL_SPI_IsActiveFlag_TXE(spi_port_defs[port].channel)) ; #endif - LL_SPI_TransmitData8(PORT.channel, tx_data ? tx_data[j] : 0xFF); + LL_SPI_TransmitData8(spi_port_defs[port].channel, tx_data ? tx_data[j] : 0xFF); #if defined(STM32H7) - while (!LL_SPI_IsActiveFlag_RXP(PORT.channel)) + while (!LL_SPI_IsActiveFlag_RXP(spi_port_defs[port].channel)) ; #else - while (!LL_SPI_IsActiveFlag_RXNE(PORT.channel)) + while (!LL_SPI_IsActiveFlag_RXNE(spi_port_defs[port].channel)) ; #endif - const uint8_t ret = LL_SPI_ReceiveData8(PORT.channel); + const uint8_t ret = LL_SPI_ReceiveData8(spi_port_defs[port].channel); if (rx_data != NULL) { rx_data[j] = ret; } @@ -328,13 +329,13 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs } #if defined(STM32H7) - while (!LL_SPI_IsActiveFlag_EOT(PORT.channel)) + while (!LL_SPI_IsActiveFlag_EOT(spi_port_defs[port].channel)) ; - LL_SPI_ClearFlag_TXTF(PORT.channel); - LL_SPI_Disable(PORT.channel); + LL_SPI_ClearFlag_TXTF(spi_port_defs[port].channel); + LL_SPI_Disable(spi_port_defs[port].channel); #else - LL_SPI_Disable(PORT.channel); + LL_SPI_Disable(spi_port_defs[port].channel); #endif spi_csn_disable(bus); @@ -342,8 +343,8 @@ void spi_seg_submit_wait_ex(spi_bus_device_t *bus, const spi_txn_segment_t *segs } static void handle_dma_rx_isr(spi_ports_t port) { - const dma_stream_def_t *dma_rx = &dma_stream_defs[PORT.dma_rx]; - const dma_stream_def_t *dma_tx = &dma_stream_defs[PORT.dma_tx]; + const dma_stream_def_t *dma_tx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_tx].dma]; + const dma_stream_def_t *dma_rx = &dma_stream_defs[target.dma[spi_port_defs[port].dma_rx].dma]; if (!dma_is_flag_active_tc(dma_rx)) { return; @@ -352,23 +353,23 @@ static void handle_dma_rx_isr(spi_ports_t port) { dma_clear_flag_tc(dma_rx); dma_clear_flag_tc(dma_tx); - LL_SPI_DisableDMAReq_TX(PORT.channel); - LL_SPI_DisableDMAReq_RX(PORT.channel); + LL_SPI_DisableDMAReq_TX(spi_port_defs[port].channel); + LL_SPI_DisableDMAReq_RX(spi_port_defs[port].channel); LL_DMA_DisableStream(dma_rx->port, dma_rx->stream_index); LL_DMA_DisableStream(dma_tx->port, dma_tx->stream_index); #if defined(STM32H7) // now we can disable the peripheral - LL_SPI_ClearFlag_TXTF(PORT.channel); + LL_SPI_ClearFlag_TXTF(spi_port_defs[port].channel); #endif - LL_SPI_Disable(PORT.channel); + LL_SPI_Disable(spi_port_defs[port].channel); spi_txn_finish(port); } -void spi_dma_isr(dma_device_t dev) { +void spi_dma_isr(const dma_device_t dev) { switch (dev) { case DMA_DEVICE_SPI1_RX: handle_dma_rx_isr(SPI_PORT1); diff --git a/src/driver/mcu/stm32/system.h b/src/driver/mcu/stm32/system.h index 7aa7da0d7..0f27cee97 100644 --- a/src/driver/mcu/stm32/system.h +++ b/src/driver/mcu/stm32/system.h @@ -117,16 +117,9 @@ typedef TIM_TypeDef timer_dev_t; typedef USART_TypeDef usart_dev_t; typedef struct { - uint32_t device; - DMA_TypeDef *port; uint8_t port_index; - uint32_t channel; - uint8_t channel_index; - - uint32_t request; - #ifdef STM32G4 DMA_Channel_TypeDef *stream; #else diff --git a/src/driver/mcu/stm32/timer.c b/src/driver/mcu/stm32/timer.c index 55596bbb1..73e89b7ab 100644 --- a/src/driver/mcu/stm32/timer.c +++ b/src/driver/mcu/stm32/timer.c @@ -81,6 +81,24 @@ uint32_t timer_channel_val(timer_channel_t chan) { } } +uint32_t timer_channel_addr(timer_dev_t *timer, timer_channel_t chan) { + switch (chan) { + case TIMER_CH1: + case TIMER_CH1N: + return (uint32_t)(&timer->CCR1); + case TIMER_CH2: + case TIMER_CH2N: + return (uint32_t)(&timer->CCR2); + case TIMER_CH3: + case TIMER_CH3N: + return (uint32_t)(&timer->CCR3); + case TIMER_CH4: + return (uint32_t)(&timer->CCR4); + default: + return 0; + } +} + void timer_enable_dma_request(timer_index_t tim, timer_channel_t chan, bool state) { const timer_def_t *def = &timer_defs[tim]; diff --git a/src/driver/mcu/system.h b/src/driver/mcu/system.h new file mode 100644 index 000000000..b567ab809 --- /dev/null +++ b/src/driver/mcu/system.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef STM32 +#include "driver/mcu/stm32/system.h" +#endif + +#ifdef AT32 +#include "driver/mcu/at32/system.h" +#endif + +#ifdef SIMULATOR +#include "driver/mcu/native/system.h" +#endif \ No newline at end of file diff --git a/src/driver/motor_dshot.c b/src/driver/motor_dshot.c index c30b2b5b8..746fbd8d8 100644 --- a/src/driver/motor_dshot.c +++ b/src/driver/motor_dshot.c @@ -22,18 +22,9 @@ volatile uint32_t dshot_phase = 0; uint8_t dshot_gpio_port_count = 0; dshot_gpio_port_t dshot_gpio_ports[DSHOT_MAX_PORT_COUNT] = { - { - .timer_channel = TIMER_CH1, - .dma_device = DMA_DEVICE_TIM1_CH1, - }, - { - .timer_channel = TIMER_CH3, - .dma_device = DMA_DEVICE_TIM1_CH3, - }, - { - .timer_channel = TIMER_CH4, - .dma_device = DMA_DEVICE_TIM1_CH4, - }, + {.dma_device = DMA_DEVICE_DSHOT_CH1}, + {.dma_device = DMA_DEVICE_DSHOT_CH2}, + {.dma_device = DMA_DEVICE_DSHOT_CH3}, }; volatile DMA_RAM uint16_t dshot_input_buffer[DSHOT_MAX_PORT_COUNT][GCR_DMA_BUFFER_SIZE]; @@ -46,7 +37,7 @@ static motor_direction_t motor_dir = MOTOR_FORWARD; static bool dir_change_done = true; const dshot_gpio_port_t *dshot_gpio_for_device(const dma_device_t dev) { - return &dshot_gpio_ports[dev - DMA_DEVICE_TIM1_CH1]; + return &dshot_gpio_ports[dev - DMA_DEVICE_DSHOT_CH1]; } void dshot_gpio_init_output(gpio_pins_t pin) { @@ -219,7 +210,18 @@ void motor_dshot_init() { for (uint32_t i = 0; i < MOTOR_PIN_MAX; i++) { dshot_init_motor_pin(i); } - dshot_init_timer(); + + for (uint32_t j = 0; j < dshot_gpio_port_count; j++) { + dshot_init_gpio_port(&dshot_gpio_ports[j]); + + for (uint8_t i = 0; i < DSHOT_DMA_SYMBOLS; i++) { + dshot_output_buffer[j][i * 3 + 0] = dshot_gpio_ports[j].set_mask; // start bit + dshot_output_buffer[j][i * 3 + 1] = 0; // actual bit, set below + dshot_output_buffer[j][i * 3 + 2] = dshot_gpio_ports[j].reset_mask; // return line to low + } + } + + motor_dir = MOTOR_FORWARD; } void motor_dshot_write(float *values) { diff --git a/src/driver/motor_dshot.h b/src/driver/motor_dshot.h index 78a0a129f..8a1cea61c 100644 --- a/src/driver/motor_dshot.h +++ b/src/driver/motor_dshot.h @@ -1,6 +1,7 @@ #pragma once #include "core/profile.h" +#include "core/project.h" #include "driver/dma.h" #include "driver/gpio.h" #include "driver/motor.h" @@ -19,7 +20,8 @@ typedef struct { uint32_t set_mask; uint32_t reset_mask; - timer_channel_t timer_channel; + resource_tag_t timer_tag; + dma_device_t dma_device; } dshot_gpio_port_t; @@ -60,7 +62,7 @@ extern volatile DMA_RAM uint32_t dshot_output_buffer[DSHOT_MAX_PORT_COUNT][DSHOT const dshot_gpio_port_t *dshot_gpio_for_device(const dma_device_t dev); -void dshot_init_timer(); +void dshot_init_gpio_port(dshot_gpio_port_t *port); void dshot_gpio_init_output(gpio_pins_t pin); void dshot_dma_setup_output(uint32_t index); diff --git a/src/driver/resource.c b/src/driver/resource.c new file mode 100644 index 000000000..38625cc8f --- /dev/null +++ b/src/driver/resource.c @@ -0,0 +1,78 @@ +#include "resource.h" + +#include +#include + +#include "util/cbor_helper.h" +#include "util/util.h" + +#define check_str(str) \ + ({ \ + bool match = buf_equal_string((uint8_t *)end, sizeof(str) - 1, str); \ + if (match) \ + end += sizeof(str); \ + match; \ + }) + +cbor_result_t cbor_decode_resource_tag_t(cbor_value_t *dec, resource_tag_t *t) { + const uint8_t *name; + uint32_t name_len; + + CBOR_CHECK_ERROR(cbor_result_t res = cbor_decode_tstr(dec, &name, &name_len)); + + char *end = (char *)name; + if (check_str("SPI")) { + const int32_t index = strtol(end, &end, 10); + if (check_str("_MOSI")) { + *t = SPI_TAG(index, RES_SPI_MOSI); + } else if (check_str("_MISO")) { + *t = SPI_TAG(index, RES_SPI_MISO); + } else if (check_str("_SCK")) { + *t = SPI_TAG(index, RES_SPI_SCK); + } else { + return CBOR_ERR_INVALID_TYPE; + } + } else if (check_str("TIMER")) { + const int32_t index = strtol(end, &end, 10); + if (check_str("_CH")) { + const int32_t ch = strtol(end, &end, 10); + *t = TIMER_TAG(index, ch); + } else { + return CBOR_ERR_INVALID_TYPE; + } + } else { + return CBOR_ERR_INVALID_TYPE; + } + + return res; +} + +cbor_result_t cbor_encode_resource_tag_t(cbor_value_t *enc, const resource_tag_t *d) { + char tag[64]; + int len = 0; + + switch (RESOURCE_TAG_TYPE(*d)) { + case RESOURCE_SPI: + switch (SPI_TAG_PIN(*d)) { + case RES_SPI_MOSI: + len = snprintf(tag, 64, "SPI%d_MOSI", SPI_TAG_PORT(*d)); + break; + case RES_SPI_MISO: + len = snprintf(tag, 64, "SPI%d_MISO", SPI_TAG_PORT(*d)); + break; + case RES_SPI_SCK: + len = snprintf(tag, 64, "SPI%d_SCK", SPI_TAG_PORT(*d)); + break; + default: + break; + } + break; + case RESOURCE_TIM: + len = snprintf(tag, 64, "TIMER%d_CH%d", TIMER_TAG_TIM(*d), TIMER_TAG_CH(*d)); + break; + default: + break; + } + + return cbor_encode_tstr(enc, (uint8_t *)tag, len); +} \ No newline at end of file diff --git a/src/driver/resource.h b/src/driver/resource.h index b24594600..3a5cdbc54 100644 --- a/src/driver/resource.h +++ b/src/driver/resource.h @@ -2,6 +2,8 @@ #include +#include + typedef enum { RESOURCE_INVALID, RESOURCE_TIM, @@ -42,4 +44,7 @@ typedef uint32_t resource_tag_t; #define ADC_TAG(adc, ch) RESOURCE_TAG(RESOURCE_ADC, (uint32_t)((adc) << 8) | (ch)) #define ADC_TAG_DEV(tag) (uint8_t)(((tag) >> 8) & 0xFF) -#define ADC_TAG_CH(tag) (uint8_t)((tag)&0xFF) \ No newline at end of file +#define ADC_TAG_CH(tag) (uint8_t)((tag)&0xFF) + +cbor_result_t cbor_decode_resource_tag_t(cbor_value_t *dec, resource_tag_t *t); +cbor_result_t cbor_encode_resource_tag_t(cbor_value_t *enc, const resource_tag_t *d); \ No newline at end of file diff --git a/src/driver/rgb_led.c b/src/driver/rgb_led.c deleted file mode 100644 index a7fa6027d..000000000 --- a/src/driver/rgb_led.c +++ /dev/null @@ -1,347 +0,0 @@ -//**********************************************WARNING - THIS FILE NOT YET PORTED FROM F0 SILVERWARE*********************************** - -#include "driver/rgb_led.h" - -#include "core/project.h" -#include "driver/spi.h" -#include "driver/time.h" -#include "util/util.h" - -#if (RGB_LED_NUMBER > 0) -void rgb_send(int data); - -#ifdef RGB_LED_DMA - -#define RGB_BIT_TIME ((SYS_CLOCK_FREQ_HZ / 1000 / 800) - 1) -#define RGB_T0H_TIME (RGB_BIT_TIME * 0.30 + 0.05) -#define RGB_T1H_TIME (RGB_BIT_TIME * 0.60 + 0.05) - -extern int rgb_led_value[]; - -volatile int rgb_dma_phase = 0; // 3:rgb data ready - // 2:rgb dma buffer ready - -// wait to be cascaded after dshot, or fired at next frame if no dshot activity -// 1:rgb dma busy -// 0:idle - -const int offset = RGB_PIN > LL_GPIO_PIN_7; - -volatile uint32_t rgb_data_portA[RGB_LED_NUMBER * 24 / 4] = {0}; // DMA buffer: reset output when bit data=0 at TOH timing -volatile uint16_t rgb_portX[1] = {RGB_PIN}; // sum of all rgb pins at port -volatile uint32_t RGB_DATA16[16]; // 4-bit look-up table for dma buffer making - -void rgb_init() { - if ((RGB_PIN == LL_GPIO_PIN_13 || RGB_PIN == LL_GPIO_PIN_14) && RGB_PORT == GPIOA) { - // programming port used - // wait until 2 seconds from powerup passed - while (time_micros() < 2e6) - ; - } - - gpio_config_t GPIO_InitStructure; - - GPIO_InitStructure.mode = GPIO_OUTPUT; - GPIO_InitStructure.output = GPIO_PUSHPULL; - GPIO_InitStructure.pull = GPIO_NO_PULL; - GPIO_InitStructure.drive =GPIO_DRIVE_HIGH; - - GPIO_InitStructure.Pin = RGB_PIN; - LL_GPIO_Init(RGB_PORT, &GPIO_InitStructure); - -#ifndef USE_DSHOT_DMA_DRIVER - // RGB timer/DMA init - // TIM1_UP DMA_CH5: set all output to HIGH at TIM1 update - // TIM1_CH1 DMA_CH2: reset output if data=0 at T0H timing - // TIM1_CH4 DMA_CH4: reset all output at T1H timing - - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; - TIM_OCInitTypeDef TIM_OCInitStructure; - - TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); - TIM_OCStructInit(&TIM_OCInitStructure); - // TIM1 Periph clock enable - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); - - /* Time base configuration */ - TIM_TimeBaseStructure.TIM_Period = RGB_BIT_TIME; - TIM_TimeBaseStructure.TIM_Prescaler = 0; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); - TIM_ARRPreloadConfig(TIM1, DISABLE); - - /* Timing Mode configuration: Channel 1 */ - TIM_OCInitStructure.OCMode = LL_TIM_OCMODE_FROZEN; - TIM_OCInitStructure.OCState = LL_TIM_OCSTATE_DISABLE; - TIM_OCInitStructure.CompareValue = RGB_T0H_TIME; - LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH1, &TIM_OCInitStructure); - LL_TIM_OC_DisablePreload(TIM1, LL_TIM_CHANNEL_CH1); - - /* Timing Mode configuration: Channel 4 */ - TIM_OCInitStructure.OCMode = LL_TIM_OCMODE_FROZEN; - TIM_OCInitStructure.OCState = LL_TIM_OCSTATE_DISABLE; - TIM_OCInitStructure.CompareValue = RGB_T1H_TIME; - LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH4, &TIM_OCInitStructure); - LL_TIM_OC_DisablePreload(TIM1, LL_TIM_CHANNEL_CH4); - - LL_LL_DMA_InitTypeDef DMA_InitStructure; - - LL_DMA_StructInit(&DMA_InitStructure); - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); - - /* DMA1 Channe5 configuration ----------------------------------------------*/ - LL_DMA_DeInit(DMA1_Channel3); - DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&RGB_PORT->BSRR; - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rgb_portX; - DMA_InitStructure.Direction = DMA_DIR_PeripheralDST; - DMA_InitStructure.NbData = RGB_LED_NUMBER * 24; - DMA_InitStructure.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - DMA_InitStructure.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_NOINCREMENT; - DMA_InitStructure.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; - DMA_InitStructure.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; - DMA_InitStructure.Mode = LL_DMA_MODE_NORMAL; - DMA_InitStructure.Priority = LL_DMA_PRIORITY_HIGH; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(DMA1_Channel5, &DMA_InitStructure); - - /* DMA1 Channel2 configuration ----------------------------------------------*/ - LL_DMA_DeInit(DMA1_Channel2); - DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&RGB_PORT->BRR + offset; - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rgb_data_portA; - DMA_InitStructure.Direction = DMA_DIR_PeripheralDST; - DMA_InitStructure.NbData = RGB_LED_NUMBER * 24; - DMA_InitStructure.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - DMA_InitStructure.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - DMA_InitStructure.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE; - DMA_InitStructure.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE; - DMA_InitStructure.Mode = LL_DMA_MODE_NORMAL; - DMA_InitStructure.Priority = LL_DMA_PRIORITY_HIGH; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(DMA1_Channel2, &DMA_InitStructure); - - /* DMA1 Channel4 configuration ----------------------------------------------*/ - LL_DMA_DeInit(DMA1_Channel4); - DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t)&RGB_PORT->BRR; - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rgb_portX; - DMA_InitStructure.Direction = DMA_DIR_PeripheralDST; - DMA_InitStructure.NbData = RGB_LED_NUMBER * 24; - DMA_InitStructure.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - DMA_InitStructure.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_NOINCREMENT; - DMA_InitStructure.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; - DMA_InitStructure.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; - DMA_InitStructure.Mode = LL_DMA_MODE_NORMAL; - DMA_InitStructure.Priority = LL_DMA_PRIORITY_HIGH; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(DMA1_Channel4, &DMA_InitStructure); - - TIM_DMACmd(TIM1, TIM_DMA_Update | TIM_DMA_CC4 | TIM_DMA_CC1, ENABLE); - - NVIC_InitTypeDef NVIC_InitStructure; - /* configure DMA1 Channel4 interrupt */ - NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_5_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPriority = (uint8_t)LL_DMA_PRIORITY_HIGH; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - /* enable DMA1 Channel4 transfer complete interrupt */ - DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE); -#endif - - for (int i = 0; i < RGB_LED_NUMBER; i++) { - rgb_led_value[i] = 0; - } - if (!rgb_dma_phase) - rgb_dma_phase = 3; - - int pin = rgb_portX[0]; - - if (offset) { - pin >>= 8; - } - - for (int i = 0; i < 16; i++) { - RGB_DATA16[i] = (i & 0x01) ? 0 : pin; - RGB_DATA16[i] <<= 8; - RGB_DATA16[i] |= (i & 0x02) ? 0 : pin; - RGB_DATA16[i] <<= 8; - RGB_DATA16[i] |= (i & 0x04) ? 0 : pin; - RGB_DATA16[i] <<= 8; - RGB_DATA16[i] |= (i & 0x08) ? 0 : pin; - } -} - -void rgb_dma_buffer_making() { - // generate rgb dma packet - int j = 0; - for (int n = 0; n < RGB_LED_NUMBER; n++) { - rgb_data_portA[j++] = RGB_DATA16[(rgb_led_value[n] >> 20) & 0x0f]; - rgb_data_portA[j++] = RGB_DATA16[(rgb_led_value[n] >> 16) & 0x0f]; - rgb_data_portA[j++] = RGB_DATA16[(rgb_led_value[n] >> 12) & 0x0f]; - rgb_data_portA[j++] = RGB_DATA16[(rgb_led_value[n] >> 8) & 0x0f]; - rgb_data_portA[j++] = RGB_DATA16[(rgb_led_value[n] >> 4) & 0x0f]; - rgb_data_portA[j++] = RGB_DATA16[(rgb_led_value[n]) & 0x0f]; - } -} - -void rgb_dma_trigger() { - TIM1->ARR = RGB_BIT_TIME; - TIM1->CCR1 = RGB_T0H_TIME; - TIM1->CCR4 = RGB_T1H_TIME; - - DMA1_Channel5->CPAR = (uint32_t)&RGB_PORT->BSRR; - DMA1_Channel5->CMAR = (uint32_t)rgb_portX; - DMA1_Channel2->CPAR = (uint32_t)&RGB_PORT->BRR + offset; - DMA1_Channel2->CMAR = (uint32_t)rgb_data_portA; - DMA1_Channel4->CPAR = (uint32_t)&RGB_PORT->BRR; - DMA1_Channel4->CMAR = (uint32_t)rgb_portX; - - DMA1_Channel2->CCR &= ~(DMA_CCR_MSIZE_0 | DMA_CCR_MSIZE_1 | DMA_CCR_PSIZE_0 | DMA_CCR_PSIZE_1); // switch from halfword to byte - - DMA_ClearFlag(DMA1_FLAG_GL2 | DMA1_FLAG_GL4 | DMA1_FLAG_GL5); - - DMA1_Channel5->CNDTR = RGB_LED_NUMBER * 24; - DMA1_Channel2->CNDTR = RGB_LED_NUMBER * 24; - DMA1_Channel4->CNDTR = RGB_LED_NUMBER * 24; - - TIM1->SR = 0; - - DMA_Cmd(DMA1_Channel2, ENABLE); - DMA_Cmd(DMA1_Channel4, ENABLE); - DMA_Cmd(DMA1_Channel5, ENABLE); - - TIM_DMACmd(TIM1, TIM_DMA_Update | TIM_DMA_CC4 | TIM_DMA_CC1, ENABLE); - - TIM_SetCounter(TIM1, RGB_BIT_TIME); - TIM_Cmd(TIM1, ENABLE); -} - -void rgb_dma_start() { - if (rgb_dma_phase <= 1) - return; - - if (rgb_dma_phase == 3) { - rgb_dma_buffer_making(); - rgb_dma_phase = 2; - return; - } - -#ifdef USE_DSHOT_DMA_DRIVER - extern int dshot_phase; - if (dshot_phase) - return; -#endif - - rgb_dma_phase = 1; - rgb_dma_trigger(); -} - -void rgb_send(int data) { - if (!rgb_dma_phase) - rgb_dma_phase = 3; -} - -// if dshot dma is used the routine is in that file -#if !defined(USE_DSHOT_DMA_DRIVER) && defined(RGB_LED_DMA) && (RGB_LED_NUMBER > 0) - -void DMA1_Channel4_5_IRQHandler() { - DMA_Cmd(DMA1_Channel5, DISABLE); - DMA_Cmd(DMA1_Channel2, DISABLE); - DMA_Cmd(DMA1_Channel4, DISABLE); - - TIM_DMACmd(TIM1, TIM_DMA_Update | TIM_DMA_CC4 | TIM_DMA_CC1, DISABLE); - DMA_ClearITPendingBit(DMA1_IT_TC4); - TIM_Cmd(TIM1, DISABLE); - - rgb_dma_phase = 0; -} -#endif - -#else - -// sets all leds to a brightness -void rgb_init() { - // spi port inits - - if ((RGB_PIN == LL_GPIO_PIN_13 || RGB_PIN == LL_GPIO_PIN_14) && RGB_PORT == GPIOA) { - // programming port used - - // wait until 2 seconds from powerup passed - while (time_micros() < 2e6) - ; - } - - gpio_config_t GPIO_InitStructure; - - GPIO_InitStructure.mode = GPIO_OUTPUT; - GPIO_InitStructure.output = GPIO_PUSHPULL; - GPIO_InitStructure.pull = GPIO_UP_PULL; - GPIO_InitStructure.drive =GPIO_DRIVE_HIGH; - - GPIO_InitStructure.Pin = RGB_PIN; - LL_GPIO_Init(RGB_PORT, &GPIO_InitStructure); - - for (int i = 0; i < RGB_LED_NUMBER; i++) { - rgb_send(0); - } -} - -#define RGBHIGH gpioset(RGB_PORT, RGB_PIN) -#define RGBLOW gpioreset(RGB_PORT, RGB_PIN); - -#pragma push - -#pragma Otime -#pragma O2 - -void delay1a() { - uint8_t count = 2; - while (count--) - ; -} - -void delay1b() { - uint8_t count = 2; - while (count--) - ; -} - -void delay2a() { - uint8_t count = 1; - while (count--) - ; -} - -void delay2b() { - uint8_t count = 3; - while (count--) - ; -} - -void rgb_send(int data) { - for (int i = 23; i >= 0; i--) { - if ((data >> i) & 1) { - RGBHIGH; - delay1a(); - RGBLOW; - delay1b(); - } else { - RGBHIGH; - delay2a(); - RGBLOW; - delay2b(); - } - } -} -#pragma pop - -#endif - -#else -// rgb led not found -// some dummy headers just in case -void rgb_init() { -} - -void rgb_send(int data) { -} -#endif diff --git a/src/driver/rgb_led.h b/src/driver/rgb_led.h index ded3d5ec5..a52dba850 100644 --- a/src/driver/rgb_led.h +++ b/src/driver/rgb_led.h @@ -1,6 +1,11 @@ #pragma once -void rgb_init(); -void rgb_send(int data); +#include +#include -void rgb_dma_start(); \ No newline at end of file +#define RGB_LED_MAX 32 + +void rgb_led_init(); +void rgb_led_set_value(uint32_t value, uint32_t count); +void rgb_led_send(); +bool rgb_led_busy(); \ No newline at end of file diff --git a/src/driver/timer.c b/src/driver/timer.c index 6f39b16f6..a5a1750ef 100644 --- a/src/driver/timer.c +++ b/src/driver/timer.c @@ -4,13 +4,6 @@ timer_assigment_t timer_assigments[TIMER_ASSIGMENT_MAX] = {}; -void timer_alloc_init() { - if (target.brushless) { - timer_assigments[0].use = TIMER_USE_MOTOR_DSHOT; - timer_assigments[0].tag = TIMER_TAG(TIMER1, TIMER_CH1 | TIMER_CH3 | TIMER_CH4); - } -} - bool timer_alloc_tag(timer_use_t use, resource_tag_t tag) { for (uint32_t i = 0; i < TIMER_ASSIGMENT_MAX; i++) { timer_assigment_t *ass = &timer_assigments[i]; diff --git a/src/driver/timer.h b/src/driver/timer.h index f5160ab4a..a28db3920 100644 --- a/src/driver/timer.h +++ b/src/driver/timer.h @@ -67,6 +67,7 @@ typedef enum { TIMER_USE_FREE, TIMER_USE_MOTOR_DSHOT, TIMER_USE_MOTOR_PWM, + TIMER_USE_RGB_LED, TIMER_USE_ELRS, TIMER_USE_SOFT_SERIAL, } timer_use_t; @@ -88,6 +89,7 @@ void timer_alloc_init(); bool timer_alloc_tag(timer_use_t use, resource_tag_t tag); resource_tag_t timer_alloc(timer_use_t use); uint32_t timer_channel_val(timer_channel_t chan); +uint32_t timer_channel_addr(timer_dev_t *timer, timer_channel_t chan); void timer_enable_dma_request(timer_index_t tim, timer_channel_t chan, bool state); void timer_up_init(timer_index_t tim, uint16_t divider, uint32_t period); \ No newline at end of file diff --git a/src/io/rgb_led.c b/src/io/rgb_led.c index f02b19202..c1ea4c191 100644 --- a/src/io/rgb_led.c +++ b/src/io/rgb_led.c @@ -1,168 +1,58 @@ -#include +#include "io/rgb_led.h" #include "core/project.h" #include "driver/rgb_led.h" -#include "driver/time.h" #include "flight/control.h" +#include "flight/filter.h" #include "util/util.h" -// normal flight rgb colour - LED switch ON -#define RGB_VALUE_INFLIGHT_ON RGB(255, 255, 255) +#define RGB_LED_COUNT 8 +#define RGB_FILTER_TIME FILTERCALC(100, 1000000) -// normal flight rgb colour - LED switch OFF -#define RGB_VALUE_INFLIGHT_OFF RGB(0, 0, 0) +static void rgb_led_set_all(uint32_t color, float fade_coeff) { + static float g_filt = 0; + const uint32_t g = (color >> 16) & 0xff; + lpf(&g_filt, g, fade_coeff); -// colour before bind -#define RGB_VALUE_BEFORE_BIND RGB(0, 128, 128) + static float r_filt = 0; + const uint32_t r = (color >> 8) & 0xff; + lpf(&r_filt, r, fade_coeff); -// fade from one color to another when changed -#define RGB_FILTER_ENABLE -#define RGB_FILTER_TIME_MICROSECONDS 50e3 + static float b_filt = 0; + const uint32_t b = (color >> 0) & 0xff; + lpf(&b_filt, b, fade_coeff); -// runs the update once every 16 loop times ( 16 mS ) -#define DOWNSAMPLE 16 - -#define RGB_FILTER_TIME lpfcalc(1000 * DOWNSAMPLE, RGB_FILTER_TIME_MICROSECONDS) -#define RGB(r, g, b) ((((int)g & 0xff) << 16) | (((int)r & 0xff) << 8) | ((int)b & 0xff)) - -#if (RGB_LED_NUMBER > 0) - -// array with individual led brightnesses -int rgb_led_value[RGB_LED_NUMBER]; -// loop count for downsampling -int rgb_loopcount = 0; -// rgb low pass filter variables -float r_filt, g_filt, b_filt; - -// sets all leds to a brightness -void rgb_led_set_all(int rgb) { -#ifdef RGB_FILTER_ENABLE - // deconstruct the colour into components - int g = rgb >> 16; - int r = (rgb & 0x0000FF00) >> 8; - int b = rgb & 0xff; - - // filter individual colors - lpf(&r_filt, r, RGB_FILTER_TIME); - lpf(&g_filt, g, RGB_FILTER_TIME); - lpf(&b_filt, b, RGB_FILTER_TIME); - - int temp = RGB(r_filt, g_filt, b_filt); - - for (int i = 0; i < RGB_LED_NUMBER; i++) - rgb_led_value[i] = temp; - -#else - for (int i = 0; i < RGB_LED_NUMBER; i++) - rgb_led_value[i] = rgb; -#endif -} - -// set an individual led brightness -void rgb_led_set_one(int led_number, int rgb) { - rgb_led_value[led_number] = rgb; + rgb_led_set_value(RGB(r_filt, g_filt, b_filt), RGB_LED_COUNT); } -// flashes between 2 colours, duty cycle 1 - 15 -void rgb_ledflash(int color1, int color2, uint32_t period, int duty) { - if (time_micros() % period > (period * duty) >> 4) { - rgb_led_set_all(color1); +// flashes between 2 colours, duty cycle 1 - 16 +static void rgb_ledflash(uint32_t color1, uint32_t color2, uint32_t period_ms, uint8_t duty) { + const uint32_t period = period_ms * 1000; + const uint32_t divider = (period * duty) >> 5; + if (time_micros() % period > divider) { + rgb_led_set_all(color1, lpfcalc(divider, period)); } else { - rgb_led_set_all(color2); + rgb_led_set_all(color2, lpfcalc(divider, period)); } } -// speed of movement -float KR_SPEED = 0.005f * DOWNSAMPLE; - -float kr_position = 0; -int kr_dir = 0; - -// knight rider style led movement -void rgb_knight_rider() { - if (kr_dir) { - kr_position += KR_SPEED; - if (kr_position > RGB_LED_NUMBER - 1) - kr_dir = !kr_dir; - } else { - kr_position -= KR_SPEED; - if (kr_position < 0) - kr_dir = !kr_dir; +void rgb_led_update() { +#if defined(USE_RGB_LED) + if (rgb_led_busy()) { + return; } - - // calculate led value - for (int i = 0; i < RGB_LED_NUMBER; i++) { - float led_bright = fabsf((float)i - kr_position); - if (led_bright > 1.0f) - led_bright = 1.0f; - led_bright = 1.0f - led_bright; - - // set a green background as well, 32 brightness - rgb_led_set_one(i, RGB((led_bright * 255.0f), (32.0f - led_bright * 32.0f), 0)); + if (flags.lowbatt) { + rgb_ledflash(RGB(255, 0, 0), RGB(0, 0, 255), 500, 16); } -} - -// 2 led flasher -void rgb_ledflash_twin(int color1, int color2, uint32_t period) { - if (time_micros() % period > (period / 2)) { - for (int i = 0; i < RGB_LED_NUMBER; i++) { - if ((i / 2) * 2 == i) - rgb_led_set_one(i, color1); - else - rgb_led_set_one(i, color2); - } - } else { - for (int i = 0; i < RGB_LED_NUMBER; i++) { - if ((i / 2) * 2 == i) - rgb_led_set_one(i, color2); - else - rgb_led_set_one(i, color1); - } + if (flags.rx_mode == RXMODE_BIND) { + rgb_ledflash(RGB(255, 0, 0), RGB(0, 0, 255), 100, 24); } -} - -// main function -void rgb_led_lvc() { - rgb_loopcount++; - if (rgb_loopcount > DOWNSAMPLE) { - rgb_loopcount = 0; - // led flash logic - if (flags.lowbatt) { - // rgb_led_set_all( RGB( 255 , 0 , 0 ) ); - rgb_ledflash(RGB(255, 0, 0), RGB(255, 32, 0), 500000, 8); - } else { - if (flags.rx_mode == RXMODE_BIND) { - // bind mode - // rgb_ledflash ( RGB( 0 , 0 , 255 ), RGB( 0 , 128 , 0 ), 1000000, 12); - // rgb_ledflash_twin( RGB( 0 , 0 , 255 ), RGB( 0 , 128 , 0 ), 1000000); - rgb_led_set_all(RGB_VALUE_BEFORE_BIND); - // rgb_knight_rider(); - } else { // non bind - if (flags.failsafe) { - // failsafe flash - rgb_ledflash(RGB(0, 128, 0), RGB(0, 0, 128), 500000, 8); - // rgb_led_set_all( RGB( 0 , 128 , 128 ) ); - } else { - - if (rx_aux_on(AUX_LEDS_ON)) - - rgb_led_set_all(RGB_VALUE_INFLIGHT_ON); - else - rgb_led_set_all(RGB_VALUE_INFLIGHT_OFF); - } - } - } - -#ifdef RGB_LED_DMA - // send dma start signal - rgb_send(0); -#else - // send data to leds - for (int i = 0; i < RGB_LED_NUMBER; i++) { - rgb_send(rgb_led_value[i]); - } -#endif + if (flags.failsafe) { + rgb_ledflash(RGB(255, 0, 0), RGB(0, 0, 255), 500, 30); } -} - + if (flags.arm_switch && (flags.throttle_safety == 1 || flags.arm_safety == 1)) { + rgb_ledflash(RGB(255, 0, 0), RGB(0, 0, 255), 100, 8); + } + rgb_led_send(); #endif +} diff --git a/src/io/rgb_led.h b/src/io/rgb_led.h index 686b389ac..921d3fee2 100644 --- a/src/io/rgb_led.h +++ b/src/io/rgb_led.h @@ -1,3 +1,5 @@ #pragma once -void rgb_led_lvc(); \ No newline at end of file +#define RGB(r, g, b) ((((uint32_t)g & 0xff) << 16) | (((uint32_t)r & 0xff) << 8) | ((uint32_t)b & 0xff)) + +void rgb_led_update(); \ No newline at end of file