diff --git a/boards/atmega8/Kconfig b/boards/atmega8/Kconfig
new file mode 100644
index 000000000000..420dc8185737
--- /dev/null
+++ b/boards/atmega8/Kconfig
@@ -0,0 +1,25 @@
+# Copyright (c) 2020 HAW Hamburg
+#
+# 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 "atmega8" if BOARD_ATMEGA8
+
+config BOARD_ATMEGA8
+ bool
+ default y
+ select CPU_MODEL_ATMEGA8
+ # Put defined MCU peripherals here (in alphabetical order)
+ select HAS_PERIPH_ADC
+ select HAS_PERIPH_GPIO
+ select HAS_PERIPH_I2C
+ select HAS_PERIPH_PWM
+ select HAS_PERIPH_SPI
+ select HAS_PERIPH_TIMER
+ select HAS_PERIPH_UART
+ # Various other features (if any)
+ select MODULE_BOARDS_COMMON_ATMEGA if TEST_KCONFIG
+
+source "$(RIOTBOARD)/common/atmega/Kconfig"
diff --git a/boards/atmega8/Makefile b/boards/atmega8/Makefile
new file mode 100644
index 000000000000..3134740b39ff
--- /dev/null
+++ b/boards/atmega8/Makefile
@@ -0,0 +1,5 @@
+MODULE = board
+
+DIRS = $(RIOTBOARD)/common/atmega
+
+include $(RIOTBASE)/Makefile.base
diff --git a/boards/atmega8/Makefile.dep b/boards/atmega8/Makefile.dep
new file mode 100644
index 000000000000..3d1c295b9b21
--- /dev/null
+++ b/boards/atmega8/Makefile.dep
@@ -0,0 +1 @@
+USEMODULE += boards_common_atmega
diff --git a/boards/atmega8/Makefile.features b/boards/atmega8/Makefile.features
new file mode 100644
index 000000000000..da674867d947
--- /dev/null
+++ b/boards/atmega8/Makefile.features
@@ -0,0 +1,9 @@
+CPU = atmega8
+
+FEATURES_PROVIDED += periph_adc
+FEATURES_PROVIDED += periph_gpio
+FEATURES_PROVIDED += periph_i2c
+FEATURES_PROVIDED += periph_pwm
+FEATURES_PROVIDED += periph_spi
+FEATURES_PROVIDED += periph_timer
+FEATURES_PROVIDED += periph_uart
diff --git a/boards/atmega8/Makefile.include b/boards/atmega8/Makefile.include
new file mode 100644
index 000000000000..df08c470af1a
--- /dev/null
+++ b/boards/atmega8/Makefile.include
@@ -0,0 +1,16 @@
+# configure the terminal program
+PORT_LINUX ?= /dev/ttyUSB0
+PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbmodem*)))
+BAUD ?= 9600
+ATMEGA8_CLOCK ?=
+
+# Allow overwriting programmer via env variables without affecting other boards
+PROGRAMMER_BOARD_ATMEGA8 ?= usbasp
+# ICSP programmer to use for avrdude
+AVRDUDE_PROGRAMMER ?= $(PROGRAMMER_BOARD_ATMEGA8)
+
+ifneq (,$(ATMEGA8_CLOCK))
+ CFLAGS += -DCLOCK_CORECLOCK=$(ATMEGA8_CLOCK)
+endif
+
+include $(RIOTBOARD)/common/atmega/Makefile.include
diff --git a/boards/atmega8/doc.txt b/boards/atmega8/doc.txt
new file mode 100644
index 000000000000..13acb87ad7db
--- /dev/null
+++ b/boards/atmega8/doc.txt
@@ -0,0 +1,99 @@
+/**
+@defgroup boards_atmega8 Standalone ATmega8
+@ingroup boards
+@brief Support for using the ATmega8 as standalone board
+
+## Overview
+
+As the ATmega8 can run from the internal oscillator, placing it on a breadboard,
+connecting an USB-UART adapter and power is enough to run RIOT on it. (An ISP
+programmer will be needed to program it; or to program a bootloader to
+subsequently allow programming via UART.)
+
+### MCU
+| MCU | ATmega8 |
+|:------------- |:--------------------------------------------- |
+| Family | AVR/ATmega |
+| Vendor | Microchip (previously Atmel) |
+| RAM | 1KiB |
+| Flash | 8KiB |
+| EEPROM | 512B |
+| Frequency | 1MHz/8MHz (up to 16MHz with external clock) |
+| Timers | 3 (2x 8bit, 1x 16bit) |
+| ADCs | 6 analog input pins |
+| UARTs | 1 |
+| SPIs | 1 |
+| I2Cs | 1 (called TWI) |
+| Vcc | 4.5V - 5.5V (ATmega8), 2.7V - 5.5V (ATmega8L) |
+| Datasheet | [Official datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf) |
+
+### Pinout
+
+\htmlonly\endhtmlonly
+@image html "https://camo.githubusercontent.com/c55beef2f138da61fe671a1e4a307ff4ffbc318d/68747470733a2f2f692e696d6775722e636f6d2f715849456368542e6a7067" "Pinout of the ATmega328p"
+
+All credit for above pinout image goes to https://github.com/MCUdude/MiniCore#pinout
+
+### Clock Frequency
+
+The ATmega8 has an internal oscillators clocked at 1MHz that allow it to be
+operated without any external clock source or crystal. By default the fuses are
+configured to use the internal oscillator and an operating mode resulting in a
+clock speed of 1MHz. By setting the `CKSEL` fuses to 0100 the clock will operate
+at 8MHz without an external clock source. This can be done like this:
+
+ avrdude -c usbasp -p m8 -B 32 -U lfuse:w:0xe4:m
+
+(Replace `usbasp` with the ISP programmer you are using. The `-B 32` might
+be needed on some ISP programmers to communicate with slow ATmega MCUs. It will
+not be needed anymore after the clock device has been disabled.)
+
+This "board" is configured to use 8MHz as core clock, so that the ATmega8
+runs at the highest frequency possible without external clock sources.
+
+By setting the environment variable `ATMEGA8_CLOCK` to a custom frequency in
+Hz (e.g. `1000000` for 1MHz), this core clock can be changed easily. Refer to
+the datasheet on how to configure the ATmega8 to use an external crystal, an
+external clock source or the clock divider.
+
+### Relation Between Supply Voltage, Clock Frequency and Power Consumption
+
+A higher supply voltage results in a higher current drawn. Thus, lower power
+consumption can be achieved by using a lower supply voltage. However, higher
+clock frequencies require higher supply voltages for reliable operation.
+
+The lowest possible supply voltage at 8 MHz is 2.7V (Atmega8L) or
+4.5V (Atmega8).
+
+## Flashing the Device
+
+In order to flash the ATmega8 without a bootloader, an ISP programmer is
+needed. Connect the programmer as follows:
+
+| ISP pin | ATmega8 pin |
+|:-------- |:-------------- |
+| MISO | 18/PB4/MISO |
+| VCC | 7/VCC |
+| SCK | 19/PB5/SCK |
+| MOSI | 17/PB3/MOSI |
+| RESET | 1/RESET |
+| Ground | 22/GND |
+
+The tool `avrdude` needs to be installed. When using the `usbasp` running
+
+ make BOARD=atmega8 flash
+
+will take care of everything. To use the programmer `` instead, run
+
+ make BOARD=atmega8 PROGRAMMER= flash
+
+## Serial Terminal
+
+Connect a TTL adapter with pins 2/RXD and 3/TXD an run
+
+ make BOARD=atmega8 term
+
+Please note that the supply voltage should be compatible with the logic level of
+the TTL adapter. Usually everything between 3.3 V and 5 V should work.
+
+ */
diff --git a/boards/atmega8/include/board.h b/boards/atmega8/include/board.h
new file mode 100644
index 000000000000..965e4448811c
--- /dev/null
+++ b/boards/atmega8/include/board.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
+ * 2016 Laurent Navet
+ * 2019 Otto-von-Guericke-Universität Magdeburg
+ * 2023 Hugues Larrive
+ *
+ * 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_atmega8
+ * @{
+ *
+ * @file
+ * @brief Board specific definitions for the standalone ATmega8 "board"
+ *
+ * @author Marian Buschsieweke
+ * @author Hinnerk van Bruinehsen
+ * @author Laurent Navet
+ * @author Hugues Larrive
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+#include "cpu.h"
+#include "periph_conf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name STDIO configuration
+ *
+ * As the CPU is too slow to handle 115200 baud, we set the default
+ * baudrate to 9600 for this board
+ * @{
+ */
+#define STDIO_UART_BAUDRATE (9600U)
+/** @} */
+
+/**
+ * @name xtimer configuration values
+ * @{
+ */
+#define XTIMER_WIDTH (16)
+#if CLOCK_CORECLOCK > 4000000UL
+#define XTIMER_HZ (CLOCK_CORECLOCK / 64)
+#else
+#define XTIMER_HZ (CLOCK_CORECLOCK / 8)
+#endif
+#define XTIMER_BACKOFF (40)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BOARD_H */
+/** @} */
diff --git a/boards/atmega8/include/periph_conf.h b/boards/atmega8/include/periph_conf.h
new file mode 100644
index 000000000000..ba64fb366961
--- /dev/null
+++ b/boards/atmega8/include/periph_conf.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
+ * 2023 Hugues Larrive
+ *
+ * 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_atmega8
+ * @{
+ *
+ * @file
+ * @brief Peripheral MCU configuration for the ATmega8 standalone "board"
+ *
+ * @author Marian Buschsieweke
+ * @author Hugues Larrive
+ */
+
+#ifndef PERIPH_CONF_H
+#define PERIPH_CONF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Clock configuration
+ * @{
+ */
+#ifndef CLOCK_CORECLOCK
+/* Using 8MHz internal oscillator as default clock source */
+#define CLOCK_CORECLOCK (8000000UL)
+#endif
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "periph_conf_atmega_common.h"
+
+#endif /* PERIPH_CONF_H */
+/** @} */
diff --git a/boards/common/atmega/include/periph_conf_atmega_common.h b/boards/common/atmega/include/periph_conf_atmega_common.h
index c2779b141069..8ba78f5c6366 100644
--- a/boards/common/atmega/include/periph_conf_atmega_common.h
+++ b/boards/common/atmega/include/periph_conf_atmega_common.h
@@ -6,6 +6,7 @@
* 2017 HAW Hamburg, Dimitri Nahm
* 2018 Matthew Blue
* 2019 Otto-von-Guericke-Universität Magdeburg
+ * 2023 Hugues Larrive
*
* 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
@@ -28,6 +29,7 @@
* @author Matthew Blue
* @author Francisco Acosta
* @author Marian Buschsieweke
+ * @author Hugues Larrive
*/
#ifndef PERIPH_CONF_ATMEGA_COMMON_H
@@ -71,6 +73,12 @@ extern "C" {
#define UART_1 MEGA_UART1
#define UART_1_ISR USART1_RX_vect
#define UART_1_ISR_TX USART1_TX_vect
+#elif defined(CPU_ATMEGA8)
+ #define UART_NUMOF (1U)
+
+ #define UART_0 MEGA_UART
+ #define UART_0_ISR USART_RXC_vect
+ #define UART_0_ISR_TX USART_TXC_vect
#elif defined(CPU_ATMEGA328P)
#define UART_NUMOF (1U)
@@ -156,7 +164,8 @@ extern "C" {
*/
#ifndef ADC_NUMOF
#if defined(CPU_ATMEGA128RFA1) || defined(CPU_ATMEGA256RFR2) || defined(CPU_ATMEGA328P) || \
- defined(CPU_ATMEGA1281) || defined(CPU_ATMEGA1284P) || defined(CPU_ATMEGA32U4)
+ defined(CPU_ATMEGA1281) || defined(CPU_ATMEGA1284P) || defined(CPU_ATMEGA32U4) || \
+ defined(CPU_ATMEGA8)
#define ADC_NUMOF (8U)
#elif defined (CPU_ATMEGA2560)
#define ADC_NUMOF (16U)
@@ -180,7 +189,9 @@ extern "C" {
* @{
*/
#ifndef PWM_NUMOF
-#if defined(CPU_ATMEGA328P)
+#if defined(CPU_ATMEGA8)
+ #define PWM_PINS_CH0 { GPIO_PIN(PORT_B, 3), GPIO_UNDEF }
+#elif defined(CPU_ATMEGA328P)
#define PWM_PINS_CH0 { GPIO_PIN(PORT_D, 6), GPIO_PIN(PORT_D, 5) }
#define PWM_PINS_CH1 { GPIO_PIN(PORT_B, 3), GPIO_PIN(PORT_D, 3) }
#elif defined(CPU_ATMEGA1281)
@@ -200,8 +211,9 @@ extern "C" {
#if defined(CPU_ATMEGA32U4) || defined(CPU_ATMEGA328P) || \
defined(CPU_ATMEGA1281) || defined(CPU_ATMEGA1284P) || \
- defined(CPU_ATMEGA2560)
+ defined(CPU_ATMEGA2560) || defined(CPU_ATMEGA8)
static const pwm_conf_t pwm_conf[] = {
+#ifndef CPU_ATMEGA8
{
.dev = MINI_TIMER0,
.pin_ch = PWM_PINS_CH0,
@@ -213,6 +225,13 @@ extern "C" {
.pin_ch = PWM_PINS_CH1,
.div = MINI_TIMER2_DIV,
}
+#endif
+#else /* CPU_ATMEGA8 */
+ {
+ .dev = MINI_TIMER2,
+ .pin_ch = PWM_PINS_CH0,
+ .div = MINI_TIMER2_DIV,
+ },
#endif
};
diff --git a/cpu/atmega8/Kconfig b/cpu/atmega8/Kconfig
new file mode 100644
index 000000000000..aa1c3c6ff1b5
--- /dev/null
+++ b/cpu/atmega8/Kconfig
@@ -0,0 +1,34 @@
+# Copyright (c) 2020 HAW Hamburg
+#
+# 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 CPU_FAM_ATMEGA8
+ bool
+ select CPU_COMMON_ATMEGA
+
+## CPU Models
+config CPU_MODEL_ATMEGA8
+ bool
+ select CPU_FAM_ATMEGA8
+ select HAS_CPU_ATMEGA8
+
+## Definition of specific features
+config HAS_CPU_ATMEGA8
+ bool
+ help
+ Indicates that a 'atmega8' cpu is being used.
+
+## Common CPU symbols
+config CPU_FAM
+ default "atmega8" if CPU_FAM_ATMEGA8
+
+config CPU_MODEL
+ default "atmega8" if CPU_MODEL_ATMEGA8
+
+config CPU
+ default "atmega8" if CPU_FAM_ATMEGA8
+
+source "$(RIOTCPU)/atmega_common/Kconfig"
diff --git a/cpu/atmega8/Makefile b/cpu/atmega8/Makefile
new file mode 100644
index 000000000000..8b5bf236d32d
--- /dev/null
+++ b/cpu/atmega8/Makefile
@@ -0,0 +1,7 @@
+# define the module that is build
+MODULE = cpu
+
+# add a list of subdirectories, that should also be build
+DIRS = $(RIOTCPU)/atmega_common/
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/atmega8/Makefile.dep b/cpu/atmega8/Makefile.dep
new file mode 100644
index 000000000000..b43170c8360a
--- /dev/null
+++ b/cpu/atmega8/Makefile.dep
@@ -0,0 +1 @@
+include $(RIOTCPU)/atmega_common/Makefile.dep
diff --git a/cpu/atmega8/Makefile.features b/cpu/atmega8/Makefile.features
new file mode 100644
index 000000000000..ec626a3bf954
--- /dev/null
+++ b/cpu/atmega8/Makefile.features
@@ -0,0 +1 @@
+include $(RIOTCPU)/atmega_common/Makefile.features
diff --git a/cpu/atmega8/Makefile.include b/cpu/atmega8/Makefile.include
new file mode 100644
index 000000000000..c0393b2e76e2
--- /dev/null
+++ b/cpu/atmega8/Makefile.include
@@ -0,0 +1,7 @@
+RAM_LEN = 1K
+ROM_LEN = 8K
+
+LINKER_SCRIPT ?= avr4.ld
+
+# CPU depends on the atmega common module, so include it
+include $(RIOTCPU)/atmega_common/Makefile.include
diff --git a/cpu/atmega8/doc.txt b/cpu/atmega8/doc.txt
new file mode 100644
index 000000000000..8980bacb9391
--- /dev/null
+++ b/cpu/atmega8/doc.txt
@@ -0,0 +1,10 @@
+/**
+ * @defgroup cpu_atmega8 Atmel ATmega8
+ * @ingroup cpu
+ * @brief Implementation of Atmel's ATmega8 MCU
+ */
+
+/**
+ * @defgroup cpu_atmega8_definitions Atmel ATmega8 Definitions
+ * @ingroup cpu_atmega8
+ */
diff --git a/cpu/atmega8/include/cpu_conf.h b/cpu/atmega8/include/cpu_conf.h
new file mode 100644
index 000000000000..b187ebf9af66
--- /dev/null
+++ b/cpu/atmega8/include/cpu_conf.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
+ * 2017 RWTH Aachen, Josua Arndt
+ * 2018 Matthew Blue
+ * 2023 Hugues Larrive
+ *
+ * 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_atmega_common
+ * @{
+ *
+ * @file
+ * @brief Implementation specific CPU configuration options
+ *
+ * @author Hauke Petersen
+ * @author Hinnerk van Bruinehsen
+ * @author Josua Arndt
+ * @author Steffen Robertz
+ * @author Matthew Blue
+ * @author Hugues Larrive
+ */
+
+#ifndef CPU_CONF_H
+#define CPU_CONF_H
+
+#include "atmega_regs_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef THREAD_EXTRA_STACKSIZE_PRINTF
+#define THREAD_EXTRA_STACKSIZE_PRINTF (64)
+#endif
+
+/**
+ * @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 (128)
+#endif
+
+/* keep THREAD_STACKSIZE_IDLE > THREAD_EXTRA_STACKSIZE_PRINTF
+ * to avoid not printing of debug in interrupts
+ */
+#ifndef THREAD_STACKSIZE_IDLE
+#if MODULE_XTIMER || MODULE_ZTIMER || MODULE_ZTIMER64
+/* For AVR no ISR stack is used, hence an IRQ will victimize the stack of
+ * whatever thread happens to be running with the IRQ kicks in. If more than
+ * trivial stuff is needed to be done in ISRs (e.g. when soft timers are used),
+ * the idle stack will overflow.
+ */
+#define THREAD_STACKSIZE_IDLE (192)
+#else
+#define THREAD_STACKSIZE_IDLE (96)
+#endif
+#endif
+/** @} */
+
+/**
+ * @brief Attribute for memory sections required by SRAM PUF
+ */
+#define PUF_SRAM_ATTRIBUTES __attribute__((used, section(".noinit")))
+
+/**
+ * @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)
+
+#ifndef DOXYGEN
+#define HAS_FLASH_UTILS_ARCH 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CPU_CONF_H */
+/** @} */
diff --git a/cpu/atmega8/include/default_timer_config.h b/cpu/atmega8/include/default_timer_config.h
new file mode 100644
index 000000000000..686c2bbde1a8
--- /dev/null
+++ b/cpu/atmega8/include/default_timer_config.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 HAW Hamburg
+ * 2016 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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_atmega8
+ * @{
+ *
+ * @file
+ * @brief Default timer configuration
+ *
+ * @author René Herthel
+ * @author Hauke Petersen
+ * @author Hugues Larrive
+ */
+
+#ifndef DEFAULT_TIMER_CONFIG_H
+#define DEFAULT_TIMER_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef TIMER_NUMOF
+#define TIMER_NUMOF (1U)
+#define TIMER_CHANNEL_NUMOF (2)
+
+#define TIMER_0 MEGA_TIMER1
+#define TIMER_0_MASK &TIMSK
+#define TIMER_0_FLAG &TIFR
+#define TIMER_0_ISRA TIMER1_COMPA_vect
+#define TIMER_0_ISRB TIMER1_COMPB_vect
+#endif /* TIMER_NUMOF */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DEFAULT_TIMER_CONFIG_H */
+/** @} */
diff --git a/cpu/atmega8/include/periph_cpu.h b/cpu/atmega8/include/periph_cpu.h
new file mode 100644
index 000000000000..d8666c83ed56
--- /dev/null
+++ b/cpu/atmega8/include/periph_cpu.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 HAW Hamburg
+ * 2016 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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_atmega8
+ * @{
+ *
+ * @file
+ * @brief CPU specific definitions for internal peripheral handling
+ *
+ * @author René Herthel
+ * @author Hauke Petersen
+ * @author Hugues Larrive
+ */
+
+#ifndef PERIPH_CPU_H
+#define PERIPH_CPU_H
+
+#include "periph_cpu_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Define a CPU specific GPIO pin generator macro
+ */
+#define GPIO_PIN(x, y) ((x << 4) | y)
+
+/**
+ * @brief Available ports on the ATmega8 family
+ */
+enum {
+ PORT_B = 1, /**< port B */
+ PORT_C = 2, /**< port C */
+ PORT_D = 3 /**< port D */
+};
+
+/**
+ * @brief Available external interrupt pins on the ATmega8 family
+ *
+ * In order of their interrupt number.
+ */
+#define CPU_ATMEGA_EXT_INTS { GPIO_PIN(PORT_D, 2), \
+ GPIO_PIN(PORT_D, 3) }
+
+/**
+ * @brief Get the interrupt vector number of the given GPIO pin
+ */
+static inline uint8_t atmega_pin2exti(uint8_t port_num, uint8_t pin_num)
+{
+ (void)port_num;
+ return pin_num - 2;
+}
+
+/**
+ * @brief Check if the given pin can be used as external interrupt
+ */
+static inline bool atmega_has_pin_exti(uint8_t port_num, uint8_t pin_num)
+{
+ if (port_num == PORT_D) {
+ return ((pin_num == 2) || (pin_num == 3));
+ }
+
+ return false;
+}
+
+/**
+ * @name Defines for the I2C interface
+ * @{
+ */
+#define I2C_PORT_REG PORTC
+#define I2C_PIN_MASK (1 << PORTC4) | (1 << PORTC5)
+/** @} */
+
+/**
+ * @name EEPROM configuration
+ * @{
+ */
+#define EEPROM_SIZE (512U) /* 512B */
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "periph_conf.h"
+#include "default_timer_config.h"
+
+#endif /* PERIPH_CPU_H */
+/** @} */
diff --git a/cpu/atmega_common/atmega_cpu.c b/cpu/atmega_common/atmega_cpu.c
index 52d93bf4c58d..6a806c63a642 100644
--- a/cpu/atmega_common/atmega_cpu.c
+++ b/cpu/atmega_common/atmega_cpu.c
@@ -3,6 +3,7 @@
* 2017 RWTH Aachen, Josua Arndt
* 2018 Matthew Blue
* 2021 Gerson Fernando Budke
+ * 2023 Hugues Larrive
*
* 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
@@ -22,6 +23,7 @@
* @author Matthew Blue
* @author Francisco Acosta
* @author Gerson Fernando Budke
+ * @author Hugues Larrive
*
* @}
*/
@@ -58,7 +60,7 @@ void avr8_reset_cause(void)
DEBUG("Watchdog reset!\n");
}
}
-#if !defined (CPU_ATMEGA328P)
+#if defined(JTRF)
if (mcusr_mirror & (1 << JTRF)) {
DEBUG("JTAG reset!\n");
}
@@ -67,7 +69,9 @@ void avr8_reset_cause(void)
void __attribute__((weak)) avr8_clk_init(void)
{
+#if defined(CLKPR)
atmega_set_prescaler(CPU_ATMEGA_CLK_SCALE_INIT);
+#endif
}
/* This is a vector which is aliased to __vector_default,
@@ -85,7 +89,7 @@ ISR(BADISR_vect)
{
avr8_reset_cause();
-#if defined (CPU_ATMEGA256RFR2)
+#if defined(CPU_ATMEGA256RFR2)
printf("IRQ_STATUS %#02x\nIRQ_STATUS1 %#02x\n",
(unsigned int)IRQ_STATUS, (unsigned int)IRQ_STATUS1);
@@ -101,7 +105,7 @@ ISR(BADISR_vect)
core_panic(PANIC_GENERAL_ERROR, "BADISR");
}
-#if defined(CPU_ATMEGA128RFA1) || defined (CPU_ATMEGA256RFR2)
+#if defined(BAT_LOW_vect)
ISR(BAT_LOW_vect, ISR_BLOCK)
{
avr8_enter_isr();
diff --git a/cpu/atmega_common/include/atmega_regs_common.h b/cpu/atmega_common/include/atmega_regs_common.h
index 5f2785f8ea23..8567deb8c9b8 100644
--- a/cpu/atmega_common/include/atmega_regs_common.h
+++ b/cpu/atmega_common/include/atmega_regs_common.h
@@ -2,6 +2,7 @@
* Copyright (C) 2016 Freie Universität Berlin
* 2016 INRIA
* 2017 Thomas Perrot
+ * 2023 Hugues Larrive
*
* 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
@@ -18,6 +19,7 @@
* @author Hauke Petersen
* @author Francisco Acosta
* @author Thomas Perrot
+ * @author Hugues Larrive
*
*/
@@ -42,6 +44,7 @@ extern "C" {
/**
* @brief Timer register map
*/
+#ifdef TCCR1C
typedef struct {
REG8 CRA; /**< control A */
REG8 CRB; /**< control B */
@@ -51,31 +54,57 @@ typedef struct {
REG16 ICR; /**< input capture */
REG16 OCR[3]; /**< output compare */
} mega_timer_t;
+#else /* atmega8 */
+typedef struct {
+ REG16 ICR; /**< input capture */
+ REG16 OCR[2]; /**< output compare */
+ REG16 CNT; /**< counter */
+ REG8 CRB; /**< control B */
+ REG8 CRA; /**< control A */
+} mega_timer_t;
+#endif
/**
* @brief 8-bit timer register map
*/
typedef struct {
+#if ((defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B)))
REG8 CRA; /**< control A */
REG8 CRB; /**< control B */
REG8 CNT; /**< counter */
REG8 OCR[2]; /**< output compare */
+#elif defined(TCCR2)
+ REG8 OCR; /**< output compare */
+ REG8 CNT; /**< counter */
+ REG8 CR; /**< control */
+#endif
} mini_timer_t;
/**
* @brief UART register map
*/
typedef struct {
+#if defined(UCSR0A) || defined(UCSR1A)
REG8 CSRA; /**< control and status register A */
REG8 CSRB; /**< control and status register B */
REG8 CSRC; /**< control and status register C */
-#ifdef CPU_ATMEGA32U4
+#ifdef UCSR1D /* 32u4 */
REG8 CSRD; /**< control and status register D */
#else
REG8 reserved; /**< reserved */
#endif
REG16 BRR; /**< baud rate register */
REG8 DR; /**< data register */
+#elif defined(UCSRA) /* atmega8 */
+ REG8 BRRL; /**< baud rate register low byte */
+ REG8 CSRB; /**< control and status register B */
+ REG8 CSRA; /**< control and status register A */
+ REG8 DR; /**< data register */
+ REG8 padding[19]; /**< 3 SPI + 3 PORTD + 3 PORTC + 3 PORTB
+ * + 3 reserved + 4 EEPROM = 19 */
+ REG8 CSRC; /**< control and status register C shared
+ * with baud rate register high byte */
+#endif
} mega_uart_t;
/**
@@ -87,14 +116,20 @@ typedef struct {
#define MINI_TIMER0_DIV TIMER_DIV1_8_64_128_1024
#endif
-#if defined(TCCR1A)
+#if defined(TCCR1C)
#define MEGA_TIMER1_BASE (uint16_t *)(&TCCR1A)
#define MEGA_TIMER1 ((mega_timer_t *)MEGA_TIMER1_BASE)
+#elif defined(TCCR1A) /* atmega8 */
+#define MEGA_TIMER1_BASE (uint16_t *)(&ICR1L)
+#define MEGA_TIMER1 ((mega_timer_t *)MEGA_TIMER1_BASE)
#endif
#if defined(TCCR2A)
#define MINI_TIMER2 ((mini_timer_t *)(uint16_t *)(&TCCR2A))
#define MINI_TIMER2_DIV TIMER_DIV1_8_32_64_128_256_1024
+#elif defined(TCCR2) /* atmega8 */
+#define MINI_TIMER2 ((mini_timer_t *)(uint16_t *)(&OCR2))
+#define MINI_TIMER2_DIV TIMER_DIV1_8_32_64_128_256_1024
#endif
#if defined(TCCR3A)
@@ -117,6 +152,11 @@ typedef struct {
* @brief Peripheral register definitions and instances
* @{
*/
+#if defined(UCSRA)
+#define MEGA_UART_BASE ((uint16_t *)(&UBRRL))
+#define MEGA_UART ((mega_uart_t *)MEGA_UART_BASE)
+#endif
+
#if defined(UCSR0A)
#define MEGA_UART0_BASE ((uint16_t *)(&UCSR0A))
#define MEGA_UART0 ((mega_uart_t *)MEGA_UART0_BASE)
diff --git a/cpu/atmega_common/include/cpu_clock.h b/cpu/atmega_common/include/cpu_clock.h
index 797f6107ea15..09120281065e 100644
--- a/cpu/atmega_common/include/cpu_clock.h
+++ b/cpu/atmega_common/include/cpu_clock.h
@@ -63,11 +63,15 @@ enum {
static inline void atmega_set_prescaler(uint8_t clk_scale)
{
/* Enable clock change */
+#ifdef CLKPR
/* Must be assignment to set all other bits to zero, see datasheet */
CLKPR = (1 << CLKPCE);
/* Write clock within 4 cycles */
CLKPR = clk_scale;
+#else
+ (void) clk_scale;
+#endif
}
#ifdef __cplusplus
diff --git a/cpu/atmega_common/include/periph_cpu_common.h b/cpu/atmega_common/include/periph_cpu_common.h
index 5d2b04f24024..02aea16981ca 100644
--- a/cpu/atmega_common/include/periph_cpu_common.h
+++ b/cpu/atmega_common/include/periph_cpu_common.h
@@ -2,6 +2,7 @@
* Copyright (C) 2015 HAW Hamburg
* 2016 Freie Universität Berlin
* 2016 INRIA
+ * 2023 Hugues Larrive
*
* 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
@@ -18,6 +19,7 @@
* @author René Herthel
* @author Hauke Petersen
* @author Francisco Acosta
+ * @author Hugues Larrive
*/
#ifndef PERIPH_CPU_COMMON_H
@@ -61,7 +63,27 @@ typedef uint8_t gpio_t;
*
* Must be identical to the address of `PINA` provided by avr/io.h
*/
-#define ATMEGA_GPIO_BASE_A (0x20)
+#if (defined(OCF1A) && defined(OCF1B) && (OCF1A > OCF1B)) \
+ || (defined(PUD) && (PUD != 4)) || (defined(INT0) && (INT0 == 6))
+ /* match with 65 devices against 61 for (PORTB == _SFR_IO8(0x18)) which
+ * did not work here anyway */
+#define GPIO_PORT_DESCENDENT
+#endif
+
+#ifdef GPIO_PORT_DESCENDENT
+#ifdef _AVR_ATTINY1634_H_INCLUDED
+/* the only one that requires particular treatment! */
+#define ATMEGA_GPIO_BASE_A (0x2F)
+#else
+/* oll other port descendent, including :
+ - _AVR_IO8534_ (only have port A but with 0x18 address) ;
+ - _AVR_IOAT94K_H_ (only have ports D and E) ;
+ - _AVR_IOTN28_H_ (only have ports A and D). */
+#define ATMEGA_GPIO_BASE_A (0x39)
+#endif /* _AVR_ATTINY1634_H_INCLUDED */
+#else /* !GPIO_PORT_DESCENDENT */
+#define ATMEGA_GPIO_BASE_A (0x20)
+#endif /* GPIO_PORT_DESCENDENT */
/**
* @brief Base of the GPIO port G register as memory address
*
@@ -137,7 +159,11 @@ typedef struct {
static inline atmega_gpio_port_t *atmega_gpio_port(uint8_t port_num)
{
static const uintptr_t base_addr = (uintptr_t)ATMEGA_GPIO_BASE_A;
+#ifdef GPIO_PORT_DESCENDENT
+ uintptr_t res = base_addr - port_num * sizeof(atmega_gpio_port_t);
+#else
uintptr_t res = base_addr + port_num * sizeof(atmega_gpio_port_t);
+#endif
/* GPIO ports up to (including) G are mapped in the I/O address space,
* port H and higher (if present) are mapped in a different contiguous
* region afterwards (e.g. 0x100 for ATmega2560). */
diff --git a/cpu/atmega_common/periph/adc.c b/cpu/atmega_common/periph/adc.c
index 6585c617083d..a68692c36913 100644
--- a/cpu/atmega_common/periph/adc.c
+++ b/cpu/atmega_common/periph/adc.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2016 Laurent Navet
* 2017 HAW Hamburg, Dimitri Nahm
+ * 2023 Hugues Larrive
*
* 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
@@ -17,6 +18,7 @@
* @author Laurent Navet
* @author Dimitri Nahm
* @author Sebastian Meiling
+ * @author Hugues Larrive
* @}
*/
@@ -52,35 +54,51 @@ int adc_init(adc_t line)
_prep();
+#if defined(DIDR0)
/* Disable corresponding Digital input */
if (line < 8) {
DIDR0 |= (1 << line);
}
-#if defined(CPU_ATMEGA2560)
+#if defined(DIDR2)
else {
DIDR2 |= (1 << (line - 8));
}
+#endif
#endif
/* Set ADC-pin as input */
-#if defined(CPU_ATMEGA328P)
+#if !defined(PORTA) && defined(PC0)
+ /* 328p and 8 do not have PORTA, on 32u4 pins are named differently
+ * and it only have PORTC6 and PORTC7 */
DDRC &= ~(1 << line);
PORTC &= ~(1 << line);
-#elif defined(CPU_ATMEGA1284P)
+#elif defined(PORTA) && !defined(DIDR2) /* 1284p do not have DIDR2 */
DDRA &= ~(1 << line);
PORTA &= ~(1 << line);
-#elif defined(CPU_ATMEGA2560) || defined(CPU_ATMEGA1281)
+#elif defined(PORTF) /* 2560 and 1281 */
if (line < 8) {
DDRF &= ~(1 << line);
PORTF &= ~(1 << line);
}
-#if defined(CPU_ATMEGA2560)
+#if defined(PORTK) /* 2560 */
+ else {
+ DDRK &= ~(1 << (line - 8));
+ PORTK &= ~(1 << (line - 8));
+ }
+#elif defined(PORTF0) && !defined(PORTF2) && !defined(PORTF3)
+ /* 32u4 do not have PORTF2 and PORTF3 */
+ else if (line == 8) {
+ DDRD &= ~(1 << PORTD4);
+ PORTD &= ~(1 << PORTD4);
+ else if (line < 11) {
+ DDRD &= ~(1 << (line - 3));
+ PORTD &= ~(1 << (line - 3));
else {
- DDRK &= ~(1 << (line-8));
- PORTK &= ~(1 << (line-8));
+ DDRB &= ~(1 << (line - 7));
+ PORTB &= ~(1 << (line - 7));
}
-#endif /* CPU_ATMEGA2560 */
-#endif /* CPU_ATMEGA328P */
+#endif /* PORTK */
+#endif /* PORTF */
/* set clock prescaler to get the maximal possible ADC clock value */
for (uint32_t clk_div = 1; clk_div < 8; ++clk_div) {
@@ -110,10 +128,12 @@ int32_t adc_sample(adc_t line, adc_res_t res)
_prep();
/* set conversion channel */
-#if defined(CPU_ATMEGA328P) || defined(CPU_ATMEGA1281) || defined(CPU_ATMEGA1284P) || defined(CPU_ATMEGA32U4)
+#if defined(ADMUX)
+#if !defined(MUX5)
+ /* atmega8 ; 328p ; 1281 ; 1284p ; 32u4 */
ADMUX &= 0xf0;
ADMUX |= line;
-#elif defined(CPU_ATMEGA2560) || defined(CPU_ATMEGA128RFA1) || defined(CPU_ATMEGA256RFR2)
+#else /* 2560 ; 128rfa1 ; 256rfr2 */
if (line < 8) {
ADCSRB &= ~(1 << MUX5);
ADMUX &= 0xf0;
@@ -124,6 +144,7 @@ int32_t adc_sample(adc_t line, adc_res_t res)
ADMUX &= 0xf0;
ADMUX |= (line-8);
}
+#endif
#endif
/* Start a new conversion. By default, this conversion will
diff --git a/cpu/atmega_common/periph/gpio.c b/cpu/atmega_common/periph/gpio.c
index 2cca6e464f1e..a81c94b265b3 100644
--- a/cpu/atmega_common/periph/gpio.c
+++ b/cpu/atmega_common/periph/gpio.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2015 HAW Hamburg
* 2016 INRIA
-
+ * 2023 Hugues Larrive
*
* 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
@@ -22,6 +22,7 @@
* @author Robert Hartung
* @author Torben Petersen
* @author Marian Buschsieweke
+ * @author Hugues Larrive
*
* @}
*/
@@ -313,20 +314,30 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
cli();
/* enable interrupt number int_num */
+#if defined(EIFR) && defined(EIMSK)
EIFR |= (1 << int_num);
EIMSK |= (1 << int_num);
+#elif defined(GIFR) && defined(GICR)
+ GIFR |= (1 << (INTF0 + int_num));
+ GICR |= (1 << (INT0 + int_num));
+#endif
/* apply flank to interrupt number int_num */
- #if defined(EICRB)
+#if defined(EICRB)
if (int_num >= 4) {
EICRB &= ~(0x3 << ((int_num % 4) * 2));
EICRB |= (flank << ((int_num % 4) * 2));
}
else
- #endif
+#endif
{
+#if defined(EICRA)
EICRA &= ~(0x3 << (int_num * 2));
EICRA |= (flank << (int_num * 2));
+#elif defined(MCUCR)
+ MCUCR &= ~(0x3 << (int_num * 2));
+ MCUCR |= (flank << (int_num * 2));
+#endif
}
/* set callback */
@@ -341,13 +352,22 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
void gpio_irq_enable(gpio_t pin)
{
+#if defined(EIFR) && defined(EIMSK)
EIFR |= (1 << _int_num(pin));
EIMSK |= (1 << _int_num(pin));
+#elif defined(GIFR) && defined(GICR)
+ GIFR |= (1 << (INTF0 + _int_num(pin)));
+ GICR |= (1 << (INTF0 + _int_num(pin)));
+#endif
}
void gpio_irq_disable(gpio_t pin)
{
+#if defined(EIMSK)
EIMSK &= ~(1 << _int_num(pin));
+#elif defined(GICR)
+ GICR &= ~(1 << (INTF0 + _int_num(pin)));
+#endif
}
static inline void irq_handler(uint8_t int_num)
diff --git a/cpu/atmega_common/periph/i2c.c b/cpu/atmega_common/periph/i2c.c
index 3b4a0d251e14..118eb0964896 100644
--- a/cpu/atmega_common/periph/i2c.c
+++ b/cpu/atmega_common/periph/i2c.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2017 Hamburg University of Applied Sciences, Dimitri Nahm
+ * 2023 Hugues Larrive
*
* 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
@@ -18,6 +19,7 @@
*
* @author Dimitri Nahm
* @author Laurent Navet
+ * @author Hugues Larrive
*
* @}
*/
@@ -238,7 +240,9 @@ static void i2c_poweron(i2c_t dev)
{
assert(dev < I2C_NUMOF);
(void) dev;
+#ifdef PRTWI
power_twi_enable();
+#endif
}
static int _start(uint8_t address, uint8_t rw_flag)
diff --git a/cpu/atmega_common/periph/pwm.c b/cpu/atmega_common/periph/pwm.c
index 6f1d970777c0..9bfaa020054e 100644
--- a/cpu/atmega_common/periph/pwm.c
+++ b/cpu/atmega_common/periph/pwm.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2017 Víctor Ariño
+ * 2023 Hugues Larrive
*
* 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
@@ -15,6 +16,7 @@
* @brief Low-level PWM driver implementation
*
* @author Víctor Ariño
+ * @author Hugues Larrive
*
* @}
*/
@@ -35,8 +37,12 @@
#define COMA1 7
static struct {
+#if (defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B))
uint8_t CRA;
uint8_t CRB;
+#elif defined(TCCR2)
+ uint8_t CR;
+#endif
uint8_t res;
} state[PWM_NUMOF];
@@ -60,6 +66,7 @@ static inline uint8_t get_prescaler(pwm_t dev, uint32_t *scale)
return pre;
}
+#if (defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B))
static inline void compute_cra_and_crb(pwm_t dev, uint8_t pre)
{
uint8_t cra = (1 << WGM1) | (1 << WGM0);
@@ -79,16 +86,25 @@ static inline void compute_cra_and_crb(pwm_t dev, uint8_t pre)
state[dev].CRA = cra;
state[dev].CRB = crb;
}
+#endif
static inline void apply_config(pwm_t dev)
{
+#if (defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B))
pwm_conf[dev].dev->CRA = state[dev].CRA;
pwm_conf[dev].dev->CRB = state[dev].CRB;
+#elif defined(TCCR2)
+ pwm_conf[dev].dev->CR = state[dev].CR;
+#endif
if (pwm_conf[dev].pin_ch[0] == GPIO_UNDEF) {
/* If channel 0 is not used, variable resolutions can be used for
* channel 1 */
+#if (defined(OCR0A) && defined(OCR0B)) || (defined(OCR2A) && defined(OCR2B))
pwm_conf[dev].dev->OCR[0] = state[dev].res;
+#elif defined(OCR2)
+ pwm_conf[dev].dev->OCR = state[dev].res;
+#endif
}
}
@@ -101,11 +117,17 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
assert(!(res != 256 && pwm_conf[dev].pin_ch[0] != GPIO_UNDEF));
/* disable PWM */
+#if (defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B))
pwm_conf[dev].dev->CRA = 0x00;
pwm_conf[dev].dev->CRB = 0x00;
pwm_conf[dev].dev->OCR[0] = 0;
pwm_conf[dev].dev->OCR[1] = 0;
+#elif defined(TCCR2)
+ pwm_conf[dev].dev->CR = 0x00;
+ pwm_conf[dev].dev->OCR = 0;
+#endif
+#if defined(PRT2) || defined(PRTIM2) || defined(PRT0) || defined(PRTIM0)
/* disable power reduction */
if (dev) {
power_timer2_enable();
@@ -113,6 +135,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
else {
power_timer0_enable();
}
+#endif
/* find out prescaler */
uint32_t scale = (CLOCK_CORECLOCK / (freq * (uint32_t)res));
@@ -121,7 +144,12 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
/* Compute configuration and store it in the state. (The state is needed
* for later calls to pwm_poweron().)*/
+#if (defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B))
compute_cra_and_crb(dev, pre);
+#elif defined(TCCR2)
+ uint8_t cr = (1 << WGM21) | (1 << WGM20) | (1 << COM21) | pre;
+ state[dev].CR = cr;
+#endif
state[dev].res = res - 1;
/* Apply configuration stored in state */
@@ -155,18 +183,30 @@ uint8_t pwm_channels(pwm_t dev)
void pwm_set(pwm_t dev, uint8_t ch, uint16_t value)
{
+#ifdef OCR2
+ (void)ch;
+#endif
assert(dev < PWM_NUMOF && ch <= 1 && pwm_conf[dev].pin_ch[ch] != GPIO_UNDEF);
if (value > state[dev].res) {
+#if (defined(OCR0A) && defined(OCR0B)) || (defined(OCR2A) && defined(OCR2B))
pwm_conf[dev].dev->OCR[ch] = state[dev].res;
+#elif defined(OCR2)
+ pwm_conf[dev].dev->OCR = state[dev].res;
+#endif
}
else {
+#if (defined(OCR0A) && defined(OCR0B)) || (defined(OCR2A) && defined(OCR2B))
pwm_conf[dev].dev->OCR[ch] = value;
+#elif defined(OCR2)
+ pwm_conf[dev].dev->OCR = value;
+#endif
}
}
void pwm_poweron(pwm_t dev)
{
assert(dev < PWM_NUMOF);
+#if defined(PRT2) || defined(PRTIM2) || defined(PRT0) || defined(PRTIM0)
/* disable power reduction */
if (dev) {
power_timer2_enable();
@@ -174,6 +214,7 @@ void pwm_poweron(pwm_t dev)
else {
power_timer0_enable();
}
+#endif
apply_config(dev);
}
@@ -181,6 +222,7 @@ void pwm_poweron(pwm_t dev)
void pwm_poweroff(pwm_t dev)
{
assert(dev < PWM_NUMOF);
+#if (defined(TCCR0A) && defined(TTCR0B)) || (defined(TCCR2A) && defined(TCCR2B))
pwm_conf[dev].dev->CRA = 0x00;
pwm_conf[dev].dev->CRB = 0x00;
/* disable timers to lower power consumption */
@@ -190,6 +232,9 @@ void pwm_poweroff(pwm_t dev)
else {
power_timer0_disable();
}
+#elif defined(TCCR2)
+ pwm_conf[dev].dev->CR = 0x00;
+#endif
if (pwm_conf[dev].pin_ch[0] != GPIO_UNDEF) {
gpio_clear(pwm_conf[dev].pin_ch[0]);
diff --git a/cpu/atmega_common/periph/spi.c b/cpu/atmega_common/periph/spi.c
index cac04cfdeb40..4231f4929baa 100644
--- a/cpu/atmega_common/periph/spi.c
+++ b/cpu/atmega_common/periph/spi.c
@@ -3,6 +3,7 @@
* 2016 Freie Universität Berlin
* 2017 Hamburg University of Applied Sciences
* 2017 Thomas Perrot
+ * 2023 Hugues Larrive
*
* 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
@@ -21,6 +22,7 @@
* @author Hauke Petersen
* @author Dimitri Nahm
* @author Thomas Perrot
+ * @author Hugues Larrive
*
* @}
*/
@@ -43,8 +45,10 @@ static mutex_t lock = MUTEX_INIT;
void spi_init(spi_t bus)
{
assert(bus == 0);
+#ifdef PRSPI
/* power off the SPI peripheral */
power_spi_disable();
+#endif
/* trigger the pin configuration */
spi_init_pins(bus);
}
@@ -53,13 +57,13 @@ void spi_init_pins(spi_t bus)
{
(void)bus;
/* set SPI pins as output */
-#if defined (CPU_ATMEGA2560) || defined (CPU_ATMEGA1281)
+#if defined(CPU_ATMEGA2560) || defined(CPU_ATMEGA1281)
DDRB |= ((1 << DDB2) | (1 << DDB1) | (1 << DDB0));
#endif
-#if defined (CPU_ATMEGA328P)
+#if defined(CPU_ATMEGA328P) || defined(CPU_ATMEGA8)
DDRB |= ((1 << DDB2) | (1 << DDB3) | (1 << DDB5));
#endif
-#if defined (CPU_ATMEGA1284P)
+#if defined(CPU_ATMEGA1284P)
DDRB |= ((1 << DDB4) | (1 << DDB5) | (1 << DDB7));
#endif
#if defined(CPU_ATMEGA128RFA1) || defined(CPU_ATMEGA256RFR2)
@@ -86,7 +90,9 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
/* lock the bus and power on the SPI peripheral */
mutex_lock(&lock);
+#ifdef PRSPI
power_spi_enable();
+#endif
/* configure as master, with given mode and clock */
SPSR = (clk >> S2X_SHIFT);
@@ -102,7 +108,9 @@ void spi_release(spi_t bus)
(void)bus;
/* power off and release the bus */
SPCR &= ~(1 << SPE);
+#ifdef PRSPI
power_spi_disable();
+#endif
mutex_unlock(&lock);
}
diff --git a/cpu/atmega_common/periph/timer.c b/cpu/atmega_common/periph/timer.c
index 6fc9350e359f..1534df5e7184 100644
--- a/cpu/atmega_common/periph/timer.c
+++ b/cpu/atmega_common/periph/timer.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
+ * 2023 Hugues Larrive
*
* 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
@@ -16,6 +17,7 @@
*
* @author Hauke Petersen
* @author Hinnerk van Bruinehsen
+ * @author Hugues Larrive
*
* @}
*/
@@ -134,7 +136,9 @@ int timer_init(tim_t tim, uint32_t freq, timer_cb_t cb, void *arg)
/* stop and reset timer */
ctx[tim].dev->CRA = 0;
ctx[tim].dev->CRB = 0;
+#ifdef TCCR1C
ctx[tim].dev->CRC = 0;
+#endif
ctx[tim].dev->CNT = 0;
/* save interrupt context and timer mode */
@@ -158,10 +162,17 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
unsigned state = irq_disable();
ctx[tim].dev->OCR[channel] = (uint16_t)value;
+#if defined(OCF1A) && defined(OCF1B) && (OCF1A < OCF1B)
+ /* clear spurious IRQs, if any */
+ *ctx[tim].flag = (1 << (OCF1A + channel));
+ /* unmask IRQ */
+ *ctx[tim].mask |= (1 << (OCIE1A + channel));
+#elif defined(OCF1A) && defined(OCF1B) && (OCF1A > OCF1B)
/* clear spurious IRQs, if any */
- *ctx[tim].flag = (1 << (channel + OCF1A));
+ *ctx[tim].flag = (1 << (OCF1A - channel));
/* unmask IRQ */
- *ctx[tim].mask |= (1 << (channel + OCIE1A));
+ *ctx[tim].mask |= (1 << (OCIE1A - channel));
+#endif
set_oneshot(tim, channel);
irq_restore(state);
@@ -179,17 +190,28 @@ int timer_set(tim_t tim, int channel, unsigned int timeout)
unsigned absolute = ctx[tim].dev->CNT + timeout;
ctx[tim].dev->OCR[channel] = absolute;
+#if defined(OCF1A) && defined(OCF1B) && (OCF1A < OCF1B)
+ /* clear spurious IRQs, if any */
+ *ctx[tim].flag = (1 << (OCF1A + channel));
+ /* unmask IRQ */
+ *ctx[tim].mask |= (1 << (OCIE1A + channel));
+#elif defined(OCF1A) && defined(OCF1B) && (OCF1A > OCF1B)
/* clear spurious IRQs, if any */
- *ctx[tim].flag = (1 << (channel + OCF1A));
+ *ctx[tim].flag = (1 << (OCF1A - channel));
/* unmask IRQ */
- *ctx[tim].mask |= (1 << (channel + OCIE1A));
+ *ctx[tim].mask |= (1 << (OCIE1A - channel));
+#endif
set_oneshot(tim, channel);
if ((absolute - ctx[tim].dev->CNT) > timeout) {
/* Timer already expired. Trigger the interrupt now and loop until it
* is triggered.
*/
+#if defined(OCF1A) && defined(OCF1B) && (OCF1A < OCF1B)
while (!(*ctx[tim].flag & (1 << (OCF1A + channel)))) {
+#elif defined(OCF1A) && defined(OCF1B) && (OCF1A > OCF1B)
+ while (!(*ctx[tim].flag & (1 << (OCF1A - channel)))) {
+#endif
ctx[tim].dev->OCR[channel] = ctx[tim].dev->CNT;
}
}
@@ -215,10 +237,17 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags
ctx[tim].dev->OCR[channel] = (uint16_t)value;
+#if defined(OCF1A) && defined(OCF1B) && (OCF1A < OCF1B)
+ /* clear spurious IRQs, if any */
+ *ctx[tim].flag = (1 << (OCF1A + channel));
+ /* unmask IRQ */
+ *ctx[tim].mask |= (1 << (OCIE1A + channel));
+#elif defined(OCF1A) && defined(OCF1B) && (OCF1A > OCF1B)
/* clear spurious IRQs, if any */
- *ctx[tim].flag = (1 << (channel + OCF1A));
+ *ctx[tim].flag = (1 << (OCF1A - channel));
/* unmask IRQ */
- *ctx[tim].mask |= (1 << (channel + OCIE1A));
+ *ctx[tim].mask |= (1 << (OCIE1A - channel));
+#endif
clear_oneshot(tim, channel);
@@ -253,7 +282,11 @@ int timer_clear(tim_t tim, int channel)
return -1;
}
- *ctx[tim].mask &= ~(1 << (channel + OCIE1A));
+#if defined(OCIE1A) && defined(OCIE1B) && (OCIE1A < OCIE1B)
+ *ctx[tim].mask &= ~(1 << (OCIE1A + channel));
+#elif defined(OCIE1A) && defined(OCIE1B) && (OCIE1A > OCIE1B)
+ *ctx[tim].mask &= ~(1 << (OCIE1A - channel));
+#endif
return 0;
}
@@ -293,7 +326,7 @@ static inline void _isr(tim_t tim, int chan)
avr8_enter_isr();
if (is_oneshot(tim, chan)) {
- *ctx[tim].mask &= ~(1 << (chan + OCIE1A));
+ timer_clear(tim, chan);
}
ctx[tim].cb(ctx[tim].arg, chan);
diff --git a/cpu/atmega_common/periph/uart.c b/cpu/atmega_common/periph/uart.c
index 5e304ec05f63..f5858505149f 100644
--- a/cpu/atmega_common/periph/uart.c
+++ b/cpu/atmega_common/periph/uart.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
* 2017 Thomas Perrot
+ * 2023 Hugues Larrive
*
* 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
@@ -18,6 +19,7 @@
* @author Hauke Petersen
* @author Hinnerk van Bruinehsen
* @author Thomas Perrot
+ * @author Hugues Larrive
*
*
* Support static BAUD rate calculation using STDIO_UART_BAUDRATE.
@@ -83,12 +85,20 @@ static uart_isr_ctx_t isr_ctx[UART_NUMOF];
static void _update_brr(uart_t uart, uint16_t brr, bool double_speed)
{
+#if defined(UCSR0A) || defined(UCSR1A)
dev[uart]->BRR = brr;
+#elif defined(UCSRA) /* atmega8 */
+ /* on atmega8 BRRH is shared with CSRC */
+ dev[uart]->CSRC = (brr >> 8);
+ dev[uart]->BRRL = (uint8_t)(brr & 0x00ff);
+#endif
if (double_speed) {
-#ifdef CPU_ATMEGA32U4
- dev[uart]->CSRA |= (1 << U2X1);
-#else
+#if defined(U2X) /* atmega8 */
+ dev[uart]->CSRA |= (1 << U2X);
+#elif defined(U2X0)
dev[uart]->CSRA |= (1 << U2X0);
+#elif defined(U2X1) /* atmega32u4 */
+ dev[uart]->CSRA |= (1 << U2X1);
#endif
}
}
@@ -129,34 +139,40 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
isr_ctx[uart].arg = arg;
/* disable and reset UART */
-#ifdef CPU_ATMEGA32U4
+#ifdef UCSR1D /* 32u4 */
dev[uart]->CSRD = 0;
#endif
dev[uart]->CSRB = 0;
dev[uart]->CSRA = 0;
/* configure UART to 8N1 mode */
-#ifdef CPU_ATMEGA32U4
- dev[uart]->CSRC = (1 << UCSZ10) | (1 << UCSZ11);
-#else
+#if defined(UCSZ0) && defined(UCSZ1) /* atmega8 */
+ dev[uart]->CSRC = (1 << UCSZ0) | (1 << UCSZ1);
+#elif defined(UCSZ00) && defined(UCSZ01)
dev[uart]->CSRC = (1 << UCSZ00) | (1 << UCSZ01);
+#elif defined(UCSZ10) && defined(UCSZ11) /* 32u4 */
+ dev[uart]->CSRC = (1 << UCSZ10) | (1 << UCSZ11);
#endif
/* set clock divider */
_set_brr(uart, baudrate);
/* enable RX and TX and their respective interrupt */
if (rx_cb) {
-#ifdef CPU_ATMEGA32U4
- dev[uart]->CSRB = ((1 << RXCIE1) | (1 << TXCIE1) | (1 << RXEN1) | (1 << TXEN1));
-#else
+#if defined(RXCIE) /* atmega8 */
+ dev[uart]->CSRB = ((1 << RXCIE) | (1 << TXCIE) | (1 << RXEN) | (1 << TXEN));
+#elif defined(RXCIE0)
dev[uart]->CSRB = ((1 << RXCIE0) | (1 << TXCIE0) | (1 << RXEN0) | (1 << TXEN0));
+#elif defined(RXCIE1) /* 32u4 */
+ dev[uart]->CSRB = ((1 << RXCIE1) | (1 << TXCIE1) | (1 << RXEN1) | (1 << TXEN1));
#endif
}
else {
-#ifdef CPU_ATMEGA32U4
- dev[uart]->CSRB = ((1 << TXEN1) | (1 << TXCIE1));
-#else
+#if defined(TXEN) /* atmega8 */
+ dev[uart]->CSRB = ((1 << TXEN) | (1 << TXCIE));
+#elif defined(TXEN0)
dev[uart]->CSRB = ((1 << TXEN0) | (1 << TXCIE0));
+#elif defined(TXEN1) /* 32u4 */
+ dev[uart]->CSRB = ((1 << TXEN1) | (1 << TXCIE1));
#endif
}
@@ -166,10 +182,12 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
for (size_t i = 0; i < len; i++) {
-#ifdef CPU_ATMEGA32U4
- while (!(dev[uart]->CSRA & (1 << UDRE1))) {};
-#else
+#if defined(UDRE) /* atmega8 */
+ while (!(dev[uart]->CSRA & (1 << UDRE))) {};
+#elif defined(UDRE0)
while (!(dev[uart]->CSRA & (1 << UDRE0))) {}
+#elif defined(UDRE1) /* 32u4 */
+ while (!(dev[uart]->CSRA & (1 << UDRE1))) {};
#endif
/* start of TX won't finish until no data in UDRn and transmit shift
register is empty */
diff --git a/cpu/avr8_common/Kconfig b/cpu/avr8_common/Kconfig
index 54bd222d82ac..e6240df54a68 100644
--- a/cpu/avr8_common/Kconfig
+++ b/cpu/avr8_common/Kconfig
@@ -10,6 +10,7 @@ config CPU_ARCH_AVR8
bool
select HAS_ARCH_8BIT
select HAS_ARCH_AVR8
+ select HAS_NO_IDLE_THREAD
select MODULE_MALLOC_THREAD_SAFE if TEST_KCONFIG
select MODULE_TINY_STRERROR_AS_STRERROR if TEST_KCONFIG
diff --git a/cpu/avr8_common/Makefile.features b/cpu/avr8_common/Makefile.features
index 1c5acda5cd1d..e5f25277b785 100644
--- a/cpu/avr8_common/Makefile.features
+++ b/cpu/avr8_common/Makefile.features
@@ -1,3 +1,4 @@
FEATURES_PROVIDED += arch_8bit
FEATURES_PROVIDED += arch_avr8
+FEATURES_PROVIDED += no_idle_thread
FEATURES_PROVIDED += cpp
diff --git a/cpu/avr8_common/avr8_cpu.c b/cpu/avr8_common/avr8_cpu.c
index 2323236e9736..c7b664efe006 100644
--- a/cpu/avr8_common/avr8_cpu.c
+++ b/cpu/avr8_common/avr8_cpu.c
@@ -3,6 +3,7 @@
* 2017 RWTH Aachen, Josua Arndt
* 2018 Matthew Blue
* 2021 Gerson Fernando Budke
+ * 2023 Hugues Larrive
*
* 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
@@ -22,6 +23,7 @@
* @author Matthew Blue
* @author Francisco Acosta
* @author Gerson Fernando Budke
+ * @author Hugues Larrive
*
* @}
*/
@@ -29,6 +31,7 @@
#include
#include
#include
+#include
#include "cpu.h"
#include "cpu_clock.h"
@@ -101,6 +104,9 @@ void cpu_init(void)
avr8_clk_init();
+ /* Set default sleep mode for LPM or threadless idle */
+ set_sleep_mode(SLEEP_MODE_IDLE);
+
/* Initialize stdio before periph_init() to allow use of DEBUG() there */
#ifdef MODULE_AVR_LIBC_EXTRA
avr8_stdio_init();
diff --git a/cpu/avr8_common/ldscripts/avr4.ld b/cpu/avr8_common/ldscripts/avr4.ld
new file mode 100644
index 000000000000..aa85ea3c82e3
--- /dev/null
+++ b/cpu/avr8_common/ldscripts/avr4.ld
@@ -0,0 +1,27 @@
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+ Copying and distribution of this script, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. */
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:4)
+
+__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 8K;
+__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
+__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
+__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
+__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
+
+MEMORY
+{
+ text (rx) : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
+ data (rw!x) : ORIGIN = 0x800060, LENGTH = __DATA_REGION_LENGTH__
+ eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
+ fuse (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+ lock (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
+ signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
+ user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
+}
+
+INCLUDE avr_common.ld
diff --git a/cpu/avr8_common/startup.c b/cpu/avr8_common/startup.c
index 22c45f2376a9..61afffa2c98b 100644
--- a/cpu/avr8_common/startup.c
+++ b/cpu/avr8_common/startup.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
* 2021 Gerson Fernando Budke
+ * 2023 Hugues Larrive
*
* 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
@@ -18,6 +19,7 @@
* @author Josua Arndt
* @author Steffen Robertz
* @author Gerson Fernando Budke
+ * @author Hugues Larrive
* @}
*/
@@ -48,7 +50,7 @@ extern void __libc_init_array(void);
* avr-libc normally uses the .init9 section for a call to main. This call
* seems to be not replaceable without hacking inside the library. We
* circumvent the call to main by using section .init7 to call the function
- * reset_handler which therefore is the real entry point and section .init8
+ * reset_handler which therefore is the real entry point and section .init8
* which should never be reached but just in case jumps to exit.
* This way there should be no way to call main directly.
*/
@@ -57,12 +59,20 @@ void init8_ovr(void) __attribute__((section(".init8")));
__attribute__((used, naked)) void init7_ovr(void)
{
+#if (ROM_LEN <= 0x2000)
+ __asm__ ("rjmp reset_handler");
+#else
__asm__ ("call reset_handler");
+#endif
}
__attribute__((used, naked)) void init8_ovr(void)
{
+#if (ROM_LEN <= 0x2000)
+ __asm__ ("rjmp exit");
+#else
__asm__ ("jmp exit");
+#endif
}
/**
diff --git a/cpu/avr8_common/thread_arch.c b/cpu/avr8_common/thread_arch.c
index 768583a93f72..92f05f66d4f5 100644
--- a/cpu/avr8_common/thread_arch.c
+++ b/cpu/avr8_common/thread_arch.c
@@ -26,6 +26,7 @@
*/
#include
+#include
#include "thread.h"
#include "sched.h"
@@ -427,3 +428,18 @@ __attribute__((always_inline)) static inline void avr8_context_restore(void)
"out __SREG__, __tmp_reg__ \n\t"
"pop __tmp_reg__ \n\t");
}
+
+void sched_arch_idle(void)
+{
+#ifdef MODULE_PM_LAYERED
+ void pm_set_lowest(void);
+ pm_set_lowest();
+#else
+ unsigned irq_state = irq_disable();
+ sleep_enable();
+ sei();
+ sleep_cpu();
+ sleep_disable();
+ irq_restore(irq_state);
+#endif
+}
diff --git a/tests/atmega8/adc/Makefile b/tests/atmega8/adc/Makefile
new file mode 100644
index 000000000000..a75b46960448
--- /dev/null
+++ b/tests/atmega8/adc/Makefile
@@ -0,0 +1,9 @@
+RIOTBASE ?= $(CURDIR)/../../..
+BOARD ?= atmega8
+PORT ?= /dev/ttyACM0
+
+include ../../Makefile.tests_common
+
+FEATURES_REQUIRED = periph_adc
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/atmega8/adc/README.md b/tests/atmega8/adc/README.md
new file mode 100644
index 000000000000..7ad2990acf2f
--- /dev/null
+++ b/tests/atmega8/adc/README.md
@@ -0,0 +1,13 @@
+Expected result
+===============
+When running this test, you should see the samples of all configured ADC lines
+continuously streamed to std-out.
+
+Background
+==========
+This test application will initialize each configured ADC lines to sample with
+10-bit accuracy. Once configured the application will continuously convert each
+available channel and print the conversion results to std-out.
+
+For verification of the output connect the ADC pins to known voltage levels
+and compare the output.
diff --git a/tests/atmega8/adc/main.c b/tests/atmega8/adc/main.c
new file mode 100644
index 000000000000..57736cf8750a
--- /dev/null
+++ b/tests/atmega8/adc/main.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014-2015 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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 tests
+ * @{
+ *
+ * @file
+ * @brief Test application for peripheral ADC drivers
+ *
+ * @author Hauke Petersen
+ * @author Hugues Larrive
+ *
+ * @}
+ */
+
+#include
+
+#include "periph/adc.h"
+
+#define RES ADC_RES_10BIT
+
+int main(void)
+{
+ int sample = 0;
+
+ puts("\nRIOT ADC peripheral driver test\n");
+ puts("This test will sample all available ADC lines with\n"
+ "a 10-bit resolution and print the sampled results to STDIO\n\n");
+
+ /* initialize all available ADC lines */
+ for (unsigned i = 0; i < ADC_NUMOF; i++) {
+ if (adc_init(ADC_LINE(i)) < 0) {
+ printf("Initialization of ADC_LINE(%u) failed\n", i);
+ return 1;
+ } else {
+ printf("Successfully initialized ADC_LINE(%u)\n", i);
+ }
+ }
+
+ while (1) {
+ for (unsigned i = 0; i < ADC_NUMOF; i++) {
+ sample = adc_sample(ADC_LINE(i), RES);
+ if (sample < 0) {
+ printf("ADC_LINE(%u): selected resolution not applicable\n", i);
+ } else {
+ printf("%i\t", sample);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/tests/atmega8/gpio/Makefile b/tests/atmega8/gpio/Makefile
new file mode 100644
index 000000000000..034530740f40
--- /dev/null
+++ b/tests/atmega8/gpio/Makefile
@@ -0,0 +1,15 @@
+RIOTBASE ?= $(CURDIR)/../../..
+BOARD ?= atmega8
+PORT ?= /dev/ttyACM0
+
+include ../../Makefile.tests_common
+
+FEATURES_REQUIRED += periph_gpio
+
+USEMODULE += shell
+
+CFLAGS += -DNDEBUG -DLOG_LEVEL=LOG_NONE
+DISABLE_MODULE += core_msg
+DEVELHELP = 0
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/atmega8/gpio/main.c b/tests/atmega8/gpio/main.c
new file mode 100644
index 000000000000..05997e67078e
--- /dev/null
+++ b/tests/atmega8/gpio/main.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2014,2017 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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 tests
+ * @{
+ *
+ * @file
+ * @brief Test application for GPIO peripheral drivers
+ *
+ * @author Hauke Petersen
+ * @author Hugues Larrive
+ *
+ * @}
+ */
+
+#include
+#include
+
+#include "shell.h"
+#include "periph/gpio.h"
+
+#define SHELL_BUFSIZE (16)
+
+static int init_pin(int argc, char **argv, gpio_mode_t mode)
+{
+ int po, pi;
+
+ if (argc < 3) {
+ printf("usage: %s \n", argv[0]);
+ return 1;
+ }
+
+ po = atoi(argv[1]);
+ pi = atoi(argv[2]);
+
+ if (gpio_init(GPIO_PIN(po, pi), mode) < 0) {
+ printf("Error to initialize GPIO_PIN(%i, %02i)\n", po, pi);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int init_out(int argc, char **argv)
+{
+ return init_pin(argc, argv, GPIO_OUT);
+}
+
+static int init_in(int argc, char **argv)
+{
+ return init_pin(argc, argv, GPIO_IN);
+}
+
+static int init_in_pu(int argc, char **argv)
+{
+ return init_pin(argc, argv, GPIO_IN_PU);
+}
+
+static int init_in_pd(int argc, char **argv)
+{
+ return init_pin(argc, argv, GPIO_IN_PD);
+}
+
+static int init_od(int argc, char **argv)
+{
+ return init_pin(argc, argv, GPIO_OD);
+}
+
+static int init_od_pu(int argc, char **argv)
+{
+ return init_pin(argc, argv, GPIO_OD_PU);
+}
+
+static int cmd_read(int argc, char **argv)
+{
+ int port, pin;
+
+ if (argc < 3) {
+ printf("usage: %s \n", argv[0]);
+ return 1;
+ }
+
+ port = atoi(argv[1]);
+ pin = atoi(argv[2]);
+
+ if (gpio_read(GPIO_PIN(port, pin))) {
+ printf("GPIO_PIN(%i.%02i) is HIGH\n", port, pin);
+ }
+ else {
+ printf("GPIO_PIN(%i.%02i) is LOW\n", port, pin);
+ }
+
+ return 0;
+}
+
+static int cmd_set(int argc, char **argv)
+{
+ if (argc < 3) {
+ printf("usage: %s \n", argv[0]);
+ return 1;
+ }
+
+ gpio_set(GPIO_PIN(atoi(argv[1]), atoi(argv[2])));
+
+ return 0;
+}
+
+static int cmd_clear(int argc, char **argv)
+{
+ if (argc < 3) {
+ printf("usage: %s \n", argv[0]);
+ return 1;
+ }
+
+ gpio_clear(GPIO_PIN(atoi(argv[1]), atoi(argv[2])));
+
+ return 0;
+}
+
+static int cmd_toggle(int argc, char **argv)
+{
+ if (argc < 3) {
+ printf("usage: %s \n", argv[0]);
+ return 1;
+ }
+
+ gpio_toggle(GPIO_PIN(atoi(argv[1]), atoi(argv[2])));
+
+ return 0;
+}
+
+static const shell_command_t shell_commands[] = {
+ { "init_out", "init as output (push-pull mode)", init_out },
+ { "init_in", "init as input w/o pull resistor", init_in },
+ { "init_in_pu", "init as input with pull-up", init_in_pu },
+ { "init_in_pd", "init as input with pull-down", init_in_pd },
+ { "init_od", "init as output (open-drain without pull resistor)", init_od },
+ { "init_od_pu", "init as output (open-drain with pull-up)", init_od_pu },
+ { "read", "read pin status", cmd_read },
+ { "set", "set pin to HIGH", cmd_set },
+ { "clear", "set pin to LOW", cmd_clear },
+ { "toggle", "toggle pin", cmd_toggle },
+ { NULL, NULL, NULL }
+};
+
+int main(void)
+{
+ puts("GPIO peripheral driver test\n");
+
+ /* start the shell */
+ char line_buf[SHELL_BUFSIZE];
+ shell_run(shell_commands, line_buf, SHELL_BUFSIZE);
+
+ return 0;
+}
diff --git a/tests/atmega8/i2c/Makefile b/tests/atmega8/i2c/Makefile
new file mode 100644
index 000000000000..386ba022d91e
--- /dev/null
+++ b/tests/atmega8/i2c/Makefile
@@ -0,0 +1,15 @@
+RIOTBASE ?= $(CURDIR)/../../..
+BOARD ?= atmega8
+PORT ?= /dev/ttyACM0
+
+include ../../Makefile.tests_common
+
+USEMODULE += pcf8574a
+EXTERNAL_MODULE_DIRS += ./
+USEMODULE += hd44780_avr
+
+CFLAGS += -DHD44780_PARAM_COLS=20
+CFLAGS += -DHD44780_PARAM_ROWS=4
+CFLAGS += -DPCF8574A_BASE_ADDR=0x3F
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/atmega8/i2c/hd44780_avr/Makefile b/tests/atmega8/i2c/hd44780_avr/Makefile
new file mode 100644
index 000000000000..48422e909a47
--- /dev/null
+++ b/tests/atmega8/i2c/hd44780_avr/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/tests/atmega8/i2c/hd44780_avr/hd44780_avr.c b/tests/atmega8/i2c/hd44780_avr/hd44780_avr.c
new file mode 100644
index 000000000000..8166b97b939a
--- /dev/null
+++ b/tests/atmega8/i2c/hd44780_avr/hd44780_avr.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2017 HAW Hamburg
+ * 2023 Hugues Larrive
+ *
+ * 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 drivers_hd44780
+ *
+ * @{
+ * @file
+ * @brief Driver for the HD44780 LCD
+ *
+ * @note The display is also known as LCM1602C from Arduino kits
+ *
+ * @author Sebastian Meiling
+ * @author Hugues Larrive
+ *
+ * @}
+ */
+
+#include
+
+#include "log.h"
+#ifdef MODULE_PCF857X
+#include "pcf857x.h"
+#include "pcf857x_params.h"
+#else
+#include "periph/gpio.h"
+#endif
+/** As xtimer was too big to fit in atmega8's 8 Kbytes flash memory, this
+ * driver was hacked to remove xtimer dependency */
+#define F_CPU (CLOCK_CORECLOCK)
+#define __DELAY_BACKWARD_COMPATIBLE__
+#include "util/delay.h"
+static void xtimer_usleep(uint32_t us)
+{
+ _delay_us(us);
+}
+#define ZTIMER_USEC 0
+
+#include "hd44780_avr.h"
+#include "hd44780_avr_internal.h"
+/************************** end of the hack ****************************/
+
+
+#ifdef MODULE_PCF857X
+static pcf857x_t _pcf857x_dev;
+#endif
+
+static inline void _command(const hd44780_t *dev, uint8_t value);
+static void _pulse(const hd44780_t *dev);
+static void _send(const hd44780_t *dev, uint8_t value, hd44780_state_t state);
+static void _write_bits(const hd44780_t *dev, uint8_t bits, uint8_t value);
+
+static inline void _gpio_set(gpio_t pin);
+static inline void _gpio_clear(gpio_t pin);
+static inline int _gpio_init(gpio_t pin, gpio_mode_t mode);
+
+/**
+ * @brief Send a command to the display
+ *
+ * @param[in] dev device descriptor of display to initialize
+ * @param[in] value the command
+ */
+static inline void _command(const hd44780_t *dev, uint8_t value)
+{
+ _send(dev, value, HD44780_OFF);
+}
+
+/**
+ * @brief Send a pulse to the display to enable new state
+ *
+ * @param[in] dev device descriptor of display to initialize
+ */
+static void _pulse(const hd44780_t *dev)
+{
+ _gpio_clear(dev->p.enable);
+ xtimer_usleep(HD44780_PULSE_WAIT_SHORT);
+ _gpio_set(dev->p.enable);
+ xtimer_usleep(HD44780_PULSE_WAIT_SHORT);
+ _gpio_clear(dev->p.enable);
+ xtimer_usleep(HD44780_PULSE_WAIT_LONG);
+}
+
+/**
+ * @brief Send a data value to the display
+ *
+ * @param[in] dev device descriptor of display to initialize
+ * @param[in] value the data value, either char or command
+ * @param[in] state send state, to distinguish chars and commands
+ */
+static void _send(const hd44780_t *dev, uint8_t value, hd44780_state_t state)
+{
+ (state == HD44780_ON) ? _gpio_set(dev->p.rs) : _gpio_clear(dev->p.rs);
+ /* if RW pin is available, set it to LOW */
+ if (gpio_is_valid(dev->p.rw)) {
+ _gpio_clear(dev->p.rw);
+ }
+ /* write data in 8Bit or 4Bit mode */
+ if (dev->flag & HD44780_8BITMODE) {
+ _write_bits(dev, 8, value);
+ }
+ else {
+ _write_bits(dev, 4, value>>4);
+ _write_bits(dev, 4, value);
+ }
+}
+
+static void _write_bits(const hd44780_t *dev, uint8_t bits, uint8_t value)
+{
+ for (unsigned i = 0; i < bits; ++i) {
+ if ((value >> i) & 0x01) {
+ _gpio_set(dev->p.data[i]);
+ }
+ else {
+ _gpio_clear(dev->p.data[i]);
+ }
+ }
+ _pulse(dev);
+}
+
+static inline int _gpio_init(gpio_t pin, gpio_mode_t mode)
+{
+#ifdef MODULE_PCF857X
+ return pcf857x_gpio_init(&_pcf857x_dev, pin, mode);
+#else
+ return gpio_init(pin, mode);
+#endif
+}
+
+static inline void _gpio_set(gpio_t pin)
+{
+#ifdef MODULE_PCF857X
+ pcf857x_gpio_set(&_pcf857x_dev, pin);
+#else
+ gpio_set(pin);
+#endif
+}
+
+static inline void _gpio_clear(gpio_t pin)
+{
+#ifdef MODULE_PCF857X
+ pcf857x_gpio_clear(&_pcf857x_dev, pin);
+#else
+ gpio_clear(pin);
+#endif
+}
+
+int hd44780_init(hd44780_t *dev, const hd44780_params_t *params)
+{
+ /* write config params to device descriptor */
+ dev->p = *params;
+ /* verify cols and rows */
+ if ((dev->p.cols > HD44780_MAX_COLS) || (dev->p.rows > HD44780_MAX_ROWS)
+ || (dev->p.rows * dev->p.cols > 80)) {
+ LOG_ERROR("hd44780_init: invalid LCD size!\n");
+ return -1;
+ }
+ dev->flag = 0;
+ /* set mode depending on configured pins */
+ if (gpio_is_valid(dev->p.data[4])) {
+ dev->flag |= HD44780_8BITMODE;
+ }
+ else {
+ dev->flag |= HD44780_4BITMODE;
+ }
+ /* set flag for 1 or 2 row mode, 4 rows are 2 rows split half */
+ if (dev->p.rows > 1) {
+ dev->flag |= HD44780_2LINE;
+ }
+ else {
+ dev->flag |= HD44780_1LINE;
+ }
+ /* set char size to 5x8 as default, 5x10 is hardly used by LCDs anyway */
+ dev->flag |= HD44780_5x8DOTS;
+ /* calc and set row offsets, depending on number of columns */
+ dev->roff[0] = 0x00;
+ dev->roff[1] = 0x40;
+ dev->roff[2] = 0x00 + dev->p.cols;
+ dev->roff[3] = 0x40 + dev->p.cols;
+
+#ifdef MODULE_PCF857X
+ /*
+ * TODO: We need an approach for defining and initializing the PCF8574.
+ * With this approach, only one PCF8574 could exist in the system
+ */
+ pcf857x_init(&_pcf857x_dev, &pcf857x_params[0]);
+#endif
+
+ _gpio_init(dev->p.rs, GPIO_OUT);
+ /* RW (read/write) of LCD not required, set it to GPIO_UNDEF */
+ if (gpio_is_valid(dev->p.rw)) {
+ _gpio_init(dev->p.rw, GPIO_OUT);
+ }
+ _gpio_init(dev->p.enable, GPIO_OUT);
+ /* configure all data pins as output */
+ for (int i = 0; i < ((dev->flag & HD44780_8BITMODE) ? 8 : 4); ++i) {
+ _gpio_init(dev->p.data[i], GPIO_OUT);
+ }
+ /* see hitachi HD44780 datasheet pages 45/46 for init specs */
+ xtimer_usleep(HD44780_INIT_WAIT_XXL);
+ _gpio_clear(dev->p.rs);
+ _gpio_clear(dev->p.enable);
+ if (gpio_is_valid(dev->p.rw)) {
+ _gpio_clear(dev->p.rw);
+ }
+ /* put the LCD into 4 bit or 8 bit mode */
+ if (!(dev->flag & HD44780_8BITMODE)) {
+ /* see hitachi HD44780 datasheet figure 24, pg 46 */
+ _write_bits(dev, 4, 0x03);
+ xtimer_usleep(HD44780_INIT_WAIT_LONG);
+
+ _write_bits(dev, 4, 0x03);
+ xtimer_usleep(HD44780_INIT_WAIT_LONG);
+
+ _write_bits(dev, 4, 0x03);
+ xtimer_usleep(HD44780_INIT_WAIT_SHORT);
+
+ _write_bits(dev, 4, 0x02);
+ } else {
+ /* see hitachi HD44780 datasheet page 45 figure 23 */
+ _command(dev, HD44780_FUNCTIONSET | dev->flag);
+ xtimer_usleep(HD44780_INIT_WAIT_LONG); /* wait more than 4.1ms */
+
+ _command(dev, HD44780_FUNCTIONSET | dev->flag);
+ xtimer_usleep(HD44780_INIT_WAIT_SHORT);
+
+ _command(dev, HD44780_FUNCTIONSET | dev->flag);
+ }
+ _command(dev, HD44780_FUNCTIONSET | dev->flag);
+
+ /* turn the display on with no cursor or blinking default, and clear */
+ dev->ctrl = HD44780_DISPLAYON | HD44780_CURSOROFF | HD44780_BLINKOFF;
+ hd44780_display(dev, HD44780_ON);
+ hd44780_clear(dev);
+ /* Initialize to default text direction for western languages */
+ dev->mode = HD44780_ENTRYLEFT | HD44780_ENTRYSHIFTDECREMENT;
+ _command(dev, HD44780_ENTRYMODESET | dev->mode);
+
+ return 0;
+}
+
+void hd44780_clear(const hd44780_t *dev)
+{
+ _command(dev, HD44780_CLEARDISPLAY);
+ xtimer_usleep(HD44780_CMD_WAIT);
+}
+
+void hd44780_home(const hd44780_t *dev)
+{
+ _command(dev, HD44780_RETURNHOME);
+ xtimer_usleep(HD44780_CMD_WAIT);
+}
+
+void hd44780_set_cursor(const hd44780_t *dev, uint8_t col, uint8_t row)
+{
+ if (row >= dev->p.rows) {
+ row = dev->p.rows - 1;
+ }
+ _command(dev, HD44780_SETDDRAMADDR | (col + dev->roff[row]));
+}
+
+void hd44780_display(hd44780_t *dev, hd44780_state_t state)
+{
+ if (state == HD44780_ON) {
+ dev->ctrl |= HD44780_DISPLAYON;
+ }
+ else {
+ dev->ctrl &= ~HD44780_DISPLAYON;
+ }
+ _command(dev, HD44780_DISPLAYCONTROL | dev->ctrl);
+}
+
+void hd44780_cursor(hd44780_t *dev, hd44780_state_t state)
+{
+ if (state == HD44780_ON) {
+ dev->ctrl |= HD44780_CURSORON;
+ }
+ else {
+ dev->ctrl &= ~HD44780_CURSORON;
+ }
+ _command(dev, HD44780_DISPLAYCONTROL | dev->ctrl);
+}
+
+void hd44780_blink(hd44780_t *dev, hd44780_state_t state)
+{
+ if (state == HD44780_ON) {
+ dev->ctrl |= HD44780_BLINKON;
+ }
+ else {
+ dev->ctrl &= ~HD44780_BLINKON;
+ }
+ _command(dev, HD44780_DISPLAYCONTROL | dev->ctrl);
+}
+
+void hd44780_scroll_left(const hd44780_t *dev)
+{
+ _command(dev, HD44780_CURSORSHIFT | HD44780_DISPLAYMOVE | HD44780_MOVELEFT);
+}
+
+void hd44780_scroll_right(const hd44780_t *dev) {
+ _command(dev, HD44780_CURSORSHIFT | HD44780_DISPLAYMOVE | HD44780_MOVERIGHT);
+}
+
+void hd44780_left2right(hd44780_t *dev)
+{
+ dev->mode |= HD44780_ENTRYLEFT;
+ _command(dev, HD44780_ENTRYMODESET | dev->mode);
+}
+
+void hd44780_right2left(hd44780_t *dev)
+{
+ dev->mode &= ~HD44780_ENTRYLEFT;
+ _command(dev, HD44780_ENTRYMODESET | dev->mode);
+}
+
+void hd44780_autoscroll(hd44780_t *dev, hd44780_state_t state)
+{
+ if (state == HD44780_ON) {
+ dev->mode |= HD44780_ENTRYSHIFTINCREMENT;
+ }
+ else {
+ dev->mode &= ~HD44780_ENTRYSHIFTINCREMENT;
+ }
+ _command(dev, HD44780_ENTRYMODESET | dev->mode);
+}
+
+void hd44780_create_char(const hd44780_t *dev, uint8_t location, uint8_t charmap[])
+{
+ location &= 0x7; /* 8 locations (0-7) possible */
+ _command(dev, HD44780_SETCGRAMADDR | (location << 3));
+ for (unsigned i = 0; i < HD44780_CGRAM_SIZE; ++i) {
+ hd44780_write(dev, charmap[i]);
+ }
+}
+
+void hd44780_write(const hd44780_t *dev, uint8_t value)
+{
+ _send(dev, value, HD44780_ON);
+}
+
+void hd44780_print(const hd44780_t *dev, const char *data )
+{
+ while (*data != '\0') {
+ hd44780_write(dev, *data++);
+ }
+}
diff --git a/tests/atmega8/i2c/hd44780_avr/hd44780_avr.h b/tests/atmega8/i2c/hd44780_avr/hd44780_avr.h
new file mode 100644
index 000000000000..a8b8f2a3571e
--- /dev/null
+++ b/tests/atmega8/i2c/hd44780_avr/hd44780_avr.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2017 HAW Hamburg
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup drivers_hd44780 HD44780 LCD driver
+ * @ingroup drivers_display
+ * @brief Driver for the Hitachi HD44780 LCD driver
+ *
+ * @note The driver currently supports direct addressing, no I2C
+ *
+ * @{
+ *
+ * @file
+ * @brief Interface definition for the HD44780 LCD driver
+ *
+ * @author Sebastian Meiling
+ */
+#ifndef HD44780_AVR_H
+#define HD44780_AVR_H
+
+#include
+
+#include "periph/gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Maximal number of columns supported by the driver
+ */
+#define HD44780_MAX_COLS (40U)
+
+/**
+ * @brief Maximal number of rows supported by the driver
+ */
+#define HD44780_MAX_ROWS (4U)
+
+/**
+ * @brief Number of data pins for communication 4 or 8.
+ */
+#define HD44780_MAX_PINS (8U)
+
+/**
+ * @brief Size of RAM for custom chars
+ *
+ * Generally the driver could support 8 chars of size 5x8 or 4 of size 5x10.
+ * However, most displays only use the former, which is (hard wired) default.
+ */
+#define HD44780_CGRAM_SIZE (8U)
+
+/**
+ * @brief Parameters needed for device initialization
+ */
+typedef struct {
+ uint8_t cols; /**< number of LCD cols */
+ uint8_t rows; /**< number of LCD rows */
+ gpio_t rs; /**< rs gpio pin */
+ gpio_t rw; /**< rw gpio pin */
+ gpio_t enable; /**< enable gpio pin */
+ gpio_t data[HD44780_MAX_PINS]; /**< data gpio pins */
+} hd44780_params_t;
+
+/**
+ * @brief Device descriptor for HD44780 LCD
+ */
+typedef struct {
+ hd44780_params_t p; /**< LCD config parameters */
+ uint8_t flag; /**< LCD functional flags */
+ uint8_t ctrl; /**< LCD control flags */
+ uint8_t mode; /**< LCD mode flags */
+ uint8_t roff[HD44780_MAX_ROWS]; /**< offsets for LCD rows */
+} hd44780_t;
+
+/**
+ * @brief Simple state values
+ */
+typedef enum {
+ HD44780_OFF, /**< disable feature */
+ HD44780_ON /**< enable feature */
+} hd44780_state_t;
+
+/**
+ * @brief Initialize the given driver
+ *
+ * @param[out] dev device descriptor of display to initialize
+ * @param[in] params configuration parameters
+ *
+ * @return 0 on success, otherwise error
+ */
+int hd44780_init(hd44780_t *dev, const hd44780_params_t *params);
+
+/**
+ * @brief Clear display, delete all chars
+ *
+ * @param[in] dev device descriptor of LCD
+ */
+void hd44780_clear(const hd44780_t *dev);
+
+/**
+ * @brief Reset cursor to row 0 and column 0
+ *
+ * @param[in] dev device descriptor of LCD
+ */
+void hd44780_home(const hd44780_t *dev);
+
+/**
+ * @brief Set cursor to specific position in column and row
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] col column position
+ * @param[in] row row position
+ */
+void hd44780_set_cursor(const hd44780_t *dev, uint8_t col, uint8_t row);
+
+/**
+ * @brief Turn display on or off
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] state display on or off
+ */
+void hd44780_display(hd44780_t *dev, hd44780_state_t state);
+
+/**
+ * @brief Show cursor, on or off
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] state cursor on or off
+ */
+void hd44780_cursor(hd44780_t *dev, hd44780_state_t state);
+
+/**
+ * @brief Blink cursor, on or off
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] state blink on or off
+ */
+void hd44780_blink(hd44780_t *dev, hd44780_state_t state);
+
+/**
+ * @brief Enable left scrolling
+ *
+ * @param[in] dev device descriptor of LCD
+ */
+void hd44780_scroll_left(const hd44780_t *dev);
+
+/**
+ * @brief Enable right scrolling
+ *
+ * @param[in] dev device descriptor of LCD
+ */
+void hd44780_scroll_right(const hd44780_t *dev);
+
+/**
+ * @brief Set display direction left to right
+ *
+ * @param[in] dev device descriptor of LCD
+ */
+void hd44780_left2right(hd44780_t *dev);
+
+/**
+ * @brief Set display direction right to left
+ *
+ * @param[in] dev device descriptor of LCD
+ */
+void hd44780_right2left(hd44780_t *dev);
+
+/**
+ * @brief Display autoscroll on or off
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] state scroll on or off
+ */
+void hd44780_autoscroll(hd44780_t *dev, hd44780_state_t state);
+
+/**
+ * @brief Create and store a custom character on display memory
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] location memory location
+ * @param[in] charmap character bitmap
+ *
+ * @pre charmap has to be of size HD44780_CGRAM_SIZE, which is 8 by default
+ */
+void hd44780_create_char(const hd44780_t *dev, uint8_t location, uint8_t charmap[]);
+
+/**
+ * @brief Write a single character on the LCD
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] value the character to print, i.e., memory location
+ */
+void hd44780_write(const hd44780_t *dev, uint8_t value);
+
+/**
+ * @brief Write a string on the LCD
+ *
+ * @param[in] dev device descriptor of LCD
+ * @param[in] data the string to print
+ */
+void hd44780_print(const hd44780_t *dev, const char *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HD44780_AVR_H */
+/** @} */
diff --git a/tests/atmega8/i2c/hd44780_avr/hd44780_avr_internal.h b/tests/atmega8/i2c/hd44780_avr/hd44780_avr_internal.h
new file mode 100644
index 000000000000..178b6873cc5f
--- /dev/null
+++ b/tests/atmega8/i2c/hd44780_avr/hd44780_avr_internal.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 HAW Hamburg
+ *
+ * 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 drivers_hd44780
+ *
+ * @{
+ * @file
+ * @brief Internal config and parameters for the HD44780 display
+ *
+ * @author Sebastian Meiling
+ */
+
+#ifndef HD44780_AVR_INTERNAL_H
+#define HD44780_AVR_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name HD44780 LCD commands
+ * @{
+ */
+#define HD44780_CLEARDISPLAY (0x01)
+#define HD44780_RETURNHOME (0x02)
+#define HD44780_ENTRYMODESET (0x04)
+#define HD44780_DISPLAYCONTROL (0x08)
+#define HD44780_CURSORSHIFT (0x10)
+#define HD44780_FUNCTIONSET (0x20)
+#define HD44780_SETCGRAMADDR (0x40)
+#define HD44780_SETDDRAMADDR (0x80)
+/** @} */
+
+/**
+ * @name HD44780 LCD entry modes flags
+ * @{
+ */
+#define HD44780_ENTRYRIGHT (0x00)
+#define HD44780_ENTRYLEFT (0x02)
+#define HD44780_ENTRYSHIFTINCREMENT (0x01)
+#define HD44780_ENTRYSHIFTDECREMENT (0x00)
+/** @} */
+
+/**
+ * @name HD44780 LCD control flags
+ * @{
+ */
+#define HD44780_DISPLAYON (0x04)
+#define HD44780_DISPLAYOFF (0x00)
+#define HD44780_CURSORON (0x02)
+#define HD44780_CURSOROFF (0x00)
+#define HD44780_BLINKON (0x01)
+#define HD44780_BLINKOFF (0x00)
+/** @} */
+
+/**
+ * @name HD44780 display and cursor shift flags
+ * @{
+ */
+#define HD44780_DISPLAYMOVE (0x08)
+#define HD44780_CURSORMOVE (0x00)
+#define HD44780_MOVERIGHT (0x04)
+#define HD44780_MOVELEFT (0x00)
+/**@}*/
+
+/**
+ * @name HD44780 LCD functional flags
+ * @{
+ */
+#define HD44780_8BITMODE (0x10)
+#define HD44780_4BITMODE (0x00)
+#define HD44780_2LINE (0x08)
+#define HD44780_1LINE (0x00)
+#define HD44780_5x10DOTS (0x04)
+#define HD44780_5x8DOTS (0x00)
+/** @} */
+
+/**
+ * @name HD44780 LCD timings
+ * @{
+ */
+#define HD44780_CMD_WAIT (2000U)
+#define HD44780_INIT_WAIT_XXL (50000U)
+#define HD44780_INIT_WAIT_LONG (4500U)
+#define HD44780_INIT_WAIT_SHORT (150U)
+#define HD44780_PULSE_WAIT_SHORT (1U)
+#define HD44780_PULSE_WAIT_LONG (100U)
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HD44780_AVR_INTERNAL_H */
+/** @} */
diff --git a/tests/atmega8/i2c/hd44780_avr/hd44780_avr_params.h b/tests/atmega8/i2c/hd44780_avr/hd44780_avr_params.h
new file mode 100644
index 000000000000..e402f76d9b27
--- /dev/null
+++ b/tests/atmega8/i2c/hd44780_avr/hd44780_avr_params.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 HAW Hamburg
+ *
+ * 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 drivers_hd44780
+ *
+ * @{
+ * @file
+ * @brief Pinout config for the HD44780 display
+ *
+ * @author Sebastian Meiling
+ */
+#ifndef HD44780_AVR_PARAMS_H
+#define HD44780_AVR_PARAMS_H
+
+#include "board.h"
+#ifdef MODULE_PCF857X
+#include "pcf857x.h"
+#else
+#include "periph/gpio.h"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* The default pins corresponds to Arduino pins on the Arduino Zero board. */
+
+#ifndef HD44780_PARAM_COLS
+#define HD44780_PARAM_COLS (16U)
+#endif
+#ifndef HD44780_PARAM_ROWS
+#define HD44780_PARAM_ROWS (2U)
+#endif
+
+#ifndef MODULE_PCF857X
+
+#ifndef HD44780_PARAM_PIN_RS
+#define HD44780_PARAM_PIN_RS GPIO_PIN(0, 14) /* Arduino D2 */
+#endif
+#ifndef HD44780_PARAM_PIN_RW
+#define HD44780_PARAM_PIN_RW GPIO_UNDEF
+#endif
+#ifndef HD44780_PARAM_PIN_ENABLE
+#define HD44780_PARAM_PIN_ENABLE GPIO_PIN(0, 9) /* Arduino D3 */
+#endif
+#ifndef HD44780_PARAM_PINS_DATA
+#define HD44780_PARAM_PINS_DATA { GPIO_PIN(0, 8), /* Arduino D4 */ \
+ GPIO_PIN(0, 15), /* Arduino D5 */ \
+ GPIO_PIN(0, 20), /* Arduino D6 */ \
+ GPIO_PIN(0, 21), /* Arduino D7 */ \
+ GPIO_UNDEF, \
+ GPIO_UNDEF, \
+ GPIO_UNDEF, \
+ GPIO_UNDEF }
+#endif
+
+#else /* !MODULE_PCF857X */
+
+#ifndef HD44780_PARAM_PIN_RS
+#define HD44780_PARAM_PIN_RS PCF857X_GPIO_PIN(0, 0) /* Bit 0 */
+#endif
+#ifndef HD44780_PARAM_PIN_RW
+#define HD44780_PARAM_PIN_RW PCF857X_GPIO_PIN(0, 1) /* Bit 1 */
+#endif
+#ifndef HD44780_PARAM_PIN_ENABLE
+#define HD44780_PARAM_PIN_ENABLE PCF857X_GPIO_PIN(0, 2) /* Bit 2 */
+#endif
+#ifndef HD44780_PARAM_PINS_DATA
+#define HD44780_PARAM_PINS_DATA { PCF857X_GPIO_PIN(0, 4), /* Bit 4 */ \
+ PCF857X_GPIO_PIN(0, 5), /* Bit 5 */ \
+ PCF857X_GPIO_PIN(0, 6), /* Bit 6 */ \
+ PCF857X_GPIO_PIN(0, 7), /* Bit 7 */ \
+ GPIO_UNDEF, \
+ GPIO_UNDEF, \
+ GPIO_UNDEF, \
+ GPIO_UNDEF }
+#endif
+
+#endif /* !MODULE_PCF857X */
+
+#ifndef HD44780_PARAMS
+#define HD44780_PARAMS { .cols = HD44780_PARAM_COLS, \
+ .rows = HD44780_PARAM_ROWS, \
+ .rs = HD44780_PARAM_PIN_RS, \
+ .rw = HD44780_PARAM_PIN_RW, \
+ .enable = HD44780_PARAM_PIN_ENABLE, \
+ .data = HD44780_PARAM_PINS_DATA }
+#endif
+
+/**
+ * @brief LCM1602C configuration
+ */
+static const hd44780_params_t hd44780_params[] =
+{
+ HD44780_PARAMS,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HD44780_AVR_PARAMS_H */
+/** @} */
diff --git a/tests/atmega8/i2c/main.c b/tests/atmega8/i2c/main.c
new file mode 100644
index 000000000000..c828bc930cc7
--- /dev/null
+++ b/tests/atmega8/i2c/main.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 HAW Hamburg
+ * 2023 Hugues Larrive
+ *
+ * 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 tests
+ * @{
+ *
+ * @file
+ * @brief Application to test i2c on atmega8 using an hacked
+ * hd44780 LCD driver and a pcf8574a i2c I/O expander.
+ *
+ * @author Sebastian Meiling
+ * @author Hugues Larrive
+ *
+ * @}
+ */
+
+#include
+
+#include "hd44780_avr/hd44780_avr.h"
+#include "hd44780_avr/hd44780_avr_params.h"
+
+int main(void)
+{
+ hd44780_t dev;
+ /* init display */
+ hd44780_init(&dev, &hd44780_params[0]);
+ hd44780_clear(&dev);
+ hd44780_home(&dev);
+ hd44780_print(&dev, "Test i2c on atmega8");
+ hd44780_set_cursor(&dev, 3, 1);
+ hd44780_print(&dev, "RIOT is here!");
+ hd44780_set_cursor(&dev, 0, 2);
+ hd44780_print(&dev, "You can read this so");
+ hd44780_set_cursor(&dev, 2, 3);
+ hd44780_print(&dev, "i2c is working!");
+
+ return 0;
+}
diff --git a/tests/atmega8/pwm/Makefile b/tests/atmega8/pwm/Makefile
new file mode 100644
index 000000000000..8ea3df5a4a63
--- /dev/null
+++ b/tests/atmega8/pwm/Makefile
@@ -0,0 +1,9 @@
+RIOTBASE ?= $(CURDIR)/../../..
+BOARD ?= atmega8
+PORT ?= /dev/ttyACM0
+
+include ../../Makefile.tests_common
+
+FEATURES_REQUIRED = periph_pwm
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/atmega8/pwm/README.md b/tests/atmega8/pwm/README.md
new file mode 100644
index 000000000000..23b0c052e0d5
--- /dev/null
+++ b/tests/atmega8/pwm/README.md
@@ -0,0 +1,8 @@
+Expected result
+===============
+If everything is running as supposed to, you should see a 1KHz PWM with oscillating duty cycle
+on each channel of the selected PWM device.
+
+Background
+==========
+Test for the low-level PWM driver.
diff --git a/tests/atmega8/pwm/main.c b/tests/atmega8/pwm/main.c
new file mode 100644
index 000000000000..b470bf3bfb70
--- /dev/null
+++ b/tests/atmega8/pwm/main.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014-2015 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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 tests
+ * @{
+ *
+ * @file
+ * @brief Test for low-level PWM drivers
+ *
+ * This test initializes the given PWM device to run at 1KHz with a 1000 step
+ * resolution.
+ *
+ * The PWM is then continuously oscillating it's duty cycle between 0% to 100%
+ * every 1s on every channel.
+ *
+ * @author Hauke Petersen
+ * @author Semjon Kerner
+ * @author Hugues Larrive
+ *
+ * @}
+ */
+
+#include
+#include
+#include
+#include
+
+#include "periph/pwm.h"
+
+#define F_CPU (CLOCK_CORECLOCK)
+#define __DELAY_BACKWARD_COMPATIBLE__
+#include "util/delay.h"
+
+#define OSC_INTERVAL (400) /* 400us */
+#define OSC_STEP (10)
+#define OSC_MODE PWM_LEFT
+#define OSC_FREQU (1000U)
+#define OSC_STEPS (256U)
+#define PWR_SLEEP (1U)
+
+static uint32_t initialized;
+
+static int _oscillate(void)
+{
+ int state = 0;
+ int step = OSC_STEP;
+
+ puts("\nRIOT PWM test");
+ puts("Connect an LED or scope to PWM pins to see something.\n");
+
+ printf("Available PWM device between 0 and %d\n", PWM_NUMOF - 1);
+ for (unsigned i = 0; i < PWM_NUMOF; i++) {
+ uint32_t real_f = pwm_init(PWM_DEV(i), OSC_MODE, OSC_FREQU, OSC_STEPS);
+ if (real_f == 0) {
+ printf("Error: initializing PWM_%u.\n", i);
+ return 1;
+ }
+ else {
+ printf("Initialized PWM_%u @ %" PRIu32 "Hz.\n", i, real_f);
+ }
+ }
+
+ puts("\nLetting the PWM pin (PB3 on atmega8) oscillate now...");
+ while (1) {
+ for (unsigned i = 0; i < PWM_NUMOF; i++) {
+ for (uint8_t chan = 0; chan < pwm_channels(PWM_DEV(i)); chan++) {
+ pwm_set(PWM_DEV(i), chan, state);
+ }
+ }
+
+ state += step;
+ if (state <= 0 || state >= (int)OSC_STEPS) {
+ step = -step;
+ }
+
+ _delay_us(OSC_INTERVAL);
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ puts("PWM peripheral driver test\n");
+ initialized = 0;
+
+ _oscillate();
+
+ return 0;
+}
diff --git a/tests/atmega8/shell/Makefile b/tests/atmega8/shell/Makefile
new file mode 100644
index 000000000000..5dd8e56d9d80
--- /dev/null
+++ b/tests/atmega8/shell/Makefile
@@ -0,0 +1,14 @@
+RIOTBASE ?= $(CURDIR)/../../..
+BOARD ?= atmega8
+PORT ?= /dev/ttyACM0
+
+include ../../Makefile.tests_common
+
+USEMODULE += shell_cmds_default
+USEMODULE += ps
+DEVELHELP = 1
+
+CFLAGS += -DNDEBUG -DLOG_LEVEL=LOG_NONE
+DISABLE_MODULE += core_msg
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/atmega8/shell/ReadMe.txt b/tests/atmega8/shell/ReadMe.txt
new file mode 100644
index 000000000000..16bf30e2416f
--- /dev/null
+++ b/tests/atmega8/shell/ReadMe.txt
@@ -0,0 +1,14 @@
+This application shows how to use own or the system shell commands. In order to use
+the system shell commands:
+
+1. Additionally to the module: shell, shell_commands,
+ the module for the corresponding system command is to include, e.g.
+ module ps for the ps command (cf. the Makefile in the application root
+ directory).
+2. Start the shell like this:
+ 2.1 reserve buffer:
+ char line_buf[SHELL_DEFAULT_BUFSIZE];
+ 2.1a run shell only with system commands:
+ shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
+ 2.1b run shell with provided commands in addition to system commands:
+ shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
diff --git a/tests/atmega8/shell/main.c b/tests/atmega8/shell/main.c
new file mode 100644
index 000000000000..aaf48314752a
--- /dev/null
+++ b/tests/atmega8/shell/main.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2013 Kaspar Schleiser
+ * Copyright (C) 2013 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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.
+ */
+
+/**
+ * @file
+ * @brief shows how to set up own and use the system shell commands.
+ * By typing help in the serial console, all the supported commands
+ * are listed.
+ *
+ * @author Kaspar Schleiser
+ * @author Zakaria Kasmi
+ * @author Hugues Larrive
+ *
+ */
+
+#include
+#include
+
+#include "shell.h"
+
+/* define buffer to be used by the shell. Note: This is intentionally
+ * smaller than 64 bytes, as the EDBG integrated UART bridge of the samr21-xpro
+ * (and likely all other EDBG boards) drops chars when sending more than 64
+ * bytes at a time. This results in the buffer overflow test failing. */
+static char line_buf[16];
+
+static int print_teststart(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ printf("[TEST_START]\n");
+
+ return 0;
+}
+
+static int print_testend(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ printf("[TEST_END]\n");
+
+ return 0;
+}
+
+static int print_shell_bufsize(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ printf("%d\n", sizeof(line_buf));
+
+ return 0;
+}
+
+static int print_echo(int argc, char **argv)
+{
+ for (int i = 0; i < argc; ++i) {
+ printf("\"%s\"", argv[i]);
+ }
+ puts("");
+
+ return 0;
+}
+
+static int print_empty(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ return 0;
+}
+
+static const shell_command_t shell_commands[] = {
+ { "start_test", "starts a test", print_teststart },
+ { "end_test", "ends a test", print_testend },
+ { "bufsize", "Get the shell's buffer size", print_shell_bufsize },
+ { "echo", "prints the input command", print_echo },
+ { "empty", "print nothing on command", print_empty },
+ { NULL, NULL, NULL }
+};
+
+int main(void)
+{
+ printf("test_shell.\n");
+
+ shell_run(shell_commands, line_buf, sizeof(line_buf));
+
+ return 0;
+}
diff --git a/tests/atmega8/spi/Makefile b/tests/atmega8/spi/Makefile
new file mode 100644
index 000000000000..35ef7bc2d63a
--- /dev/null
+++ b/tests/atmega8/spi/Makefile
@@ -0,0 +1,13 @@
+RIOTBASE ?= $(CURDIR)/../../..
+BOARD ?= atmega8
+PORT ?= /dev/ttyACM0
+
+include ../../Makefile.tests_common
+
+FEATURES_REQUIRED += periph_spi
+
+DEVELHELP = 0
+CFLAGS += -DNDEBUG -DLOG_LEVEL=LOG_NONE
+DISABLE_MODULE += core_msg
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/atmega8/spi/main.c b/tests/atmega8/spi/main.c
new file mode 100644
index 000000000000..545f939a8db3
--- /dev/null
+++ b/tests/atmega8/spi/main.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 Freie Universität Berlin
+ * 2023 Hugues Larrive
+ *
+ * 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 tests
+ * @{
+ *
+ * @file
+ * @brief Application for testing low-level SPI driver implementations
+ *
+ * This implementation covers both, master and slave configurations.
+ *
+ * @author Hauke Petersen
+ * @author Hugues Larrive
+ *
+ * @}
+ */
+
+#include
+#include
+#include
+
+#include "shell.h"
+#include "ps.h"
+#include "periph/spi.h"
+
+#define DEFAULT_SPI_CS_PORT 1
+#define DEFAULT_SPI_CS_PIN 2
+
+/**
+ * @brief Some parameters used for benchmarking
+ */
+#define BENCH_REDOS (1000)
+#define BENCH_SMALL (2)
+#define BENCH_LARGE (100)
+#define BENCH_PAYLOAD ('b')
+#define BENCH_REGADDR (0x23)
+
+/**
+ * @brief Benchmark buffers
+ */
+static uint8_t bench_wbuf[BENCH_LARGE];
+static uint8_t bench_rbuf[BENCH_LARGE];
+
+static struct {
+ spi_t dev;
+ spi_mode_t mode;
+ spi_clk_t clk;
+ spi_cs_t cs;
+} spiconf;
+
+int cmd_init(void)
+{
+ spiconf.dev = SPI_DEV(0);
+ spiconf.mode = SPI_MODE_0;
+ spiconf.clk = SPI_CLK_1MHZ;
+ spiconf.cs = (spi_cs_t)GPIO_PIN(DEFAULT_SPI_CS_PORT, DEFAULT_SPI_CS_PIN);
+ spi_init_cs(spiconf.dev, spiconf.cs);
+ return 0;
+}
+
+int cmd_bench(void)
+{
+ uint8_t in;
+ uint8_t out = (uint8_t)BENCH_PAYLOAD;
+
+ if (spiconf.dev == SPI_UNDEF) {
+ puts("error: SPI is not initialized, please initialize bus first");
+ return 1;
+ }
+
+ /* prepare buffer */
+ memset(bench_wbuf, BENCH_PAYLOAD, BENCH_LARGE);
+
+ /* get access to the bus */
+ spi_acquire(spiconf.dev, spiconf.cs, spiconf.mode, spiconf.clk);
+
+ puts("### Running some benchmarks ###");
+
+ /* 1 - write 1000 times 1 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ in = spi_transfer_byte(spiconf.dev, spiconf.cs, false, out);
+ (void)in;
+ }
+ printf(" 1 - write %i times %i byte\n", BENCH_REDOS, 1);
+
+ /* 2 - write 1000 times 2 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+ bench_wbuf, NULL, BENCH_SMALL);
+ }
+ printf(" 2 - write %i times %i byte\n", BENCH_REDOS, BENCH_SMALL);
+
+ /* 3 - write 1000 times 100 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+ bench_wbuf, NULL, BENCH_LARGE);
+ }
+ printf(" 3 - write %i times %i byte\n", BENCH_REDOS, BENCH_LARGE);
+
+ /* 4 - write 1000 times 1 byte to register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ in = spi_transfer_reg(spiconf.dev, spiconf.cs, BENCH_REGADDR, out);
+ (void)in;
+ }
+ printf(" 4 - write %i times %i byte to register\n", BENCH_REDOS, 1);
+
+ /* 5 - write 1000 times 2 byte to register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+ bench_wbuf, NULL, BENCH_SMALL);
+ }
+ printf(" 5 - write %i times %i byte to register\n", BENCH_REDOS, BENCH_SMALL);
+
+ /* 6 - write 1000 times 100 byte to register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+ bench_wbuf, NULL, BENCH_LARGE);
+ }
+ printf(" 6 - write %i times %i byte to register\n", BENCH_REDOS, BENCH_LARGE);
+
+ /* 7 - read 1000 times 2 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+ NULL, bench_rbuf, BENCH_SMALL);
+ }
+ printf(" 7 - read %i times %i byte\n", BENCH_REDOS, BENCH_SMALL);
+
+ /* 8 - read 1000 times 100 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+ NULL, bench_rbuf, BENCH_LARGE);
+ }
+ printf(" 8 - read %i times %i byte\n", BENCH_REDOS, BENCH_LARGE);
+
+ /* 9 - read 1000 times 2 byte from register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+ NULL, bench_rbuf, BENCH_SMALL);
+ }
+ printf(" 9 - read %i times %i byte from register\n", BENCH_REDOS, BENCH_SMALL);
+
+ /* 10 - read 1000 times 100 byte from register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+ NULL, bench_rbuf, BENCH_LARGE);
+ }
+ printf("10 - read %i times %i byte from register\n", BENCH_REDOS, BENCH_LARGE);
+
+ /* 11 - transfer 1000 times 2 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+ bench_wbuf, bench_rbuf, BENCH_SMALL);
+ }
+ printf("11 - transfer %i times %i byte\n", BENCH_REDOS, BENCH_SMALL);
+
+ /* 12 - transfer 1000 times 100 byte */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
+ bench_wbuf, bench_rbuf, BENCH_LARGE);
+ }
+ printf("12 - transfer %i times %i byte\n", BENCH_REDOS, BENCH_LARGE);
+
+ /* 13 - transfer 1000 times 2 byte from/to register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+ bench_wbuf, bench_rbuf, BENCH_SMALL);
+ }
+ printf("13 - transfer %i times %i byte to register\n", BENCH_REDOS, BENCH_SMALL);
+
+ /* 14 - transfer 1000 times 100 byte from/to register */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
+ bench_wbuf, bench_rbuf, BENCH_LARGE);
+ }
+ printf("14 - transfer %i times %i byte to register\n", BENCH_REDOS, BENCH_LARGE);
+
+ /* 15 - release & acquire the bus 1000 times */
+ for (int i = 0; i < BENCH_REDOS; i++) {
+ spi_release(spiconf.dev);
+ spi_acquire(spiconf.dev, spiconf.cs, spiconf.mode, spiconf.clk);
+ }
+ printf("15 - acquire/release %i times\n", BENCH_REDOS);
+
+ spi_release(spiconf.dev);
+ puts("### All runs complete ###\n");
+
+ return 0;
+}
+
+int main(void)
+{
+ puts("SPI peripheral driver test");
+
+ printf("There are %i SPI devices configured for your platform.\n",
+ (int)SPI_NUMOF);
+
+ /* reset local SPI configuration */
+ spiconf.dev = SPI_UNDEF;
+
+ cmd_init();
+
+ while (1) {
+ cmd_bench();
+ }
+
+ return 0;
+}