From 2728603fe6d73e805a539d337fd01051c46ca806 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Fri, 19 Nov 2021 18:41:02 +0000 Subject: Move tmk_core/common/ (#13918) --- platforms/arm_atsam/_timer.h | 19 + platforms/arm_atsam/_wait.h | 22 + platforms/arm_atsam/atomic_util.h | 37 ++ platforms/arm_atsam/bootloader.c | 57 +++ platforms/arm_atsam/eeprom.c | 184 ++++++++ platforms/arm_atsam/gpio.h | 77 ++++ platforms/arm_atsam/pin_defs.h | 84 ++++ platforms/arm_atsam/platform.c | 21 + platforms/arm_atsam/platform.mk | 67 +++ platforms/arm_atsam/platform_deps.h | 18 + platforms/arm_atsam/suspend.c | 77 ++++ platforms/arm_atsam/timer.c | 19 + platforms/atomic_util.h | 32 ++ platforms/avr/_print.h | 33 ++ platforms/avr/_timer.h | 19 + platforms/avr/_wait.h | 49 ++ platforms/avr/atomic_util.h | 22 + platforms/avr/bootloader.c | 293 ++++++++++++ platforms/avr/bootloader_size.c | 21 + platforms/avr/gpio.h | 49 ++ platforms/avr/pin_defs.h | 128 +++++ platforms/avr/platform.c | 21 + platforms/avr/platform.mk | 179 +++++++ platforms/avr/platform_deps.h | 20 + platforms/avr/printf.c | 20 + platforms/avr/printf.mk | 2 + platforms/avr/sleep_led.c | 124 +++++ platforms/avr/suspend.c | 152 ++++++ platforms/avr/timer.c | 133 ++++++ platforms/avr/timer_avr.h | 39 ++ platforms/avr/xprintf.S | 498 ++++++++++++++++++++ platforms/avr/xprintf.h | 103 +++++ platforms/bootloader.h | 21 + platforms/chibios/_timer.h | 19 + platforms/chibios/_wait.c | 89 ++++ platforms/chibios/_wait.h | 60 +++ platforms/chibios/atomic_util.h | 37 ++ platforms/chibios/bootloader.c | 145 ++++++ platforms/chibios/chibios_config.h | 78 ++++ platforms/chibios/eeprom_stm32.c | 687 +++++++++++++++++++++++++++ platforms/chibios/eeprom_stm32.h | 33 ++ platforms/chibios/eeprom_stm32_defs.h | 74 +++ platforms/chibios/eeprom_teensy.c | 795 ++++++++++++++++++++++++++++++++ platforms/chibios/flash_stm32.c | 208 +++++++++ platforms/chibios/flash_stm32.h | 44 ++ platforms/chibios/gd32v_compatibility.h | 120 +++++ platforms/chibios/gpio.h | 50 ++ platforms/chibios/pin_defs.h | 323 +++++++++++++ platforms/chibios/platform.c | 22 + platforms/chibios/platform.mk | 436 ++++++++++++++++++ platforms/chibios/platform_deps.h | 19 + platforms/chibios/sleep_led.c | 192 ++++++++ platforms/chibios/suspend.c | 92 ++++ platforms/chibios/syscall-fallbacks.c | 110 +++++ platforms/chibios/timer.c | 47 ++ platforms/chibios/wait.c | 41 ++ platforms/common.mk | 12 + platforms/eeprom.h | 21 + platforms/gpio.h | 22 + platforms/pin_defs.h | 23 + platforms/progmem.h | 19 + platforms/sleep_led.h | 17 + platforms/suspend.h | 20 + platforms/test/_wait.h | 22 + platforms/test/bootloader.c | 19 + platforms/test/eeprom.c | 95 ++++ platforms/test/eeprom_stm32_tests.cpp | 438 ++++++++++++++++++ platforms/test/flash_stm32_mock.c | 49 ++ platforms/test/hal.h | 18 + platforms/test/platform.c | 21 + platforms/test/platform.h | 18 + platforms/test/platform.mk | 34 ++ platforms/test/platform_deps.h | 18 + platforms/test/rules.mk | 24 + platforms/test/suspend.c | 15 + platforms/test/testlist.mk | 1 + platforms/test/timer.c | 33 ++ platforms/timer.h | 67 +++ platforms/wait.h | 30 ++ 79 files changed, 7397 insertions(+) create mode 100644 platforms/arm_atsam/_timer.h create mode 100644 platforms/arm_atsam/_wait.h create mode 100644 platforms/arm_atsam/atomic_util.h create mode 100644 platforms/arm_atsam/bootloader.c create mode 100644 platforms/arm_atsam/eeprom.c create mode 100644 platforms/arm_atsam/gpio.h create mode 100644 platforms/arm_atsam/pin_defs.h create mode 100644 platforms/arm_atsam/platform.c create mode 100644 platforms/arm_atsam/platform.mk create mode 100644 platforms/arm_atsam/platform_deps.h create mode 100644 platforms/arm_atsam/suspend.c create mode 100644 platforms/arm_atsam/timer.c create mode 100644 platforms/atomic_util.h create mode 100644 platforms/avr/_print.h create mode 100644 platforms/avr/_timer.h create mode 100644 platforms/avr/_wait.h create mode 100644 platforms/avr/atomic_util.h create mode 100644 platforms/avr/bootloader.c create mode 100644 platforms/avr/bootloader_size.c create mode 100644 platforms/avr/gpio.h create mode 100644 platforms/avr/pin_defs.h create mode 100644 platforms/avr/platform.c create mode 100644 platforms/avr/platform.mk create mode 100644 platforms/avr/platform_deps.h create mode 100644 platforms/avr/printf.c create mode 100644 platforms/avr/printf.mk create mode 100644 platforms/avr/sleep_led.c create mode 100644 platforms/avr/suspend.c create mode 100644 platforms/avr/timer.c create mode 100644 platforms/avr/timer_avr.h create mode 100644 platforms/avr/xprintf.S create mode 100644 platforms/avr/xprintf.h create mode 100644 platforms/bootloader.h create mode 100644 platforms/chibios/_timer.h create mode 100644 platforms/chibios/_wait.c create mode 100644 platforms/chibios/_wait.h create mode 100644 platforms/chibios/atomic_util.h create mode 100644 platforms/chibios/bootloader.c create mode 100644 platforms/chibios/chibios_config.h create mode 100644 platforms/chibios/eeprom_stm32.c create mode 100644 platforms/chibios/eeprom_stm32.h create mode 100644 platforms/chibios/eeprom_stm32_defs.h create mode 100644 platforms/chibios/eeprom_teensy.c create mode 100644 platforms/chibios/flash_stm32.c create mode 100644 platforms/chibios/flash_stm32.h create mode 100644 platforms/chibios/gd32v_compatibility.h create mode 100644 platforms/chibios/gpio.h create mode 100644 platforms/chibios/pin_defs.h create mode 100644 platforms/chibios/platform.c create mode 100644 platforms/chibios/platform.mk create mode 100644 platforms/chibios/platform_deps.h create mode 100644 platforms/chibios/sleep_led.c create mode 100644 platforms/chibios/suspend.c create mode 100644 platforms/chibios/syscall-fallbacks.c create mode 100644 platforms/chibios/timer.c create mode 100644 platforms/chibios/wait.c create mode 100644 platforms/common.mk create mode 100644 platforms/eeprom.h create mode 100644 platforms/gpio.h create mode 100644 platforms/pin_defs.h create mode 100644 platforms/progmem.h create mode 100644 platforms/sleep_led.h create mode 100644 platforms/suspend.h create mode 100644 platforms/test/_wait.h create mode 100644 platforms/test/bootloader.c create mode 100644 platforms/test/eeprom.c create mode 100644 platforms/test/eeprom_stm32_tests.cpp create mode 100644 platforms/test/flash_stm32_mock.c create mode 100644 platforms/test/hal.h create mode 100644 platforms/test/platform.c create mode 100644 platforms/test/platform.h create mode 100644 platforms/test/platform.mk create mode 100644 platforms/test/platform_deps.h create mode 100644 platforms/test/rules.mk create mode 100644 platforms/test/suspend.c create mode 100644 platforms/test/testlist.mk create mode 100644 platforms/test/timer.c create mode 100644 platforms/timer.h create mode 100644 platforms/wait.h (limited to 'platforms') diff --git a/platforms/arm_atsam/_timer.h b/platforms/arm_atsam/_timer.h new file mode 100644 index 0000000000..77402b612a --- /dev/null +++ b/platforms/arm_atsam/_timer.h @@ -0,0 +1,19 @@ +/* Copyright 2021 Simon Arlott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +// The platform is 32-bit, so prefer 32-bit timers to avoid overflow +#define FAST_TIMER_T_SIZE 32 diff --git a/platforms/arm_atsam/_wait.h b/platforms/arm_atsam/_wait.h new file mode 100644 index 0000000000..41b686b56c --- /dev/null +++ b/platforms/arm_atsam/_wait.h @@ -0,0 +1,22 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "clks.h" + +#define wait_ms(ms) CLK_delay_ms(ms) +#define wait_us(us) CLK_delay_us(us) +#define waitInputPinDelay() diff --git a/platforms/arm_atsam/atomic_util.h b/platforms/arm_atsam/atomic_util.h new file mode 100644 index 0000000000..848542d23a --- /dev/null +++ b/platforms/arm_atsam/atomic_util.h @@ -0,0 +1,37 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "samd51j18a.h" + +static __inline__ uint8_t __interrupt_disable__(void) { + __disable_irq(); + + return 1; +} + +static __inline__ void __interrupt_enable__(const uint8_t *__s) { + __enable_irq(); + + __asm__ volatile("" ::: "memory"); + (void)__s; +} + +#define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0) +#define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0 + +#define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented") +#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON) diff --git a/platforms/arm_atsam/bootloader.c b/platforms/arm_atsam/bootloader.c new file mode 100644 index 0000000000..9015b00aab --- /dev/null +++ b/platforms/arm_atsam/bootloader.c @@ -0,0 +1,57 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "bootloader.h" +#include "samd51j18a.h" +#include "md_bootloader.h" + +// Set watchdog timer to reset. Directs the bootloader to stay in programming mode. +void bootloader_jump(void) { +#ifdef KEYBOARD_massdrop_ctrl + // CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method. + uint8_t ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; // The version to match (NULL terminated by compiler) + uint8_t *ver_check = ver_ram_method; // Pointer to version match string for traversal + uint8_t *ver_rom = (uint8_t *)0x21A0; // Pointer to address in ROM where this specific bootloader version would exist + + while (*ver_check && *ver_rom == *ver_check) { // While there are check version characters to match and bootloader's version matches check's version + ver_check++; // Move check version pointer to next character + ver_rom++; // Move ROM version pointer to next character + } + + if (!*ver_check) { // If check version pointer is NULL, all characters have matched + *MAGIC_ADDR = BOOTLOADER_MAGIC; // Set magic number into RAM + NVIC_SystemReset(); // Perform system reset + while (1) { + } // Won't get here + } +#endif + + WDT->CTRLA.bit.ENABLE = 0; + while (WDT->SYNCBUSY.bit.ENABLE) { + } + while (WDT->CTRLA.bit.ENABLE) { + } + WDT->CONFIG.bit.WINDOW = 0; + WDT->CONFIG.bit.PER = 0; + WDT->EWCTRL.bit.EWOFFSET = 0; + WDT->CTRLA.bit.ENABLE = 1; + while (WDT->SYNCBUSY.bit.ENABLE) { + } + while (!WDT->CTRLA.bit.ENABLE) { + } + while (1) { + } // Wait on timeout +} diff --git a/platforms/arm_atsam/eeprom.c b/platforms/arm_atsam/eeprom.c new file mode 100644 index 0000000000..ff1a692623 --- /dev/null +++ b/platforms/arm_atsam/eeprom.c @@ -0,0 +1,184 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "eeprom.h" +#include "debug.h" +#include "samd51j18a.h" +#include "core_cm4.h" +#include "component/nvmctrl.h" + +#ifndef EEPROM_SIZE +# include "eeconfig.h" +# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO +#endif + +#ifndef MAX +# define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif + +#ifndef BUSY_RETRIES +# define BUSY_RETRIES 10000 +#endif + +// #define DEBUG_EEPROM_OUTPUT + +/* + * Debug print utils + */ +#if defined(DEBUG_EEPROM_OUTPUT) +# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__); +#else /* NO_DEBUG */ +# define eeprom_printf(fmt, ...) +#endif /* NO_DEBUG */ + +__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE] = {0}; +volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR; + +static inline bool eeprom_is_busy(void) { + int timeout = BUSY_RETRIES; + while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) + ; + + return NVMCTRL->SEESTAT.bit.BUSY; +} + +static uint32_t get_virtual_eeprom_size(void) { + // clang-format off + static const uint32_t VIRTUAL_EEPROM_MAP[11][8] = { + /* 4 8 16 32 64 128 256 512 */ + /* 0*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, + /* 1*/ { 512, 1024, 2048, 4096, 4096, 4096, 4096, 4096 }, + /* 2*/ { 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192 }, + /* 3*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 }, + /* 4*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 }, + /* 5*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 6*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 7*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 8*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 9*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }, + /*10*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }, + }; + // clang-format on + + static uint32_t virtual_eeprom_size = UINT32_MAX; + if (virtual_eeprom_size == UINT32_MAX) { + virtual_eeprom_size = VIRTUAL_EEPROM_MAP[NVMCTRL->SEESTAT.bit.PSZ][NVMCTRL->SEESTAT.bit.SBLK]; + } + // eeprom_printf("get_virtual_eeprom_size:: %d:%d:%d\n", NVMCTRL->SEESTAT.bit.PSZ, NVMCTRL->SEESTAT.bit.SBLK, virtual_eeprom_size); + return virtual_eeprom_size; +} + +uint8_t eeprom_read_byte(const uint8_t *addr) { + uintptr_t offset = (uintptr_t)addr; + if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) { + eeprom_printf("eeprom_read_byte:: out of bounds\n"); + return 0x0; + } + + if (get_virtual_eeprom_size() == 0) { + return buffer[offset]; + } + + if (eeprom_is_busy()) { + eeprom_printf("eeprom_write_byte:: timeout\n"); + return 0x0; + } + + return SmartEEPROM8[offset]; +} + +void eeprom_write_byte(uint8_t *addr, uint8_t value) { + uintptr_t offset = (uintptr_t)addr; + if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) { + eeprom_printf("eeprom_write_byte:: out of bounds\n"); + return; + } + + if (get_virtual_eeprom_size() == 0) { + buffer[offset] = value; + return; + } + + if (eeprom_is_busy()) { + eeprom_printf("eeprom_write_byte:: timeout\n"); + return; + } + + SmartEEPROM8[offset] = value; +} + +uint16_t eeprom_read_word(const uint16_t *addr) { + const uint8_t *p = (const uint8_t *)addr; + return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8); +} + +uint32_t eeprom_read_dword(const uint32_t *addr) { + const uint8_t *p = (const uint8_t *)addr; + return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24); +} + +void eeprom_read_block(void *buf, const void *addr, size_t len) { + const uint8_t *p = (const uint8_t *)addr; + uint8_t * dest = (uint8_t *)buf; + while (len--) { + *dest++ = eeprom_read_byte(p++); + } +} + +void eeprom_write_word(uint16_t *addr, uint16_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p, value >> 8); +} + +void eeprom_write_dword(uint32_t *addr, uint32_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p++, value >> 8); + eeprom_write_byte(p++, value >> 16); + eeprom_write_byte(p, value >> 24); +} + +void eeprom_write_block(const void *buf, void *addr, size_t len) { + uint8_t * p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} + +void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); } + +void eeprom_update_word(uint16_t *addr, uint16_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p, value >> 8); +} + +void eeprom_update_dword(uint32_t *addr, uint32_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p++, value >> 8); + eeprom_write_byte(p++, value >> 16); + eeprom_write_byte(p, value >> 24); +} + +void eeprom_update_block(const void *buf, void *addr, size_t len) { + uint8_t * p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} diff --git a/platforms/arm_atsam/gpio.h b/platforms/arm_atsam/gpio.h new file mode 100644 index 0000000000..915ed0ef4f --- /dev/null +++ b/platforms/arm_atsam/gpio.h @@ -0,0 +1,77 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "stdint.h" +#include "samd51j18a.h" + +#include "pin_defs.h" + +typedef uint8_t pin_t; + +#define SAMD_PORT(pin) ((pin & 0x20) >> 5) +#define SAMD_PIN(pin) (pin & 0x1f) +#define SAMD_PIN_MASK(pin) (1 << (pin & 0x1f)) + +#define setPinInput(pin) \ + do { \ + PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \ + PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \ + } while (0) + +#define setPinInputHigh(pin) \ + do { \ + PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \ + PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \ + PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \ + PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \ + } while (0) + +#define setPinInputLow(pin) \ + do { \ + PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \ + PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ + PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \ + PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \ + } while (0) + +#define setPinOutput(pin) \ + do { \ + PORT->Group[SAMD_PORT(pin)].DIRSET.reg = SAMD_PIN_MASK(pin); \ + PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ + } while (0) + +#define writePinHigh(pin) \ + do { \ + PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \ + } while (0) + +#define writePinLow(pin) \ + do { \ + PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ + } while (0) + +#define writePin(pin, level) \ + do { \ + if (level) \ + PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \ + else \ + PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ + } while (0) + +#define readPin(pin) ((PORT->Group[SAMD_PORT(pin)].IN.reg & SAMD_PIN_MASK(pin)) != 0) + +#define togglePin(pin) (PORT->Group[SAMD_PORT(pin)].OUTTGL.reg = SAMD_PIN_MASK(pin)) diff --git a/platforms/arm_atsam/pin_defs.h b/platforms/arm_atsam/pin_defs.h new file mode 100644 index 0000000000..5b50b23910 --- /dev/null +++ b/platforms/arm_atsam/pin_defs.h @@ -0,0 +1,84 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "samd51j18a.h" + +#define A00 PIN_PA00 +#define A01 PIN_PA01 +#define A02 PIN_PA02 +#define A03 PIN_PA03 +#define A04 PIN_PA04 +#define A05 PIN_PA05 +#define A06 PIN_PA06 +#define A07 PIN_PA07 +#define A08 PIN_PA08 +#define A09 PIN_PA09 +#define A10 PIN_PA10 +#define A11 PIN_PA11 +#define A12 PIN_PA12 +#define A13 PIN_PA13 +#define A14 PIN_PA14 +#define A15 PIN_PA15 +#define A16 PIN_PA16 +#define A17 PIN_PA17 +#define A18 PIN_PA18 +#define A19 PIN_PA19 +#define A20 PIN_PA20 +#define A21 PIN_PA21 +#define A22 PIN_PA22 +#define A23 PIN_PA23 +#define A24 PIN_PA24 +#define A25 PIN_PA25 +#define A26 PIN_PA26 +#define A27 PIN_PA27 +#define A28 PIN_PA28 +#define A29 PIN_PA29 +#define A30 PIN_PA30 +#define A31 PIN_PA31 + +#define B00 PIN_PB00 +#define B01 PIN_PB01 +#define B02 PIN_PB02 +#define B03 PIN_PB03 +#define B04 PIN_PB04 +#define B05 PIN_PB05 +#define B06 PIN_PB06 +#define B07 PIN_PB07 +#define B08 PIN_PB08 +#define B09 PIN_PB09 +#define B10 PIN_PB10 +#define B11 PIN_PB11 +#define B12 PIN_PB12 +#define B13 PIN_PB13 +#define B14 PIN_PB14 +#define B15 PIN_PB15 +#define B16 PIN_PB16 +#define B17 PIN_PB17 +#define B18 PIN_PB18 +#define B19 PIN_PB19 +#define B20 PIN_PB20 +#define B21 PIN_PB21 +#define B22 PIN_PB22 +#define B23 PIN_PB23 +#define B24 PIN_PB24 +#define B25 PIN_PB25 +#define B26 PIN_PB26 +#define B27 PIN_PB27 +#define B28 PIN_PB28 +#define B29 PIN_PB29 +#define B30 PIN_PB30 +#define B31 PIN_PB31 diff --git a/platforms/arm_atsam/platform.c b/platforms/arm_atsam/platform.c new file mode 100644 index 0000000000..3e35b4fe4c --- /dev/null +++ b/platforms/arm_atsam/platform.c @@ -0,0 +1,21 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "platform_deps.h" + +void platform_setup(void) { + // do nothing +} diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk new file mode 100644 index 0000000000..b49bf764d7 --- /dev/null +++ b/platforms/arm_atsam/platform.mk @@ -0,0 +1,67 @@ +# Hey Emacs, this is a -*- makefile -*- +############################################################################## +# Compiler settings +# +CC = $(CC_PREFIX) arm-none-eabi-gcc +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +SIZE = arm-none-eabi-size +AR = arm-none-eabi-ar +NM = arm-none-eabi-nm +HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature +EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) +BIN = + +COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/include +COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/arm/cmsis/5.0.1/CMSIS/Include + +COMPILEFLAGS += -funsigned-char +COMPILEFLAGS += -funsigned-bitfields +COMPILEFLAGS += -ffunction-sections +COMPILEFLAGS += -fshort-enums +COMPILEFLAGS += -fno-inline-small-functions +COMPILEFLAGS += -fno-strict-aliasing +COMPILEFLAGS += -mfloat-abi=hard +COMPILEFLAGS += -mfpu=fpv4-sp-d16 +COMPILEFLAGS += -mthumb + +#ALLOW_WARNINGS = yes + +CFLAGS += $(COMPILEFLAGS) + +CXXFLAGS += $(COMPILEFLAGS) +CXXFLAGS += -fno-exceptions -std=c++11 + +LDFLAGS +=-Wl,--gc-sections +LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map" +LDFLAGS += -Wl,--start-group +LDFLAGS += -Wl,--end-group +LDFLAGS += --specs=rdimon.specs +LDFLAGS += -T$(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/gcc/gcc/samd51j18a_flash.ld + +OPT_DEFS += -DPROTOCOL_ARM_ATSAM + +MCUFLAGS = -mcpu=$(MCU) +MCUFLAGS += -D__$(ARM_ATSAM)__ + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + +cpfirmware: warn-arm_atsam +.INTERMEDIATE: warn-arm_atsam +warn-arm_atsam: $(FIRMWARE_FORMAT) + $(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@) + $(info This MCU support package has a lack of support from the upstream provider (Massdrop).) + $(info There are currently questions about valid licensing, and at this stage it's likely) + $(info their boards and supporting code will be removed from QMK in the near future. Please) + $(info contact Massdrop for support, and encourage them to align their future board design) + $(info choices to gain proper license compatibility with QMK.) + $(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@) + +# Convert hex to bin. +bin: $(BUILD_DIR)/$(TARGET).hex + $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin + $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; diff --git a/platforms/arm_atsam/platform_deps.h b/platforms/arm_atsam/platform_deps.h new file mode 100644 index 0000000000..f296d1d535 --- /dev/null +++ b/platforms/arm_atsam/platform_deps.h @@ -0,0 +1,18 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +// here just to please the build diff --git a/platforms/arm_atsam/suspend.c b/platforms/arm_atsam/suspend.c new file mode 100644 index 0000000000..e51426128d --- /dev/null +++ b/platforms/arm_atsam/suspend.c @@ -0,0 +1,77 @@ +#include "matrix.h" +#include "i2c_master.h" +#include "md_rgb_matrix.h" +#include "suspend.h" + +/** \brief Suspend idle + * + * FIXME: needs doc + */ +void suspend_idle(uint8_t time) { /* Note: Not used anywhere currently */ +} + +/** \brief Run user level Power down + * + * FIXME: needs doc + */ +__attribute__((weak)) void suspend_power_down_user(void) {} + +/** \brief Run keyboard level Power down + * + * FIXME: needs doc + */ +__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } + +/** \brief Suspend power down + * + * FIXME: needs doc + */ +void suspend_power_down(void) { +#ifdef RGB_MATRIX_ENABLE + I2C3733_Control_Set(0); // Disable LED driver +#endif + + suspend_power_down_kb(); +} + +__attribute__((weak)) void matrix_power_up(void) {} +__attribute__((weak)) void matrix_power_down(void) {} +bool suspend_wakeup_condition(void) { + matrix_power_up(); + matrix_scan(); + matrix_power_down(); + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { + if (matrix_get_row(r)) return true; + } + return false; +} + +/** \brief run user level code immediately after wakeup + * + * FIXME: needs doc + */ +__attribute__((weak)) void suspend_wakeup_init_user(void) {} + +/** \brief run keyboard level code immediately after wakeup + * + * FIXME: needs doc + */ +__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); } + +/** \brief run immediately after wakeup + * + * FIXME: needs doc + */ +void suspend_wakeup_init(void) { +#ifdef RGB_MATRIX_ENABLE +# ifdef USE_MASSDROP_CONFIGURATOR + if (led_enabled) { + I2C3733_Control_Set(1); + } +# else + I2C3733_Control_Set(1); +# endif +#endif + + suspend_wakeup_init_kb(); +} diff --git a/platforms/arm_atsam/timer.c b/platforms/arm_atsam/timer.c new file mode 100644 index 0000000000..b835dd5e75 --- /dev/null +++ b/platforms/arm_atsam/timer.c @@ -0,0 +1,19 @@ +#include "samd51j18a.h" +#include "timer.h" +#include "tmk_core/protocol/arm_atsam/clks.h" + +void set_time(uint64_t tset) { ms_clk = tset; } + +void timer_init(void) { timer_clear(); } + +uint16_t timer_read(void) { return (uint16_t)ms_clk; } + +uint32_t timer_read32(void) { return (uint32_t)ms_clk; } + +uint64_t timer_read64(void) { return ms_clk; } + +uint16_t timer_elapsed(uint16_t tlast) { return TIMER_DIFF_16(timer_read(), tlast); } + +uint32_t timer_elapsed32(uint32_t tlast) { return TIMER_DIFF_32(timer_read32(), tlast); } + +void timer_clear(void) { set_time(0); } diff --git a/platforms/atomic_util.h b/platforms/atomic_util.h new file mode 100644 index 0000000000..2c95302a13 --- /dev/null +++ b/platforms/atomic_util.h @@ -0,0 +1,32 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +// Macro to help make GPIO and other controls atomic. + +#ifndef IGNORE_ATOMIC_BLOCK +# if __has_include_next("atomic_util.h") +# include_next "atomic_util.h" /* Include the platforms atomic.h */ +# else +# define ATOMIC_BLOCK _Static_assert(0, "ATOMIC_BLOCK not implemented") +# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented") +# define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON not implemented") +# endif +#else /* do nothing atomic macro */ +# define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0) +# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK +# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK +#endif diff --git a/platforms/avr/_print.h b/platforms/avr/_print.h new file mode 100644 index 0000000000..5c1fdd26d8 --- /dev/null +++ b/platforms/avr/_print.h @@ -0,0 +1,33 @@ +/* Copyright 2012 Jun Wako */ +/* Very basic print functions, intended to be used with usb_debug_only.c + * http://www.pjrc.com/teensy/ + * Copyright (c) 2008 PJRC.COM, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include "avr/xprintf.h" + +// Create user & normal print defines +#define print(s) xputs(PSTR(s)) +#define println(s) xputs(PSTR(s "\r\n")) +#define uprint(s) xputs(PSTR(s)) +#define uprintln(s) xputs(PSTR(s "\r\n")) +#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 0000000000..b81e0f68b7 --- /dev/null +++ b/platforms/avr/_timer.h @@ -0,0 +1,19 @@ +/* Copyright 2021 Simon Arlott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +// The platform is 8-bit, so prefer 16-bit timers to reduce code size +#define FAST_TIMER_T_SIZE 16 diff --git a/platforms/avr/_wait.h b/platforms/avr/_wait.h new file mode 100644 index 0000000000..683db6ae57 --- /dev/null +++ b/platforms/avr/_wait.h @@ -0,0 +1,49 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#define wait_ms(ms) \ + do { \ + if (__builtin_constant_p(ms)) { \ + _delay_ms(ms); \ + } else { \ + for (uint16_t i = ms; i > 0; i--) { \ + _delay_ms(1); \ + } \ + } \ + } while (0) +#define wait_us(us) \ + do { \ + if (__builtin_constant_p(us)) { \ + _delay_us(us); \ + } else { \ + for (uint16_t i = us; i > 0; i--) { \ + _delay_us(1); \ + } \ + } \ + } while (0) +#define wait_cpuclock(n) __builtin_avr_delay_cycles(n) +#define CPU_CLOCK F_CPU + +/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal. + * But here's more margin to make it two clocks. */ +#ifndef GPIO_INPUT_PIN_DELAY +# define GPIO_INPUT_PIN_DELAY 2 +#endif + +#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 0000000000..7c5d2e7dcc --- /dev/null +++ b/platforms/avr/atomic_util.h @@ -0,0 +1,22 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +/* atomic macro for AVR */ +#include + +#define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#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 0000000000..c0272903b8 --- /dev/null +++ b/platforms/avr/bootloader.c @@ -0,0 +1,293 @@ +#include +#include +#include +#include +#include +#include +#include +#include "bootloader.h" +#include + +#ifdef PROTOCOL_LUFA +# include +#endif + +/** \brief Bootloader Size in *bytes* + * + * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet. + * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'. + * + * Size of Bootloaders in bytes: + * Atmel DFU loader(ATmega32U4) 4096 + * Atmel DFU loader(AT90USB128) 8192 + * LUFA bootloader(ATmega32U4) 4096 + * Arduino Caterina(ATmega32U4) 4096 + * USBaspLoader(ATmega***) 2048 + * Teensy halfKay(ATmega32U4) 512 + * Teensy++ halfKay(AT90USB128) 1024 + * + * AVR Boot section is located at the end of Flash memory like the followings. + * + * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128) + * 0x0000 +---------------+ 0x00000 +---------------+ + * | | | | + * | | | | + * | Application | | Application | + * | | | | + * = = = = + * | | 32KB-4KB | | 128KB-8KB + * 0x7000 +---------------+ 0x1E000 +---------------+ + * | Bootloader | 4KB | Bootloader | 8KB + * 0x7FFF +---------------+ 0x1FFFF +---------------+ + * + * + * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128) + * 0x0000 +---------------+ 0x00000 +---------------+ + * | | | | + * | | | | + * | Application | | Application | + * | | | | + * = = = = + * | | 32KB-512B | | 128KB-1KB + * 0x7E00 +---------------+ 0x1FC00 +---------------+ + * | Bootloader | 512B | Bootloader | 1KB + * 0x7FFF +---------------+ 0x1FFFF +---------------+ + */ +#define FLASH_SIZE (FLASHEND + 1L) + +#if !defined(BOOTLOADER_SIZE) +uint16_t bootloader_start; +#endif + +// compatibility between ATMega8 and ATMega88 +#if !defined(MCUCSR) +# if defined(MCUSR) +# define MCUCSR MCUSR +# endif +#endif + +/** \brief Entering the Bootloader via Software + * + * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html + */ +#define BOOTLOADER_RESET_KEY 0xB007B007 +uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;"))); + +/** \brief initialize MCU status by watchdog reset + * + * FIXME: needs doc + */ +__attribute__((weak)) void bootloader_jump(void) { +#if !defined(BOOTLOADER_SIZE) + uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); + + if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) { + bootloader_start = (FLASH_SIZE - 512) >> 1; + } else if (high_fuse & ~(FUSE_BOOTSZ1)) { + bootloader_start = (FLASH_SIZE - 1024) >> 1; + } else if (high_fuse & ~(FUSE_BOOTSZ0)) { + bootloader_start = (FLASH_SIZE - 2048) >> 1; + } else { + bootloader_start = (FLASH_SIZE - 4096) >> 1; + } +#endif + + // Something like this might work, but it compiled larger than the block above + // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1)); + +#if defined(BOOTLOADER_HALFKAY) + // http://www.pjrc.com/teensy/jump_to_bootloader.html + cli(); + // disable watchdog, if enabled (it's not) + // disable all peripherals + // a shutdown call might make sense here + UDCON = 1; + USBCON = (1 << FRZCLK); // disable USB + UCSR1B = 0; + _delay_ms(5); +# if defined(__AVR_AT90USB162__) // Teensy 1.0 + EIMSK = 0; + PCICR = 0; + SPCR = 0; + ACSR = 0; + EECR = 0; + TIMSK0 = 0; + TIMSK1 = 0; + UCSR1B = 0; + DDRB = 0; + DDRC = 0; + DDRD = 0; + PORTB = 0; + PORTC = 0; + PORTD = 0; + asm volatile("jmp 0x3E00"); +# elif defined(__AVR_ATmega32U4__) // Teensy 2.0 + EIMSK = 0; + PCICR = 0; + SPCR = 0; + ACSR = 0; + EECR = 0; + ADCSRA = 0; + TIMSK0 = 0; + TIMSK1 = 0; + TIMSK3 = 0; + TIMSK4 = 0; + UCSR1B = 0; + TWCR = 0; + DDRB = 0; + DDRC = 0; + DDRD = 0; + DDRE = 0; + DDRF = 0; + TWCR = 0; + PORTB = 0; + PORTC = 0; + PORTD = 0; + PORTE = 0; + PORTF = 0; + asm volatile("jmp 0x7E00"); +# elif defined(__AVR_AT90USB646__) // Teensy++ 1.0 + EIMSK = 0; + PCICR = 0; + SPCR = 0; + ACSR = 0; + EECR = 0; + ADCSRA = 0; + TIMSK0 = 0; + TIMSK1 = 0; + TIMSK2 = 0; + TIMSK3 = 0; + UCSR1B = 0; + TWCR = 0; + DDRA = 0; + DDRB = 0; + DDRC = 0; + DDRD = 0; + DDRE = 0; + DDRF = 0; + PORTA = 0; + PORTB = 0; + PORTC = 0; + PORTD = 0; + PORTE = 0; + PORTF = 0; + asm volatile("jmp 0xFC00"); +# elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0 + EIMSK = 0; + PCICR = 0; + SPCR = 0; + ACSR = 0; + EECR = 0; + ADCSRA = 0; + TIMSK0 = 0; + TIMSK1 = 0; + TIMSK2 = 0; + TIMSK3 = 0; + UCSR1B = 0; + TWCR = 0; + DDRA = 0; + DDRB = 0; + DDRC = 0; + DDRD = 0; + DDRE = 0; + DDRF = 0; + PORTA = 0; + PORTB = 0; + PORTC = 0; + PORTD = 0; + PORTE = 0; + PORTF = 0; + asm volatile("jmp 0x1FC00"); +# endif + +#elif defined(BOOTLOADER_CATERINA) + // this block may be optional + // TODO: figure it out + + uint16_t *const bootKeyPtr = (uint16_t *)0x0800; + + // Value used by Caterina bootloader use to determine whether to run the + // sketch or the bootloader programmer. + uint16_t bootKey = 0x7777; + + *bootKeyPtr = bootKey; + + // setup watchdog timeout + wdt_enable(WDTO_60MS); + + while (1) { + } // wait for watchdog timer to trigger + +#elif defined(BOOTLOADER_USBASP) + // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c + wdt_enable(WDTO_15MS); + wdt_reset(); + asm volatile("cli \n\t" + "ldi r29 , %[ramendhi] \n\t" + "ldi r28 , %[ramendlo] \n\t" +# if (FLASHEND > 131071) + "ldi r18 , %[bootaddrhi] \n\t" + "st Y+, r18 \n\t" +# endif + "ldi r18 , %[bootaddrme] \n\t" + "st Y+, r18 \n\t" + "ldi r18 , %[bootaddrlo] \n\t" + "st Y+, r18 \n\t" + "out %[mcucsrio], __zero_reg__ \n\t" + "bootloader_startup_loop%=: \n\t" + "rjmp bootloader_startup_loop%= \n\t" + : + : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)), +# if (FLASHEND > 131071) + [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff), +# else + [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff), +# endif + [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff)); + +#else // Assume remaining boards are DFU, even if the flag isn't set + +# if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though? + UDCON = 1; + USBCON = (1 << FRZCLK); // disable USB + UCSR1B = 0; + _delay_ms(5); // 5 seems to work fine +# endif + +# ifdef BOOTLOADER_BOOTLOADHID + // force bootloadHID to stay in bootloader mode, so that it waits + // for a new firmware to be flashed + eeprom_write_byte((uint8_t *)1, 0x00); +# endif + + // watchdog reset + reset_key = BOOTLOADER_RESET_KEY; + wdt_enable(WDTO_250MS); + for (;;) + ; +#endif +} + +/* this runs before main() */ +void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3"))); +void bootloader_jump_after_watchdog_reset(void) { +#ifndef BOOTLOADER_HALFKAY + if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { + reset_key = 0; + + // My custom USBasploader requires this to come up. + MCUCSR = 0; + + // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. + MCUCSR &= ~(1 << WDRF); + wdt_disable(); + +// This is compled into 'icall', address should be in word unit, not byte. +# ifdef BOOTLOADER_SIZE + ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))(); +# else + asm("ijmp" ::"z"(bootloader_start)); +# endif + } +#endif +} diff --git a/platforms/avr/bootloader_size.c b/platforms/avr/bootloader_size.c new file mode 100644 index 0000000000..a029f9321f --- /dev/null +++ b/platforms/avr/bootloader_size.c @@ -0,0 +1,21 @@ +// Copyright 2017 Jack Humbert +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include + +// clang-format off +// this is not valid C - it's for computing the size available on the chip +AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE diff --git a/platforms/avr/gpio.h b/platforms/avr/gpio.h new file mode 100644 index 0000000000..e9be68491d --- /dev/null +++ b/platforms/avr/gpio.h @@ -0,0 +1,49 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include "pin_defs.h" + +typedef uint8_t pin_t; + +/* Operation of GPIO by pin. */ + +#define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF)) +#define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF)) +#define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low") +#define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF)) + +#define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF)) +#define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF)) +#define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin)) + +#define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF))) + +#define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF)) + +/* Operation of GPIO by port. */ + +typedef uint8_t port_data_t; + +#define readPort(port) PINx_ADDRESS(port) + +#define setPortBitInput(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) &= ~_BV((bit)&0xF)) +#define setPortBitInputHigh(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) |= _BV((bit)&0xF)) +#define setPortBitOutput(port, bit) (DDRx_ADDRESS(port) |= _BV((bit)&0xF)) + +#define writePortBitLow(port, bit) (PORTx_ADDRESS(port) &= ~_BV((bit)&0xF)) +#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 0000000000..23d948041d --- /dev/null +++ b/platforms/avr/pin_defs.h @@ -0,0 +1,128 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#define PORT_SHIFTER 4 // this may be 4 for all AVR chips + +// If you want to add more to this list, reference the PINx definitions in these header +// files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr + +#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) +# define ADDRESS_BASE 0x00 +# define PINB_ADDRESS 0x3 +# define PINC_ADDRESS 0x6 +# define PIND_ADDRESS 0x9 +# define PINE_ADDRESS 0xC +# define PINF_ADDRESS 0xF +#elif defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) +# define ADDRESS_BASE 0x00 +# define PINB_ADDRESS 0x3 +# define PINC_ADDRESS 0x6 +# define PIND_ADDRESS 0x9 +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) +# define ADDRESS_BASE 0x00 +# define PINA_ADDRESS 0x0 +# define PINB_ADDRESS 0x3 +# define PINC_ADDRESS 0x6 +# define PIND_ADDRESS 0x9 +# define PINE_ADDRESS 0xC +# define PINF_ADDRESS 0xF +#elif defined(__AVR_ATmega32A__) +# define ADDRESS_BASE 0x10 +# define PIND_ADDRESS 0x0 +# define PINC_ADDRESS 0x3 +# define PINB_ADDRESS 0x6 +# define PINA_ADDRESS 0x9 +#elif defined(__AVR_ATtiny85__) +# define ADDRESS_BASE 0x10 +# define PINB_ADDRESS 0x6 +#else +# error "Pins are not defined" +#endif + +#define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin) + +#define _PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + ((p) >> PORT_SHIFTER) + (offset)) +// Port X Input Pins Address +#define PINx_ADDRESS(p) _PIN_ADDRESS(p, 0) +// Port X Data Direction Register, 0:input 1:output +#define DDRx_ADDRESS(p) _PIN_ADDRESS(p, 1) +// Port X Data Register +#define PORTx_ADDRESS(p) _PIN_ADDRESS(p, 2) + +/* I/O pins */ +#ifdef PORTA +# define A0 PINDEF(A, 0) +# define A1 PINDEF(A, 1) +# define A2 PINDEF(A, 2) +# define A3 PINDEF(A, 3) +# define A4 PINDEF(A, 4) +# define A5 PINDEF(A, 5) +# define A6 PINDEF(A, 6) +# define A7 PINDEF(A, 7) +#endif +#ifdef PORTB +# define B0 PINDEF(B, 0) +# define B1 PINDEF(B, 1) +# define B2 PINDEF(B, 2) +# define B3 PINDEF(B, 3) +# define B4 PINDEF(B, 4) +# define B5 PINDEF(B, 5) +# define B6 PINDEF(B, 6) +# define B7 PINDEF(B, 7) +#endif +#ifdef PORTC +# define C0 PINDEF(C, 0) +# define C1 PINDEF(C, 1) +# define C2 PINDEF(C, 2) +# define C3 PINDEF(C, 3) +# define C4 PINDEF(C, 4) +# define C5 PINDEF(C, 5) +# define C6 PINDEF(C, 6) +# define C7 PINDEF(C, 7) +#endif +#ifdef PORTD +# define D0 PINDEF(D, 0) +# define D1 PINDEF(D, 1) +# define D2 PINDEF(D, 2) +# define D3 PINDEF(D, 3) +# define D4 PINDEF(D, 4) +# define D5 PINDEF(D, 5) +# define D6 PINDEF(D, 6) +# define D7 PINDEF(D, 7) +#endif +#ifdef PORTE +# define E0 PINDEF(E, 0) +# define E1 PINDEF(E, 1) +# define E2 PINDEF(E, 2) +# define E3 PINDEF(E, 3) +# define E4 PINDEF(E, 4) +# define E5 PINDEF(E, 5) +# define E6 PINDEF(E, 6) +# define E7 PINDEF(E, 7) +#endif +#ifdef PORTF +# define F0 PINDEF(F, 0) +# define F1 PINDEF(F, 1) +# define F2 PINDEF(F, 2) +# define F3 PINDEF(F, 3) +# define F4 PINDEF(F, 4) +# define F5 PINDEF(F, 5) +# define F6 PINDEF(F, 6) +# define F7 PINDEF(F, 7) +#endif diff --git a/platforms/avr/platform.c b/platforms/avr/platform.c new file mode 100644 index 0000000000..3e35b4fe4c --- /dev/null +++ b/platforms/avr/platform.c @@ -0,0 +1,21 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "platform_deps.h" + +void platform_setup(void) { + // do nothing +} diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk new file mode 100644 index 0000000000..b45108736f --- /dev/null +++ b/platforms/avr/platform.mk @@ -0,0 +1,179 @@ +# Hey Emacs, this is a -*- makefile -*- +############################################################################## +# Compiler settings +# +CC = $(CC_PREFIX) avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar +NM = avr-nm +HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature +EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) +BIN = + +COMPILEFLAGS += -funsigned-char +COMPILEFLAGS += -funsigned-bitfields +COMPILEFLAGS += -ffunction-sections +COMPILEFLAGS += -fdata-sections +COMPILEFLAGS += -fpack-struct +COMPILEFLAGS += -fshort-enums + +ASFLAGS += $(AVR_ASFLAGS) + +CFLAGS += $(COMPILEFLAGS) $(AVR_CFLAGS) +CFLAGS += -fno-inline-small-functions +CFLAGS += -fno-strict-aliasing + +CXXFLAGS += $(COMPILEFLAGS) +CXXFLAGS += -fno-exceptions -std=c++11 + +LDFLAGS +=-Wl,--gc-sections + +OPT_DEFS += -DF_CPU=$(F_CPU)UL + +MCUFLAGS = -mmcu=$(MCU) + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + +#---------------- Debugging Options ---------------- + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + +#============================================================================ + +# Convert hex to bin. +bin: $(BUILD_DIR)/$(TARGET).hex +ifeq ($(BOOTLOADER),lufa-ms) + $(eval BIN_PADDING=$(shell n=`expr 32768 - $(BOOTLOADER_SIZE)` && echo $$(($$n)) || echo 0)) + $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin --pad-to $(BIN_PADDING) +else + $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin +endif + $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; + +# copy bin to FLASH.bin +flashbin: bin + $(COPY) $(BUILD_DIR)/$(TARGET).bin FLASH.bin; + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(BUILD_DIR)/$(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) +