Subversion Repositories MK-Marlin

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ron 1
/* **************************************************************************
2
 
3
 Marlin 3D Printer Firmware
4
 Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
5
 
6
 Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
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
 * Description: HAL for __AVR__
24
 */
25
 
26
#ifndef _HAL_AVR_H_
27
#define _HAL_AVR_H_
28
 
29
// --------------------------------------------------------------------------
30
// Includes
31
// --------------------------------------------------------------------------
32
 
33
#include "fastio.h"
34
 
35
#include <stdint.h>
36
#include <Arduino.h>
37
#include <util/delay.h>
38
#include <avr/eeprom.h>
39
#include <avr/pgmspace.h>
40
#include <avr/interrupt.h>
41
#include <avr/io.h>
42
 
43
// --------------------------------------------------------------------------
44
// Defines
45
// --------------------------------------------------------------------------
46
 
47
//#define analogInputToDigitalPin(IO) IO
48
 
49
// Bracket code that shouldn't be interrupted
50
#ifndef CRITICAL_SECTION_START
51
  #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli()
52
  #define CRITICAL_SECTION_END    SREG = _sreg
53
#endif
54
 
55
#define ISRS_ENABLED() TEST(SREG, SREG_I)
56
#define ENABLE_ISRS()  sei()
57
#define DISABLE_ISRS() cli()
58
 
59
// --------------------------------------------------------------------------
60
// Types
61
// --------------------------------------------------------------------------
62
 
63
typedef uint16_t hal_timer_t;
64
#define HAL_TIMER_TYPE_MAX 0xFFFF
65
 
66
typedef int8_t pin_t;
67
 
68
#define HAL_SERVO_LIB Servo
69
 
70
// --------------------------------------------------------------------------
71
// Public Variables
72
// --------------------------------------------------------------------------
73
 
74
//extern uint8_t MCUSR;
75
 
76
// --------------------------------------------------------------------------
77
// Public functions
78
// --------------------------------------------------------------------------
79
 
80
//void cli(void);
81
 
82
//void _delay_ms(const int delay);
83
 
84
inline void HAL_clear_reset_source(void) { MCUSR = 0; }
85
inline uint8_t HAL_get_reset_source(void) { return MCUSR; }
86
 
87
// eeprom
88
//void eeprom_write_byte(unsigned char *pos, unsigned char value);
89
//unsigned char eeprom_read_byte(unsigned char *pos);
90
 
91
// timers
92
#define HAL_TIMER_RATE          ((F_CPU) / 8)    // i.e., 2MHz or 2.5MHz
93
 
94
#define STEP_TIMER_NUM          1
95
#define TEMP_TIMER_NUM          0
96
#define PULSE_TIMER_NUM         STEP_TIMER_NUM
97
 
98
#define TEMP_TIMER_FREQUENCY    ((F_CPU) / 64.0 / 256.0)
99
 
100
#define STEPPER_TIMER_RATE      HAL_TIMER_RATE
101
#define STEPPER_TIMER_PRESCALE  8
102
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double
103
 
104
#define PULSE_TIMER_RATE       STEPPER_TIMER_RATE   // frequency of pulse timer
105
#define PULSE_TIMER_PRESCALE   STEPPER_TIMER_PRESCALE
106
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
107
 
108
#define ENABLE_STEPPER_DRIVER_INTERRUPT()  SBI(TIMSK1, OCIE1A)
109
#define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
110
#define STEPPER_ISR_ENABLED()             TEST(TIMSK1, OCIE1A)
111
 
112
#define ENABLE_TEMPERATURE_INTERRUPT()     SBI(TIMSK0, OCIE0B)
113
#define DISABLE_TEMPERATURE_INTERRUPT()    CBI(TIMSK0, OCIE0B)
114
#define TEMPERATURE_ISR_ENABLED()         TEST(TIMSK0, OCIE0B)
115
 
116
FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
117
  UNUSED(frequency);
118
  switch (timer_num) {
119
    case STEP_TIMER_NUM:
120
      // waveform generation = 0100 = CTC
121
      SET_WGM(1, CTC_OCRnA);
122
 
123
      // output mode = 00 (disconnected)
124
      SET_COMA(1, NORMAL);
125
 
126
      // Set the timer pre-scaler
127
      // Generally we use a divider of 8, resulting in a 2MHz timer
128
      // frequency on a 16MHz MCU. If you are going to change this, be
129
      // sure to regenerate speed_lookuptable.h with
130
      // create_speed_lookuptable.py
131
      SET_CS(1, PRESCALER_8);  //  CS 2 = 1/8 prescaler
132
 
133
      // Init Stepper ISR to 122 Hz for quick starting
134
      // (F_CPU) / (STEPPER_TIMER_PRESCALE) / frequency
135
      OCR1A = 0x4000;
136
      TCNT1 = 0;
137
      break;
138
 
139
    case TEMP_TIMER_NUM:
140
      // Use timer0 for temperature measurement
141
      // Interleave temperature interrupt with millies interrupt
142
      OCR0B = 128;
143
      break;
144
  }
145
}
146
 
147
#define TIMER_OCR_1             OCR1A
148
#define TIMER_COUNTER_1         TCNT1
149
 
150
#define TIMER_OCR_0             OCR0A
151
#define TIMER_COUNTER_0         TCNT0
152
 
153
#define _CAT(a, ...) a ## __VA_ARGS__
154
#define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare)
155
#define HAL_timer_get_compare(timer) _CAT(TIMER_OCR_, timer)
156
#define HAL_timer_get_count(timer) _CAT(TIMER_COUNTER_, timer)
157
 
158
/**
159
 * On AVR there is no hardware prioritization and preemption of
160
 * interrupts, so this emulates it. The UART has first priority
161
 * (otherwise, characters will be lost due to UART overflow).
162
 * Then: Stepper, Endstops, Temperature, and -finally- all others.
163
 */
164
#define HAL_timer_isr_prologue(TIMER_NUM)
165
#define HAL_timer_isr_epilogue(TIMER_NUM)
166
 
167
/* 18 cycles maximum latency */
168
#define HAL_STEP_TIMER_ISR \
169
extern "C" void TIMER1_COMPA_vect (void) __attribute__ ((signal, naked, used, externally_visible)); \
170
extern "C" void TIMER1_COMPA_vect_bottom (void) asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
171
void TIMER1_COMPA_vect (void) { \
172
  __asm__ __volatile__ ( \
173
    A("push r16")                      /* 2 Save R16 */ \
174
    A("in r16, __SREG__")              /* 1 Get SREG */ \
175
    A("push r16")                      /* 2 Save SREG into stack */ \
176
    A("lds r16, %[timsk0]")            /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
177
    A("push r16")                      /* 2 Save TIMSK0 into the stack */ \
178
    A("andi r16,~%[msk0]")             /* 1 Disable the temperature ISR */ \
179
    A("sts %[timsk0], r16")            /* 2 And set the new value */ \
180
    A("lds r16, %[timsk1]")            /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
181
    A("andi r16,~%[msk1]")             /* 1 Disable the stepper ISR */ \
182
    A("sts %[timsk1], r16")            /* 2 And set the new value */ \
183
    A("push r16")                      /* 2 Save TIMSK1 into stack */ \
184
    A("in r16, 0x3B")                  /* 1 Get RAMPZ register */ \
185
    A("push r16")                      /* 2 Save RAMPZ into stack */ \
186
    A("in r16, 0x3C")                  /* 1 Get EIND register */ \
187
    A("push r0")                       /* C runtime can modify all the following registers without restoring them */ \
188
    A("push r1")                       \
189
    A("push r18")                      \
190
    A("push r19")                      \
191
    A("push r20")                      \
192
    A("push r21")                      \
193
    A("push r22")                      \
194
    A("push r23")                      \
195
    A("push r24")                      \
196
    A("push r25")                      \
197
    A("push r26")                      \
198
    A("push r27")                      \
199
    A("push r30")                      \
200
    A("push r31")                      \
201
    A("clr r1")                        /* C runtime expects this register to be 0 */ \
202
    A("call TIMER1_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */   \
203
    A("pop r31")                       \
204
    A("pop r30")                       \
205
    A("pop r27")                       \
206
    A("pop r26")                       \
207
    A("pop r25")                       \
208
    A("pop r24")                       \
209
    A("pop r23")                       \
210
    A("pop r22")                       \
211
    A("pop r21")                       \
212
    A("pop r20")                       \
213
    A("pop r19")                       \
214
    A("pop r18")                       \
215
    A("pop r1")                        \
216
    A("pop r0")                        \
217
    A("out 0x3C, r16")                 /* 1 Restore EIND register */ \
218
    A("pop r16")                       /* 2 Get the original RAMPZ register value */ \
219
    A("out 0x3B, r16")                 /* 1 Restore RAMPZ register to its original value */ \
220
    A("pop r16")                       /* 2 Get the original TIMSK1 value but with stepper ISR disabled */ \
221
    A("ori r16,%[msk1]")               /* 1 Reenable the stepper ISR */ \
222
    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 */ \
223
    A("sts %[timsk1], r16")            /* 2 And restore the old value - This reenables the stepper ISR */ \
224
    A("pop r16")                       /* 2 Get the temperature timer Interrupt mask register [TIMSK0] */ \
225
    A("sts %[timsk0], r16")            /* 2 And restore the old value - This reenables the temperature ISR */ \
226
    A("pop r16")                       /* 2 Get the old SREG value */ \
227
    A("out __SREG__, r16")             /* 1 And restore the SREG value */ \
228
    A("pop r16")                       /* 2 Restore R16 value */ \
229
    A("reti")                          /* 4 Return from interrupt */ \
230
    :                                   \
231
    : [timsk0] "i" ((uint16_t)&TIMSK0), \
232
      [timsk1] "i" ((uint16_t)&TIMSK1), \
233
      [msk0] "M" ((uint8_t)(1<<OCIE0B)),\
234
      [msk1] "M" ((uint8_t)(1<<OCIE1A)) \
235
    : \
236
  ); \
237
} \
238
void TIMER1_COMPA_vect_bottom(void)
239
 
240
/* 14 cycles maximum latency */
241
#define HAL_TEMP_TIMER_ISR \
242
extern "C" void TIMER0_COMPB_vect (void) __attribute__ ((signal, naked, used, externally_visible)); \
243
extern "C" void TIMER0_COMPB_vect_bottom(void)  asm ("TIMER0_COMPB_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
244
void TIMER0_COMPB_vect (void) { \
245
  __asm__ __volatile__ ( \
246
    A("push r16")                       /* 2 Save R16 */ \
247
    A("in r16, __SREG__")               /* 1 Get SREG */ \
248
    A("push r16")                       /* 2 Save SREG into stack */ \
249
    A("lds r16, %[timsk0]")             /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
250
    A("andi r16,~%[msk0]")              /* 1 Disable the temperature ISR */ \
251
    A("sts %[timsk0], r16")             /* 2 And set the new value */ \
252
    A("sei")                            /* 1 Enable global interrupts - It is safe, as the temperature ISR is disabled, so we cannot reenter it */    \
253
    A("push r16")                       /* 2 Save TIMSK0 into stack */ \
254
    A("in r16, 0x3B")                   /* 1 Get RAMPZ register */ \
255
    A("push r16")                       /* 2 Save RAMPZ into stack */ \
256
    A("in r16, 0x3C")                   /* 1 Get EIND register */ \
257
    A("push r0")                        /* C runtime can modify all the following registers without restoring them */ \
258
    A("push r1")                        \
259
    A("push r18")                       \
260
    A("push r19")                       \
261
    A("push r20")                       \
262
    A("push r21")                       \
263
    A("push r22")                       \
264
    A("push r23")                       \
265
    A("push r24")                       \
266
    A("push r25")                       \
267
    A("push r26")                       \
268
    A("push r27")                       \
269
    A("push r30")                       \
270
    A("push r31")                       \
271
    A("clr r1")                         /* C runtime expects this register to be 0 */ \
272
    A("call TIMER0_COMPB_vect_bottom")  /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */   \
273
    A("pop r31")                        \
274
    A("pop r30")                        \
275
    A("pop r27")                        \
276
    A("pop r26")                        \
277
    A("pop r25")                        \
278
    A("pop r24")                        \
279
    A("pop r23")                        \
280
    A("pop r22")                        \
281
    A("pop r21")                        \
282
    A("pop r20")                        \
283
    A("pop r19")                        \
284
    A("pop r18")                        \
285
    A("pop r1")                         \
286
    A("pop r0")                         \
287
    A("out 0x3C, r16")                  /* 1 Restore EIND register */ \
288
    A("pop r16")                        /* 2 Get the original RAMPZ register value */ \
289
    A("out 0x3B, r16")                  /* 1 Restore RAMPZ register to its original value */ \
290
    A("pop r16")                        /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
291
    A("ori r16,%[msk0]")                /* 1 Enable temperature ISR */ \
292
    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 */ \
293
    A("sts %[timsk0], r16")             /* 2 And restore the old value */ \
294
    A("pop r16")                        /* 2 Get the old SREG */ \
295
    A("out __SREG__, r16")              /* 1 And restore the SREG value */ \
296
    A("pop r16")                        /* 2 Restore R16 */ \
297
    A("reti")                           /* 4 Return from interrupt */ \
298
    :                                   \
299
    : [timsk0] "i"((uint16_t)&TIMSK0),  \
300
      [msk0] "M" ((uint8_t)(1<<OCIE0B)) \
301
    : \
302
  ); \
303
} \
304
void TIMER0_COMPB_vect_bottom(void)
305
 
306
// ADC
307
#ifdef DIDR2
308
  #define HAL_ANALOG_SELECT(pin) do{ if (pin < 8) SBI(DIDR0, pin); else SBI(DIDR2, pin & 0x07); }while(0)
309
#else
310
  #define HAL_ANALOG_SELECT(pin) do{ SBI(DIDR0, pin); }while(0)
311
#endif
312
 
313
inline void HAL_adc_init(void) {
314
  ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
315
  DIDR0 = 0;
316
  #ifdef DIDR2
317
    DIDR2 = 0;
318
  #endif
319
}
320
 
321
#define SET_ADMUX_ADCSRA(pin) ADMUX = _BV(REFS0) | (pin & 0x07); SBI(ADCSRA, ADSC)
322
#ifdef MUX5
323
  #define HAL_START_ADC(pin) if (pin > 7) ADCSRB = _BV(MUX5); else ADCSRB = 0; SET_ADMUX_ADCSRA(pin)
324
#else
325
  #define HAL_START_ADC(pin) ADCSRB = 0; SET_ADMUX_ADCSRA(pin)
326
#endif
327
 
328
#define HAL_READ_ADC()  ADC
329
#define HAL_ADC_READY() !TEST(ADCSRA, ADSC)
330
 
331
#define GET_PIN_MAP_PIN(index) index
332
#define GET_PIN_MAP_INDEX(pin) pin
333
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
334
 
335
#define HAL_SENSITIVE_PINS 0, 1
336
 
337
#endif // _HAL_AVR_H_