Skip to content

Commit

Permalink
♻️ Refactor HAL as singleton (MarlinFirmware#23295)
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkyhead authored Dec 25, 2021
1 parent 532f21f commit e211ff1
Show file tree
Hide file tree
Showing 69 changed files with 1,756 additions and 1,267 deletions.
14 changes: 7 additions & 7 deletions Marlin/src/HAL/AVR/HAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
// ------------------------

// Don't initialize/override variable (which would happen in .init4)
uint8_t reset_reason __attribute__((section(".noinit")));
uint8_t MarlinHAL::reset_reason __attribute__((section(".noinit")));

// ------------------------
// Public functions
Expand All @@ -45,22 +45,22 @@ uint8_t reset_reason __attribute__((section(".noinit")));
__attribute__((naked)) // Don't output function pro- and epilogue
__attribute__((used)) // Output the function, even if "not used"
__attribute__((section(".init3"))) // Put in an early user definable section
void HAL_save_reset_reason() {
void save_reset_reason() {
#if ENABLED(OPTIBOOT_RESET_REASON)
__asm__ __volatile__(
A("STS %0, r2")
: "=m"(reset_reason)
: "=m"(hal.reset_reason)
);
#else
reset_reason = MCUSR;
hal.reset_reason = MCUSR;
#endif

// Clear within 16ms since WDRF bit enables a 16ms watchdog timer -> Boot loop
MCUSR = 0;
hal.clear_reset_source();
wdt_disable();
}

void HAL_init() {
void MarlinHAL::init() {
// Init Servo Pins
#define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW)
#if HAS_SERVO_0
Expand All @@ -77,7 +77,7 @@ void HAL_init() {
#endif
}

void HAL_reboot() {
void MarlinHAL::reboot() {
#if ENABLED(USE_WATCHDOG)
while (1) { /* run out the watchdog */ }
#else
Expand Down
170 changes: 103 additions & 67 deletions Marlin/src/HAL/AVR/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,25 @@
#define CRITICAL_SECTION_START() unsigned char _sreg = SREG; cli()
#define CRITICAL_SECTION_END() SREG = _sreg
#endif
#define ISRS_ENABLED() TEST(SREG, SREG_I)
#define ENABLE_ISRS() sei()
#define DISABLE_ISRS() cli()

#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment

// ------------------------
// Types
// ------------------------

typedef int8_t pin_t;

// Use shared/servos.cpp
#define SHARED_SERVOS HAS_SERVOS
#define HAL_SERVO_LIB Servo

class Servo;
typedef Servo hal_servo_t;

// ------------------------
// Public Variables
// Serial ports
// ------------------------

extern uint8_t reset_reason;

// Serial ports
#ifdef USBCON
#include "../../core/serial_hook.h"
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
Expand Down Expand Up @@ -142,20 +141,31 @@ extern uint8_t reset_reason;
#endif
#endif

// ------------------------
// Public functions
// ------------------------
//
// ADC
//
#define HAL_ADC_VREF 5.0
#define HAL_ADC_RESOLUTION 10

void HAL_init();
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)

//void cli();
#define HAL_SENSITIVE_PINS 0, 1,

//void _delay_ms(const int delay);
#ifdef __AVR_AT90USB1286__
#define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
#endif

inline void HAL_clear_reset_source() { }
inline uint8_t HAL_get_reset_source() { return reset_reason; }
// AVR compatibility
#define strtof strtod

void HAL_reboot();
// ------------------------
// Class Utilities
// ------------------------

#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
Expand All @@ -166,63 +176,89 @@ extern "C" int freeMemory();

#pragma GCC diagnostic pop

// ADC
#ifdef DIDR2
#define HAL_ANALOG_SELECT(ind) do{ if (ind < 8) SBI(DIDR0, ind); else SBI(DIDR2, ind & 0x07); }while(0)
#else
#define HAL_ANALOG_SELECT(ind) SBI(DIDR0, ind);
#endif
// ------------------------
// MarlinHAL Class
// ------------------------

inline void HAL_adc_init() {
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
}
class MarlinHAL {
public:

#define SET_ADMUX_ADCSRA(ch) ADMUX = _BV(REFS0) | (ch & 0x07); SBI(ADCSRA, ADSC)
#ifdef MUX5
#define HAL_START_ADC(ch) if (ch > 7) ADCSRB = _BV(MUX5); else ADCSRB = 0; SET_ADMUX_ADCSRA(ch)
#else
#define HAL_START_ADC(ch) ADCSRB = 0; SET_ADMUX_ADCSRA(ch)
#endif
// Earliest possible init, before setup()
MarlinHAL() {}

#define HAL_ADC_VREF 5.0
#define HAL_ADC_RESOLUTION 10
#define HAL_READ_ADC() ADC
#define HAL_ADC_READY() !TEST(ADCSRA, ADSC)
static void init(); // Called early in setup()
static inline void init_board() {} // Called less early in setup()
static void reboot(); // Restart the firmware from 0x0

#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
static inline bool isr_state() { return TEST(SREG, SREG_I); }
static inline void isr_on() { sei(); }
static inline void isr_off() { cli(); }

#define HAL_SENSITIVE_PINS 0, 1,
static inline void delay_ms(const int ms) { _delay_ms(ms); }

#ifdef __AVR_AT90USB1286__
#define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
#endif
// Tasks, called from idle()
static inline void idletask() {}

// AVR compatibility
#define strtof strtod
// Reset
static uint8_t reset_reason;
static inline uint8_t get_reset_source() { return reset_reason; }
static inline void clear_reset_source() { MCUSR = 0; }

#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
// Free SRAM
static inline int freeMemory() { return freeMemory(); }

/**
* set_pwm_frequency
* Sets the frequency of the timer corresponding to the provided pin
* as close as possible to the provided desired frequency. Internally
* calculates the required waveform generation mode, prescaler and
* resolution values required and sets the timer registers accordingly.
* NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B)
* NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST FAN PWM Settings)
*/
void set_pwm_frequency(const pin_t pin, int f_desired);
//
// ADC Methods
//

/**
* set_pwm_duty
* Set the PWM duty cycle of the provided pin to the provided value
* Optionally allows inverting the duty cycle [default = false]
* Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255]
*/
void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
// Called by Temperature::init once at startup
static inline void adc_init() {
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
}

// Called by Temperature::init for each sensor at startup
static inline void adc_enable(const uint8_t ch) {
#ifdef DIDR2
if (ch > 7) { SBI(DIDR2, ch & 0x07); return; }
#endif
SBI(DIDR0, ch);
}

// Begin ADC sampling on the given channel
static inline void adc_start(const pin_t ch) {
#ifdef MUX5
if (ch > 7) { ADCSRB = _BV(MUX5); return; }
#endif
ADCSRB = 0;
ADMUX = _BV(REFS0) | (ch & 0x07); SBI(ADCSRA, ADSC);
}

// Is the ADC ready for reading?
static inline bool adc_ready() { return !TEST(ADCSRA, ADSC); }

// The current value of the ADC register
static inline __typeof__(ADC) adc_value() { return ADC; }

/**
* Set the PWM duty cycle for the pin to the given value.
* Optionally invert the duty cycle [default = false]
* Optionally change the scale of the provided value to enable finer PWM duty control [default = 255]
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);

/**
* Set the frequency of the timer for the given pin as close as
* possible to the provided desired frequency. Internally calculate
* the required waveform generation mode, prescaler, and resolution
* values and set timer registers accordingly.
* NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B)
* NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST FAN PWM Settings)
*/
static void set_pwm_frequency(const pin_t pin, int f_desired);
};

extern MarlinHAL hal;
4 changes: 2 additions & 2 deletions Marlin/src/HAL/AVR/MarlinSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);

// If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) {
if (!hal.isr_state()) {

// Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) {
Expand Down Expand Up @@ -534,7 +534,7 @@ void MarlinSerial<Cfg>::flushTX() {
if (!_written) return;

// If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) {
if (!hal.isr_state()) {

// Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !B_TXC) {
Expand Down
11 changes: 5 additions & 6 deletions Marlin/src/HAL/AVR/fast_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ struct Timer {
};

/**
* get_pwm_timer
* Get the timer information and register of the provided pin.
* Return a Timer struct containing this information.
* Used by set_pwm_frequency, set_pwm_duty
* Get the timer information and register for a pin.
* Return a Timer struct containing this information.
* Used by set_pwm_frequency, set_pwm_duty
*/
Timer get_pwm_timer(const pin_t pin) {
uint8_t q = 0;
Expand Down Expand Up @@ -150,7 +149,7 @@ Timer get_pwm_timer(const pin_t pin) {
return timer;
}

void set_pwm_frequency(const pin_t pin, int f_desired) {
void MarlinHAL::set_pwm_frequency(const pin_t pin, int f_desired) {
Timer timer = get_pwm_timer(pin);
if (timer.n == 0) return; // Don't proceed if protected timer or not recognized
uint16_t size;
Expand Down Expand Up @@ -230,7 +229,7 @@ void set_pwm_frequency(const pin_t pin, int f_desired) {

#endif // NEEDS_HARDWARE_PWM

void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
#if NEEDS_HARDWARE_PWM

// If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
Expand Down
4 changes: 2 additions & 2 deletions Marlin/src/HAL/AVR/timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) {
* (otherwise, characters will be lost due to UART overflow).
* Then: Stepper, Endstops, Temperature, and -finally- all others.
*/
#define HAL_timer_isr_prologue(T)
#define HAL_timer_isr_epilogue(T)
#define HAL_timer_isr_prologue(T) NOOP
#define HAL_timer_isr_epilogue(T) NOOP

/* 18 cycles maximum latency */
#ifndef HAL_STEP_TIMER_ISR
Expand Down
Loading

0 comments on commit e211ff1

Please sign in to comment.