From e57d5114997d412fcc98a9932a77b428018b4346 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Thu, 10 Mar 2016 11:11:12 +0100 Subject: [PATCH 1/5] cpu/atmega2560: added CMSIS style reg defs for UART --- cpu/atmega2560/include/atmega2560_regs.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cpu/atmega2560/include/atmega2560_regs.h b/cpu/atmega2560/include/atmega2560_regs.h index 2db8a7a16d..f29319a74b 100644 --- a/cpu/atmega2560/include/atmega2560_regs.h +++ b/cpu/atmega2560/include/atmega2560_regs.h @@ -46,6 +46,18 @@ typedef struct { REG16 OCR[3]; /**< output compare */ } mega_timer_t; +/** + * @brief UART register map + */ +typedef struct { + REG8 CSRA; /**< control and status register A */ + REG8 CSRB; /**< control and status register B */ + REG8 CSRC; /**< control and status register C */ + REG8 reserved; /**< reserved */ + REG16 BRR; /**< baud rate register */ + REG8 DR; /**< data register */ +} mega_uart_t; + /** * @brief Base register address definitions * @{ @@ -54,6 +66,11 @@ typedef struct { #define MEGA_TIMER3_BASE (uint16_t *)(&TCCR3A) #define MEGA_TIMER4_BASE (uint16_t *)(&TCCR4A) #define MEGA_TIMER5_BASE (uint16_t *)(&TCCR5A) + +#define MEGA_UART0_BASE ((uint16_t *)(&UCSR0A)) +#define MEGA_UART1_BASE ((uint16_t *)(&UCSR1A)) +#define MEGA_UART2_BASE ((uint16_t *)(&UCSR2A)) +#define MEGA_UART3_BASE ((uint16_t *)(&UCSR2A)) /** @} */ /** @@ -64,6 +81,11 @@ typedef struct { #define MEGA_TIMER3 ((mega_timer_t *)MEGA_TIMER3_BASE) #define MEGA_TIMER4 ((mega_timer_t *)MEGA_TIMER4_BASE) #define MEGA_TIMER5 ((mega_timer_t *)MEGA_TIMER5_BASE) + +#define MEGA_UART0 ((mega_uart_t *)MEGA_UART0_BASE) +#define MEGA_UART1 ((mega_uart_t *)MEGA_UART1_BASE) +#define MEGA_UART2 ((mega_uart_t *)MEGA_UART2_BASE) +#define MEGA_UART3 ((mega_uart_t *)MEGA_UART3_BASE) /** @} */ #ifdef __cplusplus From ccf7cde82dd6e6817ffcb0f0ad5297ca8a974757 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Thu, 10 Mar 2016 11:11:42 +0100 Subject: [PATCH 2/5] cpu/atmega2560: reworked UART implementation --- cpu/atmega2560/periph/uart.c | 235 ++++++++++------------------------- 1 file changed, 67 insertions(+), 168 deletions(-) diff --git a/cpu/atmega2560/periph/uart.c b/cpu/atmega2560/periph/uart.c index 51448f8aad..ef53df3073 100644 --- a/cpu/atmega2560/periph/uart.c +++ b/cpu/atmega2560/periph/uart.c @@ -19,216 +19,115 @@ * @} */ -#include "board.h" #include "cpu.h" -#include "thread.h" #include "sched.h" +#include "thread.h" #include "periph/uart.h" -#include "periph_conf.h" /** - * @brief Allocate memory to store the callback functions. + * @brief Configured device map + * @{ */ -static uart_isr_ctx_t config[UART_NUMOF]; +#if UART_NUMOF +static mega_uart_t *dev[] = { +#ifdef UART_0 + UART_0, +#endif +#ifdef UART_1 + UART_1, +#endif +#ifdef UART_2 + UART_2, +#endif +#ifdef UART_3 + UART_3 +#endif +}; +#else +/* fallback if no UART is defined */ +static const mega_uart_t *dev[] = { NULL }; +#endif -static int init_base(uart_t uart, uint32_t baudrate); +/** + * @brief Allocate memory to store the callback functions. + */ +static uart_isr_ctx_t isr_ctx[UART_NUMOF]; int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { - /* initialize basic functionality */ - int res = init_base(uart, baudrate); - - if (res != 0) { - return res; + /* make sure the given device is valid */ + if (uart >= UART_NUMOF) { + return -1; } - /* register callbacks */ - config[uart].rx_cb = rx_cb; - config[uart].arg = arg; + /* register interrupt context */ + isr_ctx[uart].rx_cb = rx_cb; + isr_ctx[uart].arg = arg; - /* configure interrupts and enable RX interrupt */ - switch (uart) { -#if UART_0_EN + /* disable and reset UART */ + dev[uart]->CSRB = 0; + dev[uart]->CSRA = 0; - case UART_0: - UART0_RX_IRQ_EN; - break; -#endif /* UART_0_EN */ -#if UART_1_EN - - case UART_1: - UART1_RX_IRQ_EN; - break; -#endif /* UART_1_EN */ -#if UART_2_EN - - case UART_2: - UART2_RX_IRQ_EN; - break; -#endif /* UART_2_EN */ -#if UART_3_EN - - case UART_3: - UART3_RX_IRQ_EN; - break; -#endif /* UART_3_EN */ - } - - return 0; -} - -static int init_base(uart_t uart, uint32_t baudrate) -{ - uint16_t clock_divider = CLOCK_CORECLOCK / (16 * baudrate); - - switch (uart) { -#if UART_0_EN - - case UART_0: - /* enable RX and TX */ - UART0_RX_TX_EN; - /* use 8 Bit characters */ - UART0_SET_8BIT_SIZE; - - /* set clock divider */ - UART0_BAUD_RATE_L = clock_divider; - UART0_BAUD_RATE_H = (clock_divider >> 8); - break; -#endif /* UART_0 */ -#if UART_1_EN - - case UART_1: - /* enable RX and TX */ - UART1_RX_TX_EN; - /* use 8 Bit characters */ - UART1_SET_8BIT_SIZE; - - /* set clock divider */ - UART1_BAUD_RATE_L = clock_divider; - UART1_BAUD_RATE_H = (clock_divider >> 8); - break; -#endif /* UART_1 */ -#if UART_2_EN - - case UART_2: - /* enable RX and TX */ - UART2_RX_TX_EN; - /* use 8 Bit characters */ - UART2_SET_8BIT_SIZE; - - /* set clock divider */ - UART2_BAUD_RATE_L = clock_divider; - UART2_BAUD_RATE_H = (clock_divider >> 8); - break; -#endif /* UART_2 */ -#if UART_3_EN - - case UART_3: - /* enable RX and TX */ - UART3_RX_TX_EN; - /* use 8 Bit characters */ - UART3_SET_8BIT_SIZE; - - /* set clock divider */ - UART3_BAUD_RATE_L = clock_divider; - UART3_BAUD_RATE_H = (clock_divider >> 8); - break; -#endif /* UART_3 */ - default: - (void)clock_divider; /* this makes cppcheck happy */ - } + /* configure UART to 8N1 mode */ + dev[uart]->CSRC = (1 << UCSZ00) | (1 << UCSZ01); + /* set clock divider */ + dev[uart]->BRR = CLOCK_CORECLOCK / (16 * baudrate); + /* enable RX and TX and the RX interrupt */ + dev[uart]->CSRB = ((1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0)); return 0; } void uart_write(uart_t uart, const uint8_t *data, size_t len) { - switch (uart) { -#if UART_0_EN - case UART_0: - for (unsigned i = 0; i < len; i++) { - while (!UART0_DTREG_EMPTY); - UART0_DATA_REGISTER = data[i]; - } - break; -#endif /* UART_0_EN */ -#if UART_1_EN - case UART_1: - for (unsigned i = 0; i < len; i++) { - while (!UART1_DTREG_EMPTY); - UART1_DATA_REGISTER = data[i]; - } - break; -#endif /* UART_1_EN */ -#if UART_2_EN - case UART_2: - for (unsigned i = 0; i < len; i++) { - while (!UART2_DTREG_EMPTY); - UART2_DATA_REGISTER = data[i]; - } - break; -#endif /* UART_2_EN */ -#if UART_3_EN - case UART_3: - for (unsigned i = 0; i < len; i++) { - while (!UART3_DTREG_EMPTY); - UART3_DATA_REGISTER = data[i]; - } - break; -#endif /* UART_3_EN */ + for (size_t i = 0; i < len; i++) { + while (!(dev[uart]->CSRA & (1 << UDRE0))); + dev[uart]->DR = data[i]; } } - -#if UART_0_EN -ISR(USART0_RX_vect, ISR_BLOCK) +static inline void isr_handler(int num) { - __enter_isr(); - config[UART_0].rx_cb(config[UART_0].arg, UART0_DATA_REGISTER); + isr_ctx[num].rx_cb(isr_ctx[num].arg, dev[num]->DR); if (sched_context_switch_request) { thread_yield(); } - __exit_isr(); } -#endif /* UART_0_EN */ -#if UART_1_EN -ISR(USART1_RX_vect, ISR_BLOCK) +#ifdef UART_0_ISR +ISR(UART_0_ISR, ISR_BLOCK) { __enter_isr(); - config[UART_1].rx_cb(config[UART_1].arg, UART1_DATA_REGISTER); - - if (sched_context_switch_request) { - thread_yield(); - } + isr_handler(0); __exit_isr(); } -#endif /* UART_1_EN */ +#endif /* UART_0_ISR */ -#if UART_2_EN -ISR(USART2_RX_vect, ISR_BLOCK) +#if UART_1_ISR +ISR(UART_1_ISR, ISR_BLOCK) { __enter_isr(); - config[UART_2].rx_cb(config[UART_2].arg, UART2_DATA_REGISTER); - - if (sched_context_switch_request) { - thread_yield(); - } + isr_handler(1); __exit_isr(); } -#endif /* UART_2_EN */ +#endif /* UART_1_ISR */ -#if UART_3_EN -ISR(USART3_RX_vect, ISR_BLOCK) +#if UART_2_ISR +ISR(UART_2_ISR, ISR_BLOCK) { __enter_isr(); - config[UART_3].rx_cb(config[UART_3].arg, UART3_DATA_REGISTER); - - if (sched_context_switch_request) { - thread_yield(); - } + isr_handler(2); __exit_isr(); } -#endif /* UART_3_EN */ +#endif /* UART_2_ISR */ + +#if UART_3_ISR +ISR(UART_3_ISR, ISR_BLOCK) +{ + __enter_isr(); + isr_handler(3); + __exit_isr(); +} +#endif /* UART_3_ISR */ From a2ddb1dd7fae7730a37780f7b9f4703113305334 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Thu, 10 Mar 2016 11:11:57 +0100 Subject: [PATCH 3/5] boards/atmega2560: adapted UART configuration --- boards/arduino-mega2560/include/periph_conf.h | 113 +++--------------- 1 file changed, 16 insertions(+), 97 deletions(-) diff --git a/boards/arduino-mega2560/include/periph_conf.h b/boards/arduino-mega2560/include/periph_conf.h index 5bbcd39a5e..a1c93857c6 100644 --- a/boards/arduino-mega2560/include/periph_conf.h +++ b/boards/arduino-mega2560/include/periph_conf.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen + * Copyright (C) 2014-2016 Freie Universität Berlin + * 2014 Hinnerk van Bruinehsen * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -14,6 +15,7 @@ * @brief Peripheral MCU configuration for the Arduino Mega 2560 board * * @author Hinnerk van Bruinehsen + * @author Hauke Petersen */ #ifndef PERIPH_CONF_H_ @@ -57,109 +59,26 @@ extern "C" { /** * @brief UART configuration + * + * The UART devices have fixed pin mappings, so all we need to do, is to specify + * which devices we would like to use and their corresponding RX interrupts. See + * the reference manual for the fixed pin mapping. + * * @{ */ #define UART_NUMOF (4U) -#define UART_0_EN 1 -#define UART_1_EN 1 -#define UART_2_EN 1 -#define UART_3_EN 1 -/* UART 0 registers */ -#define UART0_CTRL_STAT_A UCSR0A -#define UART0_CTRL_STAT_B UCSR0B -#define UART0_CTRL_STAT_C UCSR0C -#define UART0_BAUD_RATE_L UBRR0L -#define UART0_BAUD_RATE_H UBRR0H -#define UART0_DATA_REGISTER UDR0 +#define UART_0 MEGA_UART0 +#define UART_0_ISR USART0_RX_vect -/* Flags */ -#define UART0_RX_COMPLETE RXC0 -#define UART0_DATA_EMPTY UDRE0 -#define UART0_RX_EN RXEN0 -#define UART0_TX_EN TXEN0 -#define UART0_RXC_IRQ_EN RXCIE0 -#define UART0_TXC_IRQ_EN TXCIE0 -#define UART0_8BIT_SIZE (1 << UCSZ00) | (1 << UCSZ01) +#define UART_1 MEGA_UART1 +#define UART_1_ISR USART1_RX_vect -/* UART0 helper macros */ -#define UART0_RX_TX_EN UART0_CTRL_STAT_B |= (1 << UART0_RX_EN) | (1 << UART0_TX_EN) -#define UART0_RX_IRQ_EN UART0_CTRL_STAT_B |= (1 << UART0_RXC_IRQ_EN) -#define UART0_SET_8BIT_SIZE UART0_CTRL_STAT_C |= UART0_8BIT_SIZE -#define UART0_RECEIVED_DATA (UART0_CTRL_STAT_A & (1 << UART0_RX_COMPLETE)) -#define UART0_DTREG_EMPTY (UART0_CTRL_STAT_A & (1 << UART0_DATA_EMPTY)) +#define UART_2 MEGA_UART2 +#define UART_2_ISR USART2_RX_vect -/* UART 1 registers */ -#define UART1_CTRL_STAT_A UCSR1A -#define UART1_CTRL_STAT_B UCSR1B -#define UART1_CTRL_STAT_C UCSR1C -#define UART1_BAUD_RATE_L UBRR1L -#define UART1_BAUD_RATE_H UBRR1H -#define UART1_DATA_REGISTER UDR1 - -/* Flags */ -#define UART1_RX_COMPLETE RXC1 -#define UART1_DATA_EMPTY UDRE1 -#define UART1_RX_EN RXEN1 -#define UART1_TX_EN TXEN1 -#define UART1_RXC_IRQ_EN RXCIE1 -#define UART1_TXC_IRQ_EN TXCIE1 -#define UART1_8BIT_SIZE (1 << UCSZ10) | (1 << UCSZ11) - -/* UART1 helper macros */ -#define UART1_RX_TX_EN UART1_CTRL_STAT_B |= (1 << UART1_RX_EN) | (1 << UART1_TX_EN) -#define UART1_RX_IRQ_EN UART1_CTRL_STAT_B |= (1 << UART1_RXC_IRQ_EN) -#define UART1_SET_8BIT_SIZE UART1_CTRL_STAT_C |= UART1_8BIT_SIZE -#define UART1_RECEIVED_DATA (UART1_CTRL_STAT_A & (1 << UART1_RX_COMPLETE)) -#define UART1_DTREG_EMPTY (UART1_CTRL_STAT_A & (1 << UART1_DATA_EMPTY)) - -/* UART 2 registers */ -#define UART2_CTRL_STAT_A UCSR2A -#define UART2_CTRL_STAT_B UCSR2B -#define UART2_CTRL_STAT_C UCSR2C -#define UART2_BAUD_RATE_L UBRR2L -#define UART2_BAUD_RATE_H UBRR2H -#define UART2_DATA_REGISTER UDR2 - -/* Flags */ -#define UART2_RX_COMPLETE RXC2 -#define UART2_DATA_EMPTY UDRE2 -#define UART2_RX_EN RXEN2 -#define UART2_TX_EN TXEN2 -#define UART2_RXC_IRQ_EN RXCIE2 -#define UART2_TXC_IRQ_EN TXCIE2 -#define UART2_8BIT_SIZE (1 << UCSZ20) | (1 << UCSZ21) - -/* UART2 helper macros */ -#define UART2_RX_TX_EN UART2_CTRL_STAT_B |= (1 << UART2_RX_EN) | (1 << UART2_TX_EN) -#define UART2_RX_IRQ_EN UART2_CTRL_STAT_B |= (1 << UART2_RXC_IRQ_EN) -#define UART2_SET_8BIT_SIZE UART2_CTRL_STAT_C |= UART2_8BIT_SIZE -#define UART2_RECEIVED_DATA (UART2_CTRL_STAT_A & (1 << UART2_RX_COMPLETE)) -#define UART2_DTREG_EMPTY (UART2_CTRL_STAT_A & (1 << UART2_DATA_EMPTY)) - -/* UART 2 registers */ -#define UART3_CTRL_STAT_A UCSR3A -#define UART3_CTRL_STAT_B UCSR3B -#define UART3_CTRL_STAT_C UCSR3C -#define UART3_BAUD_RATE_L UBRR3L -#define UART3_BAUD_RATE_H UBRR3H -#define UART3_DATA_REGISTER UDR3 - -/* Flags */ -#define UART3_RX_COMPLETE RXC3 -#define UART3_DATA_EMPTY UDRE3 -#define UART3_RX_EN RXEN3 -#define UART3_TX_EN TXEN3 -#define UART3_RXC_IRQ_EN RXCIE3 -#define UART3_TXC_IRQ_EN TXCIE3 -#define UART3_8BIT_SIZE (1 << UCSZ30) | (1 << UCSZ31) - -/* UART3 helper macros */ -#define UART3_RX_TX_EN UART3_CTRL_STAT_B |= (1 << UART3_RX_EN) | (1 << UART3_TX_EN) -#define UART3_RX_IRQ_EN UART3_CTRL_STAT_B |= (1 << UART3_RXC_IRQ_EN) -#define UART3_SET_8BIT_SIZE UART3_CTRL_STAT_C |= UART3_8BIT_SIZE -#define UART3_RECEIVED_DATA (UART3_CTRL_STAT_A & (1 << UART3_RX_COMPLETE)) -#define UART3_DTREG_EMPTY (UART3_CTRL_STAT_A & (1 << UART3_DATA_EMPTY)) +#define UART_3 MEGA_UART3 +#define UART_3_ISR USART3_RX_vect /** @} */ /** From 5fc67747e64129234bce81c0bd441696f8fbfe9c Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Thu, 10 Mar 2016 18:01:42 +0100 Subject: [PATCH 4/5] cpu/atmega2560: fixed typo in reg definition --- cpu/atmega2560/include/atmega2560_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/atmega2560/include/atmega2560_regs.h b/cpu/atmega2560/include/atmega2560_regs.h index f29319a74b..9a47ee5759 100644 --- a/cpu/atmega2560/include/atmega2560_regs.h +++ b/cpu/atmega2560/include/atmega2560_regs.h @@ -70,7 +70,7 @@ typedef struct { #define MEGA_UART0_BASE ((uint16_t *)(&UCSR0A)) #define MEGA_UART1_BASE ((uint16_t *)(&UCSR1A)) #define MEGA_UART2_BASE ((uint16_t *)(&UCSR2A)) -#define MEGA_UART3_BASE ((uint16_t *)(&UCSR2A)) +#define MEGA_UART3_BASE ((uint16_t *)(&UCSR3A)) /** @} */ /** From 7f0a1a7b5a68b2672495fc3be7e4e964a3cb4c0f Mon Sep 17 00:00:00 2001 From: kYc0o Date: Fri, 3 Jun 2016 02:32:15 +0200 Subject: [PATCH 5/5] cpu/atmega2560: ISR UART typo --- cpu/atmega2560/periph/uart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpu/atmega2560/periph/uart.c b/cpu/atmega2560/periph/uart.c index ef53df3073..4736f57054 100644 --- a/cpu/atmega2560/periph/uart.c +++ b/cpu/atmega2560/periph/uart.c @@ -105,7 +105,7 @@ ISR(UART_0_ISR, ISR_BLOCK) } #endif /* UART_0_ISR */ -#if UART_1_ISR +#ifdef UART_1_ISR ISR(UART_1_ISR, ISR_BLOCK) { __enter_isr(); @@ -114,7 +114,7 @@ ISR(UART_1_ISR, ISR_BLOCK) } #endif /* UART_1_ISR */ -#if UART_2_ISR +#ifdef UART_2_ISR ISR(UART_2_ISR, ISR_BLOCK) { __enter_isr(); @@ -123,7 +123,7 @@ ISR(UART_2_ISR, ISR_BLOCK) } #endif /* UART_2_ISR */ -#if UART_3_ISR +#ifdef UART_3_ISR ISR(UART_3_ISR, ISR_BLOCK) { __enter_isr();