1 |
ron |
1 |
/**
|
|
|
2 |
* Marlin 3D Printer Firmware
|
|
|
3 |
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|
|
4 |
*
|
|
|
5 |
* Based on Sprinter and grbl.
|
|
|
6 |
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
|
|
7 |
*
|
|
|
8 |
* This program is free software: you can redistribute it and/or modify
|
|
|
9 |
* it under the terms of the GNU General Public License as published by
|
|
|
10 |
* the Free Software Foundation, either version 3 of the License, or
|
|
|
11 |
* (at your option) any later version.
|
|
|
12 |
*
|
|
|
13 |
* This program is distributed in the hope that it will be useful,
|
|
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
16 |
* GNU General Public License for more details.
|
|
|
17 |
*
|
|
|
18 |
* You should have received a copy of the GNU General Public License
|
|
|
19 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
20 |
*
|
|
|
21 |
*/
|
|
|
22 |
|
|
|
23 |
/**
|
|
|
24 |
* Fast I/O Routines for AVR
|
|
|
25 |
* Use direct port manipulation to save scads of processor time.
|
|
|
26 |
* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.
|
|
|
27 |
*/
|
|
|
28 |
|
|
|
29 |
#include <stdint.h>
|
|
|
30 |
|
|
|
31 |
#ifndef _FASTIO_ARDUINO_H_
|
|
|
32 |
#define _FASTIO_ARDUINO_H_
|
|
|
33 |
|
|
|
34 |
#include <avr/io.h>
|
|
|
35 |
|
|
|
36 |
#define AVR_AT90USB1286_FAMILY (defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286P__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB646P__) || defined(__AVR_AT90USB647__))
|
|
|
37 |
#define AVR_ATmega1284_FAMILY (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__))
|
|
|
38 |
#define AVR_ATmega2560_FAMILY (defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__))
|
|
|
39 |
#define AVR_ATmega2561_FAMILY (defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__))
|
|
|
40 |
#define AVR_ATmega328_FAMILY (defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__))
|
|
|
41 |
|
|
|
42 |
/**
|
|
|
43 |
* Include Ports and Functions
|
|
|
44 |
*/
|
|
|
45 |
#if AVR_ATmega328_FAMILY
|
|
|
46 |
#include "fastio_168.h"
|
|
|
47 |
#elif AVR_ATmega1284_FAMILY
|
|
|
48 |
#include "fastio_644.h"
|
|
|
49 |
#elif AVR_ATmega2560_FAMILY
|
|
|
50 |
#include "fastio_1280.h"
|
|
|
51 |
#elif AVR_AT90USB1286_FAMILY
|
|
|
52 |
#include "fastio_AT90USB.h"
|
|
|
53 |
#elif AVR_ATmega2561_FAMILY
|
|
|
54 |
#include "fastio_1281.h"
|
|
|
55 |
#else
|
|
|
56 |
#error "No FastIO definition for the selected AVR Board."
|
|
|
57 |
#endif
|
|
|
58 |
|
|
|
59 |
#include "macros.h"
|
|
|
60 |
|
|
|
61 |
/**
|
|
|
62 |
* Magic I/O routines
|
|
|
63 |
*
|
|
|
64 |
* Now you can simply SET_OUTPUT(PIN); WRITE(PIN, HIGH); WRITE(PIN, LOW);
|
|
|
65 |
*
|
|
|
66 |
* Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
|
|
67 |
*/
|
|
|
68 |
|
|
|
69 |
#define _READ(IO) TEST(DIO ## IO ## _RPORT, DIO ## IO ## _PIN)
|
|
|
70 |
|
|
|
71 |
#define _WRITE_NC(IO,V) do{ \
|
|
|
72 |
if (V) SBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \
|
|
|
73 |
else CBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \
|
|
|
74 |
}while(0)
|
|
|
75 |
|
|
|
76 |
#define _WRITE_C(IO,V) do{ \
|
|
|
77 |
uint8_t port_bits = DIO ## IO ## _WPORT; /* Get a mask from the current port bits */ \
|
|
|
78 |
if (V) port_bits = ~port_bits; /* For setting bits, invert the mask */ \
|
|
|
79 |
DIO ## IO ## _RPORT = port_bits & _BV(DIO ## IO ## _PIN); /* Atomically toggle the output port bits */ \
|
|
|
80 |
}while(0)
|
|
|
81 |
|
|
|
82 |
#define _WRITE(IO,V) do{ if (&(DIO ## IO ## _RPORT) < (uint8_t*)0x100) _WRITE_NC(IO,V); else _WRITE_C(IO,V); }while(0)
|
|
|
83 |
|
|
|
84 |
#define _TOGGLE(IO) (DIO ## IO ## _RPORT = _BV(DIO ## IO ## _PIN))
|
|
|
85 |
|
|
|
86 |
#define _SET_INPUT(IO) CBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
|
|
|
87 |
#define _SET_OUTPUT(IO) SBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
|
|
|
88 |
|
|
|
89 |
#define _GET_INPUT(IO) !TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
|
|
|
90 |
#define _GET_OUTPUT(IO) TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
|
|
|
91 |
#define _GET_TIMER(IO) DIO ## IO ## _PWM
|
|
|
92 |
|
|
|
93 |
#define READ(IO) _READ(IO)
|
|
|
94 |
#define WRITE(IO,V) _WRITE(IO,V)
|
|
|
95 |
#define TOGGLE(IO) _TOGGLE(IO)
|
|
|
96 |
|
|
|
97 |
#define SET_INPUT(IO) _SET_INPUT(IO)
|
|
|
98 |
#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0)
|
|
|
99 |
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
|
|
|
100 |
|
|
|
101 |
#define GET_INPUT(IO) _GET_INPUT(IO)
|
|
|
102 |
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
|
|
|
103 |
#define GET_TIMER(IO) _GET_TIMER(IO)
|
|
|
104 |
|
|
|
105 |
#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
|
|
|
106 |
|
|
|
107 |
/**
|
|
|
108 |
* Timer and Interrupt Control
|
|
|
109 |
*/
|
|
|
110 |
|
|
|
111 |
// Waveform Generation Modes
|
|
|
112 |
enum WaveGenMode : char {
|
|
|
113 |
WGM_NORMAL, // 0
|
|
|
114 |
WGM_PWM_PC_8, // 1
|
|
|
115 |
WGM_PWM_PC_9, // 2
|
|
|
116 |
WGM_PWM_PC_10, // 3
|
|
|
117 |
WGM_CTC_OCRnA, // 4 COM OCnx
|
|
|
118 |
WGM_FAST_PWM_8, // 5
|
|
|
119 |
WGM_FAST_PWM_9, // 6
|
|
|
120 |
WGM_FAST_PWM_10, // 7
|
|
|
121 |
WGM_PWM_PC_FC_ICRn, // 8
|
|
|
122 |
WGM_PWM_PC_FC_OCRnA, // 9 COM OCnA
|
|
|
123 |
WGM_PWM_PC_ICRn, // 10
|
|
|
124 |
WGM_PWM_PC_OCRnA, // 11 COM OCnA
|
|
|
125 |
WGM_CTC_ICRn, // 12 COM OCnx
|
|
|
126 |
WGM_reserved, // 13
|
|
|
127 |
WGM_FAST_PWM_ICRn, // 14 COM OCnA
|
|
|
128 |
WGM_FAST_PWM_OCRnA // 15 COM OCnA
|
|
|
129 |
};
|
|
|
130 |
|
|
|
131 |
// Compare Modes
|
|
|
132 |
enum CompareMode : char {
|
|
|
133 |
COM_NORMAL, // 0
|
|
|
134 |
COM_TOGGLE, // 1 Non-PWM: OCnx ... Both PWM (WGM 9,11,14,15): OCnA only ... else NORMAL
|
|
|
135 |
COM_CLEAR_SET, // 2 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down
|
|
|
136 |
COM_SET_CLEAR // 3 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down
|
|
|
137 |
};
|
|
|
138 |
|
|
|
139 |
// Clock Sources
|
|
|
140 |
enum ClockSource : char {
|
|
|
141 |
CS_NONE, // 0
|
|
|
142 |
CS_PRESCALER_1, // 1
|
|
|
143 |
CS_PRESCALER_8, // 2
|
|
|
144 |
CS_PRESCALER_64, // 3
|
|
|
145 |
CS_PRESCALER_256, // 4
|
|
|
146 |
CS_PRESCALER_1024, // 5
|
|
|
147 |
CS_EXT_FALLING, // 6
|
|
|
148 |
CS_EXT_RISING // 7
|
|
|
149 |
};
|
|
|
150 |
|
|
|
151 |
// Clock Sources (Timer 2 only)
|
|
|
152 |
enum ClockSource2 : char {
|
|
|
153 |
CS2_NONE, // 0
|
|
|
154 |
CS2_PRESCALER_1, // 1
|
|
|
155 |
CS2_PRESCALER_8, // 2
|
|
|
156 |
CS2_PRESCALER_32, // 3
|
|
|
157 |
CS2_PRESCALER_64, // 4
|
|
|
158 |
CS2_PRESCALER_128, // 5
|
|
|
159 |
CS2_PRESCALER_256, // 6
|
|
|
160 |
CS2_PRESCALER_1024 // 7
|
|
|
161 |
};
|
|
|
162 |
|
|
|
163 |
// Get interrupt bits in an orderly way
|
|
|
164 |
// Ex: cs = GET_CS(0); coma1 = GET_COM(A,1);
|
|
|
165 |
#define GET_WGM(T) (((TCCR##T##A >> WGM##T##0) & 0x3) | ((TCCR##T##B >> WGM##T##2 << 2) & 0xC))
|
|
|
166 |
#define GET_CS(T) ((TCCR##T##B >> CS##T##0) & 0x7)
|
|
|
167 |
#define GET_COM(T,Q) ((TCCR##T##Q >> COM##T##Q##0) & 0x3)
|
|
|
168 |
#define GET_COMA(T) GET_COM(T,A)
|
|
|
169 |
#define GET_COMB(T) GET_COM(T,B)
|
|
|
170 |
#define GET_COMC(T) GET_COM(T,C)
|
|
|
171 |
#define GET_ICNC(T) (!!(TCCR##T##B & _BV(ICNC##T)))
|
|
|
172 |
#define GET_ICES(T) (!!(TCCR##T##B & _BV(ICES##T)))
|
|
|
173 |
#define GET_FOC(T,Q) (!!(TCCR##T##C & _BV(FOC##T##Q)))
|
|
|
174 |
#define GET_FOCA(T) GET_FOC(T,A)
|
|
|
175 |
#define GET_FOCB(T) GET_FOC(T,B)
|
|
|
176 |
#define GET_FOCC(T) GET_FOC(T,C)
|
|
|
177 |
|
|
|
178 |
// Set Wave Generation Mode bits
|
|
|
179 |
// Ex: SET_WGM(5,CTC_ICRn);
|
|
|
180 |
#define _SET_WGM(T,V) do{ \
|
|
|
181 |
TCCR##T##A = (TCCR##T##A & ~(0x3 << WGM##T##0)) | (( int(V) & 0x3) << WGM##T##0); \
|
|
|
182 |
TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \
|
|
|
183 |
}while(0)
|
|
|
184 |
#define SET_WGM(T,V) _SET_WGM(T,WGM_##V)
|
|
|
185 |
|
|
|
186 |
// Set Clock Select bits
|
|
|
187 |
// Ex: SET_CS3(PRESCALER_64);
|
|
|
188 |
#define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0))
|
|
|
189 |
#define _SET_CS0(V) _SET_CS(0,V)
|
|
|
190 |
#define _SET_CS1(V) _SET_CS(1,V)
|
|
|
191 |
#ifdef TCCR2
|
|
|
192 |
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
|
|
|
193 |
#else
|
|
|
194 |
#define _SET_CS2(V) _SET_CS(2,V)
|
|
|
195 |
#endif
|
|
|
196 |
#define _SET_CS3(V) _SET_CS(3,V)
|
|
|
197 |
#define _SET_CS4(V) _SET_CS(4,V)
|
|
|
198 |
#define _SET_CS5(V) _SET_CS(5,V)
|
|
|
199 |
#define SET_CS0(V) _SET_CS0(CS_##V)
|
|
|
200 |
#define SET_CS1(V) _SET_CS1(CS_##V)
|
|
|
201 |
#ifdef TCCR2
|
|
|
202 |
#define SET_CS2(V) _SET_CS2(CS2_##V)
|
|
|
203 |
#else
|
|
|
204 |
#define SET_CS2(V) _SET_CS2(CS_##V)
|
|
|
205 |
#endif
|
|
|
206 |
#define SET_CS3(V) _SET_CS3(CS_##V)
|
|
|
207 |
#define SET_CS4(V) _SET_CS4(CS_##V)
|
|
|
208 |
#define SET_CS5(V) _SET_CS5(CS_##V)
|
|
|
209 |
#define SET_CS(T,V) SET_CS##T(V)
|
|
|
210 |
|
|
|
211 |
// Set Compare Mode bits
|
|
|
212 |
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
|
|
|
213 |
#define _SET_COM(T,Q,V) (TCCR##T##Q = (TCCR##T##Q & ~(0x3 << COM##T##Q##0)) | (int(V) << COM##T##Q##0))
|
|
|
214 |
#define SET_COM(T,Q,V) _SET_COM(T,Q,COM_##V)
|
|
|
215 |
#define SET_COMA(T,V) SET_COM(T,A,V)
|
|
|
216 |
#define SET_COMB(T,V) SET_COM(T,B,V)
|
|
|
217 |
#define SET_COMC(T,V) SET_COM(T,C,V)
|
|
|
218 |
#define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0)
|
|
|
219 |
|
|
|
220 |
// Set Noise Canceler bit
|
|
|
221 |
// Ex: SET_ICNC(2,1)
|
|
|
222 |
#define SET_ICNC(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICNC##T) : TCCR##T##B & ~_BV(ICNC##T))
|
|
|
223 |
|
|
|
224 |
// Set Input Capture Edge Select bit
|
|
|
225 |
// Ex: SET_ICES(5,0)
|
|
|
226 |
#define SET_ICES(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICES##T) : TCCR##T##B & ~_BV(ICES##T))
|
|
|
227 |
|
|
|
228 |
// Set Force Output Compare bit
|
|
|
229 |
// Ex: SET_FOC(3,A,1)
|
|
|
230 |
#define SET_FOC(T,Q,V) (TCCR##T##C = (V) ? TCCR##T##C | _BV(FOC##T##Q) : TCCR##T##C & ~_BV(FOC##T##Q))
|
|
|
231 |
#define SET_FOCA(T,V) SET_FOC(T,A,V)
|
|
|
232 |
#define SET_FOCB(T,V) SET_FOC(T,B,V)
|
|
|
233 |
#define SET_FOCC(T,V) SET_FOC(T,C,V)
|
|
|
234 |
|
|
|
235 |
|
|
|
236 |
/**
|
|
|
237 |
* PWM availability macros
|
|
|
238 |
*/
|
|
|
239 |
|
|
|
240 |
// Determine which harware PWMs are already in use
|
|
|
241 |
#if PIN_EXISTS(CONTROLLER_FAN)
|
|
|
242 |
#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)
|
|
|
243 |
#else
|
|
|
244 |
#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)
|
|
|
245 |
#endif
|
|
|
246 |
|
|
|
247 |
#if PIN_EXISTS(FAN) || PIN_EXISTS(FAN1) || PIN_EXISTS(FAN2)
|
|
|
248 |
#if PIN_EXISTS(FAN2)
|
|
|
249 |
#define PWM_CHK_FAN_A(p) (p == FAN_PIN || p == FAN1_PIN || p == FAN2_PIN)
|
|
|
250 |
#elif PIN_EXISTS(FAN1)
|
|
|
251 |
#define PWM_CHK_FAN_A(p) (p == FAN_PIN || p == FAN1_PIN)
|
|
|
252 |
#else
|
|
|
253 |
#define PWM_CHK_FAN_A(p) (p == FAN_PIN)
|
|
|
254 |
#endif
|
|
|
255 |
#else
|
|
|
256 |
#define PWM_CHK_FAN_A(p) false
|
|
|
257 |
#endif
|
|
|
258 |
|
|
|
259 |
#if HAS_MOTOR_CURRENT_PWM
|
|
|
260 |
#if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
|
|
|
261 |
#define PWM_CHK_MOTOR_CURRENT(p) (p == MOTOR_CURRENT_PWM_E || p == MOTOR_CURRENT_PWM_Z || p == MOTOR_CURRENT_PWM_XY)
|
|
|
262 |
#elif PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
|
|
|
263 |
#define PWM_CHK_MOTOR_CURRENT(p) (p == MOTOR_CURRENT_PWM_E || p == MOTOR_CURRENT_PWM_Z)
|
|
|
264 |
#else
|
|
|
265 |
#define PWM_CHK_MOTOR_CURRENT(p) (p == MOTOR_CURRENT_PWM_E)
|
|
|
266 |
#endif
|
|
|
267 |
#else
|
|
|
268 |
#define PWM_CHK_MOTOR_CURRENT(p) false
|
|
|
269 |
#endif
|
|
|
270 |
|
|
|
271 |
#ifdef NUM_SERVOS
|
|
|
272 |
#if AVR_ATmega2560_FAMILY
|
|
|
273 |
#define PWM_CHK_SERVO(p) (p == 5 || (NUM_SERVOS > 12 && p == 6) || (NUM_SERVOS > 24 && p == 46)) // PWMS 3A, 4A & 5A
|
|
|
274 |
#elif AVR_ATmega2561_FAMILY
|
|
|
275 |
#define PWM_CHK_SERVO(p) (p == 5) // PWM3A
|
|
|
276 |
#elif AVR_ATmega1284_FAMILY
|
|
|
277 |
#define PWM_CHK_SERVO(p) false
|
|
|
278 |
#elif AVR_AT90USB1286_FAMILY
|
|
|
279 |
#define PWM_CHK_SERVO(p) (p == 16) // PWM3A
|
|
|
280 |
#elif AVR_ATmega328_FAMILY
|
|
|
281 |
#define PWM_CHK_SERVO(p) false
|
|
|
282 |
#endif
|
|
|
283 |
#else
|
|
|
284 |
#define PWM_CHK_SERVO(p) false
|
|
|
285 |
#endif
|
|
|
286 |
|
|
|
287 |
#if ENABLED(BARICUDA)
|
|
|
288 |
#if HAS_HEATER_1 && HAS_HEATER_2
|
|
|
289 |
#define PWM_CHK_HEATER(p) (p == HEATER_1_PIN || p == HEATER_2_PIN)
|
|
|
290 |
#elif HAS_HEATER_1
|
|
|
291 |
#define PWM_CHK_HEATER(p) (p == HEATER_1_PIN)
|
|
|
292 |
#endif
|
|
|
293 |
#else
|
|
|
294 |
#define PWM_CHK_HEATER(p) false
|
|
|
295 |
#endif
|
|
|
296 |
|
|
|
297 |
#define PWM_CHK(p) (PWM_CHK_HEATER(p) || PWM_CHK_SERVO(p) || PWM_CHK_MOTOR_CURRENT(p)\
|
|
|
298 |
|| PWM_CHK_FAN_A(p) || PWM_CHK_FAN_B(p))
|
|
|
299 |
|
|
|
300 |
// define which hardware PWMs are available for the current CPU
|
|
|
301 |
// all timer 1 PWMS deleted from this list because they are never available
|
|
|
302 |
#if AVR_ATmega2560_FAMILY
|
|
|
303 |
#define PWM_PINS(p) ((p >= 2 && p <= 10) || p == 13 || p == 44 || p == 45 || p == 46)
|
|
|
304 |
#elif AVR_ATmega2561_FAMILY
|
|
|
305 |
#define PWM_PINS(p) ((p >= 2 && p <= 6) || p == 9)
|
|
|
306 |
#elif AVR_ATmega1284_FAMILY
|
|
|
307 |
#define PWM_PINS(p) (p == 3 || p == 4 || p == 14 || p == 15)
|
|
|
308 |
#elif AVR_AT90USB1286_FAMILY
|
|
|
309 |
#define PWM_PINS(p) (p == 0 || p == 1 || p == 14 || p == 15 || p == 16 || p == 24)
|
|
|
310 |
#elif AVR_ATmega328_FAMILY
|
|
|
311 |
#define PWM_PINS(p) (p == 3 || p == 5 || p == 6 || p == 11)
|
|
|
312 |
#else
|
|
|
313 |
#error "unknown CPU"
|
|
|
314 |
#endif
|
|
|
315 |
|
|
|
316 |
// finally - the macro that tells us if a pin is an available hardware PWM
|
|
|
317 |
#define USEABLE_HARDWARE_PWM(p) (PWM_PINS(p) && !PWM_CHK(p))
|
|
|
318 |
|
|
|
319 |
#endif // _FASTIO_ARDUINO_H_
|