diff options
Diffstat (limited to 'platforms')
43 files changed, 1574 insertions, 89 deletions
diff --git a/platforms/avr/drivers/backlight_pwm.c b/platforms/avr/drivers/backlight_pwm.c new file mode 100644 index 0000000000..d234115641 --- /dev/null +++ b/platforms/avr/drivers/backlight_pwm.c @@ -0,0 +1,463 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "progmem.h" +#include <avr/io.h> +#include <avr/interrupt.h> + +// Maximum duty cycle limit +#ifndef BACKLIGHT_LIMIT_VAL +#    define BACKLIGHT_LIMIT_VAL 255 +#endif + +// This logic is a bit complex, we support 3 setups: +// +//   1. Hardware PWM when backlight is wired to a PWM pin. +//      Depending on this pin, we use a different output compare unit. +//   2. Software PWM with hardware timers, but the used timer +//      depends on the Audio setup (Audio wins over Backlight). +//   3. Full software PWM, driven by the matrix scan, if both timers are used by Audio. + +#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7) +#    define ICRx ICR1 +#    define TCCRxA TCCR1A +#    define TCCRxB TCCR1B +#    define TIMERx_OVF_vect TIMER1_OVF_vect +#    define TIMSKx TIMSK1 +#    define TOIEx TOIE1 + +#    if BACKLIGHT_PIN == B5 +#        define COMxx0 COM1A0 +#        define COMxx1 COM1A1 +#        define OCRxx OCR1A +#    elif BACKLIGHT_PIN == B6 +#        define COMxx0 COM1B0 +#        define COMxx1 COM1B1 +#        define OCRxx OCR1B +#    elif BACKLIGHT_PIN == B7 +#        define COMxx0 COM1C0 +#        define COMxx1 COM1C1 +#        define OCRxx OCR1C +#    endif +#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == C4 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) +#    define ICRx ICR3 +#    define TCCRxA TCCR3A +#    define TCCRxB TCCR3B +#    define TIMERx_OVF_vect TIMER3_OVF_vect +#    define TIMSKx TIMSK3 +#    define TOIEx TOIE3 + +#    if BACKLIGHT_PIN == C4 +#        if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) +#            error This MCU has no C4 pin! +#        else +#            define COMxx0 COM3C0 +#            define COMxx1 COM3C1 +#            define OCRxx OCR3C +#        endif +#    elif BACKLIGHT_PIN == C5 +#        if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) +#            error This MCU has no C5 pin! +#        else +#            define COMxx0 COM3B0 +#            define COMxx1 COM3B1 +#            define OCRxx OCR3B +#        endif +#    elif BACKLIGHT_PIN == C6 +#        define COMxx0 COM3A0 +#        define COMxx1 COM3A1 +#        define OCRxx OCR3A +#    endif +#elif (defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) +#    define ICRx ICR1 +#    define TCCRxA TCCR1A +#    define TCCRxB TCCR1B +#    define TIMERx_OVF_vect TIMER1_OVF_vect +#    define TIMSKx TIMSK1 +#    define TOIEx TOIE1 + +#    if BACKLIGHT_PIN == B7 +#        define COMxx0 COM1C0 +#        define COMxx1 COM1C1 +#        define OCRxx OCR1C +#    elif BACKLIGHT_PIN == C5 +#        define COMxx0 COM1B0 +#        define COMxx1 COM1B1 +#        define OCRxx OCR1B +#    elif BACKLIGHT_PIN == C6 +#        define COMxx0 COM1A0 +#        define COMxx1 COM1A1 +#        define OCRxx OCR1A +#    endif +#elif defined(__AVR_ATmega32A__) && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5) +#    define ICRx ICR1 +#    define TCCRxA TCCR1A +#    define TCCRxB TCCR1B +#    define TIMERx_OVF_vect TIMER1_OVF_vect +#    define TIMSKx TIMSK +#    define TOIEx TOIE1 + +#    if BACKLIGHT_PIN == D4 +#        define COMxx0 COM1B0 +#        define COMxx1 COM1B1 +#        define OCRxx OCR1B +#    elif BACKLIGHT_PIN == D5 +#        define COMxx0 COM1A0 +#        define COMxx1 COM1A1 +#        define OCRxx OCR1A +#    endif +#elif (defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)) && (BACKLIGHT_PIN == B1 || BACKLIGHT_PIN == B2) +#    define ICRx ICR1 +#    define TCCRxA TCCR1A +#    define TCCRxB TCCR1B +#    define TIMERx_OVF_vect TIMER1_OVF_vect +#    define TIMSKx TIMSK1 +#    define TOIEx TOIE1 + +#    if BACKLIGHT_PIN == B1 +#        define COMxx0 COM1A0 +#        define COMxx1 COM1A1 +#        define OCRxx OCR1A +#    elif BACKLIGHT_PIN == B2 +#        define COMxx0 COM1B0 +#        define COMxx1 COM1B1 +#        define OCRxx OCR1B +#    endif +#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) +// Timer 1 is not in use by Audio feature, Backlight can use it +#    pragma message "Using hardware timer 1 with software PWM" +#    define BACKLIGHT_PWM_TIMER +#    define ICRx ICR1 +#    define TCCRxA TCCR1A +#    define TCCRxB TCCR1B +#    define TIMERx_COMPA_vect TIMER1_COMPA_vect +#    define TIMERx_OVF_vect TIMER1_OVF_vect +#    if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register +#        define TIMSKx TIMSK +#    else +#        define TIMSKx TIMSK1 +#    endif +#    define TOIEx TOIE1 + +#    define OCIExA OCIE1A +#    define OCRxx OCR1A +#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) +#    pragma message "Using hardware timer 3 with software PWM" +// Timer 3 is not in use by Audio feature, Backlight can use it +#    define BACKLIGHT_PWM_TIMER +#    define ICRx ICR1 +#    define TCCRxA TCCR3A +#    define TCCRxB TCCR3B +#    define TIMERx_COMPA_vect TIMER3_COMPA_vect +#    define TIMERx_OVF_vect TIMER3_OVF_vect +#    define TIMSKx TIMSK3 +#    define TOIEx TOIE3 + +#    define OCIExA OCIE3A +#    define OCRxx OCR3A +#endif + +#ifndef BACKLIGHT_PWM_TIMER // pwm through software + +static inline void enable_pwm(void) { +#    if BACKLIGHT_ON_STATE == 1 +    TCCRxA |= _BV(COMxx1); +#    else +    TCCRxA |= _BV(COMxx1) | _BV(COMxx0); +#    endif +} + +static inline void disable_pwm(void) { +#    if BACKLIGHT_ON_STATE == 1 +    TCCRxA &= ~(_BV(COMxx1)); +#    else +    TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0)); +#    endif +} + +#endif + +#ifdef BACKLIGHT_PWM_TIMER + +// The idea of software PWM assisted by hardware timers is the following +// we use the hardware timer in fast PWM mode like for hardware PWM, but +// instead of letting the Output Match Comparator control the led pin +// (which is not possible since the backlight is not wired to PWM pins on the +// CPU), we do the LED on/off by oursleves. +// The timer is setup to count up to 0xFFFF, and we set the Output Compare +// register to the current 16bits backlight level (after CIE correction). +// This means the CPU will trigger a compare match interrupt when the counter +// reaches the backlight level, where we turn off the LEDs, +// but also an overflow interrupt when the counter rolls back to 0, +// in which we're going to turn on the LEDs. +// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz, +// or F_CPU/BACKLIGHT_CUSTOM_RESOLUTION if used. + +// Triggered when the counter reaches the OCRx value +ISR(TIMERx_COMPA_vect) { +    backlight_pins_off(); +} + +// Triggered when the counter reaches the TOP value +// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz +ISR(TIMERx_OVF_vect) { +#    ifdef BACKLIGHT_BREATHING +    if (is_breathing()) { +        breathing_task(); +    } +#    endif +    // for very small values of OCRxx (or backlight level) +    // we can't guarantee this whole code won't execute +    // at the same time as the compare match interrupt +    // which means that we might turn on the leds while +    // trying to turn them off, leading to flickering +    // artifacts (especially while breathing, because breathing_task +    // takes many computation cycles). +    // so better not turn them on while the counter TOP is very low. +    if (OCRxx > ICRx / 250 + 5) { +        backlight_pins_on(); +    } +} + +#endif + +#define TIMER_TOP 0xFFFFU + +// See http://jared.geek.nz/2013/feb/linear-led-pwm +static uint16_t cie_lightness(uint16_t v) { +    if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max +    { +        return v / 9; // Same as dividing by 900% +    } else { +        // In the next two lines values are bit-shifted. This is to avoid loosing decimals in integer math. +        uint32_t y   = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx); // If above 8%, add ~16% of max, and normalize with (max + ~16% max) +        uint32_t out = (y * y * y * ICRx) >> 15;                                                // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing) + +        if (out > ICRx) // Avoid overflows +        { +            out = ICRx; +        } +        return (uint16_t)out; +    } +} + +// rescale the supplied backlight value to be in terms of the value limit	// range for val is [0..ICRx]. PWM pin is high while the timer count is below val. +static uint32_t rescale_limit_val(uint32_t val) { +    return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; +} + +// range for val is [0..ICRx]. PWM pin is high while the timer count is below val. +static inline void set_pwm(uint16_t val) { +    OCRxx = val; +} + +void backlight_set(uint8_t level) { +    if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; + +    if (level == 0) { +#ifdef BACKLIGHT_PWM_TIMER +        if (OCRxx) { +            TIMSKx &= ~(_BV(OCIExA)); +            TIMSKx &= ~(_BV(TOIEx)); +        } +#else +        // Turn off PWM control on backlight pin +        disable_pwm(); +#endif +        backlight_pins_off(); +    } else { +#ifdef BACKLIGHT_PWM_TIMER +        if (!OCRxx) { +            TIMSKx |= _BV(OCIExA); +            TIMSKx |= _BV(TOIEx); +        } +#else +        // Turn on PWM control of backlight pin +        enable_pwm(); +#endif +    } +    // Set the brightness +    set_pwm(cie_lightness(rescale_limit_val(ICRx * (uint32_t)level / BACKLIGHT_LEVELS))); +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING + +#    define BREATHING_NO_HALT 0 +#    define BREATHING_HALT_OFF 1 +#    define BREATHING_HALT_ON 2 +#    define BREATHING_STEPS 128 + +static uint8_t  breathing_halt    = BREATHING_NO_HALT; +static uint16_t breathing_counter = 0; + +static uint8_t breath_scale_counter = 1; +/* Run the breathing loop at ~120Hz*/ +const uint8_t   breathing_ISR_frequency     = 120; +static uint16_t breathing_freq_scale_factor = 2; + +#    ifdef BACKLIGHT_PWM_TIMER +static bool breathing = false; + +bool is_breathing(void) { +    return breathing; +} + +#        define breathing_interrupt_enable() \ +            do {                             \ +                breathing = true;            \ +            } while (0) +#        define breathing_interrupt_disable() \ +            do {                              \ +                breathing = false;            \ +            } while (0) +#    else + +bool is_breathing(void) { +    return !!(TIMSKx & _BV(TOIEx)); +} + +#        define breathing_interrupt_enable() \ +            do {                             \ +                TIMSKx |= _BV(TOIEx);        \ +            } while (0) +#        define breathing_interrupt_disable() \ +            do {                              \ +                TIMSKx &= ~_BV(TOIEx);        \ +            } while (0) +#    endif + +#    define breathing_min()        \ +        do {                       \ +            breathing_counter = 0; \ +        } while (0) +#    define breathing_max()                                                           \ +        do {                                                                          \ +            breathing_counter = get_breathing_period() * breathing_ISR_frequency / 2; \ +        } while (0) + +void breathing_enable(void) { +    breathing_counter = 0; +    breathing_halt    = BREATHING_NO_HALT; +    breathing_interrupt_enable(); +} + +void breathing_pulse(void) { +    if (get_backlight_level() == 0) +        breathing_min(); +    else +        breathing_max(); +    breathing_halt = BREATHING_HALT_ON; +    breathing_interrupt_enable(); +} + +void breathing_disable(void) { +    breathing_interrupt_disable(); +    // Restore backlight level +    backlight_set(get_backlight_level()); +} + +void breathing_self_disable(void) { +    if (get_backlight_level() == 0) +        breathing_halt = BREATHING_HALT_OFF; +    else +        breathing_halt = BREATHING_HALT_ON; +} + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { +    return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +#    ifdef BACKLIGHT_PWM_TIMER +void breathing_task(void) +#    else +/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run + * about 244 times per second. + * + * The following ISR runs at F_CPU/ISRx. With a 16MHz clock and default pwm resolution, that means 244Hz + */ +ISR(TIMERx_OVF_vect) +#    endif +{ + +    // Only run this ISR at ~120 Hz +    if (breath_scale_counter++ == breathing_freq_scale_factor) { +        breath_scale_counter = 1; +    } else { +        return; +    } +    uint16_t interval = (uint16_t)get_breathing_period() * breathing_ISR_frequency / BREATHING_STEPS; +    // resetting after one period to prevent ugly reset at overflow. +    breathing_counter = (breathing_counter + 1) % (get_breathing_period() * breathing_ISR_frequency); +    uint8_t index     = breathing_counter / interval; +    // limit index to max step value +    if (index >= BREATHING_STEPS) { +        index = BREATHING_STEPS - 1; +    } + +    if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) { +        breathing_interrupt_disable(); +    } + +    // Set PWM to a brightnessvalue scaled to the configured resolution +    set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint32_t)pgm_read_byte(&breathing_table[index]) * ICRx / 255)))); +} + +#endif // BACKLIGHT_BREATHING + +void backlight_init_ports(void) { +    // Setup backlight pin as output and output to on state. +    backlight_pins_init(); + +    // I could write a wall of text here to explain... but TL;DW +    // Go read the ATmega32u4 datasheet. +    // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on + +#ifdef BACKLIGHT_PWM_TIMER +    // TimerX setup, Fast PWM mode count to TOP set in ICRx +    TCCRxA = _BV(WGM11); // = 0b00000010; +    // clock select clk/1 +    TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; +#else                                             // hardware PWM +    // Pin PB7 = OCR1C (Timer 1, Channel C) +    // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 +    // (i.e. start high, go low when counter matches.) +    // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 +    // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 + +    /* +    14.8.3: +    "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]." +    "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)." +    */ +    TCCRxA = _BV(COMxx1) | _BV(WGM11);            // = 0b00001010; +    TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; +#endif + +#ifdef BACKLIGHT_CUSTOM_RESOLUTION +#    if (BACKLIGHT_CUSTOM_RESOLUTION > 0xFFFF || BACKLIGHT_CUSTOM_RESOLUTION < 1) +#        error "This out of range of the timer capabilities" +#    elif (BACKLIGHT_CUSTOM_RESOLUTION < 0xFF) +#        warning "Resolution lower than 0xFF isn't recommended" +#    endif +#    ifdef BACKLIGHT_BREATHING +    breathing_freq_scale_factor = F_CPU / BACKLIGHT_CUSTOM_RESOLUTION / 120; +#    endif +    ICRx = BACKLIGHT_CUSTOM_RESOLUTION; +#else +    ICRx = TIMER_TOP; +#endif + +    backlight_init(); +#ifdef BACKLIGHT_BREATHING +    if (is_backlight_breathing()) { +        breathing_enable(); +    } +#endif +} diff --git a/platforms/avr/sleep_led.c b/platforms/avr/sleep_led.c index b05431633b..ad6253be93 100644 --- a/platforms/avr/sleep_led.c +++ b/platforms/avr/sleep_led.c @@ -109,16 +109,19 @@ ISR(TIMERx_COMPA_vect) {              uint8_t duration : 2;              uint8_t index : 6;          } pwm; -    } timer = {.row = 0}; +    } timer                = {.row = 0}; +    static led_t led_state = {0};      timer.row++;      // LED on      if (timer.pwm.count == 0) { -        led_set(1 << USB_LED_CAPS_LOCK); +        led_state.caps_lock = true; +        led_set(led_state.raw);      }      // LED off      if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { -        led_set(0); +        led_state.caps_lock = false; +        led_set(led_state.raw);      }  } diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h index ab293c0b40..8621807cbb 100644 --- a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h @@ -106,7 +106,6 @@  #define RP_USB_USE_USBD0                    TRUE  #define RP_USB_FORCE_VBUS_DETECT            TRUE  #define RP_USE_EXTERNAL_VBUS_DETECT         FALSE -#define RP_USB_USE_SOF_INTR                 TRUE  #define RP_USB_USE_ERROR_DATA_SEQ_INTR      FALSE  #endif /* MCUCONF_H */ diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h index b91d762419..902f9b5005 100644 --- a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h @@ -106,7 +106,6 @@  #define RP_USB_USE_USBD0                    TRUE  #define RP_USB_FORCE_VBUS_DETECT            TRUE  #define RP_USE_EXTERNAL_VBUS_DETECT         FALSE -#define RP_USB_USE_SOF_INTR                 TRUE  #define RP_USB_USE_ERROR_DATA_SEQ_INTR      FALSE  #endif /* MCUCONF_H */ diff --git a/platforms/chibios/boards/PJRC_TEENSY_3_5/board/board.mk b/platforms/chibios/boards/GENERIC_STM32_H723XG/board/board.mk index e129836b08..3511f752a9 100644 --- a/platforms/chibios/boards/PJRC_TEENSY_3_5/board/board.mk +++ b/platforms/chibios/boards/GENERIC_STM32_H723XG/board/board.mk @@ -1,10 +1,11 @@ -include $(CHIBIOS_CONTRIB)/os/hal/boards/PJRC_TEENSY_3_5/board.mk -  # List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO144_H723ZG/board.c + +# Extra files  BOARDSRC += $(BOARD_PATH)/board/extra.c  # Required include directories -BOARDINC += $(BOARD_PATH)/board +BOARDINC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO144_H723ZG  # Shared variables  ALLCSRC += $(BOARDSRC) diff --git a/platforms/chibios/boards/GENERIC_STM32_H723XG/board/extra.c b/platforms/chibios/boards/GENERIC_STM32_H723XG/board/extra.c new file mode 100755 index 0000000000..fce0b4abad --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_H723XG/board/extra.c @@ -0,0 +1,36 @@ +// Copyright 2023 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include <hal.h> +#define BOOTLOADER_MAGIC 0xDEADBEEF + +//////////////////////////////////////////////////////////////////////////////// +// Different signalling for bootloader entry +// - RAM is cleared on reset, so we can't use the usual __ram0_end__ symbol. +// - Use backup registers in the RTC peripheral to store the magic value instead. + +static inline void enable_backup_register_access(void) { +    PWR->CR1 |= PWR_CR1_DBP; +} + +static inline void disable_backup_register_access(void) { +    PWR->CR1 &= ~PWR_CR1_DBP; +} + +void bootloader_marker_enable(void) { +    enable_backup_register_access(); +    RTC->BKP0R = BOOTLOADER_MAGIC; +    disable_backup_register_access(); +} + +bool bootloader_marker_active(void) { +    enable_backup_register_access(); +    bool ret = RTC->BKP0R == BOOTLOADER_MAGIC; +    disable_backup_register_access(); +    return ret; +} + +void bootloader_marker_disable(void) { +    enable_backup_register_access(); +    RTC->BKP0R = 0; +    disable_backup_register_access(); +} diff --git a/platforms/chibios/boards/GENERIC_STM32_H723XG/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_H723XG/configs/config.h new file mode 100644 index 0000000000..f43df29b54 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_H723XG/configs/config.h @@ -0,0 +1,9 @@ +// Copyright 2023 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#define USB_DRIVER USBD2 + +#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP +#    define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE +#endif diff --git a/platforms/chibios/boards/GENERIC_STM32_H723XG/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_H723XG/configs/mcuconf.h new file mode 100644 index 0000000000..0239ec5273 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_H723XG/configs/mcuconf.h @@ -0,0 +1,511 @@ +/* +    ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio + +    Licensed under the Apache License, Version 2.0 (the "License"); +    you may not use this file except in compliance with the License. +    You may obtain a copy of the License at + +        http://www.apache.org/licenses/LICENSE-2.0 + +    Unless required by applicable law or agreed to in writing, software +    distributed under the License is distributed on an "AS IS" BASIS, +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +    See the License for the specific language governing permissions and +    limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * STM32H723/33/25/35 drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the whole + * driver is enabled in halconf.h. + * + * IRQ priorities: + * 15...0       Lowest...Highest. + * + * DMA priorities: + * 0...3        Lowest...Highest. + */ + +#define STM32H7xx_MCUCONF +#define STM32H723_MCUCONF +#define STM32H733_MCUCONF +#define STM32H725_MCUCONF +#define STM32H735_MCUCONF + +/* + * General settings. + */ +#define STM32_NO_INIT                       FALSE + +/* + * Memory attributes settings. + */ +#define STM32_NOCACHE_ENABLE                FALSE +#define STM32_NOCACHE_MPU_REGION            MPU_REGION_6 +#define STM32_NOCACHE_RBAR                  0x24000000U +#define STM32_NOCACHE_RASR                  MPU_RASR_SIZE_16K + +/* + * PWR system settings. + * Reading STM32 Reference Manual is required, settings in PWR_CR3 are + * very critical. + * Register constants are taken from the ST header. + */ +#define STM32_VOS                           STM32_VOS_SCALE0 +#define STM32_PWR_CR1                       (PWR_CR1_SVOS_1 | PWR_CR1_SVOS_0) +#define STM32_PWR_CR2                       (PWR_CR2_BREN) +#define STM32_PWR_CR3                       (PWR_CR3_LDOEN | PWR_CR3_USB33DEN) +#define STM32_PWR_CPUCR                     0 + +/* + * Clock tree static settings. + * Reading STM32 Reference Manual is required. + */ +#define STM32_HSI_ENABLED                   TRUE +#define STM32_LSI_ENABLED                   FALSE +#define STM32_CSI_ENABLED                   FALSE +#define STM32_HSI48_ENABLED                 TRUE +#define STM32_HSE_ENABLED                   TRUE +#define STM32_LSE_ENABLED                   FALSE +#define STM32_HSIDIV                        STM32_HSIDIV_DIV1 + +/* + * PLLs static settings. + * Reading STM32 Reference Manual is required. + */ +#define STM32_PLLSRC                        STM32_PLLSRC_HSE_CK +#define STM32_PLLCFGR_MASK                  ~0 +#define STM32_PLL1_ENABLED                  TRUE +#define STM32_PLL1_P_ENABLED                TRUE +#define STM32_PLL1_Q_ENABLED                TRUE +#define STM32_PLL1_R_ENABLED                TRUE +#define STM32_PLL1_DIVM_VALUE               4 +#define STM32_PLL1_DIVN_VALUE               275 +#define STM32_PLL1_FRACN_VALUE              0 +#define STM32_PLL1_DIVP_VALUE               1 +#define STM32_PLL1_DIVQ_VALUE               10 +#define STM32_PLL1_DIVR_VALUE               4 +#define STM32_PLL2_ENABLED                  TRUE +#define STM32_PLL2_P_ENABLED                TRUE +#define STM32_PLL2_Q_ENABLED                TRUE +#define STM32_PLL2_R_ENABLED                TRUE +#define STM32_PLL2_DIVM_VALUE               4 +#define STM32_PLL2_DIVN_VALUE               400 +#define STM32_PLL2_FRACN_VALUE              0 +#define STM32_PLL2_DIVP_VALUE               40 +#define STM32_PLL2_DIVQ_VALUE               8 +#define STM32_PLL2_DIVR_VALUE               8 +#define STM32_PLL3_ENABLED                  TRUE +#define STM32_PLL3_P_ENABLED                TRUE +#define STM32_PLL3_Q_ENABLED                TRUE +#define STM32_PLL3_R_ENABLED                TRUE +#define STM32_PLL3_DIVM_VALUE               4 +#define STM32_PLL3_DIVN_VALUE               240 +#define STM32_PLL3_FRACN_VALUE              0 +#define STM32_PLL3_DIVP_VALUE               10 +#define STM32_PLL3_DIVQ_VALUE               10 +#define STM32_PLL3_DIVR_VALUE               10 + +/* + * Core clocks dynamic settings (can be changed at runtime). + * Reading STM32 Reference Manual is required. + */ +#define STM32_SW                            STM32_SW_PLL1_P_CK +#define STM32_RTCSEL                        STM32_RTCSEL_LSI_CK +#define STM32_D1CPRE                        STM32_D1CPRE_DIV1 +#define STM32_D1HPRE                        STM32_D1HPRE_DIV2 +#define STM32_D1PPRE3                       STM32_D1PPRE3_DIV2 +#define STM32_D2PPRE1                       STM32_D2PPRE1_DIV2 +#define STM32_D2PPRE2                       STM32_D2PPRE2_DIV2 +#define STM32_D3PPRE4                       STM32_D3PPRE4_DIV2 + +/* + * Peripherals clocks static settings. + * Reading STM32 Reference Manual is required. + */ +#define STM32_MCO1SEL                       STM32_MCO1SEL_HSI_CK +#define STM32_MCO1PRE_VALUE                 4 +#define STM32_MCO2SEL                       STM32_MCO2SEL_SYS_CK +#define STM32_MCO2PRE_VALUE                 4 +#define STM32_TIMPRE_ENABLE                 TRUE +#define STM32_HRTIMSEL                      0 +#define STM32_STOPKERWUCK                   0 +#define STM32_STOPWUCK                      0 +#define STM32_RTCPRE_VALUE                  8 +#define STM32_CKPERSEL                      STM32_CKPERSEL_HSE_CK +#define STM32_SDMMCSEL                      STM32_SDMMCSEL_PLL1_Q_CK +#define STM32_OCTOSPISEL                    STM32_OCTOSPISEL_HCLK +#define STM32_FMCSEL                        STM32_FMCSEL_HCLK +#define STM32_SWPSEL                        STM32_SWPSEL_PCLK1 +#define STM32_FDCANSEL                      STM32_FDCANSEL_HSE_CK +#define STM32_DFSDM1SEL                     STM32_DFSDM1SEL_PCLK2 +#define STM32_SPDIFSEL                      STM32_SPDIFSEL_PLL1_Q_CK +#define STM32_SPI45SEL                      STM32_SPI45SEL_PCLK2 +#define STM32_SPI123SEL                     STM32_SPI123SEL_PLL1_Q_CK +#define STM32_SAI1SEL                       STM32_SAI1SEL_PLL1_Q_CK +#define STM32_LPTIM1SEL                     STM32_LPTIM1SEL_PCLK1 +#define STM32_CECSEL                        STM32_CECSEL_LSE_CK +#define STM32_USBSEL                        STM32_USBSEL_PLL3_Q_CK +#define STM32_I2C1235SEL                    STM32_I2C1235SEL_PCLK1 +#define STM32_RNGSEL                        STM32_RNGSEL_PLL1_Q_CK +#define STM32_USART16910SEL                 STM32_USART16910SEL_PCLK2 +#define STM32_USART234578SEL                STM32_USART234578SEL_PCLK1 +#define STM32_SPI6SEL                       STM32_SPI6SEL_PCLK4 +#define STM32_SAI4BSEL                      STM32_SAI4BSEL_PLL1_Q_CK +#define STM32_SAI4ASEL                      STM32_SAI4ASEL_PLL1_Q_CK +#define STM32_ADCSEL                        STM32_ADCSEL_PLL2_P_CK +#define STM32_LPTIM345SEL                   STM32_LPTIM345SEL_PCLK4 +#define STM32_LPTIM2SEL                     STM32_LPTIM2SEL_PCLK4 +#define STM32_I2C4SEL                       STM32_I2C4SEL_PCLK4 +#define STM32_LPUART1SEL                    STM32_LPUART1SEL_PCLK4 + +/* + * IRQ system settings. + */ +#define STM32_IRQ_EXTI0_PRIORITY            6 +#define STM32_IRQ_EXTI1_PRIORITY            6 +#define STM32_IRQ_EXTI2_PRIORITY            6 +#define STM32_IRQ_EXTI3_PRIORITY            6 +#define STM32_IRQ_EXTI4_PRIORITY            6 +#define STM32_IRQ_EXTI5_9_PRIORITY          6 +#define STM32_IRQ_EXTI10_15_PRIORITY        6 +#define STM32_IRQ_EXTI16_PRIORITY           6 +#define STM32_IRQ_EXTI17_PRIORITY           6 +#define STM32_IRQ_EXTI18_PRIORITY           6 +#define STM32_IRQ_EXTI19_PRIORITY           6 +#define STM32_IRQ_EXTI20_21_PRIORITY        6 + +#define STM32_IRQ_FDCAN1_PRIORITY           10 +#define STM32_IRQ_FDCAN2_PRIORITY           10 + +#define STM32_IRQ_MDMA_PRIORITY             9 + +#define STM32_IRQ_OCTOSPI1_PRIORITY         10 +#define STM32_IRQ_OCTOSPI2_PRIORITY         10 + +#define STM32_IRQ_SDMMC1_PRIORITY           9 +#define STM32_IRQ_SDMMC2_PRIORITY           9 + +#define STM32_IRQ_TIM1_UP_PRIORITY          7 +#define STM32_IRQ_TIM1_CC_PRIORITY          7 +#define STM32_IRQ_TIM2_PRIORITY             7 +#define STM32_IRQ_TIM3_PRIORITY             7 +#define STM32_IRQ_TIM4_PRIORITY             7 +#define STM32_IRQ_TIM5_PRIORITY             7 +#define STM32_IRQ_TIM6_PRIORITY             7 +#define STM32_IRQ_TIM7_PRIORITY             7 +#define STM32_IRQ_TIM8_BRK_TIM12_PRIORITY   7 +#define STM32_IRQ_TIM8_UP_TIM13_PRIORITY    7 +#define STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY 7 +#define STM32_IRQ_TIM8_CC_PRIORITY          7 +#define STM32_IRQ_TIM15_PRIORITY            7 +#define STM32_IRQ_TIM16_PRIORITY            7 +#define STM32_IRQ_TIM17_PRIORITY            7 + +#define STM32_IRQ_USART1_PRIORITY           12 +#define STM32_IRQ_USART2_PRIORITY           12 +#define STM32_IRQ_USART3_PRIORITY           12 +#define STM32_IRQ_UART4_PRIORITY            12 +#define STM32_IRQ_UART5_PRIORITY            12 +#define STM32_IRQ_USART6_PRIORITY           12 +#define STM32_IRQ_UART7_PRIORITY            12 +#define STM32_IRQ_UART8_PRIORITY            12 +#define STM32_IRQ_UART9_PRIORITY            12 +#define STM32_IRQ_USART10_PRIORITY          12 +#define STM32_IRQ_LPUART1_PRIORITY          12 + +/* + * ADC driver system settings. + */ +#define STM32_ADC_DUAL_MODE                 FALSE +#define STM32_ADC_SAMPLES_SIZE              16 +#define STM32_ADC_USE_ADC12                 FALSE +#define STM32_ADC_ADC12_DMA_STREAM          STM32_DMA_STREAM_ID_ANY +#define STM32_ADC_ADC12_DMA_PRIORITY        2 +#define STM32_ADC_ADC12_IRQ_PRIORITY        5 +#define STM32_ADC_ADC12_CLOCK_MODE          ADC_CCR_CKMODE_AHB_DIV4 + +/* + * CAN driver system settings. + */ +#define STM32_CAN_USE_FDCAN1                FALSE +#define STM32_CAN_USE_FDCAN2                FALSE + +/* + * DAC driver system settings. + */ +#define STM32_DAC_DUAL_MODE                 FALSE +#define STM32_DAC_USE_DAC1_CH1              FALSE +#define STM32_DAC_USE_DAC1_CH2              FALSE +#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY     10 +#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY     10 +#define STM32_DAC_DAC1_CH1_DMA_PRIORITY     2 +#define STM32_DAC_DAC1_CH2_DMA_PRIORITY     2 +#define STM32_DAC_DAC1_CH1_DMA_STREAM       STM32_DMA_STREAM_ID_ANY +#define STM32_DAC_DAC1_CH2_DMA_STREAM       STM32_DMA_STREAM_ID_ANY + +/* + * GPT driver system settings. + */ +#define STM32_GPT_USE_TIM1                  FALSE +#define STM32_GPT_USE_TIM2                  FALSE +#define STM32_GPT_USE_TIM3                  FALSE +#define STM32_GPT_USE_TIM4                  FALSE +#define STM32_GPT_USE_TIM5                  FALSE +#define STM32_GPT_USE_TIM6                  FALSE +#define STM32_GPT_USE_TIM7                  FALSE +#define STM32_GPT_USE_TIM8                  FALSE +#define STM32_GPT_USE_TIM12                 FALSE +#define STM32_GPT_USE_TIM13                 FALSE +#define STM32_GPT_USE_TIM14                 FALSE +#define STM32_GPT_USE_TIM15                 FALSE +#define STM32_GPT_USE_TIM16                 FALSE +#define STM32_GPT_USE_TIM17                 FALSE + +/* + * I2C driver system settings. + */ +#define STM32_I2C_USE_I2C1                  FALSE +#define STM32_I2C_USE_I2C2                  FALSE +#define STM32_I2C_USE_I2C3                  FALSE +#define STM32_I2C_USE_I2C4                  FALSE +#define STM32_I2C_BUSY_TIMEOUT              50 +#define STM32_I2C_I2C1_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C1_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C2_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C2_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C3_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C3_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C4_RX_BDMA_STREAM       STM32_BDMA_STREAM_ID_ANY +#define STM32_I2C_I2C4_TX_BDMA_STREAM       STM32_BDMA_STREAM_ID_ANY +#define STM32_I2C_I2C1_IRQ_PRIORITY         5 +#define STM32_I2C_I2C2_IRQ_PRIORITY         5 +#define STM32_I2C_I2C3_IRQ_PRIORITY         5 +#define STM32_I2C_I2C4_IRQ_PRIORITY         5 +#define STM32_I2C_I2C1_DMA_PRIORITY         3 +#define STM32_I2C_I2C2_DMA_PRIORITY         3 +#define STM32_I2C_I2C3_DMA_PRIORITY         3 +#define STM32_I2C_I2C4_DMA_PRIORITY         3 +#define STM32_I2C_DMA_ERROR_HOOK(i2cp)      osalSysHalt("DMA failure") + +/* + * ICU driver system settings. + */ +#define STM32_ICU_USE_TIM1                  FALSE +#define STM32_ICU_USE_TIM2                  FALSE +#define STM32_ICU_USE_TIM3                  FALSE +#define STM32_ICU_USE_TIM4                  FALSE +#define STM32_ICU_USE_TIM5                  FALSE +#define STM32_ICU_USE_TIM8                  FALSE +#define STM32_ICU_USE_TIM12                 FALSE +#define STM32_ICU_USE_TIM13                 FALSE +#define STM32_ICU_USE_TIM14                 FALSE +#define STM32_ICU_USE_TIM15                 FALSE +#define STM32_ICU_USE_TIM16                 FALSE +#define STM32_ICU_USE_TIM17                 FALSE + +/* + * MAC driver system settings. + */ +#define STM32_MAC_TRANSMIT_BUFFERS          2 +#define STM32_MAC_RECEIVE_BUFFERS           4 +#define STM32_MAC_BUFFERS_SIZE              1522 +#define STM32_MAC_PHY_TIMEOUT               100 +#define STM32_MAC_ETH1_CHANGE_PHY_STATE     TRUE +#define STM32_MAC_ETH1_IRQ_PRIORITY         13 +#define STM32_MAC_IP_CHECKSUM_OFFLOAD       0 + +/* + * PWM driver system settings. + */ +#define STM32_PWM_USE_TIM1                  FALSE +#define STM32_PWM_USE_TIM2                  FALSE +#define STM32_PWM_USE_TIM3                  FALSE +#define STM32_PWM_USE_TIM4                  FALSE +#define STM32_PWM_USE_TIM5                  FALSE +#define STM32_PWM_USE_TIM8                  FALSE +#define STM32_PWM_USE_TIM12                 FALSE +#define STM32_PWM_USE_TIM13                 FALSE +#define STM32_PWM_USE_TIM14                 FALSE +#define STM32_PWM_USE_TIM15                 FALSE +#define STM32_PWM_USE_TIM16                 FALSE +#define STM32_PWM_USE_TIM17                 FALSE + +/* + * RTC driver system settings. + */ +#define STM32_RTC_PRESA_VALUE               32 +#define STM32_RTC_PRESS_VALUE               1024 +#define STM32_RTC_CR_INIT                   0 +#define STM32_RTC_TAMPCR_INIT               0 + +/* + * SDC driver system settings. + */ +#define STM32_SDC_USE_SDMMC1                FALSE +#define STM32_SDC_USE_SDMMC2                FALSE +#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT   TRUE +#define STM32_SDC_SDMMC_WRITE_TIMEOUT       10000 +#define STM32_SDC_SDMMC_READ_TIMEOUT        10000 +#define STM32_SDC_SDMMC_CLOCK_DELAY         10 +#define STM32_SDC_SDMMC_PWRSAV              TRUE + +/* + * SERIAL driver system settings. + */ +#define STM32_SERIAL_USE_USART1             FALSE +#define STM32_SERIAL_USE_USART2             FALSE +#define STM32_SERIAL_USE_USART3             FALSE +#define STM32_SERIAL_USE_UART4              FALSE +#define STM32_SERIAL_USE_UART5              FALSE +#define STM32_SERIAL_USE_USART6             FALSE +#define STM32_SERIAL_USE_UART7              FALSE +#define STM32_SERIAL_USE_UART8              FALSE +#define STM32_SERIAL_USE_UART9              FALSE +#define STM32_SERIAL_USE_USART10            FALSE +#define STM32_SERIAL_USE_LPUART1            FALSE + +/* + * SIO driver system settings. + */ +#define STM32_SIO_USE_USART1                FALSE +#define STM32_SIO_USE_USART2                FALSE +#define STM32_SIO_USE_USART3                FALSE +#define STM32_SIO_USE_UART4                 FALSE +#define STM32_SIO_USE_UART5                 FALSE +#define STM32_SIO_USE_USART6                FALSE +#define STM32_SIO_USE_UART7                 FALSE +#define STM32_SIO_USE_UART8                 FALSE +#define STM32_SIO_USE_UART9                 FALSE +#define STM32_SIO_USE_USART10               FALSE +#define STM32_SIO_USE_LPUART1               FALSE + +/* + * SPI driver system settings. + */ +#define STM32_SPI_USE_SPI1                  FALSE +#define STM32_SPI_USE_SPI2                  FALSE +#define STM32_SPI_USE_SPI3                  FALSE +#define STM32_SPI_USE_SPI4                  FALSE +#define STM32_SPI_USE_SPI5                  FALSE +#define STM32_SPI_USE_SPI6                  FALSE +#define STM32_SPI_SPI1_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI1_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI2_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI2_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI3_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI3_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI4_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI4_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI5_RX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI5_TX_DMA_STREAM        STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI6_RX_BDMA_STREAM       STM32_BDMA_STREAM_ID_ANY +#define STM32_SPI_SPI6_TX_BDMA_STREAM       STM32_BDMA_STREAM_ID_ANY +#define STM32_SPI_SPI1_DMA_PRIORITY         1 +#define STM32_SPI_SPI2_DMA_PRIORITY         1 +#define STM32_SPI_SPI3_DMA_PRIORITY         1 +#define STM32_SPI_SPI4_DMA_PRIORITY         1 +#define STM32_SPI_SPI5_DMA_PRIORITY         1 +#define STM32_SPI_SPI6_DMA_PRIORITY         1 +#define STM32_SPI_SPI1_IRQ_PRIORITY         10 +#define STM32_SPI_SPI2_IRQ_PRIORITY         10 +#define STM32_SPI_SPI3_IRQ_PRIORITY         10 +#define STM32_SPI_SPI4_IRQ_PRIORITY         10 +#define STM32_SPI_SPI5_IRQ_PRIORITY         10 +#define STM32_SPI_SPI6_IRQ_PRIORITY         10 +#define STM32_SPI_DMA_ERROR_HOOK(spip)      osalSysHalt("DMA failure") + +/* + * ST driver system settings. + */ +#define STM32_ST_IRQ_PRIORITY               8 +#define STM32_ST_USE_TIMER                  2 + +/* + * TRNG driver system settings. + */ +#define STM32_TRNG_USE_RNG1                 FALSE + +/* + * UART driver system settings. + */ +#define STM32_UART_USE_USART1               FALSE +#define STM32_UART_USE_USART2               FALSE +#define STM32_UART_USE_USART3               FALSE +#define STM32_UART_USE_UART4                FALSE +#define STM32_UART_USE_UART5                FALSE +#define STM32_UART_USE_USART6               FALSE +#define STM32_UART_USE_UART7                FALSE +#define STM32_UART_USE_UART8                FALSE +#define STM32_UART_USE_UART9                FALSE +#define STM32_UART_USE_USART10              FALSE +#define STM32_UART_USART1_RX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART1_TX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART2_RX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART2_TX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART3_RX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART3_TX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART4_RX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART4_TX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART5_RX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART5_TX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART6_RX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART6_TX_DMA_STREAM     STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART7_RX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART7_TX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART8_RX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART8_TX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART9_RX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART9_TX_DMA_STREAM      STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART10_RX_DMA_STREAM    STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART10_TX_DMA_STREAM    STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART1_DMA_PRIORITY      0 +#define STM32_UART_USART2_DMA_PRIORITY      0 +#define STM32_UART_USART3_DMA_PRIORITY      0 +#define STM32_UART_UART4_DMA_PRIORITY       0 +#define STM32_UART_UART5_DMA_PRIORITY       0 +#define STM32_UART_USART6_DMA_PRIORITY      0 +#define STM32_UART_UART7_DMA_PRIORITY       0 +#define STM32_UART_UART8_DMA_PRIORITY       0 +#define STM32_UART_UART9_DMA_PRIORITY       0 +#define STM32_UART_USART10_DMA_PRIORITY     0 +#define STM32_UART_DMA_ERROR_HOOK(uartp)    osalSysHalt("DMA failure") + +/* + * USB driver system settings. + */ +#define STM32_USB_USE_OTG2                  TRUE +#define STM32_USB_OTG2_IRQ_PRIORITY         14 +#define STM32_USB_OTG2_RX_FIFO_SIZE         1024 +#define STM32_USB_HOST_WAKEUP_DURATION      2 + +/* + * WDG driver system settings. + */ +#define STM32_WDG_USE_IWDG                  FALSE + +/* + * WSPI driver system settings. + */ +#define STM32_WSPI_USE_OCTOSPI1             FALSE +#define STM32_WSPI_USE_OCTOSPI2             FALSE +#define STM32_WSPI_OCTOSPI1_PRESCALER_VALUE 1 +#define STM32_WSPI_OCTOSPI2_PRESCALER_VALUE 1 +#define STM32_WSPI_OCTOSPI1_SSHIFT          FALSE +#define STM32_WSPI_OCTOSPI2_SSHIFT          FALSE +#define STM32_WSPI_OCTOSPI1_DHQC            FALSE +#define STM32_WSPI_OCTOSPI2_DHQC            FALSE +#define STM32_WSPI_OCTOSPI1_MDMA_CHANNEL    STM32_MDMA_CHANNEL_ID_ANY +#define STM32_WSPI_OCTOSPI2_MDMA_CHANNEL    STM32_MDMA_CHANNEL_ID_ANY +#define STM32_WSPI_OCTOSPI1_MDMA_PRIORITY   1 +#define STM32_WSPI_OCTOSPI2_MDMA_PRIORITY   1 +#define STM32_WSPI_OCTOSPI1_MDMA_IRQ_PRIORITY 10 +#define STM32_WSPI_OCTOSPI2_MDMA_IRQ_PRIORITY 10 +#define STM32_WSPI_DMA_ERROR_HOOK(wspip)    osalSysHalt("MDMA failure") + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/boards/GENERIC_WB32_F3G71XX/board/board.c b/platforms/chibios/boards/GENERIC_WB32_F3G71XX/board/board.c index f74c9e8be7..e38a7e0054 100644 --- a/platforms/chibios/boards/GENERIC_WB32_F3G71XX/board/board.c +++ b/platforms/chibios/boards/GENERIC_WB32_F3G71XX/board/board.c @@ -80,7 +80,3 @@ void __early_init(void) {  void boardInit(void) {  } - -void restart_usb_driver(USBDriver *usbp) { -  // Do nothing. Restarting the USB driver on these boards breaks it. -} diff --git a/platforms/chibios/boards/GENERIC_WB32_FQ95XX/board/board.c b/platforms/chibios/boards/GENERIC_WB32_FQ95XX/board/board.c index a99537fc27..22b4ff73b5 100644 --- a/platforms/chibios/boards/GENERIC_WB32_FQ95XX/board/board.c +++ b/platforms/chibios/boards/GENERIC_WB32_FQ95XX/board/board.c @@ -80,7 +80,3 @@ void __early_init(void) {  void boardInit(void) {  } - -void restart_usb_driver(USBDriver *usbp) { -  // Do nothing. Restarting the USB driver on these boards breaks it. -} diff --git a/platforms/chibios/boards/IC_TEENSY_3_1/board/board.c b/platforms/chibios/boards/IC_TEENSY_3_1/board/board.c index 424e0c975b..36ae8051ee 100644 --- a/platforms/chibios/boards/IC_TEENSY_3_1/board/board.c +++ b/platforms/chibios/boards/IC_TEENSY_3_1/board/board.c @@ -144,8 +144,3 @@ void __early_init(void) {   * @todo    Add your board-specific code, if any.   */  void boardInit(void) {} - - -void restart_usb_driver(USBDriver *usbp) { -    // Do nothing. Restarting the USB driver on these boards breaks it. -} diff --git a/platforms/chibios/boards/PJRC_TEENSY_3_5/board/extra.c b/platforms/chibios/boards/PJRC_TEENSY_3_5/board/extra.c deleted file mode 100644 index 4940d6d99b..0000000000 --- a/platforms/chibios/boards/PJRC_TEENSY_3_5/board/extra.c +++ /dev/null @@ -1,7 +0,0 @@ -#include <hal.h> - -void restart_usb_driver(USBDriver *usbp) { -    // Do nothing. Restarting the USB driver on the Teensy 3.6 breaks it, -    // resulting in a keyboard which can wake up a PC from Suspend-to-RAM, but -    // does not actually produce any keypresses until you un-plug and re-plug. -} diff --git a/platforms/chibios/boards/PJRC_TEENSY_3_6/board/board.mk b/platforms/chibios/boards/PJRC_TEENSY_3_6/board/board.mk deleted file mode 100644 index aba195db04..0000000000 --- a/platforms/chibios/boards/PJRC_TEENSY_3_6/board/board.mk +++ /dev/null @@ -1,11 +0,0 @@ -include $(CHIBIOS_CONTRIB)/os/hal/boards/PJRC_TEENSY_3_6/board.mk - -# List of all the board related files. -BOARDSRC += $(BOARD_PATH)/board/extra.c - -# Required include directories -BOARDINC += $(BOARD_PATH)/board - -# Shared variables -ALLCSRC += $(BOARDSRC) -ALLINC  += $(BOARDINC) diff --git a/platforms/chibios/boards/PJRC_TEENSY_3_6/board/extra.c b/platforms/chibios/boards/PJRC_TEENSY_3_6/board/extra.c deleted file mode 100644 index 4940d6d99b..0000000000 --- a/platforms/chibios/boards/PJRC_TEENSY_3_6/board/extra.c +++ /dev/null @@ -1,7 +0,0 @@ -#include <hal.h> - -void restart_usb_driver(USBDriver *usbp) { -    // Do nothing. Restarting the USB driver on the Teensy 3.6 breaks it, -    // resulting in a keyboard which can wake up a PC from Suspend-to-RAM, but -    // does not actually produce any keypresses until you un-plug and re-plug. -} diff --git a/platforms/chibios/boards/QMK_BLOK/configs/mcuconf.h b/platforms/chibios/boards/QMK_BLOK/configs/mcuconf.h index eb51e25171..0c2ef592d6 100644 --- a/platforms/chibios/boards/QMK_BLOK/configs/mcuconf.h +++ b/platforms/chibios/boards/QMK_BLOK/configs/mcuconf.h @@ -106,7 +106,6 @@  #define RP_USB_USE_USBD0                    TRUE  #define RP_USB_FORCE_VBUS_DETECT            TRUE  #define RP_USE_EXTERNAL_VBUS_DETECT         FALSE -#define RP_USB_USE_SOF_INTR                 TRUE  #define RP_USB_USE_ERROR_DATA_SEQ_INTR      FALSE  #endif /* MCUCONF_H */ diff --git a/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h b/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h index f19f08e93c..493dcf6434 100644 --- a/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h +++ b/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h @@ -106,7 +106,6 @@  #define RP_USB_USE_USBD0                    TRUE  #define RP_USB_FORCE_VBUS_DETECT            TRUE  #define RP_USE_EXTERNAL_VBUS_DETECT         FALSE -#define RP_USB_USE_SOF_INTR                 TRUE  #define RP_USB_USE_ERROR_DATA_SEQ_INTR      FALSE  #endif /* MCUCONF_H */ diff --git a/platforms/chibios/bootloaders/rp2040.c b/platforms/chibios/bootloaders/rp2040.c index bedc00f32e..524d13e636 100644 --- a/platforms/chibios/bootloaders/rp2040.c +++ b/platforms/chibios/bootloaders/rp2040.c @@ -1,9 +1,10 @@  // Copyright 2022 Stefan Kerkmann  // SPDX-License-Identifier: GPL-2.0-or-later -#include "quantum.h"  #include "hal.h"  #include "bootloader.h" +#include "gpio.h" +#include "wait.h"  #include "pico/bootrom.h"  #if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED) diff --git a/platforms/chibios/bootloaders/stm32_dfu.c b/platforms/chibios/bootloaders/stm32_dfu.c index f845bf21e9..fba3086e7a 100644 --- a/platforms/chibios/bootloaders/stm32_dfu.c +++ b/platforms/chibios/bootloaders/stm32_dfu.c @@ -1,4 +1,4 @@ -/* Copyright 2021 QMK +/* Copyright 2021-2023 QMK   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -15,12 +15,17 @@   */  #include "bootloader.h" +#include "util.h"  #include <ch.h>  #include <hal.h>  #include "wait.h" -extern uint32_t __ram0_end__; +#ifndef STM32_BOOTLOADER_RAM_SYMBOL +#    define STM32_BOOTLOADER_RAM_SYMBOL __ram0_end__ +#endif + +extern uint32_t STM32_BOOTLOADER_RAM_SYMBOL;  #ifndef STM32_BOOTLOADER_DUAL_BANK  #    define STM32_BOOTLOADER_DUAL_BANK FALSE @@ -72,10 +77,25 @@ void enter_bootloader_mode_if_requested(void) {}  /* This code should be checked whether it runs correctly on platforms */  #    define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))  #    define BOOTLOADER_MAGIC 0xDEADBEEF -#    define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4) +#    define MAGIC_ADDR (unsigned long *)(SYMVAL(STM32_BOOTLOADER_RAM_SYMBOL) - 4) + +__attribute__((weak)) void bootloader_marker_enable(void) { +    uint32_t *marker = (uint32_t *)MAGIC_ADDR; +    *marker          = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader +} + +__attribute__((weak)) bool bootloader_marker_active(void) { +    const uint32_t *marker = (const uint32_t *)MAGIC_ADDR; +    return (*marker == BOOTLOADER_MAGIC) ? true : false; +} + +__attribute__((weak)) void bootloader_marker_disable(void) { +    uint32_t *marker = (uint32_t *)MAGIC_ADDR; +    *marker          = 0; +}  __attribute__((weak)) void bootloader_jump(void) { -    *MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader +    bootloader_marker_enable();      NVIC_SystemReset();  } @@ -84,18 +104,44 @@ __attribute__((weak)) void mcu_reset(void) {  }  void enter_bootloader_mode_if_requested(void) { -    unsigned long *check = MAGIC_ADDR; -    if (*check == BOOTLOADER_MAGIC) { -        *check = 0; +    if (bootloader_marker_active()) { +        bootloader_marker_disable(); + +        struct system_memory_vector_t { +            uint32_t stack_top; +            void (*entrypoint)(void); +        }; +        const struct system_memory_vector_t *bootloader = (const struct system_memory_vector_t *)(STM32_BOOTLOADER_ADDRESS); + +        __disable_irq(); + +#    if defined(QMK_MCU_ARCH_CORTEX_M7) +        SCB_DisableDCache(); +        SCB_DisableICache(); +#    endif + +#    if defined(__MPU_PRESENT) && (__MPU_PRESENT == 1U) +        ARM_MPU_Disable(); +#    endif + +        SysTick->CTRL = 0; +        SysTick->VAL  = 0; +        SysTick->LOAD = 0; + +        // Clear interrupt enable and interrupt pending registers +        for (int i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) { +            NVIC->ICER[i] = 0xFFFFFFFF; +            NVIC->ICPR[i] = 0xFFFFFFFF; +        } +          __set_CONTROL(0); -        __set_MSP(*(__IO uint32_t *)STM32_BOOTLOADER_ADDRESS); +        __set_MSP(bootloader->stack_top);          __enable_irq(); -        typedef void (*BootJump_t)(void); -        BootJump_t boot_jump = *(BootJump_t *)(STM32_BOOTLOADER_ADDRESS + 4); -        boot_jump(); -        while (1) -            ; +        // Jump to bootloader +        bootloader->entrypoint(); +        while (true) { +        }      }  }  #endif diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index 52632a051e..1f8a7842fe 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -71,7 +71,11 @@  // STM32 compatibility  #if defined(MCU_STM32) -#    define CPU_CLOCK STM32_SYSCLK +#    if defined(STM32_CORE_CK) +#        define CPU_CLOCK STM32_CORE_CK +#    else +#        define CPU_CLOCK STM32_SYSCLK +#    endif  #    if defined(STM32F1XX)  #        define USE_GPIOV1 diff --git a/platforms/chibios/config.h b/platforms/chibios/config.h new file mode 100644 index 0000000000..006415a5dc --- /dev/null +++ b/platforms/chibios/config.h @@ -0,0 +1,7 @@ +// Copyright 2023 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef CORTEX_ENABLE_WFI_IDLE +#    define CORTEX_ENABLE_WFI_IDLE TRUE +#endif // CORTEX_ENABLE_WFI_IDLE diff --git a/platforms/chibios/drivers/backlight_pwm.c b/platforms/chibios/drivers/backlight_pwm.c new file mode 100644 index 0000000000..01e6f71307 --- /dev/null +++ b/platforms/chibios/drivers/backlight_pwm.c @@ -0,0 +1,173 @@ +#include "backlight.h" +#include "gpio.h" +#include "wait.h" +#include <hal.h> + +// Maximum duty cycle limit +#ifndef BACKLIGHT_LIMIT_VAL +#    define BACKLIGHT_LIMIT_VAL 255 +#endif + +#ifndef BACKLIGHT_PAL_MODE +#    if defined(USE_GPIOV1) +#        define BACKLIGHT_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL +#    else +// GPIOV2 && GPIOV3 +#        define BACKLIGHT_PAL_MODE 2 +#    endif +#endif + +// GENERIC +#ifndef BACKLIGHT_PWM_DRIVER +#    define BACKLIGHT_PWM_DRIVER PWMD4 +#endif +#ifndef BACKLIGHT_PWM_CHANNEL +#    define BACKLIGHT_PWM_CHANNEL 3 +#endif + +// Support for pins which are on TIM1_CH1N - requires STM32_PWM_USE_ADVANCED +#ifdef BACKLIGHT_PWM_COMPLEMENTARY_OUTPUT +#    if BACKLIGHT_ON_STATE == 1 +#        define PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW; +#    else +#        define PWM_OUTPUT_MODE PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH; +#    endif +#else +#    if BACKLIGHT_ON_STATE == 1 +#        define PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_HIGH; +#    else +#        define PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_LOW; +#    endif +#endif + +#ifndef BACKLIGHT_PWM_COUNTER_FREQUENCY +#    define BACKLIGHT_PWM_COUNTER_FREQUENCY 0xFFFF +#endif + +#ifndef BACKLIGHT_PWM_PERIOD +#    define BACKLIGHT_PWM_PERIOD 256 +#endif + +static PWMConfig pwmCFG = { +    .frequency = BACKLIGHT_PWM_COUNTER_FREQUENCY, /* PWM clock frequency  */ +    .period    = BACKLIGHT_PWM_PERIOD,            /* PWM period in counter ticks. e.g. clock frequency is 10KHz, period is 256 ticks then t_period is 25.6ms */ +}; + +#ifdef BACKLIGHT_BREATHING +static virtual_timer_t breathing_vt; +#endif + +// See http://jared.geek.nz/2013/feb/linear-led-pwm +static uint16_t cie_lightness(uint16_t v) { +    if (v <= 5243)    // if below 8% of max +        return v / 9; // same as dividing by 900% +    else { +        uint32_t y = (((uint32_t)v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare +        // to get a useful result with integer division, we shift left in the expression above +        // and revert what we've done again after squaring. +        y = y * y * y >> 8; +        if (y > 0xFFFFUL) { // prevent overflow +            return 0xFFFFU; +        } else { +            return (uint16_t)y; +        } +    } +} + +static uint32_t rescale_limit_val(uint32_t val) { +    // rescale the supplied backlight value to be in terms of the value limit +    return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; +} + +void backlight_init_ports(void) { +#ifdef USE_GPIOV1 +    palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), BACKLIGHT_PAL_MODE); +#else +    palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE)); +#endif + +    pwmCFG.channels[BACKLIGHT_PWM_CHANNEL - 1].mode = PWM_OUTPUT_MODE; +    pwmStart(&BACKLIGHT_PWM_DRIVER, &pwmCFG); + +    backlight_set(get_backlight_level()); + +#ifdef BACKLIGHT_BREATHING +    chVTObjectInit(&breathing_vt); +    if (is_backlight_breathing()) { +        breathing_enable(); +    } +#endif +} + +void backlight_set(uint8_t level) { +    if (level > BACKLIGHT_LEVELS) { +        level = BACKLIGHT_LEVELS; +    } + +    if (level == 0) { +        // Turn backlight off +        pwmDisableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1); +    } else { +        // Turn backlight on +        uint32_t duty = (uint32_t)(cie_lightness(rescale_limit_val(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS))); +        pwmEnableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); +    } +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING + +#    define BREATHING_STEPS 128 + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void breathing_callback(virtual_timer_t *vtp, void *p); + +bool is_breathing(void) { +    return chVTIsArmed(&breathing_vt); +} + +void breathing_enable(void) { +    /* Update frequency is 256Hz -> 3906us intervals */ +    chVTSetContinuous(&breathing_vt, TIME_US2I(3906), breathing_callback, NULL); +} + +void breathing_disable(void) { +    chVTReset(&breathing_vt); + +    // Restore backlight level +    backlight_set(get_backlight_level()); +} + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { +    return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +static void breathing_callback(virtual_timer_t *vtp, void *p) { +    uint8_t  breathing_period = get_breathing_period(); +    uint16_t interval         = (uint16_t)breathing_period * 256 / BREATHING_STEPS; + +    // resetting after one period to prevent ugly reset at overflow. +    static uint16_t breathing_counter = 0; +    breathing_counter                 = (breathing_counter + 1) % (breathing_period * 256); +    uint8_t  index                    = breathing_counter / interval % BREATHING_STEPS; +    uint32_t duty                     = cie_lightness(rescale_limit_val(scale_backlight(breathing_table[index] * 256))); + +    chSysLockFromISR(); +    pwmEnableChannelI(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); +    chSysUnlockFromISR(); +} + +// TODO: integrate generic pulse solution +void breathing_pulse(void) { +    backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS); +    wait_ms(10); +    backlight_set(is_backlight_enabled() ? get_backlight_level() : 0); +} + +#endif diff --git a/platforms/chibios/drivers/backlight_timer.c b/platforms/chibios/drivers/backlight_timer.c new file mode 100644 index 0000000000..0fabee93b1 --- /dev/null +++ b/platforms/chibios/drivers/backlight_timer.c @@ -0,0 +1,178 @@ +#include "backlight.h" +#include "backlight_driver_common.h" +#include "wait.h" + +#ifndef BACKLIGHT_GPT_DRIVER +#    define BACKLIGHT_GPT_DRIVER GPTD15 +#endif + +// Platform specific implementations +static void     backlight_timer_configure(bool enable); +static void     backlight_timer_set_duty(uint16_t duty); +static uint16_t backlight_timer_get_duty(void); + +// See http://jared.geek.nz/2013/feb/linear-led-pwm +static uint16_t cie_lightness(uint16_t v) { +    if (v <= 5243)    // if below 8% of max +        return v / 9; // same as dividing by 900% +    else { +        uint32_t y = (((uint32_t)v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare +        // to get a useful result with integer division, we shift left in the expression above +        // and revert what we've done again after squaring. +        y = y * y * y >> 8; +        if (y > 0xFFFFUL) // prevent overflow +            return 0xFFFFU; +        else +            return (uint16_t)y; +    } +} + +void backlight_init_ports(void) { +    backlight_pins_init(); + +    backlight_set(get_backlight_level()); + +#ifdef BACKLIGHT_BREATHING +    if (is_backlight_breathing()) { +        breathing_enable(); +    } +#endif +} + +void backlight_set(uint8_t level) { +    if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; + +    backlight_pins_off(); + +    backlight_timer_set_duty(cie_lightness(0xFFFFU / BACKLIGHT_LEVELS * level)); +    backlight_timer_configure(level != 0); +} + +static void backlight_timer_top(void) { +#ifdef BACKLIGHT_BREATHING +    if (is_breathing()) { +        breathing_task(); +    } +#endif + +    if (backlight_timer_get_duty() > 256) { +        backlight_pins_on(); +    } +} + +static void backlight_timer_cmp(void) { +    backlight_pins_off(); +} + +void backlight_task(void) {} + +#ifdef BACKLIGHT_BREATHING +#    define BREATHING_STEPS 128 + +static bool     breathing         = false; +static uint16_t breathing_counter = 0; + +/* To generate breathing curve in python: + * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] + */ +static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// Use this before the cie_lightness function. +static inline uint16_t scale_backlight(uint16_t v) { +    return v / BACKLIGHT_LEVELS * get_backlight_level(); +} + +void breathing_task(void) { +    uint8_t  breathing_period = get_breathing_period(); +    uint16_t interval         = (uint16_t)breathing_period * 256 / BREATHING_STEPS; +    // resetting after one period to prevent ugly reset at overflow. +    breathing_counter = (breathing_counter + 1) % (breathing_period * 256); +    uint8_t index     = breathing_counter / interval % BREATHING_STEPS; + +    // printf("index:%u\n", index); + +    backlight_timer_set_duty(cie_lightness(scale_backlight((uint16_t)breathing_table[index] * 256))); +} + +bool is_breathing(void) { +    return breathing; +} + +void breathing_enable(void) { +    breathing_counter = 0; +    breathing         = true; +} +void breathing_disable(void) { +    breathing = false; +} + +void breathing_pulse(void) { +    backlight_set(is_backlight_enabled() ? 0 : BACKLIGHT_LEVELS); +    wait_ms(10); +    backlight_set(is_backlight_enabled() ? get_backlight_level() : 0); +} +#endif + +#ifdef PROTOCOL_CHIBIOS +// On Platforms where timers fire every tick and have no capture/top events +//   - fake event in the normal timer callback +uint16_t s_duty = 0; + +static void timerCallback(void) { +    /* Software PWM +     * timer:1111 1111 1111 1111 +     *       \______/| \_______/____  count(0-255) +     *          \    \______________  unused(1) +     *           \__________________  index of step table(0-127) +     */ + +    // this works for cca 65536 irqs/sec +    static union { +        uint16_t raw; +        struct { +            uint16_t count : 8; +            uint8_t  dummy : 1; +            uint8_t  index : 7; +        } pwm; +    } timer = {.raw = 0}; + +    timer.raw++; + +    if (timer.pwm.count == 0) { +        // LED on +        backlight_timer_top(); +    } else if (timer.pwm.count == (s_duty / 256)) { +        // LED off +        backlight_timer_cmp(); +    } +} + +static void backlight_timer_set_duty(uint16_t duty) { +    s_duty = duty; +} +static uint16_t backlight_timer_get_duty(void) { +    return s_duty; +} + +// ChibiOS - Map GPT timer onto Software PWM +static void gptTimerCallback(GPTDriver *gptp) { +    (void)gptp; +    timerCallback(); +} + +static void backlight_timer_configure(bool enable) { +    static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0}; + +    static bool s_init = false; +    if (!s_init) { +        gptStart(&BACKLIGHT_GPT_DRIVER, &gptcfg); +        s_init = true; +    } + +    if (enable) { +        gptStartContinuous(&BACKLIGHT_GPT_DRIVER, gptcfg.frequency / 0xFFFF); +    } else { +        gptStopTimer(&BACKLIGHT_GPT_DRIVER); +    } +} +#endif diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 4c7a5daa17..7c49f9d005 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -24,8 +24,10 @@   * STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file. Pins B6 and B7 are used   * but using any other I2C pins should be trivial.   */ -#include "quantum.h" +  #include "i2c_master.h" +#include "gpio.h" +#include "chibios_config.h"  #include <string.h>  #include <ch.h>  #include <hal.h> diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index 0dd8e71ae8..f087d0c2ed 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c @@ -2,8 +2,8 @@   * WARNING: be careful changing this code, it is very timing dependent   */ -#include "quantum.h"  #include "serial.h" +#include "gpio.h"  #include "wait.h"  #include "synchronization_util.h" diff --git a/platforms/chibios/drivers/serial_protocol.c b/platforms/chibios/drivers/serial_protocol.c index ccaf73282d..e0f583ccde 100644 --- a/platforms/chibios/drivers/serial_protocol.c +++ b/platforms/chibios/drivers/serial_protocol.c @@ -3,10 +3,8 @@  #include <ch.h> -#include "quantum.h"  #include "serial.h"  #include "serial_protocol.h" -#include "printf.h"  #include "synchronization_util.h"  static inline bool initiate_transaction(uint8_t transaction_id); diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index 6ebbf7c8ca..767ef8726f 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c @@ -5,6 +5,7 @@  #include "serial_usart.h"  #include "serial_protocol.h"  #include "synchronization_util.h" +#include "chibios_config.h"  #if defined(SERIAL_USART_CONFIG)  static QMKSerialConfig serial_config = SERIAL_USART_CONFIG; diff --git a/platforms/chibios/drivers/serial_usart.h b/platforms/chibios/drivers/serial_usart.h index fa062cd736..dec8a292e9 100644 --- a/platforms/chibios/drivers/serial_usart.h +++ b/platforms/chibios/drivers/serial_usart.h @@ -3,7 +3,6 @@  #pragma once -#include "quantum.h"  #include "serial.h"  #include <hal.h> diff --git a/platforms/chibios/drivers/uart.c b/platforms/chibios/drivers/uart.c index 34f77232b6..39a59dd445 100644 --- a/platforms/chibios/drivers/uart.c +++ b/platforms/chibios/drivers/uart.c @@ -16,8 +16,6 @@  #include "uart.h" -#include "quantum.h" -  #if defined(MCU_KINETIS)  static SerialConfig serialConfig = {SERIAL_DEFAULT_BITRATE};  #elif defined(WB32F3G71xx) || defined(WB32FQ95xx) diff --git a/platforms/chibios/drivers/uart.h b/platforms/chibios/drivers/uart.h index e9e3b0855b..d1917bfc80 100644 --- a/platforms/chibios/drivers/uart.h +++ b/platforms/chibios/drivers/uart.h @@ -17,6 +17,7 @@  #pragma once  #include <stdint.h> +#include <stdbool.h>  #include <hal.h> diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/ps2_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/ps2_vendor.c index 937fa5de6f..d775ec29d5 100644 --- a/platforms/chibios/drivers/vendor/RP/RP2040/ps2_vendor.c +++ b/platforms/chibios/drivers/vendor/RP/RP2040/ps2_vendor.c @@ -1,12 +1,10 @@  // Copyright 2022 Marek Kraus (@gamelaster)  // SPDX-License-Identifier: GPL-2.0-or-later -#include "quantum.h" -  #include "hardware/pio.h"  #include "hardware/clocks.h"  #include "ps2.h" -#include "print.h" +#include "debug.h"  #if !defined(MCU_RP)  #    error PIO Driver is only available for Raspberry Pi 2040 MCUs! diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c index dd4723a086..3aa8e1165f 100644 --- a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -1,11 +1,12 @@  // Copyright 2022 Stefan Kerkmann  // SPDX-License-Identifier: GPL-2.0-or-later -#include "quantum.h"  #include "serial_usart.h"  #include "serial_protocol.h"  #include "hardware/pio.h"  #include "hardware/clocks.h" +#include "wait.h" +#include "debug.h"  #if !defined(MCU_RP)  #    error PIO Driver is only available for Raspberry Pi 2040 MCUs! diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c index 99a6cfaba9..8d59e13bb2 100644 --- a/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c +++ b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c @@ -2,13 +2,19 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include "ws2812.h" -#include "hardware/timer.h" -#include "hardware/clocks.h" +  // Keep this exact include order otherwise we run into naming conflicts between  // pico-sdk and rp2040.h which we don't control. -#include "quantum.h" +#include "hardware/timer.h" +#include "hardware/clocks.h" +#include <hal.h>  #include "hardware/pio.h" +#include "gpio.h" +#include "debug.h" +#include "wait.h" +#include "util.h" +  #if !defined(MCU_RP)  #    error PIO Driver is only available for Raspberry Pi 2040 MCUs!  #endif diff --git a/platforms/chibios/drivers/ws2812_bitbang.c b/platforms/chibios/drivers/ws2812_bitbang.c index d05deb1a50..c55e0f654c 100644 --- a/platforms/chibios/drivers/ws2812_bitbang.c +++ b/platforms/chibios/drivers/ws2812_bitbang.c @@ -1,7 +1,7 @@ -#include "quantum.h"  #include "ws2812.h" -#include <ch.h> -#include <hal.h> + +#include "gpio.h" +#include "chibios_config.h"  /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c index 04c8279a97..cfee547a82 100644 --- a/platforms/chibios/drivers/ws2812_pwm.c +++ b/platforms/chibios/drivers/ws2812_pwm.c @@ -1,6 +1,6 @@  #include "ws2812.h" -#include "quantum.h" -#include <hal.h> +#include "gpio.h" +#include "chibios_config.h"  /* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */ diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c index c28f5007f1..f188576e04 100644 --- a/platforms/chibios/drivers/ws2812_spi.c +++ b/platforms/chibios/drivers/ws2812_spi.c @@ -1,5 +1,7 @@ -#include "quantum.h"  #include "ws2812.h" +#include "gpio.h" +#include "util.h" +#include "chibios_config.h"  /* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ diff --git a/platforms/chibios/mcu_selection.mk b/platforms/chibios/mcu_selection.mk index f14b16b169..5122ed4634 100644 --- a/platforms/chibios/mcu_selection.mk +++ b/platforms/chibios/mcu_selection.mk @@ -705,6 +705,45 @@ ifneq (,$(filter $(MCU),STM32L412 STM32L422))    STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000  endif +ifneq (,$(filter $(MCU),STM32H723 STM32H733)) +  # Cortex version +  MCU = cortex-m7 + +  # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7 +  ARMV = 7 + +  ## chip/board settings +  # - the next two should match the directories in +  #   <chibios[-contrib]>/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES) +  #   OR +  #   <chibios[-contrib]>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES) +  MCU_FAMILY = STM32 +  MCU_SERIES = STM32H7xx + +  # Linker script to use +  # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/ +  #   or <keyboard_dir>/ld/ +  MCU_LDSCRIPT ?= STM32H723xG_ITCM64k + +  # Startup code to use +  #  - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/ +  MCU_STARTUP ?= stm32h7xx + +  # Board: it should exist either in <chibios>/os/hal/boards/, +  # <keyboard_dir>/boards/, or drivers/boards/ +  BOARD ?= GENERIC_STM32_H723XG + +  PLATFORM_NAME ?= platform_type2 + +  USE_FPU ?= yes + +  # UF2 settings +  UF2_FAMILY ?= STM32H7 + +  # Bootloader address for STM32 DFU +  STM32_BOOTLOADER_ADDRESS ?= 0x1FF09800 +endif +  ifneq ($(findstring WB32F3G71, $(MCU)),)    # Cortex version    MCU = cortex-m3 diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 6304b42d87..081b001e6d 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -432,6 +432,15 @@ else      endif  endif +# Extra config.h files for the platform +ifneq ("$(wildcard $(PLATFORM_COMMON_DIR)/vendors/$(MCU_FAMILY)/$(MCU_SERIES)/config.h)","") +    CONFIG_H += $(PLATFORM_COMMON_DIR)/vendors/$(MCU_FAMILY)/$(MCU_SERIES)/config.h +endif +ifneq ("$(wildcard $(PLATFORM_COMMON_DIR)/vendors/$(MCU_FAMILY)/config.h)","") +    CONFIG_H += $(PLATFORM_COMMON_DIR)/vendors/$(MCU_FAMILY)/config.h +endif +CONFIG_H += $(PLATFORM_COMMON_DIR)/config.h +  # Assembler flags  ASFLAGS  += $(SHARED_ASFLAGS) $(TOOLCHAIN_ASFLAGS) diff --git a/platforms/chibios/sleep_led.c b/platforms/chibios/sleep_led.c index a777d60468..a35514bf2e 100644 --- a/platforms/chibios/sleep_led.c +++ b/platforms/chibios/sleep_led.c @@ -41,17 +41,20 @@ void sleep_led_timer_callback(void) {              uint8_t duration : 2;              uint8_t index : 6;          } pwm; -    } timer = {.row = 0}; +    } timer                = {.row = 0}; +    static led_t led_state = {0};      timer.row++;      // LED on      if (timer.pwm.count == 0) { -        led_set(1 << USB_LED_CAPS_LOCK); +        led_state.caps_lock = true; +        led_set(led_state.raw);      }      // LED off      if (timer.pwm.count == breathing_table[timer.pwm.index]) { -        led_set(0); +        led_state.caps_lock = false; +        led_set(led_state.raw);      }  } @@ -190,7 +193,7 @@ void sleep_led_toggle(void) {  void sleep_led_init(void) {}  void sleep_led_enable(void) { -    led_set(1 << USB_LED_CAPS_LOCK); +    led_set(2); // Caps Lock  }  void sleep_led_disable(void) { diff --git a/platforms/chibios/suspend.c b/platforms/chibios/suspend.c index ce03433e3a..a937ccf059 100644 --- a/platforms/chibios/suspend.c +++ b/platforms/chibios/suspend.c @@ -42,6 +42,7 @@ void suspend_wakeup_init(void) {      clear_keys();  #ifdef MOUSEKEY_ENABLE      mousekey_clear(); +    mousekey_send();  #endif /* MOUSEKEY_ENABLE */  #ifdef PROGRAMMABLE_BUTTON_ENABLE      programmable_button_clear(); diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c index 239155c086..caab400531 100644 --- a/platforms/chibios/vendors/RP/pico_sdk_shims.c +++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c @@ -2,7 +2,8 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include <stdbool.h> -#include <ch.h> + +extern void chSysHalt(const char *reason) __attribute__((noreturn));  void panic(const char *fmt, ...) {      chSysHalt(fmt); diff --git a/platforms/chibios/wait.c b/platforms/chibios/wait.c index 88cb5e6d54..7fe6d477b8 100644 --- a/platforms/chibios/wait.c +++ b/platforms/chibios/wait.c @@ -21,7 +21,7 @@  #ifdef WAIT_US_TIMER  void wait_us(uint16_t duration) { -    static const GPTConfig gpt_cfg = {1000000, NULL, 0, 0}; /* 1MHz timer, no callback */ +    static const GPTConfig gpt_cfg = {.frequency = 1000000}; /* 1MHz timer, no callback */      if (duration == 0) {          duration = 1; diff --git a/platforms/test/drivers/audio_pwm.h b/platforms/test/drivers/audio_pwm.h new file mode 100644 index 0000000000..9a3fa88cec --- /dev/null +++ b/platforms/test/drivers/audio_pwm.h @@ -0,0 +1,16 @@ +// Copyright 2023 Google LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. + +#pragma once diff --git a/platforms/test/drivers/audio_pwm_hardware.c b/platforms/test/drivers/audio_pwm_hardware.c new file mode 100644 index 0000000000..336e4f5844 --- /dev/null +++ b/platforms/test/drivers/audio_pwm_hardware.c @@ -0,0 +1,20 @@ +// Copyright 2023 Google LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. + +#include "audio.h" + +void audio_driver_initialize(void) {} +void audio_driver_start() {} +void audio_driver_stop() {}  | 
