Skip to content

Commit

Permalink
♻️ Refactor HAL as singleton (#23357)
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkyhead authored Feb 18, 2022
1 parent fee85b3 commit 1bd86f1
Show file tree
Hide file tree
Showing 79 changed files with 1,952 additions and 1,394 deletions.
40 changes: 20 additions & 20 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 @@ -79,7 +79,7 @@ void HAL_init() {
init_pwm_timers(); // Init user timers to default frequency - 1000HZ
}

void HAL_reboot() {
void MarlinHAL::reboot() {
#if ENABLED(USE_WATCHDOG)
while (1) { /* run out the watchdog */ }
#else
Expand All @@ -95,20 +95,20 @@ void HAL_reboot() {

#else // !SDSUPPORT

extern "C" {
extern char __bss_end;
extern char __heap_start;
extern void* __brkval;

int freeMemory() {
int free_memory;
if ((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
extern "C" {
extern char __bss_end;
extern char __heap_start;
extern void* __brkval;

int freeMemory() {
int free_memory;
if ((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
}
}

#endif // !SDSUPPORT

Expand Down
184 changes: 110 additions & 74 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
#define PWM_FREQUENCY 1000 // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()

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

typedef int8_t pin_t;

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

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,70 +176,96 @@ 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 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)
// Interrupts
static bool isr_state() { return TEST(SREG, SREG_I); }
static void isr_on() { sei(); }
static void isr_off() { cli(); }

#define HAL_SENSITIVE_PINS 0, 1,
static 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 void idletask() {}

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

#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#define PWM_FREQUENCY 1000 // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
// Free SRAM
static 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, const uint16_t 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 void adc_init() {
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
}

/*
* init_pwm_timers
* sets the default frequency for timers 2-5 to 1000HZ
*/
void init_pwm_timers();
// Called by Temperature::init for each sensor at startup
static 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 void adc_start(const uint8_t ch) {
#ifdef MUX5
ADCSRB = ch > 7 ? _BV(MUX5) : 0;
#else
ADCSRB = 0;
#endif
ADMUX = _BV(REFS0) | (ch & 0x07);
SBI(ADCSRA, ADSC);
}

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

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

/**
* init_pwm_timers
* Set the default frequency for timers 2-5 to 1000HZ
*/
static void init_pwm_timers();

/**
* 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_PWM_FAN Settings)
*/
static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired);
};
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
6 changes: 3 additions & 3 deletions Marlin/src/HAL/AVR/MarlinSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,13 @@
rx_framing_errors;
static ring_buffer_pos_t rx_max_enqueued;

static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head();
FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_head();

static volatile bool rx_tail_value_not_stable;
static volatile uint16_t rx_tail_value_backup;

static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value);
static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail();
FORCE_INLINE static void atomic_set_rx_tail(ring_buffer_pos_t value);
FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_tail();

public:
FORCE_INLINE static void store_rxd_char();
Expand Down
6 changes: 3 additions & 3 deletions Marlin/src/HAL/AVR/fast_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const Timer get_pwm_timer(const pin_t pin) {
return Timer();
}

void set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
const Timer timer = get_pwm_timer(pin);
if (timer.isProtected || !timer.isPWM) return; // Don't proceed if protected timer or not recognized

Expand Down Expand Up @@ -176,7 +176,7 @@ void set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
_SET_ICRn(timer, res); // Set ICRn value (TOP) = res
}

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 v is 0 or v_size (max), digitalWrite to LOW or HIGH.
// Note that digitalWrite also disables PWM output for us (sets COM bit to 0)
if (v == 0)
Expand All @@ -201,7 +201,7 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255
}
}

void init_pwm_timers() {
void MarlinHAL::init_pwm_timers() {
// Init some timer frequencies to a default 1KHz
const pin_t pwm_pin[] = {
#ifdef __AVR_ATmega2560__
Expand Down
4 changes: 2 additions & 2 deletions Marlin/src/HAL/AVR/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
// C B A is longIn1
// D C B A is longIn2
//
static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) {
FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) {
uint8_t tmp1;
uint8_t tmp2;
uint16_t intRes;
Expand Down Expand Up @@ -89,7 +89,7 @@ static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2
// uses:
// r26 to store 0
// r27 to store the byte 1 of the 24 bit result
static FORCE_INLINE uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) {
FORCE_INLINE static uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) {
uint8_t tmp;
uint16_t intRes;
__asm__ __volatile__ (
Expand Down
Loading

0 comments on commit 1bd86f1

Please sign in to comment.