diff --git a/boards/atxmega-a1u-xpro/Kconfig b/boards/atxmega-a1u-xpro/Kconfig index ef85455060..7e7fdffafc 100644 --- a/boards/atxmega-a1u-xpro/Kconfig +++ b/boards/atxmega-a1u-xpro/Kconfig @@ -18,6 +18,7 @@ config BOARD_ATXMEGA_A1U_XPRO select HAS_PERIPH_I2C select HAS_PERIPH_NVM select HAS_PERIPH_PM + select HAS_PERIPH_SPI select HAS_PERIPH_TIMER select HAS_PERIPH_TIMER_PERIODIC select HAS_PERIPH_UART diff --git a/boards/atxmega-a1u-xpro/include/board.h b/boards/atxmega-a1u-xpro/include/board.h index 2314adc6ce..8ac664712d 100644 --- a/boards/atxmega-a1u-xpro/include/board.h +++ b/boards/atxmega-a1u-xpro/include/board.h @@ -88,7 +88,6 @@ extern "C" { * * @{ */ - #define XTIMER_DEV TIMER_DEV(0) #define XTIMER_CHAN (0) #define XTIMER_WIDTH (16) diff --git a/boards/atxmega-a1u-xpro/include/periph_conf.h b/boards/atxmega-a1u-xpro/include/periph_conf.h index e4840685cb..66c1c283ff 100644 --- a/boards/atxmega-a1u-xpro/include/periph_conf.h +++ b/boards/atxmega-a1u-xpro/include/periph_conf.h @@ -112,6 +112,24 @@ static const i2c_conf_t i2c_config[] = { #define I2C_NUMOF ARRAY_SIZE(i2c_config) /** @} */ +/** + * @name SPI configuration + * @{ + */ +static const spi_conf_t spi_config[] = { + { + .dev = &SPIC, + .pwr = PWR_RED_REG(PWR_PORT_C, PR_SPI_bm), + .sck_pin = GPIO_PIN(PORT_C, 7), + .miso_pin = GPIO_PIN(PORT_C, 6), + .mosi_pin = GPIO_PIN(PORT_C, 5), + .ss_pin = GPIO_PIN(PORT_C, 4), + }, +}; + +#define SPI_NUMOF ARRAY_SIZE(spi_config) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/boards/atxmega-a3bu-xplained/Kconfig b/boards/atxmega-a3bu-xplained/Kconfig index 1a91bd093e..358a90bc9d 100644 --- a/boards/atxmega-a3bu-xplained/Kconfig +++ b/boards/atxmega-a3bu-xplained/Kconfig @@ -18,6 +18,7 @@ config BOARD_ATXMEGA_A3BU_XPLAINED select HAS_PERIPH_I2C select HAS_PERIPH_NVM select HAS_PERIPH_PM + select HAS_PERIPH_SPI select HAS_PERIPH_TIMER select HAS_PERIPH_TIMER_PERIODIC select HAS_PERIPH_UART diff --git a/boards/atxmega-a3bu-xplained/include/periph_conf.h b/boards/atxmega-a3bu-xplained/include/periph_conf.h index 6fe0161026..a9106673cb 100644 --- a/boards/atxmega-a3bu-xplained/include/periph_conf.h +++ b/boards/atxmega-a3bu-xplained/include/periph_conf.h @@ -129,6 +129,24 @@ static const i2c_conf_t i2c_config[] = { #define I2C_NUMOF ARRAY_SIZE(i2c_config) /** @} */ +/** + * @name SPI configuration + * @{ + */ +static const spi_conf_t spi_config[] = { + { + .dev = &SPIC, + .pwr = PWR_RED_REG(PWR_PORT_C, PR_SPI_bm), + .sck_pin = GPIO_PIN(PORT_C, 7), + .miso_pin = GPIO_PIN(PORT_C, 6), + .mosi_pin = GPIO_PIN(PORT_C, 5), + .ss_pin = GPIO_PIN(PORT_C, 4), + }, +}; + +#define SPI_NUMOF ARRAY_SIZE(spi_config) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/atxmega/Makefile.features b/cpu/atxmega/Makefile.features index 337ccbe070..48ace1cc10 100644 --- a/cpu/atxmega/Makefile.features +++ b/cpu/atxmega/Makefile.features @@ -9,5 +9,6 @@ FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_nvm FEATURES_PROVIDED += periph_pm +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer periph_timer_periodic FEATURES_PROVIDED += periph_uart diff --git a/cpu/atxmega/include/periph_cpu.h b/cpu/atxmega/include/periph_cpu.h index 765e3da030..901a2326f1 100644 --- a/cpu/atxmega/include/periph_cpu.h +++ b/cpu/atxmega/include/periph_cpu.h @@ -301,6 +301,59 @@ typedef struct { cpu_int_lvl_t int_lvl; /**< Serial Interrupt Level */ } i2c_conf_t; +/** + * @brief Enable common SPI functions + * @{ + */ +#define PERIPH_SPI_NEEDS_INIT_CS +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE +#define PERIPH_SPI_NEEDS_TRANSFER_REG +#define PERIPH_SPI_NEEDS_TRANSFER_REGS +/** @} */ + +/** + * @brief Define global value for undefined SPI device + * @{ + */ +#define SPI_UNDEF (UCHAR_MAX) +/** @} */ + +/** + * @brief Define spi_t data type to save data + * @{ + */ +#define HAVE_SPI_T +typedef uint8_t spi_t; +/** @} */ + +/** + * @brief SPI device configuration + * @{ + */ +typedef struct { + SPI_t *dev; /**< pointer to the used SPI device */ + pwr_reduction_t pwr; /**< Power Management */ + gpio_t sck_pin; /**< pin used for SCK */ + gpio_t miso_pin; /**< pin used for MISO */ + gpio_t mosi_pin; /**< pin used for MOSI */ + gpio_t ss_pin; /**< pin used for SS line */ +} spi_conf_t; +/** @} */ + +/** + * @brief Available SPI clock speeds + * @{ + */ +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = 100000U, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ = 400000U, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ = 1000000U, /**< drive the SPI bus with 1MHz */ + SPI_CLK_5MHZ = 5000000U, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ = 10000000U, /**< drive the SPI bus with 10MHz */ +} spi_clk_t; +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/atxmega/periph/spi.c b/cpu/atxmega/periph/spi.c new file mode 100644 index 0000000000..cc0d57dfc7 --- /dev/null +++ b/cpu/atxmega/periph/spi.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 Gerson Fernando Budke + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_atxmega + * @ingroup cpu_atxmega_periph + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Gerson Fernando Budke + * + * @} + */ + +#include "cpu.h" +#include "cpu_pm.h" +#include "mutex.h" +#include "periph/spi.h" +#include "pm_layered.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +static void _print_buffer(const char* s, const uint8_t* buffer, uint16_t len) +{ + uint16_t i; + + if (buffer == NULL) { + DEBUG("%s - no buffer\n", s); + return; + } + + DEBUG("%s\n", s); + + for (i = 0; i < len; i++) { + if ((i % 16) == 0 && i != 0) { + DEBUG("\n"); + } + else if ((i % 8) == 0) { + DEBUG(" "); + } + + DEBUG("%02x ", buffer[i]); + } + + DEBUG("\n"); +} + +/** + * @brief Allocation device locks + */ +static mutex_t locks[SPI_NUMOF]; + +/** + * @brief Get the pointer to the base register of the given SPI device + * + * @param[in] dev SPI device identifier + * + * @return base register address + */ +static inline SPI_t* dev(spi_t bus) +{ + return (SPI_t*)spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + mutex_init(&locks[bus]); + spi_init_pins(bus); + + DEBUG("init\n"); +} + +void spi_init_pins(spi_t bus) +{ + /* SS pin always should be output even when it is not used */ + spi_init_cs(bus, spi_config[bus].ss_pin); + gpio_init(spi_config[bus].sck_pin, GPIO_OUT); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + (void)cs; + (void)clk; + + DEBUG("acquire\n"); + + pm_block(3); + mutex_lock(&locks[bus]); + pm_periph_enable(spi_config[bus].pwr); + + dev(bus)->CTRL = SPI_CLK2X_bm + | SPI_ENABLE_bm + | SPI_MASTER_bm + | (mode << SPI_MODE_gp) + | SPI_PRESCALER0_bm; + + (void)dev(bus)->STATUS; + (void)dev(bus)->DATA; + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + dev(bus)->CTRL &= ~SPI_ENABLE_bm; + pm_periph_disable(spi_config[bus].pwr); + mutex_unlock(&locks[bus]); + pm_unblock(3); + + DEBUG("release\n"); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; + + if (IS_ACTIVE(ENABLE_DEBUG)) { + _print_buffer("bytes - out", out, len); + } + + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t) cs); + } + + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; + + dev(bus)->DATA = tmp; + + while (!(dev(bus)->STATUS & SPI_IF_bm)){} + + tmp = dev(bus)->DATA; + + if (in_buf) { + in_buf[i] = tmp; + } + } + + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t) cs); + } + + if (IS_ACTIVE(ENABLE_DEBUG)) { + _print_buffer("bytes - in", in, len); + } +} diff --git a/examples/gnrc_lorawan/Makefile.ci b/examples/gnrc_lorawan/Makefile.ci index 3797ffe80f..eb07191e2b 100644 --- a/examples/gnrc_lorawan/Makefile.ci +++ b/examples/gnrc_lorawan/Makefile.ci @@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ msb-430 \ msb-430h \ nucleo-f031k6 \ diff --git a/tests/disp_dev/Makefile.ci b/tests/disp_dev/Makefile.ci index bb2d6aa68a..3bd15033b1 100644 --- a/tests/disp_dev/Makefile.ci +++ b/tests/disp_dev/Makefile.ci @@ -7,6 +7,8 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega1284p \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ + atxmega-a3bu-xplained \ derfmega128 \ mega-xplained \ microduino-corerf \ diff --git a/tests/driver_at86rf215/Makefile.ci b/tests/driver_at86rf215/Makefile.ci index 397996ca9c..6f458549a9 100644 --- a/tests/driver_at86rf215/Makefile.ci +++ b/tests/driver_at86rf215/Makefile.ci @@ -7,6 +7,8 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega1284p \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ + atxmega-a3bu-xplained \ bluepill-stm32f030c8 \ derfmega128 \ i-nucleo-lrwan1 \ diff --git a/tests/driver_atwinc15x0/Makefile b/tests/driver_atwinc15x0/Makefile index 0542cb1cdb..cbc8738aaa 100644 --- a/tests/driver_atwinc15x0/Makefile +++ b/tests/driver_atwinc15x0/Makefile @@ -2,6 +2,6 @@ USEMODULE = atwinc15x0 # msp430-gcc doesn't support -Wno-discarded-qualifiers -FEATURES_BLACKLIST += arch_msp430 +FEATURES_BLACKLIST += arch_msp430 cpu_core_atxmega include ../driver_netdev_common/Makefile.netdev.mk diff --git a/tests/driver_cc110x/Makefile.ci b/tests/driver_cc110x/Makefile.ci index 2ce9fe8b90..c03f8d4ad0 100644 --- a/tests/driver_cc110x/Makefile.ci +++ b/tests/driver_cc110x/Makefile.ci @@ -7,6 +7,8 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega1284p \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ + atxmega-a3bu-xplained \ blackpill \ bluepill \ bluepill-stm32f030c8 \ diff --git a/tests/driver_enc28j60/Makefile.ci b/tests/driver_enc28j60/Makefile.ci index efd592bb4a..dabf97cd3e 100644 --- a/tests/driver_enc28j60/Makefile.ci +++ b/tests/driver_enc28j60/Makefile.ci @@ -7,6 +7,8 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega1284p \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ + atxmega-a3bu-xplained \ bluepill-stm32f030c8 \ derfmega128 \ i-nucleo-lrwan1 \ diff --git a/tests/driver_encx24j600/Makefile.ci b/tests/driver_encx24j600/Makefile.ci index 7f7f4d0b7d..c856df2cca 100644 --- a/tests/driver_encx24j600/Makefile.ci +++ b/tests/driver_encx24j600/Makefile.ci @@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ i-nucleo-lrwan1 \ msb-430 \ msb-430h \ diff --git a/tests/driver_kw2xrf/Makefile.ci b/tests/driver_kw2xrf/Makefile.ci index 57b75c3dab..db32a4cc9e 100644 --- a/tests/driver_kw2xrf/Makefile.ci +++ b/tests/driver_kw2xrf/Makefile.ci @@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ bluepill-stm32f030c8 \ i-nucleo-lrwan1 \ nucleo-f031k6 \ diff --git a/tests/driver_mrf24j40/Makefile.ci b/tests/driver_mrf24j40/Makefile.ci index 586364d983..72ac56be14 100644 --- a/tests/driver_mrf24j40/Makefile.ci +++ b/tests/driver_mrf24j40/Makefile.ci @@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ bluepill-stm32f030c8 \ i-nucleo-lrwan1 \ nucleo-f031k6 \ diff --git a/tests/driver_nrf24l01p_ng/Makefile.ci b/tests/driver_nrf24l01p_ng/Makefile.ci index 3386c82573..0949f760d5 100644 --- a/tests/driver_nrf24l01p_ng/Makefile.ci +++ b/tests/driver_nrf24l01p_ng/Makefile.ci @@ -8,6 +8,8 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega128rfa1 \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ + atxmega-a3bu-xplained \ bluepill-stm32f030c8 \ derfmega128 \ i-nucleo-lrwan1 \ diff --git a/tests/driver_w5100/Makefile.ci b/tests/driver_w5100/Makefile.ci index 28ea82d339..fcbdf2a160 100644 --- a/tests/driver_w5100/Makefile.ci +++ b/tests/driver_w5100/Makefile.ci @@ -6,6 +6,7 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ + atxmega-a1u-xpro \ bluepill-stm32f030c8 \ i-nucleo-lrwan1 \ msb-430 \