diff options
| author | Joel Challis <git@zvecr.com> | 2021-11-19 18:41:02 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-19 10:41:02 -0800 |
| commit | 2728603fe6d73e805a539d337fd01051c46ca806 (patch) | |
| tree | 5c83ffc7efa112da870bd5d8502a9d91d4792f35 /platforms/avr | |
| parent | 43b9e23bae12916d5161f03700c9bfe46737324b (diff) | |
| download | qmk_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.h | 33 | ||||
| -rw-r--r-- | platforms/avr/_timer.h | 19 | ||||
| -rw-r--r-- | platforms/avr/_wait.h | 49 | ||||
| -rw-r--r-- | platforms/avr/atomic_util.h | 22 | ||||
| -rw-r--r-- | platforms/avr/bootloader.c | 293 | ||||
| -rw-r--r-- | platforms/avr/bootloader_size.c | 21 | ||||
| -rw-r--r-- | platforms/avr/gpio.h | 49 | ||||
| -rw-r--r-- | platforms/avr/pin_defs.h | 128 | ||||
| -rw-r--r-- | platforms/avr/platform.c | 21 | ||||
| -rw-r--r-- | platforms/avr/platform.mk | 179 | ||||
| -rw-r--r-- | platforms/avr/platform_deps.h | 20 | ||||
| -rw-r--r-- | platforms/avr/printf.c | 20 | ||||
| -rw-r--r-- | platforms/avr/printf.mk | 2 | ||||
| -rw-r--r-- | platforms/avr/sleep_led.c | 124 | ||||
| -rw-r--r-- | platforms/avr/suspend.c | 152 | ||||
| -rw-r--r-- | platforms/avr/timer.c | 133 | ||||
| -rw-r--r-- | platforms/avr/timer_avr.h | 39 | ||||
| -rw-r--r-- | platforms/avr/xprintf.S | 498 | ||||
| -rw-r--r-- | platforms/avr/xprintf.h | 103 |
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) | ||
| 59 | uint16_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 | ||
| 74 | uint32_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() */ | ||
| 272 | void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3"))); | ||
| 273 | void 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 | ||
| 21 | AVR_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 | |||
| 21 | typedef 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 | |||
| 40 | typedef 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 | |||
| 19 | void 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 | # | ||
| 5 | CC = $(CC_PREFIX) avr-gcc | ||
| 6 | OBJCOPY = avr-objcopy | ||
| 7 | OBJDUMP = avr-objdump | ||
| 8 | SIZE = avr-size | ||
| 9 | AR = avr-ar | ||
| 10 | NM = avr-nm | ||
| 11 | HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature | ||
| 12 | EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) | ||
| 13 | BIN = | ||
| 14 | |||
| 15 | COMPILEFLAGS += -funsigned-char | ||
| 16 | COMPILEFLAGS += -funsigned-bitfields | ||
| 17 | COMPILEFLAGS += -ffunction-sections | ||
| 18 | COMPILEFLAGS += -fdata-sections | ||
| 19 | COMPILEFLAGS += -fpack-struct | ||
| 20 | COMPILEFLAGS += -fshort-enums | ||
| 21 | |||
| 22 | ASFLAGS += $(AVR_ASFLAGS) | ||
| 23 | |||
| 24 | CFLAGS += $(COMPILEFLAGS) $(AVR_CFLAGS) | ||
| 25 | CFLAGS += -fno-inline-small-functions | ||
| 26 | CFLAGS += -fno-strict-aliasing | ||
| 27 | |||
| 28 | CXXFLAGS += $(COMPILEFLAGS) | ||
| 29 | CXXFLAGS += -fno-exceptions -std=c++11 | ||
| 30 | |||
| 31 | LDFLAGS +=-Wl,--gc-sections | ||
| 32 | |||
| 33 | OPT_DEFS += -DF_CPU=$(F_CPU)UL | ||
| 34 | |||
| 35 | MCUFLAGS = -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. | ||
| 41 | EXTRALIBDIRS = | ||
| 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 | |||
| 54 | EXTMEMOPTS = | ||
| 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. | ||
| 62 | DEBUG = dwarf-2 | ||
| 63 | |||
| 64 | # For simulavr only - target MCU frequency. | ||
| 65 | DEBUG_MFREQ = $(F_CPU) | ||
| 66 | |||
| 67 | # Set the DEBUG_UI to either gdb or insight. | ||
| 68 | # DEBUG_UI = gdb | ||
| 69 | DEBUG_UI = insight | ||
| 70 | |||
| 71 | # Set the debugging back-end to either avarice, simulavr. | ||
| 72 | DEBUG_BACKEND = avarice | ||
| 73 | #DEBUG_BACKEND = simulavr | ||
| 74 | |||
| 75 | # GDB Init Filename. | ||
| 76 | GDBINIT_FILE = __avr_gdbinit | ||
| 77 | |||
| 78 | # When using avarice settings for the JTAG | ||
| 79 | JTAG_DEV = /dev/com1 | ||
| 80 | |||
| 81 | # Debugging port used to communicate between GDB / avarice / simulavr. | ||
| 82 | DEBUG_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. | ||
| 87 | DEBUG_HOST = localhost | ||
| 88 | |||
| 89 | #============================================================================ | ||
| 90 | |||
| 91 | # Convert hex to bin. | ||
| 92 | bin: $(BUILD_DIR)/$(TARGET).hex | ||
| 93 | ifeq ($(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) | ||
| 96 | else | ||
| 97 | $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin | ||
| 98 | endif | ||
| 99 | $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; | ||
| 100 | |||
| 101 | # copy bin to FLASH.bin | ||
| 102 | flashbin: 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(). | ||
| 108 | gdb-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) | ||
| 115 | ifeq ($(DEBUG_BACKEND),simulavr) | ||
| 116 | @echo load >> $(GDBINIT_FILE) | ||
| 117 | endif | ||
| 118 | @echo break main >> $(GDBINIT_FILE) | ||
| 119 | |||
| 120 | debug: gdb-config $(BUILD_DIR)/$(TARGET).elf | ||
| 121 | ifeq ($(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 | |||
| 127 | else | ||
| 128 | @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ | ||
| 129 | $(DEBUG_MFREQ) --port $(DEBUG_PORT) | ||
| 130 | endif | ||
| 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. | ||
| 137 | COFFCONVERT = $(OBJCOPY) --debugging | ||
| 138 | COFFCONVERT += --change-section-address .data-0x800000 | ||
| 139 | COFFCONVERT += --change-section-address .bss-0x800000 | ||
| 140 | COFFCONVERT += --change-section-address .noinit-0x800000 | ||
| 141 | COFFCONVERT += --change-section-address .eeprom-0x810000 | ||
| 142 | |||
| 143 | |||
| 144 | |||
| 145 | coff: $(BUILD_DIR)/$(TARGET).elf | ||
| 146 | @$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof | ||
| 147 | $(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof | ||
| 148 | |||
| 149 | |||
| 150 | extcoff: $(BUILD_DIR)/$(TARGET).elf | ||
| 151 | @$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof | ||
| 152 | $(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof | ||
| 153 | |||
| 154 | ifeq ($(strip $(BOOTLOADER)), qmk-dfu) | ||
| 155 | QMK_BOOTLOADER_TYPE = DFU | ||
| 156 | else ifeq ($(strip $(BOOTLOADER)), qmk-hid) | ||
| 157 | QMK_BOOTLOADER_TYPE = HID | ||
| 158 | endif | ||
| 159 | |||
| 160 | bootloader: | ||
| 161 | ifeq ($(strip $(QMK_BOOTLOADER_TYPE)),) | ||
| 162 | $(error Please set BOOTLOADER to "qmk-dfu" or "qmk-hid" first!) | ||
| 163 | else | ||
| 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 | ||
| 173 | endif | ||
| 174 | |||
| 175 | production: $(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 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #include "xprintf.h" | ||
| 18 | #include "sendchar.h" | ||
| 19 | |||
| 20 | void 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 @@ | |||
| 1 | TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S | ||
| 2 | TMK_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 | ||
| 29 | error("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 | */ | ||
| 49 | void 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 | */ | ||
| 66 | void 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 | */ | ||
| 75 | void 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 | */ | ||
| 84 | void 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 | */ | ||
| 96 | static 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 | |||
| 98 | ISR(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 | */ | ||
| 23 | void 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 | */ | ||
| 67 | static uint8_t wdt_timeout = 0; | ||
| 68 | |||
| 69 | /** \brief Power down | ||
| 70 | * | ||
| 71 | * FIXME: needs doc | ||
| 72 | */ | ||
| 73 | static 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 | */ | ||
| 100 | void 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) {} | ||
| 120 | bool 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 | */ | ||
| 134 | void 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 */ | ||
| 143 | ISR(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 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along 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; }} | ||
| 27 | volatile uint32_t timer_count; | ||
| 28 | |||
| 29 | /** \brief timer initialization | ||
| 30 | * | ||
| 31 | * FIXME: needs doc | ||
| 32 | */ | ||
| 33 | void 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 | */ | ||
| 75 | inline void timer_clear(void) { | ||
| 76 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; } | ||
| 77 | } | ||
| 78 | |||
| 79 | /** \brief timer read | ||
| 80 | * | ||
| 81 | * FIXME: needs doc | ||
| 82 | */ | ||
| 83 | inline 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 | */ | ||
| 95 | inline 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 | */ | ||
| 107 | inline 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 | */ | ||
| 119 | inline 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 | ||
| 133 | ISR(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 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along 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. | ||
| 51 | xfunc_out: .ds.w 1 | ||
| 52 | .section .text | ||
| 53 | |||
| 54 | |||
| 55 | .func xputc | ||
| 56 | .global xputc | ||
| 57 | xputc: | ||
| 58 | #if CR_CRLF | ||
| 59 | cpi r24, 10 ;LF --> CRLF | ||
| 60 | brne 1f ; | ||
| 61 | ldi r24, 13 ; | ||
| 62 | rcall 1f ; | ||
| 63 | ldi r24, 10 ;/ | ||
| 64 | 1: | ||
| 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 | ||
| 73 | 2: 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 | ||
| 88 | xputs: | ||
| 89 | _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string | ||
| 90 | 1: _LPMI r24 | ||
| 91 | cpi r24, 0 | ||
| 92 | breq 2f | ||
| 93 | rcall xputc | ||
| 94 | rjmp 1b | ||
| 95 | 2: 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 | ||
| 109 | xitoa: | ||
| 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 ;/ | ||
| 128 | 0: 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 | ||
| 133 | 1: ldi r21, 32 ;r26 = r25:r22 % r20 | ||
| 134 | clr r26 ;r25:r22 /= r20 | ||
| 135 | 2: 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 ; | ||
| 144 | 3: dec r21 ; | ||
| 145 | brne 2b ;/ | ||
| 146 | cpi r26, 10 ;r26 is a numeral digit '0'-'F' | ||
| 147 | brcs 4f ; | ||
| 148 | subi r26, -7 ; | ||
| 149 | 4: 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 ;/ | ||
| 162 | 5: cp r31, r18 ;Filler | ||
| 163 | brcc 6f ; | ||
| 164 | push r19 ; | ||
| 165 | inc r31 ; | ||
| 166 | rjmp 5b ;/ | ||
| 167 | |||
| 168 | 6: 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 | ||
| 190 | xvprintf: | ||
| 191 | ld ZL, Y+ ;Z = pointer to format string | ||
| 192 | ld ZH, Y+ ;/ | ||
| 193 | |||
| 194 | 0: _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 ;/ | ||
| 199 | 1: rcall xputc ;Put a normal character | ||
| 200 | rjmp 0b ;/ | ||
| 201 | 90: ret | ||
| 202 | |||
| 203 | 20: 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 ;/ | ||
| 211 | 22: _LPMI r21 ;Get width | ||
| 212 | 23: 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 | |||
| 224 | 24: brtc 25f ;get value (low word) | ||
| 225 | neg r18 ; | ||
| 226 | 25: 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 ;/ | ||
| 244 | 26: 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 ;/ | ||
| 253 | 27: 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 | ||
| 263 | 40: push ZH ;Output the value | ||
| 264 | push ZL ; | ||
| 265 | rcall xitoa ; | ||
| 266 | 42: pop ZL ; | ||
| 267 | pop ZH ; | ||
| 268 | rjmp 0b ;/ | ||
| 269 | |||
| 270 | 50: push ZH ;Put a string on the RAM | ||
| 271 | push ZL | ||
| 272 | _MOVW ZH,ZL, r25,r24 | ||
| 273 | 51: ld r24, Z+ | ||
| 274 | cpi r24, 0 | ||
| 275 | breq 42b | ||
| 276 | rcall xputc | ||
| 277 | rjmp 51b | ||
| 278 | |||
| 279 | 60: 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 | ||
| 308 | putram: | ||
| 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 | ||
| 402 | xatoi: | ||
| 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 ;/ | ||
| 415 | 40: adiw ZL, 1 ;Z++; | ||
| 416 | 41: 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 ;} | ||
| 424 | 42: 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 ;} | ||
| 438 | 43: cpi r22, 'x' ;if(r22 != 'x') error; | ||
| 439 | brne 51f ;/ | ||
| 440 | ldi r25, 16 ;r25 = 16; | ||
| 441 | |||
| 442 | 50: adiw ZL, 1 ;Z++; | ||
| 443 | ld r22, Z ;r22 = *Z; | ||
| 444 | 51: 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 ;/ | ||
| 449 | 52: 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 ;} | ||
| 456 | 53: cp r22, r25 ;if(r22 >= r25) error; | ||
| 457 | brcc 70f ;/ | ||
| 458 | 60: ldi r24, 33 ;r21:r18 *= r25; | ||
| 459 | sub r23, r23 ; | ||
| 460 | 61: brcc 62f ; | ||
| 461 | add r23, r25 ; | ||
| 462 | 62: 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 | |||
| 475 | 70: ldi r24, 0 | ||
| 476 | rjmp 81f | ||
| 477 | 80: ldi r24, 1 | ||
| 478 | 81: 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 | ||
| 488 | 82: 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 | ||
| 11 | extern "C" { | ||
| 12 | #endif | ||
| 13 | |||
| 14 | extern 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 | |||
| 21 | void 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 | /*-----------------------------------------------------------------------------*/ | ||
| 28 | void xputs(const char *string_p); | ||
| 29 | |||
| 30 | /* The string placed in the ROM is forwarded to xputc() directly. | ||
| 31 | */ | ||
| 32 | |||
| 33 | /*-----------------------------------------------------------------------------*/ | ||
| 34 | void 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 | |||
| 54 | void __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 | /*-----------------------------------------------------------------------------*/ | ||
| 84 | char 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 | ||
