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 #23357

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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