aboutsummaryrefslogtreecommitdiff
path: root/platforms/avr
diff options
context:
space:
mode:
authorJoel Challis <git@zvecr.com>2021-11-19 18:41:02 +0000
committerGitHub <noreply@github.com>2021-11-19 10:41:02 -0800
commit2728603fe6d73e805a539d337fd01051c46ca806 (patch)
tree5c83ffc7efa112da870bd5d8502a9d91d4792f35 /platforms/avr
parent43b9e23bae12916d5161f03700c9bfe46737324b (diff)
downloadqmk_firmware-2728603fe6d73e805a539d337fd01051c46ca806.tar.gz
qmk_firmware-2728603fe6d73e805a539d337fd01051c46ca806.zip
Move tmk_core/common/<plat> (#13918)
Diffstat (limited to 'platforms/avr')
-rw-r--r--platforms/avr/_print.h33
-rw-r--r--platforms/avr/_timer.h19
-rw-r--r--platforms/avr/_wait.h49
-rw-r--r--platforms/avr/atomic_util.h22
-rw-r--r--platforms/avr/bootloader.c293
-rw-r--r--platforms/avr/bootloader_size.c21
-rw-r--r--platforms/avr/gpio.h49
-rw-r--r--platforms/avr/pin_defs.h128
-rw-r--r--platforms/avr/platform.c21
-rw-r--r--platforms/avr/platform.mk179
-rw-r--r--platforms/avr/platform_deps.h20
-rw-r--r--platforms/avr/printf.c20
-rw-r--r--platforms/avr/printf.mk2
-rw-r--r--platforms/avr/sleep_led.c124
-rw-r--r--platforms/avr/suspend.c152
-rw-r--r--platforms/avr/timer.c133
-rw-r--r--platforms/avr/timer_avr.h39
-rw-r--r--platforms/avr/xprintf.S498
-rw-r--r--platforms/avr/xprintf.h103
19 files changed, 1905 insertions, 0 deletions
diff --git a/platforms/avr/_print.h b/platforms/avr/_print.h
new file mode 100644
index 000000000..5c1fdd26d
--- /dev/null
+++ b/platforms/avr/_print.h
@@ -0,0 +1,33 @@
1/* Copyright 2012 Jun Wako <wakojun@gmail.com> */
2/* Very basic print functions, intended to be used with usb_debug_only.c
3 * http://www.pjrc.com/teensy/
4 * Copyright (c) 2008 PJRC.COM, LLC
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#pragma once
25
26#include "avr/xprintf.h"
27
28// Create user & normal print defines
29#define print(s) xputs(PSTR(s))
30#define println(s) xputs(PSTR(s "\r\n"))
31#define uprint(s) xputs(PSTR(s))
32#define uprintln(s) xputs(PSTR(s "\r\n"))
33#define uprintf(fmt, ...) __xprintf(PSTR(fmt), ##__VA_ARGS__) \ No newline at end of file
diff --git a/platforms/avr/_timer.h b/platforms/avr/_timer.h
new file mode 100644
index 000000000..b81e0f68b
--- /dev/null
+++ b/platforms/avr/_timer.h
@@ -0,0 +1,19 @@
1/* Copyright 2021 Simon Arlott
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// The platform is 8-bit, so prefer 16-bit timers to reduce code size
19#define FAST_TIMER_T_SIZE 16
diff --git a/platforms/avr/_wait.h b/platforms/avr/_wait.h
new file mode 100644
index 000000000..683db6ae5
--- /dev/null
+++ b/platforms/avr/_wait.h
@@ -0,0 +1,49 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <util/delay.h>
19
20#define wait_ms(ms) \
21 do { \
22 if (__builtin_constant_p(ms)) { \
23 _delay_ms(ms); \
24 } else { \
25 for (uint16_t i = ms; i > 0; i--) { \
26 _delay_ms(1); \
27 } \
28 } \
29 } while (0)
30#define wait_us(us) \
31 do { \
32 if (__builtin_constant_p(us)) { \
33 _delay_us(us); \
34 } else { \
35 for (uint16_t i = us; i > 0; i--) { \
36 _delay_us(1); \
37 } \
38 } \
39 } while (0)
40#define wait_cpuclock(n) __builtin_avr_delay_cycles(n)
41#define CPU_CLOCK F_CPU
42
43/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal.
44 * But here's more margin to make it two clocks. */
45#ifndef GPIO_INPUT_PIN_DELAY
46# define GPIO_INPUT_PIN_DELAY 2
47#endif
48
49#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
diff --git a/platforms/avr/atomic_util.h b/platforms/avr/atomic_util.h
new file mode 100644
index 000000000..7c5d2e7dc
--- /dev/null
+++ b/platforms/avr/atomic_util.h
@@ -0,0 +1,22 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18/* atomic macro for AVR */
19#include <util/atomic.h>
20
21#define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
22#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
diff --git a/platforms/avr/bootloader.c b/platforms/avr/bootloader.c
new file mode 100644
index 000000000..c0272903b
--- /dev/null
+++ b/platforms/avr/bootloader.c
@@ -0,0 +1,293 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include <avr/io.h>
4#include <avr/eeprom.h>
5#include <avr/interrupt.h>
6#include <avr/wdt.h>
7#include <util/delay.h>
8#include "bootloader.h"
9#include <avr/boot.h>
10
11#ifdef PROTOCOL_LUFA
12# include <LUFA/Drivers/USB/USB.h>
13#endif
14
15/** \brief Bootloader Size in *bytes*
16 *
17 * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
18 * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
19 *
20 * Size of Bootloaders in bytes:
21 * Atmel DFU loader(ATmega32U4) 4096
22 * Atmel DFU loader(AT90USB128) 8192
23 * LUFA bootloader(ATmega32U4) 4096
24 * Arduino Caterina(ATmega32U4) 4096
25 * USBaspLoader(ATmega***) 2048
26 * Teensy halfKay(ATmega32U4) 512
27 * Teensy++ halfKay(AT90USB128) 1024
28 *
29 * AVR Boot section is located at the end of Flash memory like the followings.
30 *
31 * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128)
32 * 0x0000 +---------------+ 0x00000 +---------------+
33 * | | | |
34 * | | | |
35 * | Application | | Application |
36 * | | | |
37 * = = = =
38 * | | 32KB-4KB | | 128KB-8KB
39 * 0x7000 +---------------+ 0x1E000 +---------------+
40 * | Bootloader | 4KB | Bootloader | 8KB
41 * 0x7FFF +---------------+ 0x1FFFF +---------------+
42 *
43 *
44 * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128)
45 * 0x0000 +---------------+ 0x00000 +---------------+
46 * | | | |
47 * | | | |
48 * | Application | | Application |
49 * | | | |
50 * = = = =
51 * | | 32KB-512B | | 128KB-1KB
52 * 0x7E00 +---------------+ 0x1FC00 +---------------+
53 * | Bootloader | 512B | Bootloader | 1KB
54 * 0x7FFF +---------------+ 0x1FFFF +---------------+
55 */
56#define FLASH_SIZE (FLASHEND + 1L)
57
58#if !defined(BOOTLOADER_SIZE)
59uint16_t bootloader_start;
60#endif
61
62// compatibility between ATMega8 and ATMega88
63#if !defined(MCUCSR)
64# if defined(MCUSR)
65# define MCUCSR MCUSR
66# endif
67#endif
68
69/** \brief Entering the Bootloader via Software
70 *
71 * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
72 */
73#define BOOTLOADER_RESET_KEY 0xB007B007
74uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));
75
76/** \brief initialize MCU status by watchdog reset
77 *
78 * FIXME: needs doc
79 */
80__attribute__((weak)) void bootloader_jump(void) {
81#if !defined(BOOTLOADER_SIZE)
82 uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
83
84 if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) {
85 bootloader_start = (FLASH_SIZE - 512) >> 1;
86 } else if (high_fuse & ~(FUSE_BOOTSZ1)) {
87 bootloader_start = (FLASH_SIZE - 1024) >> 1;
88 } else if (high_fuse & ~(FUSE_BOOTSZ0)) {
89 bootloader_start = (FLASH_SIZE - 2048) >> 1;
90 } else {
91 bootloader_start = (FLASH_SIZE - 4096) >> 1;
92 }
93#endif
94
95 // Something like this might work, but it compiled larger than the block above
96 // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1));
97
98#if defined(BOOTLOADER_HALFKAY)
99 // http://www.pjrc.com/teensy/jump_to_bootloader.html
100 cli();
101 // disable watchdog, if enabled (it's not)
102 // disable all peripherals
103 // a shutdown call might make sense here
104 UDCON = 1;
105 USBCON = (1 << FRZCLK); // disable USB
106 UCSR1B = 0;
107 _delay_ms(5);
108# if defined(__AVR_AT90USB162__) // Teensy 1.0
109 EIMSK = 0;
110 PCICR = 0;
111 SPCR = 0;
112 ACSR = 0;
113 EECR = 0;
114 TIMSK0 = 0;
115 TIMSK1 = 0;
116 UCSR1B = 0;
117 DDRB = 0;
118 DDRC = 0;
119 DDRD = 0;
120 PORTB = 0;
121 PORTC = 0;
122 PORTD = 0;
123 asm volatile("jmp 0x3E00");
124# elif defined(__AVR_ATmega32U4__) // Teensy 2.0
125 EIMSK = 0;
126 PCICR = 0;
127 SPCR = 0;
128 ACSR = 0;
129 EECR = 0;
130 ADCSRA = 0;
131 TIMSK0 = 0;
132 TIMSK1 = 0;
133 TIMSK3 = 0;
134 TIMSK4 = 0;
135 UCSR1B = 0;
136 TWCR = 0;
137 DDRB = 0;
138 DDRC = 0;
139 DDRD = 0;
140 DDRE = 0;
141 DDRF = 0;
142 TWCR = 0;
143 PORTB = 0;
144 PORTC = 0;
145 PORTD = 0;
146 PORTE = 0;
147 PORTF = 0;
148 asm volatile("jmp 0x7E00");
149# elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
150 EIMSK = 0;
151 PCICR = 0;
152 SPCR = 0;
153 ACSR = 0;
154 EECR = 0;
155 ADCSRA = 0;
156 TIMSK0 = 0;
157 TIMSK1 = 0;
158 TIMSK2 = 0;
159 TIMSK3 = 0;
160 UCSR1B = 0;
161 TWCR = 0;
162 DDRA = 0;
163 DDRB = 0;
164 DDRC = 0;
165 DDRD = 0;
166 DDRE = 0;
167 DDRF = 0;
168 PORTA = 0;
169 PORTB = 0;
170 PORTC = 0;
171 PORTD = 0;
172 PORTE = 0;
173 PORTF = 0;
174 asm volatile("jmp 0xFC00");
175# elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
176 EIMSK = 0;
177 PCICR = 0;
178 SPCR = 0;
179 ACSR = 0;
180 EECR = 0;
181 ADCSRA = 0;
182 TIMSK0 = 0;
183 TIMSK1 = 0;
184 TIMSK2 = 0;
185 TIMSK3 = 0;
186 UCSR1B = 0;
187 TWCR = 0;
188 DDRA = 0;
189 DDRB = 0;
190 DDRC = 0;
191 DDRD = 0;
192 DDRE = 0;
193 DDRF = 0;
194 PORTA = 0;
195 PORTB = 0;
196 PORTC = 0;
197 PORTD = 0;
198 PORTE = 0;
199 PORTF = 0;
200 asm volatile("jmp 0x1FC00");
201# endif
202
203#elif defined(BOOTLOADER_CATERINA)
204 // this block may be optional
205 // TODO: figure it out
206
207 uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
208
209 // Value used by Caterina bootloader use to determine whether to run the
210 // sketch or the bootloader programmer.
211 uint16_t bootKey = 0x7777;
212
213 *bootKeyPtr = bootKey;
214
215 // setup watchdog timeout
216 wdt_enable(WDTO_60MS);
217
218 while (1) {
219 } // wait for watchdog timer to trigger
220
221#elif defined(BOOTLOADER_USBASP)
222 // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
223 wdt_enable(WDTO_15MS);
224 wdt_reset();
225 asm volatile("cli \n\t"
226 "ldi r29 , %[ramendhi] \n\t"
227 "ldi r28 , %[ramendlo] \n\t"
228# if (FLASHEND > 131071)
229 "ldi r18 , %[bootaddrhi] \n\t"
230 "st Y+, r18 \n\t"
231# endif
232 "ldi r18 , %[bootaddrme] \n\t"
233 "st Y+, r18 \n\t"
234 "ldi r18 , %[bootaddrlo] \n\t"
235 "st Y+, r18 \n\t"
236 "out %[mcucsrio], __zero_reg__ \n\t"
237 "bootloader_startup_loop%=: \n\t"
238 "rjmp bootloader_startup_loop%= \n\t"
239 :
240 : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
241# if (FLASHEND > 131071)
242 [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
243# else
244 [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
245# endif
246 [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
247
248#else // Assume remaining boards are DFU, even if the flag isn't set
249
250# if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though?
251 UDCON = 1;
252 USBCON = (1 << FRZCLK); // disable USB
253 UCSR1B = 0;
254 _delay_ms(5); // 5 seems to work fine
255# endif
256
257# ifdef BOOTLOADER_BOOTLOADHID
258 // force bootloadHID to stay in bootloader mode, so that it waits
259 // for a new firmware to be flashed
260 eeprom_write_byte((uint8_t *)1, 0x00);
261# endif
262
263 // watchdog reset
264 reset_key = BOOTLOADER_RESET_KEY;
265 wdt_enable(WDTO_250MS);
266 for (;;)
267 ;
268#endif
269}
270
271/* this runs before main() */
272void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
273void bootloader_jump_after_watchdog_reset(void) {
274#ifndef BOOTLOADER_HALFKAY
275 if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
276 reset_key = 0;
277
278 // My custom USBasploader requires this to come up.
279 MCUCSR = 0;
280
281 // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
282 MCUCSR &= ~(1 << WDRF);
283 wdt_disable();
284
285// This is compled into 'icall', address should be in word unit, not byte.
286# ifdef BOOTLOADER_SIZE
287 ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
288# else
289 asm("ijmp" ::"z"(bootloader_start));
290# endif
291 }
292#endif
293}
diff --git a/platforms/avr/bootloader_size.c b/platforms/avr/bootloader_size.c
new file mode 100644
index 000000000..a029f9321
--- /dev/null
+++ b/platforms/avr/bootloader_size.c
@@ -0,0 +1,21 @@
1// Copyright 2017 Jack Humbert
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16#include <avr/io.h>
17#include <avr/boot.h>
18
19// clang-format off
20// this is not valid C - it's for computing the size available on the chip
21AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE
diff --git a/platforms/avr/gpio.h b/platforms/avr/gpio.h
new file mode 100644
index 000000000..e9be68491
--- /dev/null
+++ b/platforms/avr/gpio.h
@@ -0,0 +1,49 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <avr/io.h>
19#include "pin_defs.h"
20
21typedef uint8_t pin_t;
22
23/* Operation of GPIO by pin. */
24
25#define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
26#define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
27#define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low")
28#define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
29
30#define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
31#define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
32#define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin))
33
34#define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
35
36#define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF))
37
38/* Operation of GPIO by port. */
39
40typedef uint8_t port_data_t;
41
42#define readPort(port) PINx_ADDRESS(port)
43
44#define setPortBitInput(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
45#define setPortBitInputHigh(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) |= _BV((bit)&0xF))
46#define setPortBitOutput(port, bit) (DDRx_ADDRESS(port) |= _BV((bit)&0xF))
47
48#define writePortBitLow(port, bit) (PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
49#define writePortBitHigh(port, bit) (PORTx_ADDRESS(port) |= _BV((bit)&0xF))
diff --git a/platforms/avr/pin_defs.h b/platforms/avr/pin_defs.h
new file mode 100644
index 000000000..23d948041
--- /dev/null
+++ b/platforms/avr/pin_defs.h
@@ -0,0 +1,128 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <avr/io.h>
19
20#define PORT_SHIFTER 4 // this may be 4 for all AVR chips
21
22// If you want to add more to this list, reference the PINx definitions in these header
23// files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr
24
25#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
26# define ADDRESS_BASE 0x00
27# define PINB_ADDRESS 0x3
28# define PINC_ADDRESS 0x6
29# define PIND_ADDRESS 0x9
30# define PINE_ADDRESS 0xC
31# define PINF_ADDRESS 0xF
32#elif defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
33# define ADDRESS_BASE 0x00
34# define PINB_ADDRESS 0x3
35# define PINC_ADDRESS 0x6
36# define PIND_ADDRESS 0x9
37#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
38# define ADDRESS_BASE 0x00
39# define PINA_ADDRESS 0x0
40# define PINB_ADDRESS 0x3
41# define PINC_ADDRESS 0x6
42# define PIND_ADDRESS 0x9
43# define PINE_ADDRESS 0xC
44# define PINF_ADDRESS 0xF
45#elif defined(__AVR_ATmega32A__)
46# define ADDRESS_BASE 0x10
47# define PIND_ADDRESS 0x0
48# define PINC_ADDRESS 0x3
49# define PINB_ADDRESS 0x6
50# define PINA_ADDRESS 0x9
51#elif defined(__AVR_ATtiny85__)
52# define ADDRESS_BASE 0x10
53# define PINB_ADDRESS 0x6
54#else
55# error "Pins are not defined"
56#endif
57
58#define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin)
59
60#define _PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + ((p) >> PORT_SHIFTER) + (offset))
61// Port X Input Pins Address
62#define PINx_ADDRESS(p) _PIN_ADDRESS(p, 0)
63// Port X Data Direction Register, 0:input 1:output
64#define DDRx_ADDRESS(p) _PIN_ADDRESS(p, 1)
65// Port X Data Register
66#define PORTx_ADDRESS(p) _PIN_ADDRESS(p, 2)
67
68/* I/O pins */
69#ifdef PORTA
70# define A0 PINDEF(A, 0)
71# define A1 PINDEF(A, 1)
72# define A2 PINDEF(A, 2)
73# define A3 PINDEF(A, 3)
74# define A4 PINDEF(A, 4)
75# define A5 PINDEF(A, 5)
76# define A6 PINDEF(A, 6)
77# define A7 PINDEF(A, 7)
78#endif
79#ifdef PORTB
80# define B0 PINDEF(B, 0)
81# define B1 PINDEF(B, 1)
82# define B2 PINDEF(B, 2)
83# define B3 PINDEF(B, 3)
84# define B4 PINDEF(B, 4)
85# define B5 PINDEF(B, 5)
86# define B6 PINDEF(B, 6)
87# define B7 PINDEF(B, 7)
88#endif
89#ifdef PORTC
90# define C0 PINDEF(C, 0)
91# define C1 PINDEF(C, 1)
92# define C2 PINDEF(C, 2)
93# define C3 PINDEF(C, 3)
94# define C4 PINDEF(C, 4)
95# define C5 PINDEF(C, 5)
96# define C6 PINDEF(C, 6)
97# define C7 PINDEF(C, 7)
98#endif
99#ifdef PORTD
100# define D0 PINDEF(D, 0)
101# define D1 PINDEF(D, 1)
102# define D2 PINDEF(D, 2)
103# define D3 PINDEF(D, 3)
104# define D4 PINDEF(D, 4)
105# define D5 PINDEF(D, 5)
106# define D6 PINDEF(D, 6)
107# define D7 PINDEF(D, 7)
108#endif
109#ifdef PORTE
110# define E0 PINDEF(E, 0)
111# define E1 PINDEF(E, 1)
112# define E2 PINDEF(E, 2)
113# define E3 PINDEF(E, 3)
114# define E4 PINDEF(E, 4)
115# define E5 PINDEF(E, 5)
116# define E6 PINDEF(E, 6)
117# define E7 PINDEF(E, 7)
118#endif
119#ifdef PORTF
120# define F0 PINDEF(F, 0)
121# define F1 PINDEF(F, 1)
122# define F2 PINDEF(F, 2)
123# define F3 PINDEF(F, 3)
124# define F4 PINDEF(F, 4)
125# define F5 PINDEF(F, 5)
126# define F6 PINDEF(F, 6)
127# define F7 PINDEF(F, 7)
128#endif
diff --git a/platforms/avr/platform.c b/platforms/avr/platform.c
new file mode 100644
index 000000000..3e35b4fe4
--- /dev/null
+++ b/platforms/avr/platform.c
@@ -0,0 +1,21 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "platform_deps.h"
18
19void platform_setup(void) {
20 // do nothing
21}
diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk
new file mode 100644
index 000000000..b45108736
--- /dev/null
+++ b/platforms/avr/platform.mk
@@ -0,0 +1,179 @@
1# Hey Emacs, this is a -*- makefile -*-
2##############################################################################
3# Compiler settings
4#
5CC = $(CC_PREFIX) avr-gcc
6OBJCOPY = avr-objcopy
7OBJDUMP = avr-objdump
8SIZE = avr-size
9AR = avr-ar
10NM = avr-nm
11HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature
12EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
13BIN =
14
15COMPILEFLAGS += -funsigned-char
16COMPILEFLAGS += -funsigned-bitfields
17COMPILEFLAGS += -ffunction-sections
18COMPILEFLAGS += -fdata-sections
19COMPILEFLAGS += -fpack-struct
20COMPILEFLAGS += -fshort-enums
21
22ASFLAGS += $(AVR_ASFLAGS)
23
24CFLAGS += $(COMPILEFLAGS) $(AVR_CFLAGS)
25CFLAGS += -fno-inline-small-functions
26CFLAGS += -fno-strict-aliasing
27
28CXXFLAGS += $(COMPILEFLAGS)
29CXXFLAGS += -fno-exceptions -std=c++11
30
31LDFLAGS +=-Wl,--gc-sections
32
33OPT_DEFS += -DF_CPU=$(F_CPU)UL
34
35MCUFLAGS = -mmcu=$(MCU)
36
37# List any extra directories to look for libraries here.
38# Each directory must be seperated by a space.
39# Use forward slashes for directory separators.
40# For a directory that has spaces, enclose it in quotes.
41EXTRALIBDIRS =
42
43
44#---------------- External Memory Options ----------------
45
46# 64 KB of external RAM, starting after internal RAM (ATmega128!),
47# used for variables (.data/.bss) and heap (malloc()).
48#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
49
50# 64 KB of external RAM, starting after internal RAM (ATmega128!),
51# only used for heap (malloc()).
52#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
53
54EXTMEMOPTS =
55
56#---------------- Debugging Options ----------------
57
58# Debugging format.
59# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
60# AVR Studio 4.10 requires dwarf-2.
61# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
62DEBUG = dwarf-2
63
64# For simulavr only - target MCU frequency.
65DEBUG_MFREQ = $(F_CPU)
66
67# Set the DEBUG_UI to either gdb or insight.
68# DEBUG_UI = gdb
69DEBUG_UI = insight
70
71# Set the debugging back-end to either avarice, simulavr.
72DEBUG_BACKEND = avarice
73#DEBUG_BACKEND = simulavr
74
75# GDB Init Filename.
76GDBINIT_FILE = __avr_gdbinit
77
78# When using avarice settings for the JTAG
79JTAG_DEV = /dev/com1
80
81# Debugging port used to communicate between GDB / avarice / simulavr.
82DEBUG_PORT = 4242
83
84# Debugging host used to communicate between GDB / avarice / simulavr, normally
85# just set to localhost unless doing some sort of crazy debugging when
86# avarice is running on a different computer.
87DEBUG_HOST = localhost
88
89#============================================================================
90
91# Convert hex to bin.
92bin: $(BUILD_DIR)/$(TARGET).hex
93ifeq ($(BOOTLOADER),lufa-ms)
94 $(eval BIN_PADDING=$(shell n=`expr 32768 - $(BOOTLOADER_SIZE)` && echo $$(($$n)) || echo 0))
95 $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin --pad-to $(BIN_PADDING)
96else
97 $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
98endif
99 $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;
100
101# copy bin to FLASH.bin
102flashbin: bin
103 $(COPY) $(BUILD_DIR)/$(TARGET).bin FLASH.bin;
104
105# Generate avr-gdb config/init file which does the following:
106# define the reset signal, load the target file, connect to target, and set
107# a breakpoint at main().
108gdb-config:
109 @$(REMOVE) $(GDBINIT_FILE)
110 @echo define reset >> $(GDBINIT_FILE)
111 @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
112 @echo end >> $(GDBINIT_FILE)
113 @echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE)
114 @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
115ifeq ($(DEBUG_BACKEND),simulavr)
116 @echo load >> $(GDBINIT_FILE)
117endif
118 @echo break main >> $(GDBINIT_FILE)
119
120debug: gdb-config $(BUILD_DIR)/$(TARGET).elf
121ifeq ($(DEBUG_BACKEND), avarice)
122 @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
123 @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
124 $(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
125 @$(WINSHELL) /c pause
126
127else
128 @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
129 $(DEBUG_MFREQ) --port $(DEBUG_PORT)
130endif
131 @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
132
133
134
135
136# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
137COFFCONVERT = $(OBJCOPY) --debugging
138COFFCONVERT += --change-section-address .data-0x800000
139COFFCONVERT += --change-section-address .bss-0x800000
140COFFCONVERT += --change-section-address .noinit-0x800000
141COFFCONVERT += --change-section-address .eeprom-0x810000
142
143
144
145coff: $(BUILD_DIR)/$(TARGET).elf
146 @$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof
147 $(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof
148
149
150extcoff: $(BUILD_DIR)/$(TARGET).elf
151 @$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof
152 $(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof
153
154ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
155QMK_BOOTLOADER_TYPE = DFU
156else ifeq ($(strip $(BOOTLOADER)), qmk-hid)
157QMK_BOOTLOADER_TYPE = HID
158endif
159
160bootloader:
161ifeq ($(strip $(QMK_BOOTLOADER_TYPE)),)
162 $(error Please set BOOTLOADER to "qmk-dfu" or "qmk-hid" first!)
163else
164 make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ clean
165 $(QMK_BIN) generate-dfu-header --quiet --keyboard $(KEYBOARD) --output lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Keyboard.h
166 $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) -D__ASSEMBLER__ $(CFLAGS) $(OPT_DEFS) platforms/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
167 $(eval PROGRAM_SIZE_KB=$(shell n=`expr $(MAX_SIZE) / 1024` && echo $$(($$n)) || echo 0))
168 $(eval BOOT_SECTION_SIZE_KB=$(shell n=`expr $(BOOTLOADER_SIZE) / 1024` && echo $$(($$n)) || echo 0))
169 $(eval FLASH_SIZE_KB=$(shell n=`expr $(PROGRAM_SIZE_KB) + $(BOOT_SECTION_SIZE_KB)` && echo $$(($$n)) || echo 0))
170 make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ MCU=$(MCU) ARCH=$(ARCH) F_CPU=$(F_CPU) FLASH_SIZE_KB=$(FLASH_SIZE_KB) BOOT_SECTION_SIZE_KB=$(BOOT_SECTION_SIZE_KB)
171 printf "Bootloader$(QMK_BOOTLOADER_TYPE).hex copied to $(TARGET)_bootloader.hex\n"
172 cp lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Bootloader$(QMK_BOOTLOADER_TYPE).hex $(TARGET)_bootloader.hex
173endif
174
175production: $(BUILD_DIR)/$(TARGET).hex bootloader cpfirmware
176 @cat $(BUILD_DIR)/$(TARGET).hex | awk '/^:00000001FF/ == 0' > $(TARGET)_production.hex
177 @cat $(TARGET)_bootloader.hex >> $(TARGET)_production.hex
178 echo "File sizes:"
179 $(SIZE) $(TARGET).hex $(TARGET)_bootloader.hex $(TARGET)_production.hex
diff --git a/platforms/avr/platform_deps.h b/platforms/avr/platform_deps.h
new file mode 100644
index 000000000..45d9dcebf
--- /dev/null
+++ b/platforms/avr/platform_deps.h
@@ -0,0 +1,20 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <avr/pgmspace.h>
19#include <avr/io.h>
20#include <avr/interrupt.h>
diff --git a/platforms/avr/printf.c b/platforms/avr/printf.c
new file mode 100644
index 000000000..9ad7a3869
--- /dev/null
+++ b/platforms/avr/printf.c
@@ -0,0 +1,20 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "xprintf.h"
18#include "sendchar.h"
19
20void print_set_sendchar(sendchar_func_t func) { xdev_out(func); }
diff --git a/platforms/avr/printf.mk b/platforms/avr/printf.mk
new file mode 100644
index 000000000..060ad88c5
--- /dev/null
+++ b/platforms/avr/printf.mk
@@ -0,0 +1,2 @@
1TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
2TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
diff --git a/platforms/avr/sleep_led.c b/platforms/avr/sleep_led.c
new file mode 100644
index 000000000..9a3b52abe
--- /dev/null
+++ b/platforms/avr/sleep_led.c
@@ -0,0 +1,124 @@
1#include <stdint.h>
2#include <avr/io.h>
3#include <avr/interrupt.h>
4#include <avr/pgmspace.h>
5#include "led.h"
6#include "sleep_led.h"
7
8#ifndef SLEEP_LED_TIMER
9# define SLEEP_LED_TIMER 1
10#endif
11
12#if SLEEP_LED_TIMER == 1
13# define TCCRxB TCCR1B
14# define TIMERx_COMPA_vect TIMER1_COMPA_vect
15# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
16# define TIMSKx TIMSK
17# else
18# define TIMSKx TIMSK1
19# endif
20# define OCIExA OCIE1A
21# define OCRxx OCR1A
22#elif SLEEP_LED_TIMER == 3
23# define TCCRxB TCCR3B
24# define TIMERx_COMPA_vect TIMER3_COMPA_vect
25# define TIMSKx TIMSK3
26# define OCIExA OCIE3A
27# define OCRxx OCR3A
28#else
29error("Invalid SLEEP_LED_TIMER config")
30#endif
31
32/* Software PWM
33 * ______ ______ __
34 * | ON |___OFF___| ON |___OFF___| ....
35 * |<-------------->|<-------------->|<- ....
36 * PWM period PWM period
37 *
38 * 256 interrupts/period[resolution]
39 * 64 periods/second[frequency]
40 * 256*64 interrupts/second
41 * F_CPU/(256*64) clocks/interrupt
42 */
43#define SLEEP_LED_TIMER_TOP F_CPU / (256 * 64)
44
45/** \brief Sleep LED initialization
46 *
47 * FIXME: needs doc
48 */
49void sleep_led_init(void) {
50 /* Timer1 setup */
51 /* CTC mode */
52 TCCRxB |= _BV(WGM12);
53 /* Clock selelct: clk/1 */
54 TCCRxB |= _BV(CS10);
55 /* Set TOP value */
56 uint8_t sreg = SREG;
57 cli();
58 OCRxx = SLEEP_LED_TIMER_TOP;
59 SREG = sreg;
60}
61
62/** \brief Sleep LED enable
63 *
64 * FIXME: needs doc
65 */
66void sleep_led_enable(void) {
67 /* Enable Compare Match Interrupt */
68 TIMSKx |= _BV(OCIExA);
69}
70
71/** \brief Sleep LED disable
72 *
73 * FIXME: needs doc
74 */
75void sleep_led_disable(void) {
76 /* Disable Compare Match Interrupt */
77 TIMSKx &= ~_BV(OCIExA);
78}
79
80/** \brief Sleep LED toggle
81 *
82 * FIXME: needs doc
83 */
84void sleep_led_toggle(void) {
85 /* Disable Compare Match Interrupt */
86 TIMSKx ^= _BV(OCIExA);
87}
88
89/** \brief Breathing Sleep LED brighness(PWM On period) table
90 *
91 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
92 *
93 * https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
94 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
95 */
96static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
97
98ISR(TIMERx_COMPA_vect) {
99 /* Software PWM
100 * timer:1111 1111 1111 1111
101 * \_____/\/ \_______/____ count(0-255)
102 * \ \______________ duration of step(4)
103 * \__________________ index of step table(0-63)
104 */
105 static union {
106 uint16_t row;
107 struct {
108 uint8_t count : 8;
109 uint8_t duration : 2;
110 uint8_t index : 6;
111 } pwm;
112 } timer = {.row = 0};
113
114 timer.row++;
115
116 // LED on
117 if (timer.pwm.count == 0) {
118 led_set(1 << USB_LED_CAPS_LOCK);
119 }
120 // LED off
121 if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) {
122 led_set(0);
123 }
124}
diff --git a/platforms/avr/suspend.c b/platforms/avr/suspend.c
new file mode 100644
index 000000000..b614746e6
--- /dev/null
+++ b/platforms/avr/suspend.c
@@ -0,0 +1,152 @@
1#include <stdbool.h>
2#include <avr/sleep.h>
3#include <avr/wdt.h>
4#include <avr/interrupt.h>
5#include "matrix.h"
6#include "action.h"
7#include "suspend.h"
8#include "timer.h"
9#include "led.h"
10#include "host.h"
11
12#ifdef PROTOCOL_LUFA
13# include "lufa.h"
14#endif
15#ifdef PROTOCOL_VUSB
16# include "vusb.h"
17#endif
18
19/** \brief Suspend idle
20 *
21 * FIXME: needs doc
22 */
23void suspend_idle(uint8_t time) {
24 cli();
25 set_sleep_mode(SLEEP_MODE_IDLE);
26 sleep_enable();
27 sei();
28 sleep_cpu();
29 sleep_disable();
30}
31
32// TODO: This needs some cleanup
33
34#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
35
36// clang-format off
37#define wdt_intr_enable(value) \
38__asm__ __volatile__ ( \
39 "in __tmp_reg__,__SREG__" "\n\t" \
40 "cli" "\n\t" \
41 "wdr" "\n\t" \
42 "sts %0,%1" "\n\t" \
43 "out __SREG__,__tmp_reg__" "\n\t" \
44 "sts %0,%2" "\n\t" \
45 : /* no outputs */ \
46 : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
47 "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
48 "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | _BV(WDIE) | (value & 0x07))) \
49 : "r0" \
50)
51// clang-format on
52
53/** \brief Power down MCU with watchdog timer
54 *
55 * wdto: watchdog timer timeout defined in <avr/wdt.h>
56 * WDTO_15MS
57 * WDTO_30MS
58 * WDTO_60MS
59 * WDTO_120MS
60 * WDTO_250MS
61 * WDTO_500MS
62 * WDTO_1S
63 * WDTO_2S
64 * WDTO_4S
65 * WDTO_8S
66 */
67static uint8_t wdt_timeout = 0;
68
69/** \brief Power down
70 *
71 * FIXME: needs doc
72 */
73static void power_down(uint8_t wdto) {
74 wdt_timeout = wdto;
75
76 // Watchdog Interrupt Mode
77 wdt_intr_enable(wdto);
78
79 // TODO: more power saving
80 // See PicoPower application note
81 // - I/O port input with pullup
82 // - prescale clock
83 // - BOD disable
84 // - Power Reduction Register PRR
85 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
86 sleep_enable();
87 sei();
88 sleep_cpu();
89 sleep_disable();
90
91 // Disable watchdog after sleep
92 wdt_disable();
93}
94#endif
95
96/** \brief Suspend power down
97 *
98 * FIXME: needs doc
99 */
100void suspend_power_down(void) {
101#ifdef PROTOCOL_LUFA
102 if (USB_DeviceState == DEVICE_STATE_Configured) return;
103#endif
104#ifdef PROTOCOL_VUSB
105 if (!vusb_suspended) return;
106#endif
107
108 suspend_power_down_quantum();
109
110#ifndef NO_SUSPEND_POWER_DOWN
111 // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt)
112# if defined(WDT_vect)
113 power_down(WDTO_15MS);
114# endif
115#endif
116}
117
118__attribute__((weak)) void matrix_power_up(void) {}
119__attribute__((weak)) void matrix_power_down(void) {}
120bool suspend_wakeup_condition(void) {
121 matrix_power_up();
122 matrix_scan();
123 matrix_power_down();
124 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
125 if (matrix_get_row(r)) return true;
126 }
127 return false;
128}
129
130/** \brief run immediately after wakeup
131 *
132 * FIXME: needs doc
133 */
134void suspend_wakeup_init(void) {
135 // clear keyboard state
136 clear_keyboard();
137
138 suspend_wakeup_init_quantum();
139}
140
141#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
142/* watchdog timeout */
143ISR(WDT_vect) {
144 // compensate timer for sleep
145 switch (wdt_timeout) {
146 case WDTO_15MS:
147 timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
148 break;
149 default:;
150 }
151}
152#endif
diff --git a/platforms/avr/timer.c b/platforms/avr/timer.c
new file mode 100644
index 000000000..c2e6c6e08
--- /dev/null
+++ b/platforms/avr/timer.c
@@ -0,0 +1,133 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <avr/io.h>
19#include <avr/interrupt.h>
20#include <util/atomic.h>
21#include <stdint.h>
22#include "timer_avr.h"
23#include "timer.h"
24
25// counter resolution 1ms
26// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
27volatile uint32_t timer_count;
28
29/** \brief timer initialization
30 *
31 * FIXME: needs doc
32 */
33void timer_init(void) {
34#if TIMER_PRESCALER == 1
35 uint8_t prescaler = _BV(CS00);
36#elif TIMER_PRESCALER == 8
37 uint8_t prescaler = _BV(CS01);
38#elif TIMER_PRESCALER == 64
39 uint8_t prescaler = _BV(CS00) | _BV(CS01);
40#elif TIMER_PRESCALER == 256
41 uint8_t prescaler = _BV(CS02);
42#elif TIMER_PRESCALER == 1024
43 uint8_t prescaler = _BV(CS00) | _BV(CS02);
44#else
45# error "Timer prescaler value is not valid"
46#endif
47
48#if defined(__AVR_ATmega32A__)
49 // Timer0 CTC mode
50 TCCR0 = _BV(WGM01) | prescaler;
51
52 OCR0 = TIMER_RAW_TOP;
53 TIMSK = _BV(OCIE0);
54#elif defined(__AVR_ATtiny85__)
55 // Timer0 CTC mode
56 TCCR0A = _BV(WGM01);
57 TCCR0B = prescaler;
58
59 OCR0A = TIMER_RAW_TOP;
60 TIMSK = _BV(OCIE0A);
61#else
62 // Timer0 CTC mode
63 TCCR0A = _BV(WGM01);
64 TCCR0B = prescaler;
65
66 OCR0A = TIMER_RAW_TOP;
67 TIMSK0 = _BV(OCIE0A);
68#endif
69}
70
71/** \brief timer clear
72 *
73 * FIXME: needs doc
74 */
75inline void timer_clear(void) {
76 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; }
77}
78
79/** \brief timer read
80 *
81 * FIXME: needs doc
82 */
83inline uint16_t timer_read(void) {
84 uint32_t t;
85
86 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
87
88 return (t & 0xFFFF);
89}
90
91/** \brief timer read32
92 *
93 * FIXME: needs doc
94 */
95inline uint32_t timer_read32(void) {
96 uint32_t t;
97
98 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
99
100 return t;
101}
102
103/** \brief timer elapsed
104 *
105 * FIXME: needs doc
106 */
107inline uint16_t timer_elapsed(uint16_t last) {
108 uint32_t t;
109
110 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
111
112 return TIMER_DIFF_16((t & 0xFFFF), last);
113}
114
115/** \brief timer elapsed32
116 *
117 * FIXME: needs doc
118 */
119inline uint32_t timer_elapsed32(uint32_t last) {
120 uint32_t t;
121
122 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
123
124 return TIMER_DIFF_32(t, last);
125}
126
127// excecuted once per 1ms.(excess for just timer count?)
128#ifndef __AVR_ATmega32A__
129# define TIMER_INTERRUPT_VECTOR TIMER0_COMPA_vect
130#else
131# define TIMER_INTERRUPT_VECTOR TIMER0_COMP_vect
132#endif
133ISR(TIMER_INTERRUPT_VECTOR, ISR_NOBLOCK) { timer_count++; }
diff --git a/platforms/avr/timer_avr.h b/platforms/avr/timer_avr.h
new file mode 100644
index 000000000..c1b726bd0
--- /dev/null
+++ b/platforms/avr/timer_avr.h
@@ -0,0 +1,39 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21
22#ifndef TIMER_PRESCALER
23# if F_CPU > 16000000
24# define TIMER_PRESCALER 256
25# elif F_CPU > 2000000
26# define TIMER_PRESCALER 64
27# elif F_CPU > 250000
28# define TIMER_PRESCALER 8
29# else
30# define TIMER_PRESCALER 1
31# endif
32#endif
33#define TIMER_RAW_FREQ (F_CPU / TIMER_PRESCALER)
34#define TIMER_RAW TCNT0
35#define TIMER_RAW_TOP (TIMER_RAW_FREQ / 1000)
36
37#if (TIMER_RAW_TOP > 255)
38# error "Timer0 can't count 1ms at this clock freq. Use larger prescaler."
39#endif
diff --git a/platforms/avr/xprintf.S b/platforms/avr/xprintf.S
new file mode 100644
index 000000000..c5a414c35
--- /dev/null
+++ b/platforms/avr/xprintf.S
@@ -0,0 +1,498 @@
1;---------------------------------------------------------------------------;
2; Extended itoa, puts, printf and atoi (C)ChaN, 2011
3;---------------------------------------------------------------------------;
4
5 // Base size is 152 bytes
6#define CR_CRLF 0 // Convert \n to \r\n (+10 bytes)
7#define USE_XPRINTF 1 // Enable xprintf function (+194 bytes)
8#define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes)
9#define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes)
10#define USE_XATOI 0 // Enable xatoi function (+182 bytes)
11
12
13#if FLASHEND > 0x1FFFF
14#error xitoa module does not support 256K devices
15#endif
16
17.nolist
18#include <avr/io.h> // Include device specific definitions.
19.list
20
21#ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw".
22.macro _LPMI reg
23 lpm \reg, Z+
24.endm
25.macro _MOVW dh,dl, sh,sl
26 movw \dl, \sl
27.endm
28#else // Earlier devices do not have "lpm Rd,Z+" nor "movw".
29.macro _LPMI reg
30 lpm
31 mov \reg, r0
32 adiw ZL, 1
33.endm
34.macro _MOVW dh,dl, sh,sl
35 mov \dl, \sl
36 mov \dh, \sh
37.endm
38#endif
39
40
41
42;---------------------------------------------------------------------------
43; Stub function to forward to user output function
44;
45;Prototype: void xputc (char chr // a character to be output
46; );
47;Size: 12/12 words
48
49.section .bss
50.global xfunc_out ; xfunc_out must be initialized before using this module.
51xfunc_out: .ds.w 1
52.section .text
53
54
55.func xputc
56.global xputc
57xputc:
58#if CR_CRLF
59 cpi r24, 10 ;LF --> CRLF
60 brne 1f ;
61 ldi r24, 13 ;
62 rcall 1f ;
63 ldi r24, 10 ;/
641:
65#endif
66 push ZH
67 push ZL
68 lds ZL, xfunc_out+0 ;Pointer to the registered output function.
69 lds ZH, xfunc_out+1 ;/
70 sbiw ZL, 0 ;Skip if null
71 breq 2f ;/
72 icall
732: pop ZL
74 pop ZH
75 ret
76.endfunc
77
78
79
80;---------------------------------------------------------------------------
81; Direct ROM string output
82;
83;Prototype: void xputs (const char *str_p // rom string to be output
84; );
85
86.func xputs
87.global xputs
88xputs:
89 _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string
901: _LPMI r24
91 cpi r24, 0
92 breq 2f
93 rcall xputc
94 rjmp 1b
952: ret
96.endfunc
97
98
99;---------------------------------------------------------------------------
100; Extended direct numeral string output (32bit version)
101;
102;Prototype: void xitoa (long value, // value to be output
103; char radix, // radix
104; char width); // minimum width
105;
106
107.func xitoa
108.global xitoa
109xitoa:
110 ;r25:r22 = value, r20 = base, r18 = digits
111 clr r31 ;r31 = stack level
112 ldi r30, ' ' ;r30 = sign
113 ldi r19, ' ' ;r19 = filler
114 sbrs r20, 7 ;When base indicates signd format and the value
115 rjmp 0f ;is minus, add a '-'.
116 neg r20 ;
117 sbrs r25, 7 ;
118 rjmp 0f ;
119 ldi r30, '-' ;
120 com r22 ;
121 com r23 ;
122 com r24 ;
123 com r25 ;
124 adc r22, r1 ;
125 adc r23, r1 ;
126 adc r24, r1 ;
127 adc r25, r1 ;/
1280: sbrs r18, 7 ;When digits indicates zero filled,
129 rjmp 1f ;filler is '0'.
130 neg r18 ;
131 ldi r19, '0' ;/
132 ;----- string conversion loop
1331: ldi r21, 32 ;r26 = r25:r22 % r20
134 clr r26 ;r25:r22 /= r20
1352: lsl r22 ;
136 rol r23 ;
137 rol r24 ;
138 rol r25 ;
139 rol r26 ;
140 cp r26, r20 ;
141 brcs 3f ;
142 sub r26, r20 ;
143 inc r22 ;
1443: dec r21 ;
145 brne 2b ;/
146 cpi r26, 10 ;r26 is a numeral digit '0'-'F'
147 brcs 4f ;
148 subi r26, -7 ;
1494: subi r26, -'0' ;/
150 push r26 ;Stack it
151 inc r31 ;/
152 cp r22, r1 ;Repeat until r25:r22 gets zero
153 cpc r23, r1 ;
154 cpc r24, r1 ;
155 cpc r25, r1 ;
156 brne 1b ;/
157
158 cpi r30, '-' ;Minus sign if needed
159 brne 5f ;
160 push r30 ;
161 inc r31 ;/
1625: cp r31, r18 ;Filler
163 brcc 6f ;
164 push r19 ;
165 inc r31 ;
166 rjmp 5b ;/
167
1686: pop r24 ;Flush stacked digits and exit
169 rcall xputc ;
170 dec r31 ;
171 brne 6b ;/
172
173 ret
174.endfunc
175
176
177
178;---------------------------------------------------------------------------;
179; Formatted string output (16/32bit version)
180;
181;Prototype:
182; void __xprintf (const char *format_p, ...);
183; void __xsprintf(char*, const char *format_p, ...);
184; void __xfprintf(void(*func)(char), const char *format_p, ...);
185;
186
187#if USE_XPRINTF
188
189.func xvprintf
190xvprintf:
191 ld ZL, Y+ ;Z = pointer to format string
192 ld ZH, Y+ ;/
193
1940: _LPMI r24 ;Get a format char
195 cpi r24, 0 ;End of format string?
196 breq 90f ;/
197 cpi r24, '%' ;Is format?
198 breq 20f ;/
1991: rcall xputc ;Put a normal character
200 rjmp 0b ;/
20190: ret
202
20320: ldi r18, 0 ;r18: digits
204 clt ;T: filler
205 _LPMI r21 ;Get flags
206 cpi r21, '%' ;Is a %?
207 breq 1b ;/
208 cpi r21, '0' ;Zero filled?
209 brne 23f ;
210 set ;/
21122: _LPMI r21 ;Get width
21223: cpi r21, '9'+1 ;
213 brcc 24f ;
214 subi r21, '0' ;
215 brcs 90b ;
216 lsl r18 ;
217 mov r0, r18 ;
218 lsl r18 ;
219 lsl r18 ;
220 add r18, r0 ;
221 add r18, r21 ;
222 rjmp 22b ;/
223
22424: brtc 25f ;get value (low word)
225 neg r18 ;
22625: ld r24, Y+ ;
227 ld r25, Y+ ;/
228 cpi r21, 'c' ;Is type character?
229 breq 1b ;/
230 cpi r21, 's' ;Is type RAM string?
231 breq 50f ;/
232 cpi r21, 'S' ;Is type ROM string?
233 breq 60f ;/
234 _MOVW r23,r22,r25,r24 ;r25:r22 = value
235 clr r24 ;
236 clr r25 ;
237 clt ;/
238 cpi r21, 'l' ;Is long int?
239 brne 26f ;
240 ld r24, Y+ ;get value (high word)
241 ld r25, Y+ ;
242 set ;
243 _LPMI r21 ;/
24426: cpi r21, 'd' ;Is type signed decimal?
245 brne 27f ;/
246 ldi r20, -10 ;
247 brts 40f ;
248 sbrs r23, 7 ;
249 rjmp 40f ;
250 ldi r24, -1 ;
251 ldi r25, -1 ;
252 rjmp 40f ;/
25327: cpi r21, 'u' ;Is type unsigned decimal?
254 ldi r20, 10 ;
255 breq 40f ;/
256 cpi r21, 'X' ;Is type hexdecimal?
257 ldi r20, 16 ;
258 breq 40f ;/
259 cpi r21, 'b' ;Is type binary?
260 ldi r20, 2 ;
261 breq 40f ;/
262 ret ;abort
26340: push ZH ;Output the value
264 push ZL ;
265 rcall xitoa ;
26642: pop ZL ;
267 pop ZH ;
268 rjmp 0b ;/
269
27050: push ZH ;Put a string on the RAM
271 push ZL
272 _MOVW ZH,ZL, r25,r24
27351: ld r24, Z+
274 cpi r24, 0
275 breq 42b
276 rcall xputc
277 rjmp 51b
278
27960: push ZH ;Put a string on the ROM
280 push ZL
281 rcall xputs
282 rjmp 42b
283.endfunc
284
285
286.func __xprintf
287.global __xprintf
288__xprintf:
289 push YH
290 push YL
291 in YL, _SFR_IO_ADDR(SPL)
292#ifdef SPH
293 in YH, _SFR_IO_ADDR(SPH)
294#else
295 clr YH
296#endif
297 adiw YL, 5 ;Y = pointer to arguments
298 rcall xvprintf
299 pop YL
300 pop YH
301 ret
302.endfunc
303
304
305#if USE_XSPRINTF
306
307.func __xsprintf
308putram:
309 _MOVW ZH,ZL, r15,r14
310 st Z+, r24
311 _MOVW r15,r14, ZH,ZL
312 ret
313.global __xsprintf
314__xsprintf:
315 push YH
316 push YL
317 in YL, _SFR_IO_ADDR(SPL)
318#ifdef SPH
319 in YH, _SFR_IO_ADDR(SPH)
320#else
321 clr YH
322#endif
323 adiw YL, 5 ;Y = pointer to arguments
324 lds ZL, xfunc_out+0 ;Save registered output function
325 lds ZH, xfunc_out+1 ;
326 push ZL ;
327 push ZH ;/
328 ldi ZL, lo8(pm(putram));Set local output function
329 ldi ZH, hi8(pm(putram));
330 sts xfunc_out+0, ZL ;
331 sts xfunc_out+1, ZH ;/
332 push r15 ;Initialize pointer to string buffer
333 push r14 ;
334 ld r14, Y+ ;
335 ld r15, Y+ ;/
336 rcall xvprintf
337 _MOVW ZH,ZL, r15,r14 ;Terminate string
338 st Z, r1 ;
339 pop r14 ;
340 pop r15 ;/
341 pop ZH ;Restore registered output function
342 pop ZL ;
343 sts xfunc_out+0, ZL ;
344 sts xfunc_out+1, ZH ;/
345 pop YL
346 pop YH
347 ret
348.endfunc
349#endif
350
351
352#if USE_XFPRINTF
353.func __xfprintf
354.global __xfprintf
355__xfprintf:
356 push YH
357 push YL
358 in YL, _SFR_IO_ADDR(SPL)
359#ifdef SPH
360 in YH, _SFR_IO_ADDR(SPH)
361#else
362 clr YH
363#endif
364 adiw YL, 5 ;Y = pointer to arguments
365 lds ZL, xfunc_out+0 ;Save registered output function
366 lds ZH, xfunc_out+1 ;
367 push ZL ;
368 push ZH ;/
369 ld ZL, Y+ ;Set output function
370 ld ZH, Y+ ;
371 sts xfunc_out+0, ZL ;
372 sts xfunc_out+1, ZH ;/
373 rcall xvprintf
374 pop ZH ;Restore registered output function
375 pop ZL ;
376 sts xfunc_out+0, ZL ;
377 sts xfunc_out+1, ZH ;/
378 pop YL
379 pop YH
380 ret
381.endfunc
382#endif
383
384#endif
385
386
387
388;---------------------------------------------------------------------------
389; Extended numeral string input
390;
391;Prototype:
392; char xatoi ( /* 1: Successful, 0: Failed */
393; const char **str, /* pointer to pointer to source string */
394; long *res /* result */
395; );
396;
397
398
399#if USE_XATOI
400.func xatoi
401.global xatoi
402xatoi:
403 _MOVW r1, r0, r23, r22
404 _MOVW XH, XL, r25, r24
405 ld ZL, X+
406 ld ZH, X+
407 clr r18 ;r21:r18 = 0;
408 clr r19 ;
409 clr r20 ;
410 clr r21 ;/
411 clt ;T = 0;
412
413 ldi r25, 10 ;r25 = 10;
414 rjmp 41f ;/
41540: adiw ZL, 1 ;Z++;
41641: ld r22, Z ;r22 = *Z;
417 cpi r22, ' ' ;if(r22 == ' ') continue
418 breq 40b ;/
419 brcs 70f ;if(r22 < ' ') error;
420 cpi r22, '-' ;if(r22 == '-') {
421 brne 42f ; T = 1;
422 set ; continue;
423 rjmp 40b ;}
42442: cpi r22, '9'+1 ;if(r22 > '9') error;
425 brcc 70f ;/
426 cpi r22, '0' ;if(r22 < '0') error;
427 brcs 70f ;/
428 brne 51f ;if(r22 > '0') cv_start;
429 ldi r25, 8 ;r25 = 8;
430 adiw ZL, 1 ;r22 = *(++Z);
431 ld r22, Z ;/
432 cpi r22, ' '+1 ;if(r22 <= ' ') exit;
433 brcs 80f ;/
434 cpi r22, 'b' ;if(r22 == 'b') {
435 brne 43f ; r25 = 2;
436 ldi r25, 2 ; cv_start;
437 rjmp 50f ;}
43843: cpi r22, 'x' ;if(r22 != 'x') error;
439 brne 51f ;/
440 ldi r25, 16 ;r25 = 16;
441
44250: adiw ZL, 1 ;Z++;
443 ld r22, Z ;r22 = *Z;
44451: cpi r22, ' '+1 ;if(r22 <= ' ') break;
445 brcs 80f ;/
446 cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20;
447 brcs 52f ;
448 subi r22, 0x20 ;/
44952: subi r22, '0' ;if((r22 -= '0') < 0) error;
450 brcs 70f ;/
451 cpi r22, 10 ;if(r22 >= 10) {
452 brcs 53f ; r22 -= 7;
453 subi r22, 7 ; if(r22 < 10)
454 cpi r22, 10 ;
455 brcs 70f ;}
45653: cp r22, r25 ;if(r22 >= r25) error;
457 brcc 70f ;/
45860: ldi r24, 33 ;r21:r18 *= r25;
459 sub r23, r23 ;
46061: brcc 62f ;
461 add r23, r25 ;
46262: lsr r23 ;
463 ror r21 ;
464 ror r20 ;
465 ror r19 ;
466 ror r18 ;
467 dec r24 ;
468 brne 61b ;/
469 add r18, r22 ;r21:r18 += r22;
470 adc r19, r24 ;
471 adc r20, r24 ;
472 adc r21, r24 ;/
473 rjmp 50b ;repeat
474
47570: ldi r24, 0
476 rjmp 81f
47780: ldi r24, 1
47881: brtc 82f
479 clr r22
480 com r18
481 com r19
482 com r20
483 com r21
484 adc r18, r22
485 adc r19, r22
486 adc r20, r22
487 adc r21, r22
48882: st -X, ZH
489 st -X, ZL
490 _MOVW XH, XL, r1, r0
491 st X+, r18
492 st X+, r19
493 st X+, r20
494 st X+, r21
495 clr r1
496 ret
497.endfunc
498#endif
diff --git a/platforms/avr/xprintf.h b/platforms/avr/xprintf.h
new file mode 100644
index 000000000..80834f171
--- /dev/null
+++ b/platforms/avr/xprintf.h
@@ -0,0 +1,103 @@
1/*---------------------------------------------------------------------------
2 Extended itoa, puts and printf (C)ChaN, 2011
3-----------------------------------------------------------------------------*/
4
5#pragma once
6
7#include <inttypes.h>
8#include <avr/pgmspace.h>
9
10#ifdef __cplusplus
11extern "C" {
12#endif
13
14extern void (*xfunc_out)(uint8_t);
15#define xdev_out(func) xfunc_out = (void (*)(uint8_t))(func)
16
17/* This is a pointer to user defined output function. It must be initialized
18 before using this modle.
19*/
20
21void xputc(char chr);
22
23/* This is a stub function to forward outputs to user defined output function.
24 All outputs from this module are output via this function.
25*/
26
27/*-----------------------------------------------------------------------------*/
28void xputs(const char *string_p);
29
30/* The string placed in the ROM is forwarded to xputc() directly.
31 */
32
33/*-----------------------------------------------------------------------------*/
34void xitoa(long value, char radix, char width);
35
36/* Extended itoa().
37
38 value radix width output
39 100 10 6 " 100"
40 100 10 -6 "000100"
41 100 10 0 "100"
42 4294967295 10 0 "4294967295"
43 4294967295 -10 0 "-1"
44 655360 16 -8 "000A0000"
45 1024 16 0 "400"
46 0x55 2 -8 "01010101"
47*/
48
49/*-----------------------------------------------------------------------------*/
50#define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__)
51#define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__)
52#define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__)
53
54void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */
55// void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */
56// void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */
57
58/* Format string is placed in the ROM. The format flags is similar to printf().
59
60 %[flag][width][size]type
61
62 flag
63 A '0' means filled with '0' when output is shorter than width.
64 ' ' is used in default. This is effective only numeral type.
65 width
66 Minimum width in decimal number. This is effective only numeral type.
67 Default width is zero.
68 size
69 A 'l' means the argument is long(32bit). Default is short(16bit).
70 This is effective only numeral type.
71 type
72 'c' : Character, argument is the value
73 's' : String placed on the RAM, argument is the pointer
74 'S' : String placed on the ROM, argument is the pointer
75 'd' : Signed decimal, argument is the value
76 'u' : Unsigned decimal, argument is the value
77 'X' : Hexdecimal, argument is the value
78 'b' : Binary, argument is the value
79 '%' : '%'
80
81*/
82
83/*-----------------------------------------------------------------------------*/
84char xatoi(char **str, long *ret);
85
86/* Get value of the numeral string.
87
88 str
89 Pointer to pointer to source string
90
91 "0b11001010" binary
92 "0377" octal
93 "0xff800" hexdecimal
94 "1250000" decimal
95 "-25000" decimal
96
97 ret
98 Pointer to return value
99*/
100
101#ifdef __cplusplus
102}
103#endif