Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor HAL as singleton #23295

Merged
merged 12 commits into from
Dec 25, 2021
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