From df170040803c689e9275c55efe74f18c1dd65c21 Mon Sep 17 00:00:00 2001 From: Hugues Larrive Date: Thu, 22 Jun 2023 11:24:30 +0200 Subject: [PATCH] cpu/atmega_common: checking features instead of CPU models --- cpu/atmega_common/atmega_cpu.c | 17 +++++-- .../include/atmega_regs_common.h | 44 +++++++++++++++- cpu/atmega_common/include/cpu_clock.h | 4 ++ cpu/atmega_common/include/periph_cpu_common.h | 28 ++++++++++- cpu/atmega_common/periph/adc.c | 45 +++++++++++++---- cpu/atmega_common/periph/gpio.c | 26 ++++++++-- cpu/atmega_common/periph/i2c.c | 4 ++ cpu/atmega_common/periph/pwm.c | 45 +++++++++++++++++ cpu/atmega_common/periph/spi.c | 14 ++++-- cpu/atmega_common/periph/timer.c | 49 +++++++++++++++--- cpu/atmega_common/periph/uart.c | 50 +++++++++++++------ 11 files changed, 277 insertions(+), 49 deletions(-) diff --git a/cpu/atmega_common/atmega_cpu.c b/cpu/atmega_common/atmega_cpu.c index 52d93bf4c58d1..532c16c14d0a4 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,9 +89,12 @@ ISR(BADISR_vect) { avr8_reset_cause(); -#if defined (CPU_ATMEGA256RFR2) - printf("IRQ_STATUS %#02x\nIRQ_STATUS1 %#02x\n", - (unsigned int)IRQ_STATUS, (unsigned int)IRQ_STATUS1); +#if defined(TRX_CTRL_0) /* megaRF */ + printf("IRQ_STATUS %#02x\n", (unsigned int)IRQ_STATUS); + +#if defined(IRQ_STATUS1) + printf("IRQ_STATUS1 %#02x\n", (unsigned int)IRQ_STATUS1); +#endif printf("SCIRQS %#02x\nBATMON %#02x\n", (unsigned int)SCIRQS, (unsigned int)BATMON); @@ -101,7 +108,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 5f2785f8ea23e..8567deb8c9b81 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 797f6107ea15e..09120281065e5 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 5d2b04f24024b..4a9910a5353e6 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 +/* all other port descendent, including : + - _AVR_IO8534_ (only have port A but with 0x1B 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 6585c617083d2..52271feaf5ebe 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,53 @@ 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 +130,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 +146,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 2cca6e464f1eb..788055e665690 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 << (INT0 + _int_num(pin))); +#endif } void gpio_irq_disable(gpio_t pin) { +#if defined(EIMSK) EIMSK &= ~(1 << _int_num(pin)); +#elif defined(GICR) + GICR &= ~(1 << (INT0 + _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 3b4a0d251e149..118eb0964896a 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 6f1d970777c0d..9bfaa020054e4 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 cac04cfdeb409..4231f4929baae 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 6fc9350e359f7..1534df5e71845 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 5e304ec05f636..f5858505149fe 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 */