2018-06-14 02:08:26 +02:00
/**
* Marlin 3 D Printer Firmware
2019-02-12 22:06:53 +01:00
* Copyright ( C ) 2019 MarlinFirmware [ https : //github.com/MarlinFirmware/Marlin]
2018-06-14 02:08:26 +02:00
* Copyright ( c ) 2016 Bob Cousins bobcousins42 @ googlemail . com
*
* 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 3 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/>.
*/
2018-11-04 09:25:55 +01:00
# pragma once
2017-06-18 01:36:10 +02:00
// --------------------------------------------------------------------------
// Includes
// --------------------------------------------------------------------------
# include <stdint.h>
2019-05-02 07:45:50 +02:00
# include "../shared/Marduino.h"
2018-08-14 10:28:52 +02:00
# include "../shared/HAL_SPI.h"
2017-06-18 01:36:10 +02:00
# include "fastio_AVR.h"
# include "watchdog_AVR.h"
# include "math_AVR.h"
2017-11-05 15:49:38 +01:00
# ifdef USBCON
# include "HardwareSerial.h"
# else
# include "MarlinSerial.h"
# endif
2019-05-02 07:45:50 +02:00
# include <util/delay.h>
# include <avr/eeprom.h>
# include <avr/pgmspace.h>
# include <avr/interrupt.h>
# include <avr/io.h>
2017-06-18 01:36:10 +02:00
// --------------------------------------------------------------------------
// Defines
// --------------------------------------------------------------------------
//#define analogInputToDigitalPin(IO) IO
# ifndef CRITICAL_SECTION_START
2018-06-17 00:42:32 +02:00
# define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli()
# define CRITICAL_SECTION_END SREG = _sreg
2017-06-18 01:36:10 +02:00
# endif
2018-06-02 02:02:22 +02:00
# define ISRS_ENABLED() TEST(SREG, SREG_I)
# define ENABLE_ISRS() sei()
# define DISABLE_ISRS() cli()
2017-06-18 01:36:10 +02:00
// On AVR this is in math.h?
//#define square(x) ((x)*(x))
// --------------------------------------------------------------------------
// Types
// --------------------------------------------------------------------------
2017-11-06 02:31:07 +01:00
typedef uint16_t hal_timer_t ;
2017-06-18 01:36:10 +02:00
# define HAL_TIMER_TYPE_MAX 0xFFFF
2017-10-26 20:37:26 +02:00
typedef int8_t pin_t ;
2017-06-18 01:36:10 +02:00
# define HAL_SERVO_LIB Servo
// --------------------------------------------------------------------------
// Public Variables
// --------------------------------------------------------------------------
//extern uint8_t MCUSR;
2018-10-03 07:47:27 +02:00
// Serial ports
2017-11-05 15:49:38 +01:00
# ifdef USBCON
# if ENABLED(BLUETOOTH)
# define MYSERIAL0 bluetoothSerial
# else
# define MYSERIAL0 Serial
# endif
2018-10-03 07:47:27 +02:00
# define NUM_SERIAL 1
2017-11-05 15:49:38 +01:00
# else
2018-10-03 07:47:27 +02:00
# if !WITHIN(SERIAL_PORT, -1, 3)
# error "SERIAL_PORT must be from -1 to 3"
# endif
# define MYSERIAL0 customizedSerial1
# ifdef SERIAL_PORT_2
# if !WITHIN(SERIAL_PORT_2, -1, 3)
# error "SERIAL_PORT_2 must be from -1 to 3"
# elif SERIAL_PORT_2 == SERIAL_PORT
# error "SERIAL_PORT_2 must be different than SERIAL_PORT"
# endif
# define NUM_SERIAL 2
# define MYSERIAL1 customizedSerial2
# else
# define NUM_SERIAL 1
# endif
2017-11-05 15:49:38 +01:00
# endif
2017-06-18 01:36:10 +02:00
// --------------------------------------------------------------------------
// Public functions
// --------------------------------------------------------------------------
//void cli(void);
2017-09-27 11:57:33 +02:00
//void _delay_ms(const int delay);
2017-06-18 01:36:10 +02:00
inline void HAL_clear_reset_source ( void ) { MCUSR = 0 ; }
inline uint8_t HAL_get_reset_source ( void ) { return MCUSR ; }
extern " C " {
int freeMemory ( void ) ;
}
// timers
2017-10-07 20:34:25 +02:00
# define HAL_TIMER_RATE ((F_CPU) / 8) // i.e., 2MHz or 2.5MHz
2017-12-10 02:57:25 +01:00
2018-05-13 23:48:02 +02:00
# define STEP_TIMER_NUM 1
# define TEMP_TIMER_NUM 0
2018-06-03 08:43:00 +02:00
# define PULSE_TIMER_NUM STEP_TIMER_NUM
2017-12-10 02:57:25 +01:00
2018-05-13 23:48:02 +02:00
# define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0)
2018-06-12 06:04:26 +02:00
# define STEPPER_TIMER_RATE HAL_TIMER_RATE
# define STEPPER_TIMER_PRESCALE 8
# define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double
2017-12-10 02:57:25 +01:00
2018-06-12 06:04:26 +02:00
# define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
# define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
# define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
2017-12-10 02:59:12 +01:00
2017-06-18 01:36:10 +02:00
# define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
# define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
2018-04-24 05:05:07 +02:00
# define STEPPER_ISR_ENABLED() TEST(TIMSK1, OCIE1A)
2017-06-18 01:36:10 +02:00
2018-04-24 05:05:07 +02:00
# define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0B)
# define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0B)
# define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0B)
2017-06-18 01:36:10 +02:00
2018-06-03 08:43:00 +02:00
FORCE_INLINE void HAL_timer_start ( const uint8_t timer_num , const uint32_t frequency ) {
UNUSED ( frequency ) ;
switch ( timer_num ) {
case STEP_TIMER_NUM :
// waveform generation = 0100 = CTC
SET_WGM ( 1 , CTC_OCRnA ) ;
// output mode = 00 (disconnected)
SET_COMA ( 1 , NORMAL ) ;
// Set the timer pre-scaler
// Generally we use a divider of 8, resulting in a 2MHz timer
// frequency on a 16MHz MCU. If you are going to change this, be
// sure to regenerate speed_lookuptable.h with
// create_speed_lookuptable.py
SET_CS ( 1 , PRESCALER_8 ) ; // CS 2 = 1/8 prescaler
// Init Stepper ISR to 122 Hz for quick starting
// (F_CPU) / (STEPPER_TIMER_PRESCALE) / frequency
OCR1A = 0x4000 ;
TCNT1 = 0 ;
break ;
case TEMP_TIMER_NUM :
// Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt
OCR0B = 128 ;
break ;
}
}
2017-06-18 01:36:10 +02:00
2018-06-12 06:04:26 +02:00
# define TIMER_OCR_1 OCR1A
# define TIMER_COUNTER_1 TCNT1
# define TIMER_OCR_0 OCR0A
# define TIMER_COUNTER_0 TCNT0
2019-03-17 05:43:06 +01:00
# define _CAT(a,V...) a##V
2018-02-11 03:42:00 +01:00
# define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare)
# define HAL_timer_get_compare(timer) _CAT(TIMER_OCR_, timer)
# define HAL_timer_get_count(timer) _CAT(TIMER_COUNTER_, timer)
2017-06-18 01:36:10 +02:00
2018-04-24 05:05:07 +02:00
/**
* On AVR there is no hardware prioritization and preemption of
* interrupts , so this emulates it . The UART has first priority
* ( otherwise , characters will be lost due to UART overflow ) .
* Then : Stepper , Endstops , Temperature , and - finally - all others .
*/
2018-05-13 21:46:08 +02:00
# define HAL_timer_isr_prologue(TIMER_NUM)
# define HAL_timer_isr_epilogue(TIMER_NUM)
/* 18 cycles maximum latency */
2019-03-11 02:43:59 +01:00
# define HAL_STEP_TIMER_ISR() \
2018-05-13 21:46:08 +02:00
extern " C " void TIMER1_COMPA_vect ( void ) __attribute__ ( ( signal , naked , used , externally_visible ) ) ; \
extern " C " void TIMER1_COMPA_vect_bottom ( void ) asm ( " TIMER1_COMPA_vect_bottom " ) __attribute__ ( ( used , externally_visible , noinline ) ) ; \
void TIMER1_COMPA_vect ( void ) { \
__asm__ __volatile__ ( \
A ( " push r16 " ) /* 2 Save R16 */ \
A ( " in r16, __SREG__ " ) /* 1 Get SREG */ \
A ( " push r16 " ) /* 2 Save SREG into stack */ \
A ( " lds r16, %[timsk0] " ) /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
A ( " push r16 " ) /* 2 Save TIMSK0 into the stack */ \
A ( " andi r16,~%[msk0] " ) /* 1 Disable the temperature ISR */ \
A ( " sts %[timsk0], r16 " ) /* 2 And set the new value */ \
A ( " lds r16, %[timsk1] " ) /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
A ( " andi r16,~%[msk1] " ) /* 1 Disable the stepper ISR */ \
A ( " sts %[timsk1], r16 " ) /* 2 And set the new value */ \
A ( " push r16 " ) /* 2 Save TIMSK1 into stack */ \
A ( " in r16, 0x3B " ) /* 1 Get RAMPZ register */ \
A ( " push r16 " ) /* 2 Save RAMPZ into stack */ \
A ( " in r16, 0x3C " ) /* 1 Get EIND register */ \
A ( " push r0 " ) /* C runtime can modify all the following registers without restoring them */ \
A ( " push r1 " ) \
A ( " push r18 " ) \
A ( " push r19 " ) \
A ( " push r20 " ) \
A ( " push r21 " ) \
A ( " push r22 " ) \
A ( " push r23 " ) \
A ( " push r24 " ) \
A ( " push r25 " ) \
A ( " push r26 " ) \
A ( " push r27 " ) \
A ( " push r30 " ) \
A ( " push r31 " ) \
A ( " clr r1 " ) /* C runtime expects this register to be 0 */ \
A ( " call TIMER1_COMPA_vect_bottom " ) /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A ( " pop r31 " ) \
A ( " pop r30 " ) \
A ( " pop r27 " ) \
A ( " pop r26 " ) \
A ( " pop r25 " ) \
A ( " pop r24 " ) \
A ( " pop r23 " ) \
A ( " pop r22 " ) \
A ( " pop r21 " ) \
A ( " pop r20 " ) \
A ( " pop r19 " ) \
A ( " pop r18 " ) \
A ( " pop r1 " ) \
A ( " pop r0 " ) \
A ( " out 0x3C, r16 " ) /* 1 Restore EIND register */ \
A ( " pop r16 " ) /* 2 Get the original RAMPZ register value */ \
A ( " out 0x3B, r16 " ) /* 1 Restore RAMPZ register to its original value */ \
A ( " pop r16 " ) /* 2 Get the original TIMSK1 value but with stepper ISR disabled */ \
A ( " ori r16,%[msk1] " ) /* 1 Reenable the stepper ISR */ \
A ( " cli " ) /* 1 Disable global interrupts - Reenabling Stepper ISR can reenter amd temperature can reenter, and we want that, if it happens, after this ISR has ended */ \
A ( " sts %[timsk1], r16 " ) /* 2 And restore the old value - This reenables the stepper ISR */ \
A ( " pop r16 " ) /* 2 Get the temperature timer Interrupt mask register [TIMSK0] */ \
A ( " sts %[timsk0], r16 " ) /* 2 And restore the old value - This reenables the temperature ISR */ \
A ( " pop r16 " ) /* 2 Get the old SREG value */ \
A ( " out __SREG__, r16 " ) /* 1 And restore the SREG value */ \
A ( " pop r16 " ) /* 2 Restore R16 value */ \
A ( " reti " ) /* 4 Return from interrupt */ \
: \
: [ timsk0 ] " i " ( ( uint16_t ) & TIMSK0 ) , \
[ timsk1 ] " i " ( ( uint16_t ) & TIMSK1 ) , \
[ msk0 ] " M " ( ( uint8_t ) ( 1 < < OCIE0B ) ) , \
[ msk1 ] " M " ( ( uint8_t ) ( 1 < < OCIE1A ) ) \
: \
) ; \
} \
void TIMER1_COMPA_vect_bottom ( void )
/* 14 cycles maximum latency */
2019-03-11 02:43:59 +01:00
# define HAL_TEMP_TIMER_ISR() \
2018-05-13 21:46:08 +02:00
extern " C " void TIMER0_COMPB_vect ( void ) __attribute__ ( ( signal , naked , used , externally_visible ) ) ; \
extern " C " void TIMER0_COMPB_vect_bottom ( void ) asm ( " TIMER0_COMPB_vect_bottom " ) __attribute__ ( ( used , externally_visible , noinline ) ) ; \
void TIMER0_COMPB_vect ( void ) { \
__asm__ __volatile__ ( \
A ( " push r16 " ) /* 2 Save R16 */ \
A ( " in r16, __SREG__ " ) /* 1 Get SREG */ \
A ( " push r16 " ) /* 2 Save SREG into stack */ \
A ( " lds r16, %[timsk0] " ) /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
A ( " andi r16,~%[msk0] " ) /* 1 Disable the temperature ISR */ \
A ( " sts %[timsk0], r16 " ) /* 2 And set the new value */ \
A ( " sei " ) /* 1 Enable global interrupts - It is safe, as the temperature ISR is disabled, so we cannot reenter it */ \
A ( " push r16 " ) /* 2 Save TIMSK0 into stack */ \
A ( " in r16, 0x3B " ) /* 1 Get RAMPZ register */ \
A ( " push r16 " ) /* 2 Save RAMPZ into stack */ \
A ( " in r16, 0x3C " ) /* 1 Get EIND register */ \
A ( " push r0 " ) /* C runtime can modify all the following registers without restoring them */ \
A ( " push r1 " ) \
A ( " push r18 " ) \
A ( " push r19 " ) \
A ( " push r20 " ) \
A ( " push r21 " ) \
A ( " push r22 " ) \
A ( " push r23 " ) \
A ( " push r24 " ) \
A ( " push r25 " ) \
A ( " push r26 " ) \
A ( " push r27 " ) \
A ( " push r30 " ) \
A ( " push r31 " ) \
A ( " clr r1 " ) /* C runtime expects this register to be 0 */ \
A ( " call TIMER0_COMPB_vect_bottom " ) /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A ( " pop r31 " ) \
A ( " pop r30 " ) \
A ( " pop r27 " ) \
A ( " pop r26 " ) \
A ( " pop r25 " ) \
A ( " pop r24 " ) \
A ( " pop r23 " ) \
A ( " pop r22 " ) \
A ( " pop r21 " ) \
A ( " pop r20 " ) \
A ( " pop r19 " ) \
A ( " pop r18 " ) \
A ( " pop r1 " ) \
A ( " pop r0 " ) \
A ( " out 0x3C, r16 " ) /* 1 Restore EIND register */ \
A ( " pop r16 " ) /* 2 Get the original RAMPZ register value */ \
A ( " out 0x3B, r16 " ) /* 1 Restore RAMPZ register to its original value */ \
A ( " pop r16 " ) /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
A ( " ori r16,%[msk0] " ) /* 1 Enable temperature ISR */ \
2018-06-02 02:02:22 +02:00
A ( " cli " ) /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don't want to reenter this handler until the current one is done */ \
2018-05-13 21:46:08 +02:00
A ( " sts %[timsk0], r16 " ) /* 2 And restore the old value */ \
A ( " pop r16 " ) /* 2 Get the old SREG */ \
A ( " out __SREG__, r16 " ) /* 1 And restore the SREG value */ \
A ( " pop r16 " ) /* 2 Restore R16 */ \
A ( " reti " ) /* 4 Return from interrupt */ \
: \
: [ timsk0 ] " i " ( ( uint16_t ) & TIMSK0 ) , \
[ msk0 ] " M " ( ( uint8_t ) ( 1 < < OCIE0B ) ) \
: \
) ; \
} \
void TIMER0_COMPB_vect_bottom ( void )
2017-06-18 01:36:10 +02:00
// ADC
# ifdef DIDR2
2018-03-14 04:33:08 +01:00
# define HAL_ANALOG_SELECT(pin) do{ if (pin < 8) SBI(DIDR0, pin); else SBI(DIDR2, pin & 0x07); }while(0)
2017-06-18 01:36:10 +02:00
# else
# define HAL_ANALOG_SELECT(pin) do{ SBI(DIDR0, pin); }while(0)
# endif
inline void HAL_adc_init ( void ) {
ADCSRA = _BV ( ADEN ) | _BV ( ADSC ) | _BV ( ADIF ) | 0x07 ;
DIDR0 = 0 ;
# ifdef DIDR2
DIDR2 = 0 ;
# endif
}
# define SET_ADMUX_ADCSRA(pin) ADMUX = _BV(REFS0) | (pin & 0x07); SBI(ADCSRA, ADSC)
# ifdef MUX5
# define HAL_START_ADC(pin) if (pin > 7) ADCSRB = _BV(MUX5); else ADCSRB = 0; SET_ADMUX_ADCSRA(pin)
# else
# define HAL_START_ADC(pin) ADCSRB = 0; SET_ADMUX_ADCSRA(pin)
# endif
2018-07-26 10:59:19 +02:00
# define HAL_READ_ADC() ADC
# define HAL_ADC_READY() !TEST(ADCSRA, ADSC)
2017-06-18 01:36:10 +02:00
2017-10-26 20:37:26 +02:00
# define GET_PIN_MAP_PIN(index) index
# define GET_PIN_MAP_INDEX(pin) pin
# define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
# define HAL_SENSITIVE_PINS 0, 1
2018-09-28 01:02:50 +02:00
# ifdef __AVR_AT90USB1286__
# define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
# endif
2018-07-01 22:20:28 +02:00
// AVR compatibility
# define strtof strtod
2019-03-26 07:03:23 +01:00
/**
* 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 ) ;
/**
* set_pwm_duty
* Sets 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 ) ;