1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #15758 from nandojve/avr8_xmega

Introduce ATxmega CPU and Boards
This commit is contained in:
benpicco 2021-03-20 22:09:07 +01:00 committed by GitHub
commit ee5b70730b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
108 changed files with 3591 additions and 137 deletions

View File

@ -9,6 +9,7 @@
/.murdock @kaspar030
/boards/common/atxmega/ @nandojve
/boards/common/esp*/ @gschorcht
/boards/common/nrf*/ @aabadie @haukepetersen
/boards/common/nucleo*/ @aabadie
@ -34,11 +35,14 @@
/boards/stk3*00/ @basilfx
/boards/openmote*/ @MrKevinWeiss
/boards/cc1352p-launchpad @luisan00
/boards/atxmega*/ @nandojve
/core/ @kaspar030
/cpu/arm7_common/ @kaspar030 @maribu
/cpu/avr8_common/ @kYc0o @roberthartung @maribu @nandojve
/cpu/atmega*/ @kYc0o @roberthartung @maribu
/cpu/atxmega/ @nandojve
/cpu/cc2538/ @hexluthor @smlng @fjmolinas
/cpu/cc26x0/ @hexluthor @smlng
/cpu/cc26x2_cc13x2/ @hexluthor @smlng

View File

@ -20,7 +20,6 @@
#include "board.h"
#include "cpu.h"
#include "irq.h"
#include "periph/gpio.h"
#ifndef CPU_ATMEGA_CLK_SCALE_INIT
@ -38,5 +37,4 @@ void board_init(void)
avr8_stdio_init();
cpu_init();
led_init();
irq_enable();
}

View File

@ -0,0 +1,24 @@
# Copyright (c) 2020 HAW Hamburg
# Copyright (c) 2021 Gerson Fernando Budle
#
# 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.
config BOARD
default "atxmega-a1u-xpro" if BOARD_ATXMEGA_A1U_XPRO
config BOARD_ATXMEGA_A1U_XPRO
bool
default y
select CPU_MODEL_XMEGA128A1U
select HAS_PERIPH_CPUID
select HAS_PERIPH_GPIO
select HAS_PERIPH_GPIO_IRQ
select HAS_PERIPH_NVM
select HAS_PERIPH_PM
select HAS_PERIPH_TIMER
select HAS_PERIPH_TIMER_PERIODIC
select HAS_PERIPH_UART
select HAVE_SAUL_GPIO

View File

@ -0,0 +1,5 @@
MODULE = board
DIRS = $(RIOTBOARD)/common/atxmega
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,5 @@
USEMODULE += boards_common_atxmega
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
endif

View File

@ -0,0 +1,3 @@
CPU_MODEL = atxmega128a1u
include $(RIOTBOARD)/common/atxmega/Makefile.features

View File

@ -0,0 +1,4 @@
AVRDUDE_PROGRAMMER = xplainedpro_pdi
DEBUGPROTO = -X
include $(RIOTBOARD)/common/atxmega/Makefile.include

View File

@ -0,0 +1,66 @@
/**
@defgroup boards_atxmega-a1u-xpro ATxmega-A1U Xplained Pro board
@ingroup boards
@brief Support for the ATxmega-A1U Xplained Pro board
## Overview
The ATxmega-A1U Xplained Pro is the reference to develop with XMEGA's.
### MCU
| MCU | ATxmega128A1U |
|:------------- |:--------------------------------------------- |
| Family | AVR/ATxmega |
| Vendor | Microchip (previously Atmel) |
| Flash | 128KiB |
| RAM | 8KiB |
| EBI | 16MiB SRAM, 128MiB SDRAM |
| EEPROM | 2KiB |
| Frequency | up to 32MHz |
| Timers | 8 16bit (32 bit combining 2 x 16 bit) |
| ACs | 4 Analog Comparators |
| ADCs | 2 - 16 channels - 12 bit - 2msps |
| ADCs | 2 - 2 channels - 12 bit - 1msps |
| UARTs | 8 (can be used in SPI mode) with 1 IrDA |
| SPIs | 4 |
| I2Cs | 4 (called TWI) |
| USB | 1 port |
| DMA | 4 Channels |
| Event System | 8 Channels |
| Ext. INT | All GPIOs |
| Crypto | AES/DES, CRC-16, CRC-32 |
| Vcc | 1.6V - 3.6V |
| Datasheet | [Datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/ATxmega128A1U-64A1U-Data-Sheet-DS40002058A.pdf) |
| Xmega Manual | [Manual](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8331-8-and-16-bit-AVR-Microcontroller-XMEGA-AU_Manual.pdf) |
| Guide | [User Guide](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42211-XMEGA-A1U-Xplained-Pro_User-Guide.pdf) |
| Design Files | [Files](https://ww1.microchip.com/downloads/en/DeviceDoc/XMEGA-A1U-Xplained-Pro_Design-Documentation.zip) |
## Flashing the Device
The ATxmega-A1U Xplained Pro came with a full EDBG + CDC-ACM. The EDBG works
with default avrdude tool. However, the below programmer must have at
/etc/avrdude.conf file:
programmer
id = "xplainedpro_pdi";
desc = "Atmel AVR XplainedPro in PDI mode";
type = "jtagice3_pdi";
connection_type = usb;
usbpid = 0x2111;
;
In order to flash the ATxmega128A1U, simple run:
make BOARD=atxmega-a1u-xpro flash
## Serial Terminal
The CDC-ACM will enumerate a /dev/ttyACM device.
make BOARD=atxmega-a1u-xpro term
## On-Chip Debugging (OCD)
make debug
*/

View File

@ -0,0 +1,104 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke
*
* 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 boards_atxmega-a1u-xpro
* @{
*
* @file
* @brief Board specific definitions for the ATxmegaA1U Xplained Pro board.
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#ifndef BOARD_H
#define BOARD_H
#include "cpu.h"
#include "macros/units.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Clock configuration
*/
#define CLOCK_CORECLOCK MHZ(32)
/**
* @name Baudrate for STDIO terminal
*
* The standard configuration for STDIO in cpu/atxmega/periph/uart.c
* is to use double speed.
*
* For 32MHz F_CPU following Baudrate have good error rates
* 115200
*
* Matches this with BAUD in Board/Makefile.include
*
* @{
*/
#ifndef STDIO_UART_BAUDRATE
#define STDIO_UART_BAUDRATE (115200U)
#endif
/** @} */
/**
* @name LED pin definitions and handlers
* @{
*/
#define LED_PORT PORTQ
#define LED0_PIN GPIO_PIN(PORT_Q, 3)
#define LED0_MODE GPIO_OUT
#define LED0_MASK (PIN3_bm)
#define LED0_ON (LED_PORT.OUTCLR = LED0_MASK)
#define LED0_OFF (LED_PORT.OUTSET = LED0_MASK)
#define LED0_TOGGLE (LED_PORT.OUTTGL = LED0_MASK)
#define LED_PORT_MASK (LED0_MASK)
/** @} */
/**
* @name Button pin configuration
* @{
*/
#define BTN0_PIN GPIO_PIN(PORT_Q, 2)
#define BTN0_MODE (GPIO_IN | GPIO_OPC_PU | GPIO_SLEW_RATE)
#define BTN0_INT_FLANK (GPIO_ISC_FALLING | GPIO_LVL_LOW)
/** @} */
/**
* @name xtimer configuration values
* if XTIMER_HZ > 1MHz then (XTIMER_HZ != (1000000ul << XTIMER_SHIFT))
* if XTIMER_HZ < 1MHz then ((XTIMER_HZ << XTIMER_SHIFT) != 1000000ul)
*
* 32MHz Core Clock
* XTIMER_HZ 4000000 (clkdiv 8 ) XTIMER_SHIFT 2
* XTIMER_HZ 1000000 () XTIMER_SHIFT 0
* XTIMER_HZ 500000 (clkdiv 64) XTIMER_SHIFT 1
* XTIMER_HZ 250000 (clkdiv 128) XTIMER_SHIFT 2
* XTIMER_HZ 31250 (clkdiv 1024) XTIMER_SHIFT 5
*
* @{
*/
#define XTIMER_DEV TIMER_DEV(0)
#define XTIMER_CHAN (0)
#define XTIMER_WIDTH (16)
#define XTIMER_HZ KHZ(500)
#define XTIMER_BACKOFF (150)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* BOARD_H */
/** @} */

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke
*
* 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 boards_atxmega-a1u-xpro
* @{
*
* @file
* @brief Configuration of SAUL mapped GPIO pins
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief GPIO configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
{
.name = "SW0",
.pin = BTN0_PIN,
.mode = BTN0_MODE,
.flags = SAUL_GPIO_INVERTED,
},
{
.name = "LED0 (Yellow)",
.pin = LED0_PIN,
.mode = LED0_MODE,
.flags = SAUL_GPIO_INVERTED,
},
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke
*
* 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 boards_atxmega-a1u-xpro
* @{
*
* @file
* @brief Peripheral MCU configuration for the ATxmegaA1U Xplained Pro board.
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#include "mutex.h"
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <avr/io.h>
#include "periph_cpu.h"
/**
* @name Timer peripheral configuration
* @{
*/
static const timer_conf_t timer_config[] = {
{
.dev = (void *)&TCC1,
.type = TC_TYPE_1,
.int_lvl = { CPU_INT_LVL_LOW,
CPU_INT_LVL_OFF,
CPU_INT_LVL_OFF,
CPU_INT_LVL_OFF },
},
{
.dev = (void *)&TCC0,
.type = TC_TYPE_0,
.int_lvl = { CPU_INT_LVL_LOW,
CPU_INT_LVL_LOW,
CPU_INT_LVL_LOW,
CPU_INT_LVL_LOW },
}
};
#define TIMER_0_ISRA TCC1_CCA_vect
#define TIMER_1_ISRA TCC0_CCA_vect
#define TIMER_1_ISRB TCC0_CCB_vect
#define TIMER_1_ISRC TCC0_CCC_vect
#define TIMER_1_ISRD TCC0_CCD_vect
#define TIMER_NUMOF ARRAY_SIZE(timer_config)
/** @} */
/**
* @name UART configuration
* @{
*/
static const uart_conf_t uart_config[] = {
{ /* CDC-ACM */
.dev = &USARTE0,
.rx_pin = GPIO_PIN(PORT_E, 2),
.tx_pin = GPIO_PIN(PORT_E, 3),
#ifdef MODULE_PERIPH_UART_HW_FC
.rts_pin = GPIO_UNDEF,
.cts_pin = GPIO_UNDEF,
#endif
.rx_int_lvl = CPU_INT_LVL_LOW,
.tx_int_lvl = CPU_INT_LVL_LOW,
.dre_int_lvl = CPU_INT_LVL_OFF,
},
};
/* interrupt function name mapping */
#define UART_0_RXC_ISR USARTE0_RXC_vect /* Reception Complete Interrupt */
#define UART_0_DRE_ISR USARTE0_DRE_vect /* Data Register Empty Interrupt */
#define UART_0_TXC_ISR USARTE0_TXC_vect /* Transmission Complete Interrupt */
#define UART_NUMOF ARRAY_SIZE(uart_config)
/** @} */
#ifdef __cplusplus
}
#endif
#include "periph_conf_common.h"
#endif /* PERIPH_CONF_H */
/** @} */

View File

@ -20,7 +20,6 @@
#include "board.h"
#include "cpu.h"
#include "irq.h"
#include "periph/gpio.h"
#ifndef CPU_ATMEGA_CLK_SCALE_INIT
@ -42,5 +41,4 @@ void __attribute__((weak)) board_init(void)
#ifdef LED0_ON
led_init();
#endif
irq_enable();
}

View File

@ -0,0 +1,3 @@
MODULE = boards_common_atxmega
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
CPU = atxmega

View File

@ -0,0 +1,38 @@
INCLUDES += -I$(RIOTBOARD)/common/atxmega/include
# Use JTAG as default protocol for debugging
DEBUGPROTO ?= -x
FLASHFILE ?= $(ELFFILE)
# Use avrdude programmer with Atmel ICE as default flash/debug system
PROGRAMMER ?= avrdude
AVRDUDE_PROGRAMMER ?= atmelice
ifneq (,$(filter flash%,$(MAKECMDGOALS)))
FFLAGS_EXTRA ?= -e
endif
# If avrdude specific programmer is not set, set it based on the bootloader used
ifeq (,$(AVRDUDE_PROGRAMMER))
FLASHFILE ?= $(BINFILE)
ifeq (stk500v2,$(BOOTLOADER))
AVRDUDE_PROGRAMMER = stk500v2
BOOTLOADER_SIZE ?= 4K
# Disable auto erase; erasing the flash is done implicitly by the bootloader
# and explicit erase is not supported
FFLAGS_EXTRA += -D
endif
ifeq (avr109,$(BOOTLOADER))
AVRDUDE_PROGRAMMER = avr109
BOOTLOADER_SIZE ?= 4K
endif
ifneq (,$(BOOTLOADER_BAUD))
FFLAGS_EXTRA += -b $(BOOTLOADER_BAUD)
endif
endif
BOOTLOADER_SIZE ?= 0
ROM_RESERVED ?= $(BOOTLOADER_SIZE)

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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 boards_common
* @{
*
* @file
* @brief Common implementations for ATxmega boards
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
* @}
*/
#include "board.h"
#include "cpu.h"
#ifdef LED_PORT
void __attribute__((weak)) led_init(void)
{
LED_PORT.DIR = LED_PORT_MASK;
LED_PORT.OUT = LED_PORT_MASK;
}
#endif
void __attribute__((weak)) board_init(void)
{
cpu_init();
#ifdef LED_PORT
led_init();
#endif
}

View File

@ -0,0 +1,5 @@
/**
@defgroup boards_common_atxmega ATxmega common
@ingroup boards
@brief Shared files and configuration for ATxmega-based boards
*/

View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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 boards_common_atxmega
* @{
*
* @file
* @brief Common configuration of MCU periphery for ATxmega boards
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#ifndef PERIPH_CONF_COMMON_H
#define PERIPH_CONF_COMMON_H
#include "periph_cpu.h"
#include "macros/units.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Clock configuration
* @{
*/
#ifndef CLOCK_CORECLOCK
#define CLOCK_CORECLOCK MHZ(32)
#endif /* CLOCK_CORECLOCK */
/** @} */
/**
* @name ADC Configuration
*
* @{
*/
#ifndef ADC_NUMOF
#define ADC_NUMOF (0U)
#endif /* ADC_NUMOF */
/** @} */
/**
* @name I2C configuration
* @{
*/
#ifndef I2C_NUMOF
#define I2C_NUMOF (0U)
#endif /* I2C_NUMOF */
/** @} */
/**
* @name PWM configuration
*
* @{
*/
#ifndef PWM_NUMOF
#define PWM_NUMOF (0U)
#endif /* PWM_NUMOF */
/** @} */
/**
* @name SPI configuration
*
* The SS pin must be configured as output for the SPI device to work as
* master correctly, though we do not use it for now (as we handle the chip
* select externally for now)
*
* @{
*/
#ifndef SPI_NUMOF
#define SPI_NUMOF (0U)
#endif /* SPI_NUMOF */
/** @} */
/**
* @name UART configuration
*
* The UART devices have fixed pin mappings, so all we need to do, is to specify
* which devices we would like to use and their corresponding RX interrupts. See
* the reference manual for the fixed pin mapping.
*
* @{
*/
#ifndef UART_NUMOF
#define UART_NUMOF (0U)
#endif /* UART_NUMOF */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CONF_COMMON_H */
/** @} */

View File

@ -24,7 +24,6 @@
#include "board.h"
#include "cpu.h"
#include "irq.h"
/**
* @brief Initialize the boards on-board LEDs (green and red)
@ -61,5 +60,4 @@ void board_init(void)
cpu_init();
led_init();
irq_enable();
}

View File

@ -4,11 +4,16 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config HAS_CPU_CORE_ATMEGA
bool
select CPU_ARCH_AVR8
select HAS_CPP
config CPU_COMMON_ATMEGA
bool
select CPU_CORE_AVR
select HAS_CPU_CORE_ATMEGA
select HAS_ATMEGA_PCINT0
select HAS_CPP
select HAS_DBGPIN
select HAS_PERIPH_CPUID
select HAS_PERIPH_EEPROM

View File

@ -3,6 +3,7 @@ include $(RIOTCPU)/avr8_common/Makefile.features
# common feature are defined in avr8_common/Makefile.features
# Only add Additional features
FEATURES_PROVIDED += cpu_core_atmega
FEATURES_PROVIDED += atmega_pcint0
FEATURES_PROVIDED += dbgpin
FEATURES_PROVIDED += periph_cpuid

85
cpu/atxmega/Kconfig Normal file
View File

@ -0,0 +1,85 @@
# Copyright (c) 2020 HAW Hamburg
# Copyright (c) 2021 Gerson Fernando Budke
#
# 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.
#
config HAS_CPU_CORE_ATXMEGA
bool
select CPU_ARCH_AVR8
select HAS_CPU_ATXMEGA
select HAS_CPP
config CPU_COMMON_ATXMEGA
bool
select HAS_CPU_CORE_ATXMEGA
select HAS_PERIPH_CPUID
select HAS_PERIPH_GPIO
select HAS_PERIPH_GPIO_IRQ
select HAS_PERIPH_NVM
select HAS_PERIPH_PM
select HAS_PERIPH_TIMER
select HAS_PERIPH_TIMER_PERIODIC
select HAS_PERIPH_UART
config CPU_CORE_ATXMEGA_A1
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_A3
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_A4
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_B1
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_B3
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_C3
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_C4
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_D3
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_D4
bool
select CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_E5
bool
select CPU_COMMON_ATXMEGA
config CPU
default "atxmega" if CPU_COMMON_ATXMEGA
source "$(RIOTCPU)/atxmega/Kconfig.XMEGAA"
source "$(RIOTCPU)/atxmega/Kconfig.XMEGAB"
source "$(RIOTCPU)/atxmega/Kconfig.XMEGAC"
source "$(RIOTCPU)/atxmega/Kconfig.XMEGAD"
source "$(RIOTCPU)/atxmega/Kconfig.XMEGAE"
## Declaration of specific features
config HAS_CPU_ATXMEGA
bool
config HAS_PERIPH_NVM
bool
help
Indicates that the Non Volatile Memory controller is present.
source "$(RIOTCPU)/avr8_common/Kconfig"

105
cpu/atxmega/Kconfig.XMEGAA Normal file
View File

@ -0,0 +1,105 @@
## CPU Models
# XMEGA - A1/A1U
config CPU_MODEL_XMEGA64A1
bool
select CPU_CORE_ATXMEGA_A1
config CPU_MODEL_XMEGA128A1
bool
select CPU_CORE_ATXMEGA_A1
config CPU_MODEL_XMEGA64A1U
bool
select CPU_CORE_ATXMEGA_A1
config CPU_MODEL_XMEGA128A1U
bool
select CPU_CORE_ATXMEGA_A1
# XMEGA - A3/A3U/A3BU
config CPU_MODEL_XMEGA64A3
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA128A3
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA192A3
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA256A3
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA64A3U
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA128A3U
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA192A3U
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA256A3U
bool
select CPU_CORE_ATXMEGA_A3
config CPU_MODEL_XMEGA256A3BU
bool
select CPU_CORE_ATXMEGA_A3
# XMEGA - A4/A4U
config CPU_MODEL_XMEGA16A4
bool
select CPU_CORE_ATXMEGA_A4
config CPU_MODEL_XMEGA32A4
bool
select CPU_CORE_ATXMEGA_A4
config CPU_MODEL_XMEGA16A4U
bool
select CPU_CORE_ATXMEGA_A4
config CPU_MODEL_XMEGA32A4U
bool
select CPU_CORE_ATXMEGA_A4
config CPU_MODEL_XMEGA64A4U
bool
select CPU_CORE_ATXMEGA_A4
config CPU_MODEL_XMEGA128A4U
bool
select CPU_CORE_ATXMEGA_A4
config CPU_MODEL
string
default "atxmega64a1" if CPU_MODEL_XMEGA64A1
default "atxmega128a1" if CPU_MODEL_XMEGA128A1
default "atxmega192a1" if CPU_MODEL_XMEGA192A1
default "atxmega256a1" if CPU_MODEL_XMEGA256A1
default "atxmega64a1u" if CPU_MODEL_XMEGA64A1U
default "atxmega128a1u" if CPU_MODEL_XMEGA128A1U
default "atxmega64a3" if CPU_MODEL_XMEGA64A3
default "atxmega128a3" if CPU_MODEL_XMEGA128A3
default "atxmega192a3" if CPU_MODEL_XMEGA192A3
default "atxmega256a3" if CPU_MODEL_XMEGA256A3
default "atxmega64a3u" if CPU_MODEL_XMEGA64A3U
default "atxmega128a3u" if CPU_MODEL_XMEGA128A3U
default "atxmega192a3u" if CPU_MODEL_XMEGA192A3U
default "atxmega256a3u" if CPU_MODEL_XMEGA256A3U
default "atxmega256a3bu" if CPU_MODEL_XMEGA256A3BU
default "atxmega16a4" if CPU_MODEL_XMEGA16A4
default "atxmega32a4" if CPU_MODEL_XMEGA32A4
default "atxmega16a4u" if CPU_MODEL_XMEGA16A4U
default "atxmega32a4u" if CPU_MODEL_XMEGA32A4U
default "atxmega64a4u" if CPU_MODEL_XMEGA64A4U
default "atxmega128a4u" if CPU_MODEL_XMEGA128A4U

View File

@ -0,0 +1,25 @@
## CPU Models
# XMEGA - B1
config CPU_MODEL_XMEGA64B1
bool
select CPU_CORE_ATXMEGA_B1
config CPU_MODEL_XMEGA128B1
bool
select CPU_CORE_ATXMEGA_B1
# XMEGA - B3
config CPU_MODEL_XMEGA64B3
bool
select CPU_CORE_ATXMEGA_B3
config CPU_MODEL_XMEGA128B3
bool
select CPU_CORE_ATXMEGA_B3
config CPU_MODEL
default "atxmega64b3" if CPU_MODEL_XMEGA64B3
default "atxmega128b3" if CPU_MODEL_XMEGA128B3
default "atxmega64b1" if CPU_MODEL_XMEGA64B1
default "atxmega128b1" if CPU_MODEL_XMEGA128B1

View File

@ -0,0 +1,45 @@
## CPU Models
# XMEGA - C3
config CPU_MODEL_XMEGA32C3
bool
select CPU_CORE_ATXMEGA_C3
config CPU_MODEL_XMEGA64C3
bool
select CPU_CORE_ATXMEGA_C3
config CPU_MODEL_XMEGC128C3
bool
select CPU_CORE_ATXMEGA_C3
config CPU_MODEL_XMEGC192C3
bool
select CPU_CORE_ATXMEGA_C3
config CPU_MODEL_XMEGA256C3
bool
select CPU_CORE_ATXMEGA_C3
config CPU_MODEL_XMEGA384C3
bool
select CPU_CORE_ATXMEGA_C3
# XMEGA - C4
config CPU_MODEL_XMEGA16C4
bool
select CPU_CORE_ATXMEGA_C4
config CPU_MODEL_XMEGA32C4
bool
select CPU_CORE_ATXMEGA_C4
config CPU_MODEL
default "atxmega32c3" if CPU_MODEL_XMEGA32C3
default "atxmega64c3" if CPU_MODEL_XMEGA64C3
default "atxmega128c3" if CPU_MODEL_XMEGC128C3
default "atxmega192c3" if CPU_MODEL_XMEGC192C3
default "atxmega256c3" if CPU_MODEL_XMEGA256C3
default "atxmega384c3" if CPU_MODEL_XMEGA384C3
default "atxmega16c4" if CPU_MODEL_XMEGA16C4
default "atxmega32c4" if CPU_MODEL_XMEGA32C4

View File

@ -0,0 +1,55 @@
## CPU Models
# XMEGA - D3
config CPU_MODEL_XMEGA32D3
bool
select CPU_CORE_ATXMEGA_D3
config CPU_MODEL_XMEGA64D3
bool
select CPU_CORE_ATXMEGA_D3
config CPU_MODEL_XMEGC128D3
bool
select CPU_CORE_ATXMEGA_D3
config CPU_MODEL_XMEGC192D3
bool
select CPU_CORE_ATXMEGA_D3
config CPU_MODEL_XMEGA256D3
bool
select CPU_CORE_ATXMEGA_D3
config CPU_MODEL_XMEGA384D3
bool
select CPU_CORE_ATXMEGA_D3
# XMEGA - D4
config CPU_MODEL_XMEGA16D4
bool
select CPU_CORE_ATXMEGA_D4
config CPU_MODEL_XMEGA32D4
bool
select CPU_CORE_ATXMEGA_D4
config CPU_MODEL_XMEGA64D4
bool
select CPU_CORE_ATXMEGA_D4
config CPU_MODEL_XMEGA128D4
bool
select CPU_CORE_ATXMEGA_D4
config CPU_MODEL
default "atxmega32d3" if CPU_MODEL_XMEGA32D3
default "atxmega64d3" if CPU_MODEL_XMEGA64D3
default "atxmega128d3" if CPU_MODEL_XMEGC128D3
default "atxmega192d3" if CPU_MODEL_XMEGC192D3
default "atxmega256d3" if CPU_MODEL_XMEGA256D3
default "atxmega384d3" if CPU_MODEL_XMEGA384D3
default "atxmega16d4" if CPU_MODEL_XMEGA16D4
default "atxmega32d4" if CPU_MODEL_XMEGA32D4
default "atxmega64d4" if CPU_MODEL_XMEGA64D4
default "atxmega128d4" if CPU_MODEL_XMEGA128D4

View File

@ -0,0 +1,17 @@
## CPU Models
config CPU_MODEL_XMEGA8E5
bool
select CPU_CORE_ATXMEGA_E5
config CPU_MODEL_XMEGA16E5
bool
select CPU_CORE_ATXMEGA_E5
config CPU_MODEL_XMEGA32E5
bool
select CPU_CORE_ATXMEGA_E5
config CPU_MODEL
default "atxmega8e5" if CPU_MODEL_XMEGA8E5
default "atxmega16e5" if CPU_MODEL_XMEGA16E5
default "atxmega32e5" if CPU_MODEL_XMEGA32E5

7
cpu/atxmega/Makefile Normal file
View File

@ -0,0 +1,7 @@
# define the module that is build
MODULE = cpu
# add a list of subdirectories, that should also be build
DIRS = periph $(RIOTCPU)/avr8_common/
include $(RIOTBASE)/Makefile.base

11
cpu/atxmega/Makefile.dep Normal file
View File

@ -0,0 +1,11 @@
# peripheral drivers are linked into the final binary
USEMODULE += atxmega_periph
# All ATxmega based CPUs provide PM
USEMODULE += pm_layered
ifeq (,$(filter cpuid,$(USEMODULE)))
USEMODULE += periph_nvm
endif
include $(RIOTCPU)/avr8_common/Makefile.dep

View File

@ -0,0 +1,12 @@
include $(RIOTCPU)/avr8_common/Makefile.features
# common feature are defined in avr8_common/Makefile.features
# Only add Additional features
FEATURES_PROVIDED += cpu_core_atxmega
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_nvm
FEATURES_PROVIDED += periph_pm
FEATURES_PROVIDED += periph_timer periph_timer_periodic
FEATURES_PROVIDED += periph_uart

View File

@ -0,0 +1,38 @@
export CPU_ATXMEGA 1
# CPU ROM/RAM
ifneq (,$(findstring atxmega8,$(CPU_MODEL)))
RAM_LEN = 1K
ROM_LEN = 8K
endif
ifneq (,$(findstring atxmega16,$(CPU_MODEL)))
RAM_LEN = 2K
ROM_LEN = 16K
endif
ifneq (,$(findstring atxmega32,$(CPU_MODEL)))
RAM_LEN = 4K
ROM_LEN = 32K
endif
ifneq (,$(findstring atxmega64,$(CPU_MODEL)))
RAM_LEN ?= 4K
ROM_LEN = 64K
endif
#ifneq (,$(findstring atxmega128,$(CPU_MODEL)))
RAM_LEN ?= 8K
ROM_LEN = 128K
#endif
ifneq (,$(findstring atxmega192,$(CPU_MODEL)))
RAM_LEN = 16K
ROM_LEN = 192K
endif
ifneq (,$(findstring atxmega256,$(CPU_MODEL)))
RAM_LEN = 16K
ROM_LEN = 256K
endif
ifneq (,$(findstring atxmega384,$(CPU_MODEL)))
RAM_LEN = 32K
ROM_LEN = 384K
endif
# CPU depends on the avr8 common module, so include it
include $(RIOTCPU)/avr8_common/Makefile.include

132
cpu/atxmega/atxmega_cpu.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke
*
* 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_atxmega
* @{
*
* @file
* @brief Implementation of the CPU initialization
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
* @}
*/
#include <avr/pgmspace.h>
#include "cpu.h"
#include "cpu_clock.h"
#include "panic.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#ifndef CPU_ATXMEGA_CLK_SCALE_INIT
#define CPU_ATXMEGA_CLK_SCALE_INIT CPU_ATXMEGA_CLK_SCALE_DIV1
#endif
#ifndef CPU_ATXMEGA_BUS_SCALE_INIT
#define CPU_ATXMEGA_BUS_SCALE_INIT CPU_ATXMEGA_BUS_SCALE_DIV1_1
#endif
extern uint8_t mcusr_mirror;
void avr8_reset_cause(void)
{
if (mcusr_mirror & (1 << RST_PORF_bp)) {
DEBUG("Power-on reset.\n");
}
if (mcusr_mirror & (1 << RST_EXTRF_bp)) {
DEBUG("External reset!\n");
}
if (mcusr_mirror & (1 << RST_BORF_bp)) {
DEBUG("Brown-out reset!\n");
}
if (mcusr_mirror & (1 << RST_WDRF_bp)) {
DEBUG("Watchdog reset!\n");
}
if (mcusr_mirror & (1 << RST_PDIRF_bp)) {
DEBUG("Programming and Debug Interface reset!\n");
}
if (mcusr_mirror & (1 << RST_SRF_bp)) {
DEBUG("Software reset!\n");
}
if (mcusr_mirror & (1 << RST_SDRF_bp)) {
DEBUG("Spike Detection reset!\n");
}
}
void __attribute__((weak)) avr8_clk_init(void)
{
volatile uint8_t *reg = (uint8_t *)&PR.PRGEN;
uint8_t i;
/* Turn off all peripheral clocks that can be turned off. */
for (i = 0; i <= 7; i++) {
reg[i] = 0xff;
}
/* Turn on all peripheral clocks that can be turned on. */
for (i = 0; i <= 7; i++) {
reg[i] = 0x00;
}
/* XMEGA A3U [DATASHEET] p.23 After reset, the device starts up running
* from the 2MHz internal oscillator. The other clock sources, DFLLs
* and PLL, are turned off by default.
*
* Configure clock to 32MHz with calibration
* application note AVR1003
*
* From errata http://www.avrfreaks.net/forum/xmega-dfll-does-it-work
* In order to use the automatic runtime calibration for the 2 MHz or
* the 32 MHz internal oscillators, the DFLL for both oscillators and
* both oscillators has to be enabled for one to work.
*/
OSC.PLLCTRL = 0;
/* Enable the internal PLL & 32MHz & 32KHz oscillators */
OSC.CTRL |= OSC_PLLEN_bm | OSC_RC32MEN_bm | OSC_RC32KEN_bm;
/* Wait for 32Khz and 32MHz oscillator to stabilize */
while ((OSC.STATUS & (OSC_RC32KRDY_bm | OSC_RC32MRDY_bm))
!= (OSC_RC32KRDY_bm | OSC_RC32MRDY_bm)) {}
/* Enable DFLL - defaults to calibrate against internal 32Khz clock */
DFLLRC32M.CTRL = DFLL_ENABLE_bm;
/* Enable DFLL - defaults to calibrate against internal 32Khz clock */
DFLLRC2M.CTRL = DFLL_ENABLE_bm;
atxmega_set_prescaler(CPU_ATXMEGA_CLK_SCALE_INIT,
CPU_ATXMEGA_BUS_SCALE_INIT);
/* Disable CCP for Protected IO register and set new value*/
/* Switch to 32MHz clock */
_PROTECTED_WRITE(CLK.CTRL, CLK_SCLKSEL_RC32M_gc);
}
/* 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.
*/
ISR(BADISR_vect)
{
avr8_reset_cause();
#ifdef LED_PANIC
/* Use LED light to signal ERROR. */
LED_PANIC;
#endif
core_panic(PANIC_GENERAL_ERROR,
PSTR("FATAL ERROR: BADISR_vect called, unprocessed Interrupt.\n"
"STOP Execution.\n"));
}

10
cpu/atxmega/doc.txt Normal file
View File

@ -0,0 +1,10 @@
/**
* @defgroup cpu_atxmega Atmel ATxmega MCU
* @ingroup cpu
* @brief Implementation of Atmel's ATxmega MCU
*/
/**
* @defgroup cpu_atxmega_periph Atmel ATxmega MCU Peripherals
* @ingroup cpu_atxmega
*/

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @brief Common implementations and headers for ATxmega family based micro-controllers
* @{
*
* @file
* @brief Basic definitions for the ATxmega common clock module
*
* When ever you want to do something hardware related, that is accessing MCUs registers directly,
* just include this file. It will then make sure that the MCU specific headers are included.
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
*/
#ifndef CPU_CLOCK_H
#define CPU_CLOCK_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ATxmega system clock prescaler settings
*
* Some CPUs may not support the highest prescaler settings
*/
enum {
CPU_ATXMEGA_CLK_SCALE_DIV1 = 0,
CPU_ATXMEGA_CLK_SCALE_DIV2 = 1,
CPU_ATXMEGA_CLK_SCALE_DIV4 = 3,
CPU_ATXMEGA_CLK_SCALE_DIV8 = 5,
CPU_ATXMEGA_CLK_SCALE_DIV16 = 7,
CPU_ATXMEGA_CLK_SCALE_DIV32 = 9,
CPU_ATXMEGA_CLK_SCALE_DIV64 = 11,
CPU_ATXMEGA_CLK_SCALE_DIV128 = 13,
CPU_ATXMEGA_CLK_SCALE_DIV256 = 15,
CPU_ATXMEGA_CLK_SCALE_DIV512 = 17,
};
enum {
CPU_ATXMEGA_BUS_SCALE_DIV1_1 = 0,
CPU_ATXMEGA_BUS_SCALE_DIV1_2 = 1,
CPU_ATXMEGA_BUS_SCALE_DIV4_1 = 2,
CPU_ATXMEGA_BUS_SCALE_DIV2_2 = 3,
};
/**
* @brief Initializes system clock prescaler
*/
static inline void atxmega_set_prescaler(uint8_t clk_scale, uint8_t bus_scale)
{
/* Disable CCP for Protected IO register and set new value
* Set system clock prescalers to zero. PSCTRL contains A Prescaler
* Value and one value for and B and C Prescaler
*/
_PROTECTED_WRITE(CLK.PSCTRL, clk_scale | bus_scale);
}
#ifdef __cplusplus
}
#endif
#endif /* CPU_CLOCK_H */
/** @} */

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke
*
* 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_atxmega
* @{
*
* @file
* @brief Implementation specific CPU configuration options
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#ifndef CPU_CONF_H
#define CPU_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
#define THREAD_EXTRA_STACKSIZE_PRINTF (128)
/**
* @name Kernel configuration
*
* Since printf seems to get memory allocated by the
* linker/avr-libc the stack size tested successfully
* even with pretty small stacks.
* @{
*/
#ifndef THREAD_STACKSIZE_DEFAULT
#define THREAD_STACKSIZE_DEFAULT (512)
#endif
/* keep THREAD_STACKSIZE_IDLE > THREAD_EXTRA_STACKSIZE_PRINTF
* to avoid not printing of debug in interrupts
*/
#ifndef THREAD_STACKSIZE_IDLE
#ifdef MODULE_XTIMER
/* xtimer's 64 bit arithmetic doesn't perform well on 8 bit archs. In order to
* prevent a stack overflow when an timer triggers while the idle thread is
* running, we have to increase the stack size then
*/
#define THREAD_STACKSIZE_IDLE (384)
#else
#define THREAD_STACKSIZE_IDLE (192)
#endif
#endif
/** @} */
/**
* @brief Declare the heap_stats function as available
*/
#define HAVE_HEAP_STATS
/**
* @brief This arch uses the inlined IRQ API.
*/
#define IRQ_API_INLINED (1)
/**
* @brief This arch require special clock initialization.
*/
#define CPU_AVR8_HAS_CLOCK_INIT 1
#ifdef __cplusplus
}
#endif
#endif /* CPU_CONF_H */
/** @} */

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @brief Non Volatile Memory (NVM) internal API
* @{
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
*/
#ifndef CPU_NVM_H
#define CPU_NVM_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get offset of calibration bytes in the production signature row
*
* @note In some distributions may require most recent vendor headers, even
* more recent than the upstream avr-libc. The headers can be download
* directly from Microchip web site. In general, Microchip have a
* dedicated page at Tools and Software / AVR and SAM Downloads Archive.
* The most recent version is AVR 8-bit Toolchain (3.4.4) 6.2.0.334.
* http://ww1.microchip.com/downloads/archive/avr8-headers-6.2.0.334.zip
*
* The official RIOT-OS docker container, Debian and Ubuntu are
* distributions that already had updated versions of those files.
*
* @param regname Name of register within the production signature row
* @retval Offset of register into the production signature row
*/
#define nvm_get_production_signature_row_offset(regname) \
offsetof(NVM_PROD_SIGNATURES_t, regname)
/**
* @brief Read one byte from the production signature row
*
* This function reads one byte from the production signature row of the device
* at the given address.
*
* @note This function is modifying the NVM.CMD register.
* If the application are using program space access in interrupts
* (__flash pointers in IAR EW or pgm_read_byte in GCC) interrupts
* needs to be disabled when running EEPROM access functions. If not
* the program space reads will be corrupted.
*
* @param address Byte offset into the signature row
*/
uint8_t nvm_read_production_signature_row(uint8_t address);
#ifdef __cplusplus
}
#endif
#endif /* CPU_NVM_H */
/** @} */

View File

@ -0,0 +1,247 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @{
*
* @file
* @brief CPU specific definitions for internal peripheral handling
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#ifndef PERIPH_CPU_H
#define PERIPH_CPU_H
#include <avr/io.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Length of the CPU_ID in octets
* @{
*/
#define CPUID_LEN (11U)
/** @} */
/**
* @name Interrupt level used to control nested interrupts
* @{
*/
typedef enum {
CPU_INT_LVL_OFF, /**< Interrupt Disabled */
CPU_INT_LVL_LOW, /**< Interrupt Low Level */
CPU_INT_LVL_MID, /**< Interrupt Medium Level */
CPU_INT_LVL_HIGH, /**< Interrupt High Level */
} cpu_int_lvl_t;
/** @} */
/**
* @brief Available ports on the ATxmega family
*/
enum {
PORT_A, /**< port A - 600 - 0 */
PORT_B, /**< port B - 620 - 1 */
PORT_C, /**< port C - 640 - 2 */
PORT_D, /**< port D - 660 - 3 */
PORT_E, /**< port E - 680 - 4 */
PORT_F, /**< port F - 6A0 - 5 */
PORT_G, /**< port G - 6C0 - 6 */
PORT_H, /**< port H - 6E0 - 7 */
PORT_J, /**< port J - 700 - 8 */
PORT_K, /**< port K - 720 - 9 */
PORT_L, /**< port L - 740 - A */
PORT_M, /**< port M - 760 - B */
PORT_N, /**< port N - 780 - C */
PORT_P, /**< port P - 7A0 - D */
PORT_Q, /**< port Q - 7C0 - E */
PORT_R, /**< port R - 7E0 - F */
/* ... */
PORT_MAX,
};
/**
* @name Power management configuration
* @{
*/
#define PM_NUM_MODES (4)
/** @} */
/**
* @brief Define the number of GPIO interrupts vectors for ATxmega CPU.
* @{
*/
#define GPIO_EXT_INT_NUMOF (2 * PORT_MAX)
/** @} */
/**
* @brief Override GPIO type
* @{
*/
#define HAVE_GPIO_T
typedef uint16_t gpio_t;
/** @} */
/**
* @brief Definition of a fitting UNDEF value
*/
#define GPIO_UNDEF (0xffff)
/**
* @brief Define a CPU specific GPIO pin generator macro
*
* The ATxmega internally uses pin mask to manipulate all gpio functions.
* This allows simultaneous pin actions at any method call. ATxmega specific
* applications can use ATXMEGA_GPIO_PIN macro to define pins and generic
* RIOT-OS application should continue to use GPIO_PIN API for compatibility.
*
* @{
*/
#define ATXMEGA_GPIO_PIN(x, y) (((x & 0x0f) << 8) | (y & 0xff))
#define GPIO_PIN(x, y) ATXMEGA_GPIO_PIN(x, (1U << (y & 0x07)))
/** @} */
/**
* @brief Available pin modes
*
* Generally, a pin can be configured to be input or output. In output mode, a
* pin can further be put into push-pull or open drain configuration. Though
* this is supported by most platforms, this is not always the case, so driver
* implementations may return an error code if a mode is not supported.
* @{
*/
#define HAVE_GPIO_MODE_T
typedef enum GPIO_MODE {
GPIO_SLEW_RATE = (1 << 7), /**< enable slew rate */
GPIO_INVERTED = (1 << 6), /**< enable inverted signal */
GPIO_OPC_TOTEN = (0 << 3), /**< select no pull resistor (TOTEM) */
GPIO_OPC_BSKPR = (1 << 3), /**< push-pull mode (BUSKEEPER) */
GPIO_OPC_PD = (2 << 3), /**< pull-down resistor */
GPIO_OPC_PU = (3 << 3), /**< pull-up resistor */
GPIO_OPC_WRD_OR = (4 << 3), /**< enable wired OR */
GPIO_OPC_WRD_AND = (5 << 3), /**< enable wired AND */
GPIO_OPC_WRD_OR_PULL = (6 << 3), /**< enable wired OR and pull-down resistor */
GPIO_OPC_WRD_AND_PULL = (7 << 3), /**< enable wired AND and pull-up resistor */
GPIO_ANALOG = (1 << 1), /**< select GPIO for analog function */
GPIO_IN = (0 << 0), /**< select GPIO MASK as input */
GPIO_OUT = (1 << 0), /**< select GPIO MASK as output */
/* Compatibility Mode */
GPIO_IN_PU = GPIO_IN | GPIO_OPC_PU,
GPIO_IN_PD = GPIO_IN | GPIO_OPC_PD,
GPIO_OD = GPIO_OUT | GPIO_OPC_WRD_OR,
GPIO_OD_PU = GPIO_OUT | GPIO_OPC_WRD_OR_PULL,
} gpio_mode_t;
/** @} */
/**
* @brief Definition of possible active flanks for external interrupt mode
* @{
*/
#define HAVE_GPIO_FLANK_T
typedef enum {
GPIO_ISC_BOTH = (0 << 4), /**< emit interrupt on both flanks (default) */
GPIO_ISC_RISING = (1 << 4), /**< emit interrupt on rising flank */
GPIO_ISC_FALLING = (2 << 4), /**< emit interrupt on falling flank */
GPIO_ISC_LOW_LEVEL = (3 << 4), /**< emit interrupt on low level */
GPIO_INT_DISABLED_ALL = (1 << 3), /**< disable all interrupts */
GPIO_INT0_VCT = (0 << 2), /**< enable interrupt on Vector 0 (default) */
GPIO_INT1_VCT = (1 << 2), /**< enable interrupt on Vector 1 */
GPIO_LVL_OFF = (0 << 0), /**< interrupt disabled (default) */
GPIO_LVL_LOW = (1 << 0), /**< interrupt low level */
GPIO_LVL_MID = (2 << 0), /**< interrupt medium level */
GPIO_LVL_HIGH = (3 << 0), /**< interrupt higher */
/* Compatibility Mode */
GPIO_FALLING = GPIO_ISC_FALLING | GPIO_LVL_LOW,
GPIO_RISING = GPIO_ISC_RISING | GPIO_LVL_LOW,
GPIO_BOTH = GPIO_ISC_BOTH | GPIO_LVL_LOW,
} gpio_flank_t;
/** @} */
/**
* @brief Max number of available UARTs
*/
#define UART_MAX_NUMOF (7)
/**
* @brief Size of the UART TX buffer for non-blocking mode.
*/
#ifndef UART_TXBUF_SIZE
#define UART_TXBUF_SIZE (64)
#endif
/**
* @brief UART device configuration
*/
typedef struct {
USART_t *dev; /**< pointer to the used UART device */
gpio_t rx_pin; /**< pin used for RX */
gpio_t tx_pin; /**< pin used for TX */
#ifdef MODULE_PERIPH_UART_HW_FC
gpio_t rts_pin; /**< RTS pin */
gpio_t cts_pin; /**< CTS pin */
#endif
cpu_int_lvl_t rx_int_lvl; /**< RX Complete Interrupt Level */
cpu_int_lvl_t tx_int_lvl; /**< TX Complete Interrupt Level */
cpu_int_lvl_t dre_int_lvl; /**< Data Registry Empty Interrupt Level */
} uart_conf_t;
/**
* @brief Max number of available timer channels
*/
#define TIMER_CH_MAX_NUMOF (4)
/**
* @brief A low-level timer_set() implementation is provided
*/
#define PERIPH_TIMER_PROVIDES_SET
/**
* @brief Timer Type
*
* Timer Type 1 is equal to Type 0 (two channels instead four)
* Timer Type 2 is Type 0 configured as two 8 bit timers instead one 16 bit
* Timer Type 2 won't be available as a standard timer
* Timer Type 5 is equal to Type 4 (two channels instead four)
*/
typedef enum {
TC_TYPE_0 = 0,
TC_TYPE_1 = 1,
TC_TYPE_2 = 2,
TC_TYPE_4 = 4,
TC_TYPE_5 = 5,
} timer_type_t;
/**
* @brief Timer device configuration
*
* All timers can be derived from TC0_t struct. Need check at runtime the
* type and number of channels to perform all operations.
*/
typedef struct {
TC0_t *dev; /**< Pointer to the used as Timer device */
timer_type_t type; /**< Timer Type */
cpu_int_lvl_t int_lvl[TIMER_CH_MAX_NUMOF]; /**< Interrupt channels level */
} timer_conf_t;
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CPU_H */
/** @} */

View File

@ -0,0 +1,3 @@
MODULE = atxmega_periph
include $(RIOTMAKE)/periph.mk

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level CPUID driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
* @}
*/
#include "periph_cpu.h"
#include "cpu_nvm.h"
#define ENABLE_DEBUG 0
#include "debug.h"
void cpuid_get(void *id)
{
uint8_t *addr = id;
addr[0x0] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(LOTNUM0));
addr[0x1] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(LOTNUM1));
addr[0x2] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(LOTNUM2));
addr[0x3] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(LOTNUM3));
addr[0x4] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(LOTNUM4));
addr[0x5] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(LOTNUM5));
addr[0x6] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(WAFNUM));
addr[0x7] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(COORDX0));
addr[0x8] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(COORDX1));
addr[0x9] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(COORDY0));
addr[0xa] = nvm_read_production_signature_row(
nvm_get_production_signature_row_offset(COORDY1));
if (IS_ACTIVE(ENABLE_DEBUG)) {
DEBUG("CPUID: ");
for (uint8_t i = 0; i < CPUID_LEN; i++) {
DEBUG("%02x ", addr[i]);
}
DEBUG("\n");
}
}

546
cpu/atxmega/periph/gpio.c Normal file
View File

@ -0,0 +1,546 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
* @}
*/
#include <stdio.h>
#include <avr/interrupt.h>
#include "cpu.h"
#include "periph_conf.h"
#include "periph/gpio.h"
#include "bitarithm.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief GPIO port base
*
* GPIO_PORT_BASE resides in the IO address space and must be 16 bits.
*/
#define GPIO_PORT_BASE ((uint16_t)&PORTA)
/**
* @brief GPIO port structure offset
*
* The PORT_t struct it is not complete filled and it is necessary define the
* address offset manually.
*/
#define GPIO_PORT_OFFSET (0x20)
static gpio_isr_ctx_t config_ctx[GPIO_EXT_INT_NUMOF];
static uint8_t config_irq[GPIO_EXT_INT_NUMOF];
/**
* @brief Extract the pin number of the given pin
*/
static inline uint8_t _pin_mask(gpio_t pin)
{
return (pin & 0xff);
}
/**
* @brief Extract the port number of the given pin
*/
static inline uint8_t _port_num(gpio_t pin)
{
return (pin >> 8) & 0x0f;
}
/**
* @brief Generate the PORTx address of the give pin in the IO address space
*/
static inline PORT_t *_port_addr(gpio_t pin)
{
uint8_t port_num = _port_num(pin);
uint16_t port_addr = GPIO_PORT_BASE + (port_num * GPIO_PORT_OFFSET);
return (PORT_t *) port_addr;
}
static inline void _print_config(gpio_t pin)
{
PORT_t *port = _port_addr(pin);
uint8_t pin_mask = _pin_mask(pin);
volatile uint8_t *pin_ctrl = &port->PIN0CTRL;
DEBUG("PORT: 0x%04x, PIN: 0x%02x\n", (uint16_t)port, pin_mask);
DEBUG("DIR: 0x%02x, IN: 0x%02x, OUT: 0x%02x\n", port->DIR, port->IN, port->OUT);
DEBUG("INTCTRL: 0x%02x\nINTFLAGS: 0x%02x\n", port->INTCTRL, port->INTFLAGS);
DEBUG("INT0MASK: 0x%02x\nINT1MASK: 0x%02x\n", port->INT0MASK, port->INT1MASK);
for (uint8_t p = 0; p < 8; p++) {
DEBUG("PIN%dCTRL: 0x%02x\n", p, pin_ctrl[p]);
}
}
static inline void _gpio_pinctrl_set(gpio_t pin, gpio_mode_t mode,
gpio_flank_t flank, gpio_cb_t cb,
void *arg)
{
uint8_t pin_mask = _pin_mask(pin);
uint8_t port_num = _port_num(pin);
PORT_t *port = _port_addr(pin);
volatile uint8_t *pin_ctrl = &port->PIN0CTRL;
uint8_t irq_state;
uint8_t in_sense_cfg;
uint8_t pins;
uint8_t pin_idx;
in_sense_cfg = (mode & ~PORT_ISC_gm);
in_sense_cfg |= (mode & GPIO_ANALOG)
? PORT_ISC_INPUT_DISABLE_gc
: ((flank >> 4) & PORT_ISC_gm);
pins = pin_mask;
pin_idx = 0;
if (mode & GPIO_OUT) {
port->DIRSET = pin_mask;
}
else {
port->DIRCLR = pin_mask;
}
irq_state = irq_disable();
while (pins) {
pins = bitarithm_test_and_clear(pins, &pin_idx);
pin_ctrl[pin_idx] = in_sense_cfg;
}
if (flank & GPIO_INT_DISABLED_ALL) {
config_ctx[port_num + PORT_MAX].cb = NULL;
config_ctx[port_num + PORT_MAX].arg = NULL;
config_irq[port_num + PORT_MAX] = 0;
config_ctx[port_num].cb = NULL;
config_ctx[port_num].arg = NULL;
config_irq[port_num] = 0;
port->INTCTRL = 0;
port->INT1MASK = 0;
port->INT0MASK = 0;
port->INTFLAGS = PORT_INT1IF_bm | PORT_INT0IF_bm;
}
else if (flank & GPIO_INT1_VCT) {
config_ctx[port_num + PORT_MAX].cb = cb;
config_ctx[port_num + PORT_MAX].arg = arg;
config_irq[port_num + PORT_MAX] = (flank & GPIO_LVL_HIGH)
<< PORT_INT1LVL_gp;
if ((flank & GPIO_LVL_HIGH) == GPIO_LVL_OFF) {
port->INT1MASK &= ~pin_mask;
}
else {
port->INT1MASK |= pin_mask;
}
port->INTFLAGS = PORT_INT1IF_bm;
/* Get mask from INT 0 and apply new INT 1 mask */
port->INTCTRL = (port->INTCTRL & PORT_INT0LVL_gm)
| config_irq[port_num + PORT_MAX];
}
else {
config_ctx[port_num].cb = cb;
config_ctx[port_num].arg = arg;
config_irq[port_num] = (flank & GPIO_LVL_HIGH)
<< PORT_INT0LVL_gp;
if ((flank & GPIO_LVL_HIGH) == GPIO_LVL_OFF) {
port->INT0MASK &= ~pin_mask;
}
else {
port->INT0MASK |= pin_mask;
}
port->INTFLAGS = PORT_INT0IF_bm;
/* Get mask from INT 1 and apply new INT 0 mask */
port->INTCTRL = (port->INTCTRL & PORT_INT1LVL_gm)
| config_irq[port_num];
}
irq_restore(irq_state);
}
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
DEBUG("gpio_init pin = 0x%02x mode = 0x%02x\n", pin, mode);
_gpio_pinctrl_set(pin, mode, GPIO_INT_DISABLED_ALL, NULL, NULL);
return 0;
}
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
DEBUG("gpio_init_int pin = 0x%02x mode = 0x%02x flank = 0x%02x\n", pin,
mode, flank);
if (mode & GPIO_ANALOG) {
DEBUG("Pin can't be ANALOG (input buffer disabled) and INT at same time.\n");
return -1;
}
_gpio_pinctrl_set(pin, mode, flank, cb, arg);
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
return 0;
}
void gpio_irq_enable(gpio_t pin)
{
DEBUG("gpio_irq_enable pin = 0x%04x \n", pin);
uint8_t pin_mask = _pin_mask(pin);
uint8_t port_num = _port_num(pin);
PORT_t *port = _port_addr(pin);
if (port->INT1MASK & pin_mask) {
port->INTFLAGS = PORT_INT1IF_bm;
port->INTCTRL |= config_irq[port_num + PORT_MAX];
}
if (port->INT0MASK & pin_mask) {
port->INTFLAGS = PORT_INT0IF_bm;
port->INTCTRL |= config_irq[port_num];
}
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
}
void gpio_irq_disable(gpio_t pin)
{
DEBUG("gpio_irq_disable pin = 0x%04x \n", pin);
uint8_t pin_mask = _pin_mask(pin);
PORT_t *port = _port_addr(pin);
if (port->INT1MASK & pin_mask) {
port->INTCTRL &= ~PORT_INT1LVL_gm;
}
if (port->INT0MASK & pin_mask) {
port->INTCTRL &= ~PORT_INT0LVL_gm;
}
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
}
int gpio_read(gpio_t pin)
{
PORT_t *port = _port_addr(pin);
uint8_t pin_mask = _pin_mask(pin);
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
return port->IN & pin_mask;
}
void gpio_set(gpio_t pin)
{
DEBUG("gpio_set pin = 0x%04x \n", pin);
PORT_t *port = _port_addr(pin);
uint8_t pin_mask = _pin_mask(pin);
port->OUTSET = pin_mask;
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
}
void gpio_clear(gpio_t pin)
{
DEBUG("gpio_clear pin = 0x%04x \n", pin);
PORT_t *port = _port_addr(pin);
uint8_t pin_mask = _pin_mask(pin);
port->OUTCLR = pin_mask;
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
}
void gpio_toggle(gpio_t pin)
{
DEBUG("gpio_toggle pin = 0x%04x \n", pin);
PORT_t *port = _port_addr(pin);
uint8_t pin_mask = _pin_mask(pin);
port->OUTTGL = pin_mask;
if (IS_ACTIVE(ENABLE_DEBUG)) {
_print_config(pin);
}
}
void gpio_write(gpio_t pin, int value)
{
DEBUG("gpio_write pin = 0x%04x, value = 0x%02x \n", pin, value);
if (value) {
gpio_set(pin);
}
else {
gpio_clear(pin);
}
}
static inline void irq_handler(uint8_t port_num, uint8_t isr_vct_num)
{
avr8_enter_isr();
DEBUG("irq_handler port = 0x%02x, vct_num = %d \n", port_num, isr_vct_num);
if (isr_vct_num) {
port_num += PORT_MAX;
}
if (config_ctx[port_num].cb) {
config_ctx[port_num].cb(config_ctx[port_num].arg);
}
else {
DEBUG("WARNING! irq_handler without callback\n");
}
avr8_exit_isr();
}
#if defined(PORTA_INT0_vect)
ISR(PORTA_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_A, 0);
}
#endif
#if defined(PORTA_INT1_vect)
ISR(PORTA_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_A, 1);
}
#endif
#if defined(PORTB_INT0_vect)
ISR(PORTB_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_B, 0);
}
#endif
#if defined(PORTB_INT1_vect)
ISR(PORTB_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_B, 1);
}
#endif
#if defined(PORTC_INT0_vect)
ISR(PORTC_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_C, 0);
}
#endif
#if defined(PORTC_INT1_vect)
ISR(PORTC_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_C, 1);
}
#endif
#if defined(PORTD_INT0_vect)
ISR(PORTD_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_D, 0);
}
#endif
#if defined(PORTD_INT1_vect)
ISR(PORTD_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_D, 1);
}
#endif
#if defined(PORTE_INT0_vect)
ISR(PORTE_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_E, 0);
}
#endif
#if defined(PORTE_INT1_vect)
ISR(PORTE_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_E, 1);
}
#endif
#if defined(PORTF_INT0_vect)
ISR(PORTF_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_F, 0);
}
#endif
#if defined(PORTF_INT1_vect)
ISR(PORTF_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_F, 1);
}
#endif
#if defined(PORTG_INT0_vect)
ISR(PORTG_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_G, 0);
}
#endif
#if defined(PORTG_INT1_vect)
ISR(PORTG_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_G, 1);
}
#endif
#if defined(PORTH_INT0_vect)
ISR(PORTH_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_H, 0);
}
#endif
#if defined(PORTH_INT1_vect)
ISR(PORTH_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_H, 1);
}
#endif
#if defined(PORTJ_INT0_vect)
ISR(PORTJ_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_J, 0);
}
#endif
#if defined(PORTJ_INT1_vect)
ISR(PORTJ_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_J, 1);
}
#endif
#if defined(PORTK_INT0_vect)
ISR(PORTK_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_K, 0);
}
#endif
#if defined(PORTK_INT1_vect)
ISR(PORTK_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_K, 1);
}
#endif
#if defined(PORTL_INT0_vect)
ISR(PORTL_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_L, 0);
}
#endif
#if defined(PORTL_INT1_vect)
ISR(PORTL_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_L, 1);
}
#endif
#if defined(PORTM_INT0_vect)
ISR(PORTM_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_M, 0);
}
#endif
#if defined(PORTM_INT1_vect)
ISR(PORTM_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_M, 1);
}
#endif
#if defined(PORTN_INT0_vect)
ISR(PORTN_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_N, 0);
}
#endif
#if defined(PORTN_INT1_vect)
ISR(PORTN_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_N, 1);
}
#endif
#if defined(PORTP_INT0_vect)
ISR(PORTP_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_P, 0);
}
#endif
#if defined(PORTP_INT1_vect)
ISR(PORTP_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_P, 1);
}
#endif
#if defined(PORTQ_INT0_vect)
ISR(PORTQ_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_Q, 0);
}
#endif
#if defined(PORTQ_INT1_vect)
ISR(PORTQ_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_Q, 1);
}
#endif
#if defined(PORTR_INT0_vect)
ISR(PORTR_INT0_vect, ISR_BLOCK)
{
irq_handler(PORT_R, 0);
}
#endif
#if defined(PORTR_INT1_vect)
ISR(PORTR_INT1_vect, ISR_BLOCK)
{
irq_handler(PORT_R, 1);
}
#endif

78
cpu/atxmega/periph/nvm.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level NVM driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
* @}
*/
#include <avr/io.h>
#include "cpu_nvm.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief Read one byte using the Load Program Memory (LPM) instruction
* @internal
*
* This function sets the specified NVM_CMD, reads one byte using at the
* specified byte address with the LPM instruction. NVM_CMD is restored after
* use.
*
* @note This will disable interrupts during execution.
*
* @param nvm_cmd NVM command to load before running LPM
* @param address Byte offset into the signature row
*/
static inline uint8_t _nvm_read_byte(uint8_t nvm_cmd, uint16_t address)
{
uint8_t result;
__asm__ volatile (
"in __tmp_reg__, __SREG__ \n\t"
"cli \n\t"
"lds __zero_reg__, %3 \n\t"
"sts %3, %1 \n\t"
"lpm %0, %a2 \n\t"
"sts %3, __zero_reg__ \n\t"
"clr __zero_reg__ \n\t"
"out __SREG__, __tmp_reg__ \n\t"
:
"=&r" (result)
:
"r" (nvm_cmd), "e" (address), "m" (NVM_CMD)
: /* no clobbers */
);
return result;
}
/**
* @brief Read one byte from the production signature row
*
* This function reads one byte from the production signature row of the device
* at the given address.
*
* @note The execution can take some time. It is recommended not call this
* inside an interrupt service routine.
*
* @param address Byte offset into the signature row
*/
uint8_t nvm_read_production_signature_row(uint8_t address)
{
return _nvm_read_byte(NVM_CMD_READ_CALIB_ROW_gc, address);
}

80
cpu/atxmega/periph/pm.c Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level PM driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
* @}
*/
#include <avr/sleep.h>
#include "periph_conf.h"
#include "periph/pm.h"
#define ENABLE_DEBUG 0
#include "debug.h"
void pm_reboot(void)
{
DEBUG("Reboot Software Reset\n" );
/* XMEGA AU [MANUAL] p. 116 CTRL->Control register
* page 13 3.12.1 Sequence for write operation to protected I/O registers
* page 15 3.14.1 CCP Configuration Change Protection register
*/
/* Disable CCP for Protected IO registerand set new value*/
_PROTECTED_WRITE(RST_CTRL, RST_SWRST_bm);
while (1) {}
}
/*
* DEBUG may affect this routine.
*
* --- Do NOT add DEBUG macro here ---
*
*/
void pm_set(unsigned mode)
{
unsigned irq_state = irq_disable();
if (avr8_is_uart_tx_pending() && mode < 4) {
irq_restore(irq_state);
return;
}
switch (mode) {
case 0:
set_sleep_mode(SLEEP_SMODE_PDOWN_gc);
break;
case 1:
set_sleep_mode(SLEEP_SMODE_PSAVE_gc);
break;
case 2:
set_sleep_mode(SLEEP_SMODE_STDBY_gc);
break;
case 3:
set_sleep_mode(SLEEP_SMODE_ESTDBY_gc);
break;
default:
set_sleep_mode(SLEEP_SMODE_IDLE_gc);
}
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
irq_restore(irq_state);
}

533
cpu/atxmega/periph/timer.c Normal file
View File

@ -0,0 +1,533 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level TIMER driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
* @}
*/
#include <avr/interrupt.h>
#include <assert.h>
#include "cpu.h"
#include "thread.h"
#include "periph/timer.h"
#include "board.h"
#include "periph_conf.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief We have 7 possible prescaler values
*/
#define PRESCALE_NUMOF (7U)
/**
* @brief Possible prescaler values, encoded as 2 ^ val
*/
static const uint8_t prescalers[] = { 0, 1, 2, 3, 6, 8, 10 };
/**
* @brief Timer state context
*/
typedef struct {
timer_cb_t cb; /**< interrupt callback */
void *arg; /**< interrupt callback argument */
uint8_t prescaler; /**< remember the prescaler value */
uint8_t channels; /**< number of channels */
} ctx_t;
/**
* @brief Allocate memory for saving the device states
* @{
*/
#ifdef TIMER_NUMOF
static ctx_t ctx[TIMER_NUMOF] = { { NULL } };
#else
/* fallback if no timer is configured */
static ctx_t *ctx[] = { { NULL } };
#endif
/** @} */
static uint32_t _oneshot;
static inline void set_oneshot(tim_t tim, int chan)
{
_oneshot |= (1 << chan) << (TIMER_CH_MAX_NUMOF * tim);
}
static inline void clear_oneshot(tim_t tim, int chan)
{
_oneshot &= ~((1 << chan) << (TIMER_CH_MAX_NUMOF * tim));
}
static inline bool is_oneshot(tim_t tim, int chan)
{
return _oneshot & ((1 << chan) << (TIMER_CH_MAX_NUMOF * tim));
}
/**
* @brief Setup the given timer
*/
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
{
DEBUG("timer.c: freq = %ld, Core Clock = %ld\n", freq, CLOCK_CORECLOCK);
TC0_t *dev;
uint8_t pre;
uint8_t ch;
assert(TIMER_CH_MAX_NUMOF * TIMER_NUMOF < 32);
/* make sure given device is valid */
if (tim >= TIMER_NUMOF) {
return -1;
}
/* figure out if freq is applicable */
for (pre = 0; pre < PRESCALE_NUMOF; pre++) {
if ((CLOCK_CORECLOCK >> prescalers[pre]) == freq) {
break;
}
}
if (pre == PRESCALE_NUMOF) {
DEBUG("timer.c: prescaling failed!\n");
return -1;
}
dev = timer_config[tim].dev;
/* stop and reset timer */
dev->CTRLA = 0; /* Stop */
dev->CTRLFSET = TC_CMD_RESET_gc; /* Force Reset */
/* save interrupt context and timer Prescaler */
ctx[tim].cb = cb;
ctx[tim].arg = arg;
ctx[tim].prescaler = (0x07 & (pre + 1));
/* Check enabled channels */
ctx[tim].channels = 0;
for (ch = 0; ch < TIMER_CH_MAX_NUMOF; ch++) {
if (timer_config[tim].int_lvl[ch] != CPU_INT_LVL_OFF) {
ctx[tim].channels++;
}
}
if (timer_config[tim].type != TC_TYPE_0
&& timer_config[tim].type != TC_TYPE_4) {
if (ctx[tim].channels > 2) {
DEBUG("timer.c: wrong number of channels. max value is 2.\n");
return -1;
}
}
if (timer_config[tim].type == TC_TYPE_2) {
DEBUG("timer.c: Timer version %d is current not supported.\n",
timer_config[tim].type);
return -1;
}
/* Normal Counter with rollover */
dev->CTRLB = TC_WGMODE_NORMAL_gc;
/* Compare or Capture disable all channels */
dev->INTCTRLB = 0;
/* Free running counter */
dev->PER = 0xFFFF;
DEBUG("timer.c: prescaler set to %d \n", ctx[tim].prescaler);
dev->CTRLA = ctx[tim].prescaler;
return 0;
}
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
{
if (tim >= TIMER_NUMOF) {
return -1;
}
if (channel >= ctx[tim].channels) {
return -1;
}
DEBUG("Setting timer %i channel %i to %04x\n", tim, channel, value);
TC0_t *dev = timer_config[tim].dev;
dev->INTCTRLB &= ~(TC0_CCAINTLVL_gm << (channel * 2));
dev->INTFLAGS |= TC0_CCAIF_bm << channel;
uint8_t irq_state = irq_disable();
*(((uint16_t *)(&dev->CCA)) + channel) = (uint16_t)value;
irq_restore(irq_state);
set_oneshot(tim, channel);
dev->INTCTRLB |= (timer_config[tim].int_lvl[channel] << (channel * 2));
return 0;
}
int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags)
{
(void)flags;
if (tim >= TIMER_NUMOF) {
return -1;
}
if (channel > 0 || ctx[tim].channels != 1) {
DEBUG("Only channel 0 can be set as periodic and channels must be 1\n");
return -1;
}
DEBUG("Setting timer %i channel 0 to %i and flags %i (repeating)\n",
tim, value, flags);
TC0_t *dev = timer_config[tim].dev;
uint8_t irq_state = irq_disable();
dev->CTRLA = 0;
dev->CTRLFSET = TC_CMD_RESET_gc;
dev->CTRLB = TC_WGMODE_FRQ_gc;
dev->INTCTRLB = 0;
dev->INTFLAGS |= TC0_CCAIF_bm;
dev->CCA = (uint16_t)value;
dev->INTCTRLB = timer_config[tim].int_lvl[0];
dev->CTRLA = ctx[tim].prescaler;
clear_oneshot(tim, channel);
irq_restore(irq_state);
return 0;
}
int timer_clear(tim_t tim, int channel)
{
if (tim >= TIMER_NUMOF) {
return -1;
}
if (channel >= ctx[tim].channels) {
return -1;
}
DEBUG("timer_clear channel %d\n", channel );
TC0_t *dev = timer_config[tim].dev;
/* Compare or Capture Disable */
dev->INTCTRLB &= ~(TC0_CCAINTLVL_gm << (channel * 2));
/* Clear Interrupt Flag
* The CCxIF is automatically cleared when the corresponding
* interrupt vector is executed.*/
dev->INTFLAGS |= TC0_CCAIF_bm << channel;
return 0;
}
int timer_set(tim_t tim, int channel, unsigned int timeout)
{
if (tim >= TIMER_NUMOF) {
return -1;
}
if (channel >= ctx[tim].channels) {
return -1;
}
TC0_t *dev = timer_config[tim].dev;
/* Compare or Capture Disable */
dev->INTCTRLB &= ~(TC0_CCAINTLVL_gm << (channel * 2));
/* Clear Interrupt Flag */
dev->INTFLAGS |= TC0_CCAIF_bm << channel;
uint8_t irq_state = irq_disable();
/* set value to compare with rollover */
uint16_t absolute = dev->CNT + timeout;
*(((uint16_t *)(&dev->CCA)) + channel) = absolute;
irq_restore(irq_state);
set_oneshot(tim, channel);
/* Compare or Capture Enable */
dev->INTCTRLB |= (timer_config[tim].int_lvl[channel] << (channel * 2));
return 0;
}
unsigned int timer_read(tim_t tim)
{
if (tim >= TIMER_NUMOF) {
return -1;
}
DEBUG("timer_read\n");
return (unsigned int)timer_config[tim].dev->CNT;
}
void timer_stop(tim_t tim)
{
if (tim >= TIMER_NUMOF) {
return;
}
DEBUG("timer_stop\n");
timer_config[tim].dev->CTRLA = 0;
timer_config[tim].dev->CTRLFSET = TC_CMD_RESTART_gc;
}
void timer_start(tim_t tim)
{
if (tim >= TIMER_NUMOF) {
return;
}
DEBUG("timer_start\n");
timer_config[tim].dev->CTRLA = ctx[tim].prescaler;
}
#ifdef TIMER_NUMOF
static inline void _isr(tim_t tim, int channel)
{
avr8_enter_isr();
DEBUG("timer %d _isr channel %d\n", tim, channel);
if (is_oneshot(tim, channel)) {
timer_config[tim].dev->INTCTRLB &= ~(TC0_CCAINTLVL_gm << (channel * 2));
}
if (ctx[tim].cb) {
ctx[tim].cb(ctx[tim].arg, channel);
}
avr8_exit_isr();
}
#endif
#ifdef TIMER_0_ISRA
ISR(TIMER_0_ISRA, ISR_BLOCK)
{
_isr(0, 0);
}
#endif
#ifdef TIMER_0_ISRB
ISR(TIMER_0_ISRB, ISR_BLOCK)
{
_isr(0, 1);
}
#endif
#ifdef TIMER_0_ISRC
ISR(TIMER_0_ISRC, ISR_BLOCK)
{
_isr(0, 2);
}
#endif
#ifdef TIMER_0_ISRD
ISR(TIMER_0_ISRD, ISR_BLOCK)
{
_isr(0, 3);
}
#endif /* TIMER_0 */
#ifdef TIMER_1_ISRA
ISR(TIMER_1_ISRA, ISR_BLOCK)
{
_isr(1, 0);
}
#endif
#ifdef TIMER_1_ISRB
ISR(TIMER_1_ISRB, ISR_BLOCK)
{
_isr(1, 1);
}
#endif
#ifdef TIMER_1_ISRC
ISR(TIMER_1_ISRC, ISR_BLOCK)
{
_isr(1, 2);
}
#endif
#ifdef TIMER_1_ISRD
ISR(TIMER_1_ISRD, ISR_BLOCK)
{
_isr(1, 3);
}
#endif /* TIMER_1 */
#ifdef TIMER_2_ISRA
ISR(TIMER_2_ISRA, ISR_BLOCK)
{
_isr(2, 0);
}
#endif
#ifdef TIMER_2_ISRB
ISR(TIMER_2_ISRB, ISR_BLOCK)
{
_isr(2, 1);
}
#endif
#ifdef TIMER_2_ISRC
ISR(TIMER_2_ISRC, ISR_BLOCK)
{
_isr(2, 2);
}
#endif
#ifdef TIMER_2_ISRD
ISR(TIMER_2_ISRD, ISR_BLOCK)
{
_isr(2, 3);
}
#endif /* TIMER_2 */
#ifdef TIMER_3_ISRA
ISR(TIMER_3_ISRA, ISR_BLOCK)
{
_isr(3, 0);
}
#endif
#ifdef TIMER_3_ISRB
ISR(TIMER_3_ISRB, ISR_BLOCK)
{
_isr(3, 1);
}
#endif
#ifdef TIMER_3_ISRC
ISR(TIMER_3_ISRC, ISR_BLOCK)
{
_isr(3, 2);
}
#endif
#ifdef TIMER_3_ISRD
ISR(TIMER_3_ISRD, ISR_BLOCK)
{
_isr(3, 3);
}
#endif /* TIMER_3 */
#ifdef TIMER_4_ISRA
ISR(TIMER_4_ISRA, ISR_BLOCK)
{
_isr(4, 0);
}
#endif
#ifdef TIMER_4_ISRB
ISR(TIMER_4_ISRB, ISR_BLOCK)
{
_isr(4, 1);
}
#endif
#ifdef TIMER_4_ISRC
ISR(TIMER_4_ISRC, ISR_BLOCK)
{
_isr(4, 2);
}
#endif
#ifdef TIMER_4_ISRD
ISR(TIMER_4_ISRD, ISR_BLOCK)
{
_isr(4, 3);
}
#endif /* TIMER_4 */
#ifdef TIMER_5_ISRA
ISR(TIMER_5_ISRA, ISR_BLOCK)
{
_isr(5, 0);
}
#endif
#ifdef TIMER_5_ISRB
ISR(TIMER_5_ISRB, ISR_BLOCK)
{
_isr(5, 1);
}
#endif
#ifdef TIMER_5_ISRC
ISR(TIMER_5_ISRC, ISR_BLOCK)
{
_isr(5, 2);
}
#endif
#ifdef TIMER_5_ISRD
ISR(TIMER_5_ISRD, ISR_BLOCK)
{
_isr(5, 3);
}
#endif /* TIMER_5 */
#ifdef TIMER_6_ISRA
ISR(TIMER_6_ISRA, ISR_BLOCK)
{
_isr(6, 0);
}
#endif
#ifdef TIMER_6_ISRB
ISR(TIMER_6_ISRB, ISR_BLOCK)
{
_isr(6, 1);
}
#endif
#ifdef TIMER_6_ISRC
ISR(TIMER_6_ISRC, ISR_BLOCK)
{
_isr(6, 2);
}
#endif
#ifdef TIMER_6_ISRD
ISR(TIMER_6_ISRD, ISR_BLOCK)
{
_isr(6, 3);
}
#endif /* TIMER_6 */
#ifdef TIMER_7_ISRA
ISR(TIMER_7_ISRA, ISR_BLOCK)
{
_isr(7, 0);
}
#endif
#ifdef TIMER_7_ISRB
ISR(TIMER_7_ISRB, ISR_BLOCK)
{
_isr(7, 1);
}
#endif
#ifdef TIMER_7_ISRC
ISR(TIMER_7_ISRC, ISR_BLOCK)
{
_isr(7, 2);
}
#endif
#ifdef TIMER_7_ISRB
ISR(TIMER_7_ISRD, ISR_BLOCK)
{
_isr(7, 3);
}
#endif /* TIMER_7 */

425
cpu/atxmega/periph/uart.c Normal file
View File

@ -0,0 +1,425 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level UART driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*
*
* Supports runtime calculation of the BSEL and BSCALE register values.
* Supports reconfiguring UART after a clock change.
*
* @}
*/
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include "board.h"
#include "cpu.h"
#include "sched.h"
#include "thread.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief UART Baudrate Tolerance
*
* The tolerance is expressed as baud rate percentage multiplied by 100.
* For bigger tolerances UART double frequency can be avoided, thus saving
* power.
*
* The default baud tolerance is 2%.
*/
#ifndef BAUD_TOL
#define BAUD_TOL 2 * 100
#endif
/**
* @brief Allocate memory to store the callback functions.
*/
static uart_isr_ctx_t isr_ctx[UART_NUMOF];
/**
* @brief Get the pointer to the base register of the given USART device
*
* @param[in] dev USART device identifier
*
* @return base register address
*/
static inline USART_t *dev(uart_t dev)
{
return uart_config[dev].dev;
}
static inline int8_t _check_bsel(uint32_t baud, uint32_t calcbaud,
int16_t *precision)
{
/* Avoid negative values and with precision of two positions
* after the decimal point for the deviation in percent
*
* result is the absolute deviation eg. 10 001
*
* MAX BAUD fper/2 = 16MHz a shift of 8 can be used to increase
* accuracy
*/
uint16_t pre;
if (baud < calcbaud) {
pre = (uint16_t)((calcbaud * 10000ULL) / baud);
}
else {
pre = (uint16_t)((baud * 10000ULL) / calcbaud);
}
if (pre < ((uint16_t)*precision)) {
*precision = pre;
return 1;
}
return 0;
}
static inline int16_t _xmega_bsel_bscale(uint32_t *fper, uint32_t *baud,
uint8_t clk2x, uint16_t *bsel,
int8_t *bscale)
{
uint32_t calcbaud = 0;
uint32_t deno = 0;
int16_t precision = UINT_MAX;
uint16_t loc_bsel = 0;
int8_t loc_bscale;
/* Some explanation for equation transformation
* bsel = ( (fper / (2^bscale*16*baud) ) - 1 )
* = ( (fper / (2^bscale*(16-8*clk2x)*baud) ) - 1 )
* = ( fper - (2^bscale*(16-8*clk2x)*baud) )
* / (2^bscale*(16-8*clk2x)*baud)
*
* deno = ( baud * (16-8*clk2x) * 2^bscale )
* = ( baud * (1<<(4-clk2x)) * (1<<bscale) )
* = ( baud<<( 4-clk2x +bscale));
*
* some rounding math explanation for unsigned integer
* ABS(x +0,5) = (x*10+ 5 )/(10)
* Equation above is as follows, using denominator as base to round
* bsel = ( x - y )/y
* = ( x - y +0,5*y )/y
* = ( 2*x - y )/(2*y)
* = ((x<<1)- y )/(y<<1)
*
* baud = (fper*1/2^bscale) / ((bsel+1)*16)
*/
for (loc_bscale = 0; loc_bscale <= 7; loc_bscale++) {
int32_t sub = 0;
deno = (*baud << (4 - clk2x + loc_bscale));
sub = (*fper << 1) - (deno);
if (sub <= 0) {
break;
}
loc_bsel = (sub / (deno << 1));
if (loc_bsel >= 4095) {
continue;
}
/* Omit division by 16 get higher accuracy at small baudrates*/
calcbaud = (*fper >> loc_bscale) / ((loc_bsel + 1) << (4 - clk2x));
if (_check_bsel(*baud, calcbaud, &precision)) {
*bsel = loc_bsel;
*bscale = loc_bscale;
}
}
/* More math for the negative equation
* bscale is negative so 1/2^bscale = 2^|bscale| which is a factor and
* not a division again runding the result before division with
* 0.5 * denominator
*
* bsel = 1/2^bscale *( fcpu / ( (16*baud)-1) )
* = ( fcpu*2^|bscale| - (16*baud)*2^|bscale| )/(16*baud)
* = ( fcpu*2^|bscale| - (16*baud)*2^|bscale| + 0.5*(16*baud) )/(16*baud)
*
* deno = (16/2*baud) = (baud<<(3-clk2x))
*
* bsel = ( (fcpu - (deno<<(1))<<|bscale|) + deno )/(deno<<1)
*
* Baud = (fper*1/2^bscale)/ (16*(bsel+1/2^bscale))
*/
for (loc_bscale = -1; loc_bscale >= -7; loc_bscale--) {
uint32_t num = 0;
deno = (*baud << (3 - clk2x));
num = ((*fper - (deno << 1)) << (-loc_bscale)) + deno;
num = (num / (deno << 1));
if (num >= 4095) {
break;
}
loc_bsel = (uint16_t)(num & 0xFFF);
/* Omit division by 16 get higher accuracy at small baudrates */
calcbaud = (*fper << (-loc_bscale))
/ ((loc_bsel + (1 << (-loc_bscale))) << (4 - clk2x));
if (_check_bsel(*baud, calcbaud, &precision)) {
*bsel = loc_bsel;
*bscale = loc_bscale;
}
}
return precision;
}
/**
* @brief Calculates bsel and bscale for a given periphery clock and baudrate.
* Limitation are the periphery clock maximum is 32MHz, unsigned int
* overflows if clock is bigger. And the periphery clock has to be not
* smaller then 1 when divided by 128.
*
* fper/128 !=0 must be divide able by 128
* fper*128 != uint23_max => 32MHz max fper
*/
static inline int16_t _xmega_calculate_bsel_bscale(uint32_t fcpu, uint32_t baud,
uint8_t *clk2x,
uint16_t *bsel,
int8_t *bscale)
{
int16_t precision = 0;
precision = _xmega_bsel_bscale(&fcpu, &baud, 0, bsel, bscale );
/* default 2% precision, required precision is at least 2% */
if (precision <= (10000 + BAUD_TOL)) {
return (precision - 10000);
}
/* Precision goal was not met calculate baudrate with uart frequency doubled */
precision = _xmega_bsel_bscale(&fcpu, &baud, 1, bsel, bscale );
*clk2x = 1;
return (precision - 10000);
}
static inline void _configure_pins(uart_t uart)
{
/* configure RX pin */
if (gpio_is_valid(uart_config[uart].rx_pin)) {
gpio_init(uart_config[uart].rx_pin, GPIO_IN);
}
/* configure TX pin */
if (gpio_is_valid(uart_config[uart].tx_pin)) {
gpio_set(uart_config[uart].tx_pin);
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
}
#ifdef MODULE_PERIPH_UART_HW_FC
/* TODO */
#endif
}
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
int8_t bscale;
uint8_t clk2x;
uint16_t bsel;
/* make sure the given device is valid */
if (uart >= UART_NUMOF) {
return UART_NODEV;
}
uint16_t count = UINT16_MAX;
while (avr8_is_uart_tx_pending() && count--) {}
/* register interrupt context */
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
/* disable and reset UART */
dev(uart)->CTRLA = 0;
dev(uart)->CTRLB = 0;
dev(uart)->CTRLC = 0;
_configure_pins(uart);
/* configure UART to 8N1 mode */
dev(uart)->CTRLC = USART_CMODE_ASYNCHRONOUS_gc
| USART_PMODE_DISABLED_gc
| USART_CHSIZE_8BIT_gc;
/* set clock divider */
_xmega_calculate_bsel_bscale(CLOCK_CORECLOCK, baudrate, &clk2x,
&bsel, &bscale);
dev(uart)->BAUDCTRLA = (uint8_t)(bsel & 0x00ff);
dev(uart)->BAUDCTRLB = (bscale << USART_BSCALE_gp)
| ((uint8_t)((bsel & 0x0fff) >> 8));
if (clk2x == 1) {
dev(uart)->CTRLB |= USART_CLK2X_bm;
}
/* enable RX and TX Interrupts and set level*/
if (rx_cb) {
dev(uart)->CTRLA = (uart_config[uart].rx_int_lvl << USART_RXCINTLVL_gp)
| (uart_config[uart].tx_int_lvl << USART_TXCINTLVL_gp)
| (uart_config[uart].dre_int_lvl << USART_DREINTLVL_gp);
dev(uart)->CTRLB = USART_RXEN_bm | USART_TXEN_bm;
}
else {
/* only transmit */
dev(uart)->CTRLB = USART_TXEN_bm;
}
DEBUG("Set clk2x %" PRIu8 " bsel %" PRIu16 "bscale %" PRIi8 "\n",
clk2x, bsel, bscale);
return UART_OK;
}
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
for (size_t i = 0; i < len; i++) {
while (!(dev(uart)->STATUS & USART_DREIF_bm)) {}
/* start of TX won't finish until no data in DATAn and transmit shift
register is empty */
uint8_t irq_state = irq_disable();
avr8_state |= AVR8_STATE_FLAG_UART_TX(uart);
irq_restore(irq_state);
dev(uart)->DATA = data[i];
}
}
void uart_poweron(uart_t uart)
{
(void)uart;
/* not implemented (yet) */
}
void uart_poweroff(uart_t uart)
{
(void)uart;
/* not implemented (yet) */
}
static inline void _rx_isr_handler(int num)
{
avr8_enter_isr();
if (isr_ctx[num].rx_cb) {
isr_ctx[num].rx_cb(isr_ctx[num].arg, dev(num)->DATA);
}
avr8_exit_isr();
}
static inline void _tx_isr_handler(int num)
{
avr8_enter_isr();
/* entire frame in the Transmit Shift Register has been shifted out and
there are no new data currently present in the transmit buffer */
avr8_state &= ~AVR8_STATE_FLAG_UART_TX(num);
avr8_exit_isr();
}
#ifdef UART_0_RXC_ISR
ISR(UART_0_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(0);
}
ISR(UART_0_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(0);
}
#endif /* UART_0_ISR */
#ifdef UART_1_RXC_ISR
ISR(UART_1_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(1);
}
ISR(UART_1_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(1);
}
#endif /* UART_1_ISR */
#ifdef UART_2_RXC_ISR
ISR(UART_2_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(2);
}
ISR(UART_2_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(2);
}
#endif /* UART_2_ISR */
#ifdef UART_3_RXC_ISR
ISR(UART_3_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(3);
}
ISR(UART_3_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(3);
}
#endif /* UART_3_ISR */
#ifdef UART_4_RXC_ISR
ISR(UART_4_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(4);
}
ISR(UART_4_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(4);
}
#endif /* UART_4_ISR */
#ifdef UART_5_RXC_ISR
ISR(UART_5_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(5);
}
ISR(UART_5_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(5);
}
#endif /* UART_5_ISR */
#ifdef UART_6_RXC_ISR
ISR(UART_6_RXC_ISR, ISR_BLOCK)
{
_rx_isr_handler(6);
}
ISR(UART_6_TXC_ISR, ISR_BLOCK)
{
_tx_isr_handler(6);
}
#endif /* UART_6_ISR */

View File

@ -5,15 +5,12 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config CPU_ARCH_AVR8
bool
select HAS_ARCH_8BIT
select HAS_ARCH_AVR8
config CPU_CORE_AVR
bool
select CPU_ARCH_AVR8
## Common CPU symbols
config CPU_ARCH
default "avr8" if CPU_ARCH_AVR8

View File

@ -3,4 +3,4 @@ INCLUDES += -I$(RIOTCPU)/avr8_common/include \
-isystem$(RIOTCPU)/avr8_common/avr_libc_extra/include \
-isystem$(RIOTCPU)/avr8_common/avr_libc_extra/include/vendor
include $(RIOTMAKE)/arch/atmega.inc.mk
include $(RIOTMAKE)/arch/avr8.inc.mk

View File

@ -31,19 +31,29 @@
#include <avr/pgmspace.h>
#include "cpu.h"
#ifdef CPU_AVR8_HAS_CLOCK_INIT
#include "cpu_clock.h"
#endif
#include "board.h"
#include "irq.h"
#include "periph/init.h"
#include "panic.h"
#include "kernel_defines.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#ifdef RST
/* In ATxmega there is a special register to get reset cause */
#define MCUSR RST.STATUS
#else
#ifndef MCUSR
/* In older ATmegas the MCUSR register was still named MCUCSR. Current avrlibc
* versions provide the MCUSR macro for those as well, but adding a fallback
* here doesn't hurt*/
#define MCUSR MCUCSR
#endif /* !MCUSR */
#endif /* RST */
/*
* Since atmega MCUs do not feature a software reset, the watchdog timer
@ -86,6 +96,10 @@ void cpu_init(void)
wdt_reset(); /* should not be nececessary as done in bootloader */
wdt_disable(); /* but when used without bootloader this is needed */
#ifdef CPU_AVR8_HAS_CLOCK_INIT
avr8_clk_init();
#endif
/* Initialize stdio before periph_init() to allow use of DEBUG() there */
#ifdef MODULE_AVR_LIBC_EXTRA
avr8_stdio_init();
@ -95,6 +109,15 @@ void cpu_init(void)
/* rtc_init */
/* hwrng_init */
periph_init();
#ifdef CPU_ATXMEGA
/* Enable Multilevel Interrupt Controller */
PMIC.CTRL |= PMIC_HILVLEN_bm
| PMIC_MEDLVLEN_bm
| PMIC_LOLVLEN_bm;
#endif
irq_enable();
}
struct __freelist {

View File

@ -63,6 +63,11 @@ extern "C"
#define AVR8_STATE_FLAG_ISR (0x80U) /**< In ISR */
#define AVR8_STATE_FLAG_UART0_TX (0x01U) /**< TX pending for UART 0 */
#define AVR8_STATE_FLAG_UART1_TX (0x02U) /**< TX pending for UART 1 */
#define AVR8_STATE_FLAG_UART2_TX (0x04U) /**< TX pending for UART 2 */
#define AVR8_STATE_FLAG_UART3_TX (0x08U) /**< TX pending for UART 3 */
#define AVR8_STATE_FLAG_UART4_TX (0x10U) /**< TX pending for UART 4 */
#define AVR8_STATE_FLAG_UART5_TX (0x20U) /**< TX pending for UART 5 */
#define AVR8_STATE_FLAG_UART6_TX (0x40U) /**< TX pending for UART 6 */
#define AVR8_STATE_FLAG_UART_TX(x) (0x01U << x) /**< TX pending for UART x */
/** @} */
@ -77,14 +82,18 @@ extern "C"
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 7 6 5 4 3 2 1 0
* +---+---+---+---+---+---+---+---+
* |IRQ| unused |TX1|TX0|
* |IRQ|TX6|TX5|TX4|TX3|TX2|TX1|TX0|
* +---+---+---+---+---+---+---+---+
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* | Label | Description |
* |:-------|:--------------------------------------------------------------|
* | IRQ | This bit is set when in IRQ context |
* | unused | This bits are currently not used |
* | TX6 | This bit is set when on UART6 TX is pending |
* | TX5 | This bit is set when on UART5 TX is pending |
* | TX4 | This bit is set when on UART4 TX is pending |
* | TX3 | This bit is set when on UART3 TX is pending |
* | TX2 | This bit is set when on UART2 TX is pending |
* | TX1 | This bit is set when on UART1 TX is pending |
* | TX0 | This bit is set when on UART0 TX is pending |
*/
@ -138,7 +147,13 @@ static inline void avr8_enter_isr(void)
static inline int avr8_is_uart_tx_pending(void)
{
uint8_t state = avr8_get_state();
return (state & (AVR8_STATE_FLAG_UART0_TX | AVR8_STATE_FLAG_UART1_TX));
return (state & (AVR8_STATE_FLAG_UART0_TX
| AVR8_STATE_FLAG_UART1_TX
| AVR8_STATE_FLAG_UART2_TX
| AVR8_STATE_FLAG_UART3_TX
| AVR8_STATE_FLAG_UART4_TX
| AVR8_STATE_FLAG_UART5_TX
| AVR8_STATE_FLAG_UART6_TX));
}
/**
@ -151,6 +166,11 @@ void avr8_exit_isr(void);
*/
void cpu_init(void);
/**
* @brief Initialization of the CPU clock
*/
void avr8_clk_init(void);
/**
* @brief Print the last instruction's address
*/

View File

@ -2,7 +2,7 @@
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
* 2017 Thomas Perrot <thomas.perrot@tupi.fr>
* 2018 RWTH Aachen, Josua Arndt <jarndt@ias.rwth-aachen.de>
* 2021 Gerson Fernando Budke
* 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* 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
@ -14,7 +14,8 @@
* @{
*
* @file
* @brief Implementation of the kernel's architecture dependent thread interface
* @brief Implementation of the kernel's architecture dependent thread
* interface
*
* @author Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de>
* @author Thomas Perrot <thomas.perrot@tupi.fr>
@ -31,14 +32,31 @@
#include "irq.h"
#include "cpu.h"
#include "board.h"
#include "macros/xtstr.h"
#define CHECK_EIND_REG FLASHEND > 0x1ffff
#if defined(DATAMEM_SIZE)
#define CHECK_RAMPZ_REG DATAMEM_SIZE > 0xffff || FLASHEND > 0xffff
#define CHECK_RAMPDXY_REG DATAMEM_SIZE > 0xffff
#else
#define CHECK_RAMPZ_REG FLASHEND > 0xffff
#define CHECK_RAMPDXY_REG 0
#endif
#if (CHECK_EIND_REG)
#ifndef __EIND__
#define __EIND__ 0x3C
#endif
#endif
static void avr8_context_save(void);
static void avr8_context_restore(void);
static void avr8_enter_thread_mode(void);
/**
* @brief Since AVR doesn't support direct manipulation of the program counter we
* model a stack like it would be left by avr8_context_save().
* @brief Since AVR doesn't support direct manipulation of the program counter
* we model a stack like it would be left by avr8_context_save().
* The resulting layout in memory is the following:
* ---------------thread_t (not created by thread_stack_init) ----------
* local variables (a temporary value and the stackpointer)
@ -46,18 +64,18 @@ static void avr8_enter_thread_mode(void);
* a marker (AFFE) - for debugging purposes (helps finding the stack
* -----------------------------------------------------------------------
* a 16 Bit pointer to sched_task_exit
* (Optional 17 bit (bit is set to zero) for devices with > 128kb FLASH)
* (Optional EIND bits are set to zero for devices with > 128kb FLASH)
* -----------------------------------------------------------------------
* a 16 Bit pointer to task_func
* this is placed exactly at the place where the program counter would be
* stored normally and thus can be returned to when avr8_context_restore()
* has been run
* (Optional 17 bit (bit is set to zero) for devices with > 128kb FLASH)
* (Optional EIND bits are set to zero for devices with > 128kb FLASH)
* -----------------------------------------------------------------------
* saved registers from context:
* r0
* status register
* (Optional EIND and RAMPZ registers)
* (Optional EIND, RAMPZ, RAMPX, RAMPY, RAMPD registers)
* r1 - r23
* pointer to arg in r24 and r25
* r26 - r31
@ -91,8 +109,9 @@ char *thread_stack_init(thread_task_func_t task_func, void *arg,
tmp_adress >>= 8;
*stk = (uint8_t)(tmp_adress & (uint16_t)0x00ff);
#if FLASHEND > 0x1ffff
/* Devices with more than 128kb FLASH use a 17 bit PC, we set whole the top byte forcibly to 0 */
#if (CHECK_EIND_REG)
/* Devices with more than 128kb FLASH use a PC with more than 16bits, we
* set whole the top byte forcibly to 0 */
stk--;
*stk = (uint8_t)0x00;
#endif
@ -105,8 +124,9 @@ char *thread_stack_init(thread_task_func_t task_func, void *arg,
tmp_adress >>= 8;
*stk = (uint8_t)(tmp_adress & (uint16_t)0x00ff);
#if FLASHEND > 0x1ffff
/* Devices with more than 128kb FLASH use a 17 bit PC, we set whole the top byte forcibly to 0 */
#if (CHECK_EIND_REG)
/* Devices with more than 128kb FLASH use a PC with more than 16bits, we
* set whole the top byte forcibly to 0 */
stk--;
*stk = (uint8_t)0x00;
#endif
@ -119,13 +139,23 @@ char *thread_stack_init(thread_task_func_t task_func, void *arg,
stk--;
*stk = (uint8_t)0x80;
#if defined(EIND)
#if (CHECK_RAMPZ_REG)
stk--;
*stk = (uint8_t)0x00;
*stk = (uint8_t)0x00; /* RAMPZ */
#endif
#if defined(RAMPZ) && !defined(__AVR_ATmega32U4__)
#if (CHECK_RAMPDXY_REG)
stk--;
*stk = (uint8_t)0x00;
*stk = (uint8_t)0x00; /* RAMPY */
stk--;
*stk = (uint8_t)0x00; /* RAMPX */
stk--;
*stk = (uint8_t)0x00; /* RAMPD */
#endif
#if (CHECK_EIND_REG)
stk--;
*stk = (uint8_t)0x00; /* EIND */
#endif
/* r1 - has always to be 0 */
@ -210,7 +240,8 @@ extern char * __malloc_heap_end;
extern char *__brkval;
/**
* @brief Set the MCU into Thread-Mode and load the initial task from the stack and run it
* @brief Set the MCU into Thread-Mode and load the initial task from the
* stack and run it
*/
void NORETURN avr8_enter_thread_mode(void)
{
@ -223,6 +254,7 @@ void NORETURN avr8_enter_thread_mode(void)
* thread-mode. Therefore, it can be considered as the top of the heap.
*/
__malloc_heap_end = STACK_POINTER - __malloc_margin;
/* __brkval has to be initialized if necessary */
if (__brkval == NULL) {
__brkval = __malloc_heap_start;
@ -250,8 +282,10 @@ void thread_yield_higher(void)
void avr8_exit_isr(void)
{
avr8_state &= ~AVR8_STATE_FLAG_ISR;
/* Force access to avr8_state to take place */
__asm__ volatile ("" : : : "memory");
if (sched_context_switch_request) {
avr8_context_save();
sched_run();
@ -263,108 +297,131 @@ void avr8_exit_isr(void)
__attribute__((always_inline)) static inline void avr8_context_save(void)
{
__asm__ volatile (
"push __tmp_reg__ \n\t"
"in __tmp_reg__, __SREG__ \n\t"
"cli \n\t"
"push __tmp_reg__ \n\t"
#if defined(RAMPZ) && !defined(__AVR_ATmega32U4__)
"in __tmp_reg__, __RAMPZ__ \n\t"
"push __tmp_reg__ \n\t"
"push __tmp_reg__ \n\t"
"in __tmp_reg__, __SREG__ \n\t"
"cli \n\t"
"push __tmp_reg__ \n\t"
#if (CHECK_RAMPZ_REG)
"in __tmp_reg__, __RAMPZ__ \n\t"
"push __tmp_reg__ \n\t"
#endif
#if defined(EIND)
"in __tmp_reg__, 0x3c \n\t"
"push __tmp_reg__ \n\t"
#if (CHECK_RAMPDXY_REG)
"in __tmp_reg__, __RAMPY__ \n\t"
"push __tmp_reg__ \n\t"
"in __tmp_reg__, __RAMPX__ \n\t"
"push __tmp_reg__ \n\t"
"in __tmp_reg__, __RAMPD__ \n\t"
"push __tmp_reg__ \n\t"
#endif
"push r1 \n\t"
"clr r1 \n\t"
"push r2 \n\t"
"push r3 \n\t"
"push r4 \n\t"
"push r5 \n\t"
"push r6 \n\t"
"push r7 \n\t"
"push r8 \n\t"
"push r9 \n\t"
"push r10 \n\t"
"push r11 \n\t"
"push r12 \n\t"
"push r13 \n\t"
"push r14 \n\t"
"push r15 \n\t"
"push r16 \n\t"
"push r17 \n\t"
"push r18 \n\t"
"push r19 \n\t"
"push r20 \n\t"
"push r21 \n\t"
"push r22 \n\t"
"push r23 \n\t"
"push r24 \n\t"
"push r25 \n\t"
"push r26 \n\t"
"push r27 \n\t"
"push r28 \n\t"
"push r29 \n\t"
"push r30 \n\t"
"push r31 \n\t"
"lds r26, sched_active_thread \n\t"
"lds r27, sched_active_thread + 1 \n\t"
"in __tmp_reg__, __SP_L__ \n\t"
"st x+, __tmp_reg__ \n\t"
"in __tmp_reg__, __SP_H__ \n\t"
"st x+, __tmp_reg__ \n\t");
#if (CHECK_EIND_REG)
"in __tmp_reg__, " XTSTR(__EIND__) " \n\t"
"push __tmp_reg__ \n\t"
#endif
"push r1 \n\t"
"clr r1 \n\t"
"push r2 \n\t"
"push r3 \n\t"
"push r4 \n\t"
"push r5 \n\t"
"push r6 \n\t"
"push r7 \n\t"
"push r8 \n\t"
"push r9 \n\t"
"push r10 \n\t"
"push r11 \n\t"
"push r12 \n\t"
"push r13 \n\t"
"push r14 \n\t"
"push r15 \n\t"
"push r16 \n\t"
"push r17 \n\t"
"push r18 \n\t"
"push r19 \n\t"
"push r20 \n\t"
"push r21 \n\t"
"push r22 \n\t"
"push r23 \n\t"
"push r24 \n\t"
"push r25 \n\t"
"push r26 \n\t"
"push r27 \n\t"
"push r28 \n\t"
"push r29 \n\t"
"push r30 \n\t"
"push r31 \n\t"
"lds r26, sched_active_thread \n\t"
"lds r27, sched_active_thread + 1 \n\t"
"in __tmp_reg__, __SP_L__ \n\t"
"st x+, __tmp_reg__ \n\t"
"in __tmp_reg__, __SP_H__ \n\t"
"st x+, __tmp_reg__ \n\t");
}
__attribute__((always_inline)) static inline void avr8_context_restore(void)
{
__asm__ volatile (
"lds r26, sched_active_thread \n\t"
"lds r27, sched_active_thread + 1 \n\t"
"ld r28, x+ \n\t"
"out __SP_L__, r28 \n\t"
"ld r29, x+ \n\t"
"out __SP_H__, r29 \n\t"
"pop r31 \n\t"
"pop r30 \n\t"
"pop r29 \n\t"
"pop r28 \n\t"
"pop r27 \n\t"
"pop r26 \n\t"
"pop r25 \n\t"
"pop r24 \n\t"
"pop r23 \n\t"
"pop r22 \n\t"
"pop r21 \n\t"
"pop r20 \n\t"
"pop r19 \n\t"
"pop r18 \n\t"
"pop r17 \n\t"
"pop r16 \n\t"
"pop r15 \n\t"
"pop r14 \n\t"
"pop r13 \n\t"
"pop r12 \n\t"
"pop r11 \n\t"
"pop r10 \n\t"
"pop r9 \n\t"
"pop r8 \n\t"
"pop r7 \n\t"
"pop r6 \n\t"
"pop r5 \n\t"
"pop r4 \n\t"
"pop r3 \n\t"
"pop r2 \n\t"
"pop r1 \n\t"
#if defined(EIND)
"pop __tmp_reg__ \n\t"
"out 0x3c, __tmp_reg__ \n\t"
"lds r26, sched_active_thread \n\t"
"lds r27, sched_active_thread + 1 \n\t"
"ld r28, x+ \n\t"
"out __SP_L__, r28 \n\t"
"ld r29, x+ \n\t"
"out __SP_H__, r29 \n\t"
"pop r31 \n\t"
"pop r30 \n\t"
"pop r29 \n\t"
"pop r28 \n\t"
"pop r27 \n\t"
"pop r26 \n\t"
"pop r25 \n\t"
"pop r24 \n\t"
"pop r23 \n\t"
"pop r22 \n\t"
"pop r21 \n\t"
"pop r20 \n\t"
"pop r19 \n\t"
"pop r18 \n\t"
"pop r17 \n\t"
"pop r16 \n\t"
"pop r15 \n\t"
"pop r14 \n\t"
"pop r13 \n\t"
"pop r12 \n\t"
"pop r11 \n\t"
"pop r10 \n\t"
"pop r9 \n\t"
"pop r8 \n\t"
"pop r7 \n\t"
"pop r6 \n\t"
"pop r5 \n\t"
"pop r4 \n\t"
"pop r3 \n\t"
"pop r2 \n\t"
"pop r1 \n\t"
#if (CHECK_EIND_REG)
"pop __tmp_reg__ \n\t"
"out " XTSTR(__EIND__) ", __tmp_reg__ \n\t"
#endif
#if defined(RAMPZ) && !defined(__AVR_ATmega32U4__)
"pop __tmp_reg__ \n\t"
"out __RAMPZ__, __tmp_reg__ \n\t"
#if (CHECK_RAMPDXY_REG)
"pop __tmp_reg__ \n\t"
"out __RAMPD__, __tmp_reg__ \n\t"
"pop __tmp_reg__ \n\t"
"out __RAMPX__, __tmp_reg__ \n\t"
"pop __tmp_reg__ \n\t"
"out __RAMPY__, __tmp_reg__ \n\t"
#endif
"pop __tmp_reg__ \n\t"
"out __SREG__, __tmp_reg__ \n\t"
"pop __tmp_reg__ \n\t");
#if (CHECK_RAMPZ_REG)
"pop __tmp_reg__ \n\t"
"out __RAMPZ__, __tmp_reg__ \n\t"
#endif
"pop __tmp_reg__ \n\t"
"out __SREG__, __tmp_reg__ \n\t"
"pop __tmp_reg__ \n\t");
}

View File

@ -7,16 +7,16 @@
config MODULE_WS281X
bool "WS2812/SK6812 RGB LED (NeoPixel)"
depends on HAS_ARCH_AVR8 || HAS_ARCH_ESP32 || HAS_ARCH_NATIVE
depends on HAS_CPU_CORE_ATMEGA || HAS_ARCH_ESP32 || HAS_ARCH_NATIVE
depends on TEST_KCONFIG
select MODULE_XTIMER
select MODULE_WS281X_ATMEGA if HAS_ARCH_AVR8
select MODULE_WS281X_ATMEGA if HAS_CPU_CORE_ATMEGA
select MODULE_WS281X_VT100 if HAS_ARCH_NATIVE
select MODULE_WS281X_ESP32 if HAS_ARCH_ESP32
config MODULE_WS281X_ATMEGA
bool
depends on HAS_ARCH_AVR8
depends on HAS_CPU_CORE_ATMEGA
config MODULE_WS281X_VT100
bool

View File

@ -1,7 +1,7 @@
FEATURES_REQUIRED_ANY += arch_avr8|arch_esp32|arch_native
FEATURES_REQUIRED_ANY += cpu_core_atmega|arch_esp32|arch_native
ifeq (,$(filter ws281x_%,$(USEMODULE)))
ifneq (,$(filter arch_avr8,$(FEATURES_USED)))
ifneq (,$(filter cpu_core_atmega,$(FEATURES_USED)))
USEMODULE += ws281x_atmega
endif
ifneq (,$(filter arch_native,$(FEATURES_USED)))
@ -13,7 +13,7 @@ ifeq (,$(filter ws281x_%,$(USEMODULE)))
endif
ifneq (,$(filter ws281x_atmega,$(USEMODULE)))
FEATURES_REQUIRED += arch_avr8
FEATURES_REQUIRED += cpu_core_atmega
endif
USEMODULE += xtimer

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
hifive1 \
hifive1b \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
chronos \
derfmega128 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
b-l072z-lrwan1 \
blackpill \
blackpill-128kib \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
blackpill \
bluepill \
bluepill-stm32f030c8 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
chronos \
i-nucleo-lrwan1 \

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \

View File

@ -2,7 +2,14 @@
TARGET_ARCH_AVR ?= avr
TARGET_ARCH ?= $(TARGET_ARCH_AVR)
CFLAGS_CPU = -mmcu=$(CPU) $(CFLAGS_FPU)
ifeq (atxmega,$(CPU))
ifeq (,$(CPU_MODEL))
$(error CPU_MODEL must have been defined by the board Makefile.features)
endif
CFLAGS_CPU ?= -mmcu=$(CPU_MODEL) $(CFLAGS_FPU)
else
CFLAGS_CPU ?= -mmcu=$(CPU) $(CFLAGS_FPU)
endif
CFLAGS_LINK = -ffunction-sections -fdata-sections -fno-builtin -fshort-enums
CFLAGS_DBG ?= -ggdb -g3
CFLAGS_OPT ?= -Os

View File

@ -12,14 +12,18 @@ ifneq (,$(filter $(CPU),atmega328p))
# Use debugWIRE as protocol for debugging (ATmega328P does not support JTAG)
DEBUGPROTO := -w
else
# Use JTAG as protocol for debugging
DEBUGPROTO := -j $(AVR_DEBUGINTERFACE)
# Use JTAG as protocol for debugging as default
DEBUGPROTO ?= -j $(AVR_DEBUGINTERFACE)
endif
DEBUGSERVER_FLAGS ?= "$(AVR_DEBUGDEVICE) $(DEBUGPROTO) :$(DEBUGSERVER_PORT)"
DEBUGGER_FLAGS ?= "-x $(AVARICE_PATH)/gdb.conf $(ELFFILE)"
DEBUGGER = "$(AVARICE_PATH)/debug.sh" $(DEBUGSERVER_FLAGS) $(AVARICE_PATH) $(DEBUGSERVER_PORT)
AVRDUDE_PROGRAMMER_FLAGS = -p $(subst atmega,m,$(CPU))
ifeq (atxmega,$(CPU))
AVRDUDE_PROGRAMMER_FLAGS ?= -p $(subst atxmega,x,$(CPU_MODEL))
else
AVRDUDE_PROGRAMMER_FLAGS = -p $(subst atmega,m,$(CPU))
endif
# Set flasher port only for programmers that require it
ifneq (,$(filter $(AVRDUDE_PROGRAMMER),arduino avr109 buspirate stk500v1 stk500v2 wiring))

View File

@ -3,6 +3,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
im880b \
nucleo-l011k4 \

View File

@ -4,6 +4,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
nucleo-f031k6 \
nucleo-l011k4 \
samd10-xmini \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
msb-430 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \

View File

@ -4,6 +4,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
b-l072z-lrwan1 \
blackpill \
blackpill-128kib \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
b-l072z-lrwan1 \
blackpill \
blackpill-128kib \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
blackpill \
bluepill \
bluepill-stm32f030c8 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
msb-430 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
msb-430 \
msb-430h \
nucleo-f031k6 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
msb-430 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
i-nucleo-lrwan1 \
msb-430 \
msb-430h \

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
b-l072z-lrwan1 \
blackpill \
blackpill-128kib \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
msb-430 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
hifive1 \
hifive1b \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
blackpill \
bluepill \
bluepill-stm32f030c8 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
msb-430 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
msb-430 \
msb-430h \
nucleo-f031k6 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
derfmega128 \
hifive1 \

View File

@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega328p \
atmega1281 \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
msb-430 \

View File

@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
blackpill \
bluepill \
bluepill-stm32f030c8 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
mega-xplained \

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \

View File

@ -2,6 +2,10 @@ include ../Makefile.tests_common
FEATURES_REQUIRED = periph_timer
BOARDS_TIMER_500kHz := \
atxmega-a1u-xpro \
#
BOARDS_TIMER_250kHz := \
arduino-duemilanove \
arduino-leonardo \
@ -39,7 +43,9 @@ BOARDS_TIMER_CLOCK_CORECLOCK := \
waspmote-pro \
#
ifneq (,$(filter $(BOARDS_TIMER_250kHz),$(BOARD)))
ifneq (,$(filter $(BOARDS_TIMER_500kHz),$(BOARD)))
TIMER_SPEED ?= 500000
else ifneq (,$(filter $(BOARDS_TIMER_250kHz),$(BOARD)))
TIMER_SPEED ?= 250000
else ifneq (,$(filter $(BOARDS_TIMER_32kHz),$(BOARD)))
TIMER_SPEED ?= 32768

View File

@ -5,6 +5,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega1284p \
atmega328p \
atxmega-a1u-xpro \
blackpill \
bluepill \
derfmega128 \

View File

@ -4,6 +4,7 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atxmega-a1u-xpro \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \

Some files were not shown because too many files have changed in this diff Show More