From 3c906c6c3db4c1dbf117d1826728ecf0ec3c70e6 Mon Sep 17 00:00:00 2001 From: Josarn Date: Tue, 27 Feb 2018 14:04:19 +0100 Subject: [PATCH] cpu/atmega256rfr2: ATmega256rfr2 MCU support Signed-off-by: Josua Arndt Signed-off-by: Steffen Robertz --- cpu/atmega256rfr2/Makefile | 5 + cpu/atmega256rfr2/Makefile.features | 7 ++ cpu/atmega256rfr2/Makefile.include | 14 +++ cpu/atmega256rfr2/cpu.c | 137 +++++++++++++++++++++++++ cpu/atmega256rfr2/doc.txt | 5 + cpu/atmega256rfr2/include/cpu_conf.h | 51 +++++++++ cpu/atmega256rfr2/include/periph_cpu.h | 71 +++++++++++++ cpu/atmega256rfr2/periph/Makefile | 1 + cpu/atmega256rfr2/periph/cpuid.c | 76 ++++++++++++++ cpu/atmega256rfr2/startup.c | 72 +++++++++++++ 10 files changed, 439 insertions(+) create mode 100644 cpu/atmega256rfr2/Makefile create mode 100644 cpu/atmega256rfr2/Makefile.features create mode 100644 cpu/atmega256rfr2/Makefile.include create mode 100644 cpu/atmega256rfr2/cpu.c create mode 100644 cpu/atmega256rfr2/doc.txt create mode 100644 cpu/atmega256rfr2/include/cpu_conf.h create mode 100644 cpu/atmega256rfr2/include/periph_cpu.h create mode 100644 cpu/atmega256rfr2/periph/Makefile create mode 100644 cpu/atmega256rfr2/periph/cpuid.c create mode 100644 cpu/atmega256rfr2/startup.c diff --git a/cpu/atmega256rfr2/Makefile b/cpu/atmega256rfr2/Makefile new file mode 100644 index 0000000000..5148810cfa --- /dev/null +++ b/cpu/atmega256rfr2/Makefile @@ -0,0 +1,5 @@ +# define the module that is build +MODULE = cpu +# add a list of subdirectories, that should also be build +DIRS = periph $(ATMEGA_COMMON) +include $(RIOTBASE)/Makefile.base diff --git a/cpu/atmega256rfr2/Makefile.features b/cpu/atmega256rfr2/Makefile.features new file mode 100644 index 0000000000..f5ad466ab1 --- /dev/null +++ b/cpu/atmega256rfr2/Makefile.features @@ -0,0 +1,7 @@ +include $(RIOTCPU)/atmega_common/Makefile.features + +# common feature are defined in atmega_common/Makefile.features +# Only add Additional features + +# Various other features (if any) +FEATURES_PROVIDED += periph_cpuid diff --git a/cpu/atmega256rfr2/Makefile.include b/cpu/atmega256rfr2/Makefile.include new file mode 100644 index 0000000000..4e3aa39e06 --- /dev/null +++ b/cpu/atmega256rfr2/Makefile.include @@ -0,0 +1,14 @@ +# tell the build system that the CPU depends on the atmega common files +USEMODULE += atmega_common +# define path to atmega common module, which is needed for this CPU +export ATMEGA_COMMON = $(RIOTCPU)/atmega_common/ + +# explicitly tell the linker to link the syscalls and startup code. +# Without this the interrupt vectors will not be linked correctly! +export UNDEF += $(BINDIR)/cpu/startup.o + +#include periph module +USEMODULE += periph + +# CPU depends on the atmega common module, so include it +include $(ATMEGA_COMMON)Makefile.include diff --git a/cpu/atmega256rfr2/cpu.c b/cpu/atmega256rfr2/cpu.c new file mode 100644 index 0000000000..fa3b7d4e33 --- /dev/null +++ b/cpu/atmega256rfr2/cpu.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2017 RWTH Aachen, Josua Arndt + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_atmega256rfr2 + * @{ + * + * @file + * @brief Implementation of the CPU initialization + * + * @author Steffen Robertz + * @author Josua Arndt + * @} + */ + +#include +#include +#include +#include "cpu.h" +#include "board.h" +#include "periph/init.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* +* Since this MCU does not feature a software reset, the watchdog timer +* is being used. It will be set to the shortest time and then force a +* reset. Therefore the MCUSR register needs to be resetted as fast as +* possible. In this case in the bootloader already. In order to regain +* information about the reset cause, the MCUSR is copied to r2 beforehand. +* When a software reset was triggered, r3 will contain 0xAA. In order to +* prevent changes to the values from the .init section, r2 and r3 are saved +* in the .init0 section +*/ +uint8_t mcusr_mirror __attribute__((section(".noinit"))); +uint8_t soft_rst __attribute__((section(".noinit"))); +void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init0"))); +void get_mcusr(void) +{ + /* save the reset flags passed from the bootloader */ + __asm__ __volatile__("mov %0, r2\n" : "=r" (mcusr_mirror) :); + __asm__ __volatile__("mov %0, r3\n" : "=r" (soft_rst) :); +} + +void _reset_cause(void) +{ + if (mcusr_mirror & (1 << PORF)) { + DEBUG("Power-on reset.\n"); + } + if (mcusr_mirror & (1 << EXTRF)) { + DEBUG("External reset!\n"); + } + if (mcusr_mirror & (1 << BORF)) { + DEBUG("Brownout reset!\n"); + } + if (mcusr_mirror & (1 << WDRF)) { + if (soft_rst & 0xAA) { + DEBUG("Software reset!\n"); + } else { + DEBUG("Watchdog reset!\n"); + } + } + if (mcusr_mirror & (1 << JTRF)) { + DEBUG("JTAG reset!\n"); + } +} + +void cpu_init(void) +{ + _reset_cause(); + + wdt_reset(); /* should not be nececessary as done in bootloader */ + wdt_disable(); /* but when used without bootloader this is needed */ + + /* Set system clock Prescaler */ + CLKPR = (1 << CLKPCE); /* enable a change to CLKPR */ + /* set the Division factor to 1 results in divisor 2 for internal Oscillator + * So FCPU = 8MHz + * + * Attention! + * The CPU can not be used with the external xtal oscillator if the core + * should be put in sleep while the transceiver is in rx mode. + * + * It seems the as teh peripheral clock divider is set to 1 and this all + * clocks of the timer, etc run with 16MHz increasing power consumption. + * */ + CLKPR = 0; + + /* Initialize peripherals for which modules are included in the makefile.*/ + /* spi_init */ + /* rtc_init */ + /* hwrng_init */ + periph_init(); +} + +/* This is a vector which is aliased to __vector_default, + * the vector executed when an ISR fires with no accompanying + * ISR handler. This may be used along with the ISR() macro to + * create a catch-all for undefined but used ISRs for debugging + * purposes. + * SCIRQS – Symbol Counter Interrupt Status Register + * BATMON – Battery Monitor Control and Status Register + * IRQ_STATUS /1 – Transceiver Interrupt Status Register + * EIFR – External Interrupt Flag Register + * PCIFR – Pin Change Interrupt Flag Register + */ +ISR(BADISR_vect){ + + _reset_cause(); + + printf_P(PSTR("FATAL ERROR: BADISR_vect called, unprocessed Interrupt.\n" + "STOP Execution.\n")); + + printf("IRQ_STATUS %#02x\nIRQ_STATUS1 %#02x\n", + (unsigned int)IRQ_STATUS, (unsigned int)IRQ_STATUS1 ); + + printf("SCIRQS %#02x\nBATMON %#02x\n", (unsigned int)SCIRQS, (unsigned int)BATMON ); + + printf("EIFR %#02x\nPCIFR %#02x\n", (unsigned int)EIFR, (unsigned int)PCIFR ); + + /* White LED light is used to signal ERROR. */ + LED_PORT |= (LED2_MASK | LED1_MASK | LED0_MASK); + + while (1) {} +} + +ISR(BAT_LOW_vect, ISR_BLOCK){ + __enter_isr(); + DEBUG("BAT_LOW \n"); + __exit_isr(); +} diff --git a/cpu/atmega256rfr2/doc.txt b/cpu/atmega256rfr2/doc.txt new file mode 100644 index 0000000000..44fff73707 --- /dev/null +++ b/cpu/atmega256rfr2/doc.txt @@ -0,0 +1,5 @@ +/** + * @defgroup cpu_atmega256rfr2 Atmel ATmega256rfr2 + * @ingroup cpu + * @brief Implementation of Atmel's ATmega256rfr2 MCU + */ diff --git a/cpu/atmega256rfr2/include/cpu_conf.h b/cpu/atmega256rfr2/include/cpu_conf.h new file mode 100644 index 0000000000..0a4cee9368 --- /dev/null +++ b/cpu/atmega256rfr2/include/cpu_conf.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017 RWTH Aachen, Josua Arndt + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_atmega256rfr2 + * @{ + * + * @file + * @brief Implementation specific CPU configuration options + * + * @author Josua Arndt + * @author Steffen Robertz + */ + +#ifndef CPU_CONF_H +#define CPU_CONF_H + +#include "atmega_regs_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Kernel configuration + * + * Since printf seems to get memory allocated by the linker/avr-libc the stack + * size tested sucessfully even with pretty small stacks.k + * @{ + */ + +/* keep THREAD_STACKSIZE_IDLE > THREAD_EXTRA_STACKSIZE_PRINTF + * to avoid not printing of debug in interrupts + */ +#define THREAD_EXTRA_STACKSIZE_PRINTF (128) + +#ifndef THREAD_STACKSIZE_DEFAULT +#define THREAD_STACKSIZE_DEFAULT (512) +#endif + +#define THREAD_STACKSIZE_IDLE (129) +#ifdef __cplusplus +} +#endif +#endif /* CPU_CONF_H */ +/** @} */ diff --git a/cpu/atmega256rfr2/include/periph_cpu.h b/cpu/atmega256rfr2/include/periph_cpu.h new file mode 100644 index 0000000000..731149bb5a --- /dev/null +++ b/cpu/atmega256rfr2/include/periph_cpu.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) Josua Arndt, Steffen Robertz 2017 RWTH Aachen + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_atmega256rfr2 + * @{ + * + * @file + * @brief CPU specific definitions for internal peripheral handling + * + * @author Josua Arndt + * @author Steffen Robertz + */ + +#ifndef PERIPH_CPU_H +#define PERIPH_CPU_H + +#include "periph_cpu_common.h" +#include "atmega_regs_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Length of the CPU_ID in octets + * @{ + */ +#define CPUID_LEN (8U) +/** @} */ + +/** + * @name Available ports on the ATmega256rfr family + * @{ + */ +enum { + PORT_B = 1, /**< port B */ + PORT_D = 3, /**< port D */ + PORT_E = 4, /**< port E */ + PORT_F = 5, /**< port F */ + PORT_G = 6, /**< port G */ +}; + +/** + * @name Defines for the I2C interface + * @{ + */ +#define I2C_PORT_REG PORTD +#define I2C_PIN_MASK (1 << PORTD1) | (1 << PORTD0) +/** @} */ + +/** + * @name GPIO pin not defined + * @{ + */ +#ifndef GPIO_UNDEF +#define GPIO_UNDEF (0xFFFF) +#endif +/** @}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CPU_H */ +/** @} */ diff --git a/cpu/atmega256rfr2/periph/Makefile b/cpu/atmega256rfr2/periph/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/cpu/atmega256rfr2/periph/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/cpu/atmega256rfr2/periph/cpuid.c b/cpu/atmega256rfr2/periph/cpuid.c new file mode 100644 index 0000000000..2fa936bea3 --- /dev/null +++ b/cpu/atmega256rfr2/periph/cpuid.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 RWTH Aachen, Josua Arndt, Steffen Robertz + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_atmega256rfr2 + * @{ + * + * @file + * @brief Low-level CPUID driver implementation + * + * @author Steffen Robertz + * @author Josua Arndt + * + * @} + */ +#include +#include +#include + +#include "periph/cpuid.h" + +#include "atmega_regs_common.h" +#include "avr/boot.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief CPU_ID build from MCU register + * + * CPIUD is taken from MCU Control Register and Signature bytes. + * CPUID: 1e a8 02 1f 94 03 ff ff + * CPUID: 1e a8 02 1f 94 92 XX XX + * MEGA62/128/256_RFR2 [MANUAL] p.505 + * MEGA62/128/256_RFR2 [MANUAL] p.138 + * MEGA62/128/256_RFR2 [MANUAL] p.492 + * + * usr_sign_0/1 are configurable values on flash page 1. + */ +void cpuid_get(void *id) +{ + uint8_t signature_0 = boot_signature_byte_get(0x00); + uint8_t signature_1 = boot_signature_byte_get(0x02); + uint8_t signature_2 = boot_signature_byte_get(0x04); + + uint8_t usr_sign_0 = boot_signature_byte_get(0x0100); + uint8_t usr_sign_1 = boot_signature_byte_get(0x0102); + + uint8_t addr[CPUID_LEN] = { + signature_0, /* 0x1E Atmel manufacturer ID */ + signature_1, /* 0xA8 Part Number high byte */ + signature_2, /* 0x02 Part Number low byte */ + MAN_ID_0, /* 0x1F Atmel JEDEC manufacturer ID */ + PART_NUM, /* 0x94 PART_NUM Identification */ + VERSION_NUM, /* 0x02 VERSION_NUM Identification */ +/* last two bytes can be set to flash page 1. for differentiation of different boards */ + usr_sign_0, /* user signature 0 */ + usr_sign_1, /* user signature 1 */ + }; + +#if defined(ENABLE_DEBUG) + DEBUG("CPUID: " ); + for (uint8_t i=0; i + * @author Josua Arndt + * @author Steffen Robertz + * @} + */ + +#include +#include +#include + +/* For Catchall-Loop */ +#include "board.h" + +/** + * @brief functions for initializing the board, std-lib and kernel + */ +extern void board_init(void); +extern void kernel_init(void); +extern void __libc_init_array(void); + +/** + * @brief This pair of functions hook circumvent the call to main + * + * avr-libc normally uses the .init9 section for a call to main. This call + * seems to be not replaceable without hacking inside the library. We + * circumvent the call to main by using section .init7 to call the function + * reset_handler which therefore is the real entry point and section .init8 + * which should never be reached but just in case jumps to exit. + * This way there should be no way to call main directly. + */ +void init7_ovr(void) __attribute__((section(".init7"))); +void init8_ovr(void) __attribute__((section(".init8"))); + +__attribute__((used, naked)) void init7_ovr(void) +{ + __asm__ ("call reset_handler"); +} + +__attribute__((used, naked)) void init8_ovr(void) +{ + __asm__ ("jmp exit"); +} + +/** + * @brief This function is the entry point after a system reset + * + * After a system reset, the following steps are necessary and carried out: + * 1. initialize the board (sync clock, setup std-IO) + * 2. initialize and start RIOTs kernel + */ +__attribute__((used)) void reset_handler(void) +{ + /* initialize the board and startup the kernel */ + board_init(); + /* startup the kernel */ + kernel_init(); +}