Blame | Last modification | View Log | RSS feed
/*** Marlin 3D Printer Firmware* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]** Based on Sprinter and grbl.* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm** 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/>.**//*** Fast I/O Routines for AVR* Use direct port manipulation to save scads of processor time.* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.*/#include <stdint.h>#ifndef _FASTIO_ARDUINO_H_#define _FASTIO_ARDUINO_H_#include <avr/io.h>#define AVR_AT90USB1286_FAMILY (defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286P__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB646P__) || defined(__AVR_AT90USB647__))#define AVR_ATmega1284_FAMILY (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__))#define AVR_ATmega2560_FAMILY (defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__))#define AVR_ATmega2561_FAMILY (defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__))#define AVR_ATmega328_FAMILY (defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__))/*** Include Ports and Functions*/#if AVR_ATmega328_FAMILY#include "fastio_168.h"#elif AVR_ATmega1284_FAMILY#include "fastio_644.h"#elif AVR_ATmega2560_FAMILY#include "fastio_1280.h"#elif AVR_AT90USB1286_FAMILY#include "fastio_AT90USB.h"#elif AVR_ATmega2561_FAMILY#include "fastio_1281.h"#else#error "No FastIO definition for the selected AVR Board."#endif#include "macros.h"/*** Magic I/O routines** Now you can simply SET_OUTPUT(PIN); WRITE(PIN, HIGH); WRITE(PIN, LOW);** Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html*/#define _READ(IO) TEST(DIO ## IO ## _RPORT, DIO ## IO ## _PIN)#define _WRITE_NC(IO,V) do{ \if (V) SBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \else CBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \}while(0)#define _WRITE_C(IO,V) do{ \uint8_t port_bits = DIO ## IO ## _WPORT; /* Get a mask from the current port bits */ \if (V) port_bits = ~port_bits; /* For setting bits, invert the mask */ \DIO ## IO ## _RPORT = port_bits & _BV(DIO ## IO ## _PIN); /* Atomically toggle the output port bits */ \}while(0)#define _WRITE(IO,V) do{ if (&(DIO ## IO ## _RPORT) < (uint8_t*)0x100) _WRITE_NC(IO,V); else _WRITE_C(IO,V); }while(0)#define _TOGGLE(IO) (DIO ## IO ## _RPORT = _BV(DIO ## IO ## _PIN))#define _SET_INPUT(IO) CBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)#define _SET_OUTPUT(IO) SBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)#define _GET_INPUT(IO) !TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)#define _GET_OUTPUT(IO) TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)#define _GET_TIMER(IO) DIO ## IO ## _PWM#define READ(IO) _READ(IO)#define WRITE(IO,V) _WRITE(IO,V)#define TOGGLE(IO) _TOGGLE(IO)#define SET_INPUT(IO) _SET_INPUT(IO)#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0)#define SET_OUTPUT(IO) _SET_OUTPUT(IO)#define GET_INPUT(IO) _GET_INPUT(IO)#define GET_OUTPUT(IO) _GET_OUTPUT(IO)#define GET_TIMER(IO) _GET_TIMER(IO)#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)/*** Timer and Interrupt Control*/// Waveform Generation Modesenum WaveGenMode : char {WGM_NORMAL, // 0WGM_PWM_PC_8, // 1WGM_PWM_PC_9, // 2WGM_PWM_PC_10, // 3WGM_CTC_OCRnA, // 4 COM OCnxWGM_FAST_PWM_8, // 5WGM_FAST_PWM_9, // 6WGM_FAST_PWM_10, // 7WGM_PWM_PC_FC_ICRn, // 8WGM_PWM_PC_FC_OCRnA, // 9 COM OCnAWGM_PWM_PC_ICRn, // 10WGM_PWM_PC_OCRnA, // 11 COM OCnAWGM_CTC_ICRn, // 12 COM OCnxWGM_reserved, // 13WGM_FAST_PWM_ICRn, // 14 COM OCnAWGM_FAST_PWM_OCRnA // 15 COM OCnA};// Compare Modesenum CompareMode : char {COM_NORMAL, // 0COM_TOGGLE, // 1 Non-PWM: OCnx ... Both PWM (WGM 9,11,14,15): OCnA only ... else NORMALCOM_CLEAR_SET, // 2 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/DownCOM_SET_CLEAR // 3 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down};// Clock Sourcesenum ClockSource : char {CS_NONE, // 0CS_PRESCALER_1, // 1CS_PRESCALER_8, // 2CS_PRESCALER_64, // 3CS_PRESCALER_256, // 4CS_PRESCALER_1024, // 5CS_EXT_FALLING, // 6CS_EXT_RISING // 7};// Clock Sources (Timer 2 only)enum ClockSource2 : char {CS2_NONE, // 0CS2_PRESCALER_1, // 1CS2_PRESCALER_8, // 2CS2_PRESCALER_32, // 3CS2_PRESCALER_64, // 4CS2_PRESCALER_128, // 5CS2_PRESCALER_256, // 6CS2_PRESCALER_1024 // 7};// Get interrupt bits in an orderly way// Ex: cs = GET_CS(0); coma1 = GET_COM(A,1);#define GET_WGM(T) (((TCCR##T##A >> WGM##T##0) & 0x3) | ((TCCR##T##B >> WGM##T##2 << 2) & 0xC))#define GET_CS(T) ((TCCR##T##B >> CS##T##0) & 0x7)#define GET_COM(T,Q) ((TCCR##T##Q >> COM##T##Q##0) & 0x3)#define GET_COMA(T) GET_COM(T,A)#define GET_COMB(T) GET_COM(T,B)#define GET_COMC(T) GET_COM(T,C)#define GET_ICNC(T) (!!(TCCR##T##B & _BV(ICNC##T)))#define GET_ICES(T) (!!(TCCR##T##B & _BV(ICES##T)))#define GET_FOC(T,Q) (!!(TCCR##T##C & _BV(FOC##T##Q)))#define GET_FOCA(T) GET_FOC(T,A)#define GET_FOCB(T) GET_FOC(T,B)#define GET_FOCC(T) GET_FOC(T,C)// Set Wave Generation Mode bits// Ex: SET_WGM(5,CTC_ICRn);#define _SET_WGM(T,V) do{ \TCCR##T##A = (TCCR##T##A & ~(0x3 << WGM##T##0)) | (( int(V) & 0x3) << WGM##T##0); \TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \}while(0)#define SET_WGM(T,V) _SET_WGM(T,WGM_##V)// Set Clock Select bits// Ex: SET_CS3(PRESCALER_64);#define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0))#define _SET_CS0(V) _SET_CS(0,V)#define _SET_CS1(V) _SET_CS(1,V)#ifdef TCCR2#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))#else#define _SET_CS2(V) _SET_CS(2,V)#endif#define _SET_CS3(V) _SET_CS(3,V)#define _SET_CS4(V) _SET_CS(4,V)#define _SET_CS5(V) _SET_CS(5,V)#define SET_CS0(V) _SET_CS0(CS_##V)#define SET_CS1(V) _SET_CS1(CS_##V)#ifdef TCCR2#define SET_CS2(V) _SET_CS2(CS2_##V)#else#define SET_CS2(V) _SET_CS2(CS_##V)#endif#define SET_CS3(V) _SET_CS3(CS_##V)#define SET_CS4(V) _SET_CS4(CS_##V)#define SET_CS5(V) _SET_CS5(CS_##V)#define SET_CS(T,V) SET_CS##T(V)// Set Compare Mode bits// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);#define _SET_COM(T,Q,V) (TCCR##T##Q = (TCCR##T##Q & ~(0x3 << COM##T##Q##0)) | (int(V) << COM##T##Q##0))#define SET_COM(T,Q,V) _SET_COM(T,Q,COM_##V)#define SET_COMA(T,V) SET_COM(T,A,V)#define SET_COMB(T,V) SET_COM(T,B,V)#define SET_COMC(T,V) SET_COM(T,C,V)#define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0)// Set Noise Canceler bit// Ex: SET_ICNC(2,1)#define SET_ICNC(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICNC##T) : TCCR##T##B & ~_BV(ICNC##T))// Set Input Capture Edge Select bit// Ex: SET_ICES(5,0)#define SET_ICES(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICES##T) : TCCR##T##B & ~_BV(ICES##T))// Set Force Output Compare bit// Ex: SET_FOC(3,A,1)#define SET_FOC(T,Q,V) (TCCR##T##C = (V) ? TCCR##T##C | _BV(FOC##T##Q) : TCCR##T##C & ~_BV(FOC##T##Q))#define SET_FOCA(T,V) SET_FOC(T,A,V)#define SET_FOCB(T,V) SET_FOC(T,B,V)#define SET_FOCC(T,V) SET_FOC(T,C,V)/*** PWM availability macros*/// Determine which harware PWMs are already in use#if PIN_EXISTS(CONTROLLER_FAN)#define PWM_CHK_FAN_B(p) (p == CONTROLLER_FAN_PIN || p == E0_AUTO_FAN_PIN || p == E1_AUTO_FAN_PIN || p == E2_AUTO_FAN_PIN || p == E3_AUTO_FAN_PIN || p == E4_AUTO_FAN_PIN || p == CHAMBER_AUTO_FAN_PIN)#else#define PWM_CHK_FAN_B(p) (p == E0_AUTO_FAN_PIN || p == E1_AUTO_FAN_PIN || p == E2_AUTO_FAN_PIN || p == E3_AUTO_FAN_PIN || p == E4_AUTO_FAN_PIN || p == CHAMBER_AUTO_FAN_PIN)#endif#if PIN_EXISTS(FAN) || PIN_EXISTS(FAN1) || PIN_EXISTS(FAN2)#if PIN_EXISTS(FAN2)#define PWM_CHK_FAN_A(p) (p == FAN_PIN || p == FAN1_PIN || p == FAN2_PIN)#elif PIN_EXISTS(FAN1)#define PWM_CHK_FAN_A(p) (p == FAN_PIN || p == FAN1_PIN)#else#define PWM_CHK_FAN_A(p) (p == FAN_PIN)#endif#else#define PWM_CHK_FAN_A(p) false#endif#if HAS_MOTOR_CURRENT_PWM#if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)#define PWM_CHK_MOTOR_CURRENT(p) (p == MOTOR_CURRENT_PWM_E || p == MOTOR_CURRENT_PWM_Z || p == MOTOR_CURRENT_PWM_XY)#elif PIN_EXISTS(MOTOR_CURRENT_PWM_Z)#define PWM_CHK_MOTOR_CURRENT(p) (p == MOTOR_CURRENT_PWM_E || p == MOTOR_CURRENT_PWM_Z)#else#define PWM_CHK_MOTOR_CURRENT(p) (p == MOTOR_CURRENT_PWM_E)#endif#else#define PWM_CHK_MOTOR_CURRENT(p) false#endif#ifdef NUM_SERVOS#if AVR_ATmega2560_FAMILY#define PWM_CHK_SERVO(p) (p == 5 || (NUM_SERVOS > 12 && p == 6) || (NUM_SERVOS > 24 && p == 46)) // PWMS 3A, 4A & 5A#elif AVR_ATmega2561_FAMILY#define PWM_CHK_SERVO(p) (p == 5) // PWM3A#elif AVR_ATmega1284_FAMILY#define PWM_CHK_SERVO(p) false#elif AVR_AT90USB1286_FAMILY#define PWM_CHK_SERVO(p) (p == 16) // PWM3A#elif AVR_ATmega328_FAMILY#define PWM_CHK_SERVO(p) false#endif#else#define PWM_CHK_SERVO(p) false#endif#if ENABLED(BARICUDA)#if HAS_HEATER_1 && HAS_HEATER_2#define PWM_CHK_HEATER(p) (p == HEATER_1_PIN || p == HEATER_2_PIN)#elif HAS_HEATER_1#define PWM_CHK_HEATER(p) (p == HEATER_1_PIN)#endif#else#define PWM_CHK_HEATER(p) false#endif#define PWM_CHK(p) (PWM_CHK_HEATER(p) || PWM_CHK_SERVO(p) || PWM_CHK_MOTOR_CURRENT(p)\|| PWM_CHK_FAN_A(p) || PWM_CHK_FAN_B(p))// define which hardware PWMs are available for the current CPU// all timer 1 PWMS deleted from this list because they are never available#if AVR_ATmega2560_FAMILY#define PWM_PINS(p) ((p >= 2 && p <= 10) || p == 13 || p == 44 || p == 45 || p == 46)#elif AVR_ATmega2561_FAMILY#define PWM_PINS(p) ((p >= 2 && p <= 6) || p == 9)#elif AVR_ATmega1284_FAMILY#define PWM_PINS(p) (p == 3 || p == 4 || p == 14 || p == 15)#elif AVR_AT90USB1286_FAMILY#define PWM_PINS(p) (p == 0 || p == 1 || p == 14 || p == 15 || p == 16 || p == 24)#elif AVR_ATmega328_FAMILY#define PWM_PINS(p) (p == 3 || p == 5 || p == 6 || p == 11)#else#error "unknown CPU"#endif// finally - the macro that tells us if a pin is an available hardware PWM#define USEABLE_HARDWARE_PWM(p) (PWM_PINS(p) && !PWM_CHK(p))#endif // _FASTIO_ARDUINO_H_