From 685b42c9a23b8e7bed1b82b19cd2b0c9ce30e22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= Date: Tue, 3 May 2016 13:53:20 +0200 Subject: [PATCH 1/2] cpu/lm4f120: SPI support --- boards/ek-lm4f120xl/Makefile.features | 1 + boards/ek-lm4f120xl/include/periph_conf.h | 64 ++++++++++ cpu/lm4f120/Makefile.include | 4 + cpu/lm4f120/cpu.c | 1 + cpu/lm4f120/include/cpu_conf.h | 2 +- cpu/lm4f120/include/periph_cpu.h | 68 ++++++++++- cpu/lm4f120/periph/spi.c | 140 ++++++++++++++++++++++ 7 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 cpu/lm4f120/periph/spi.c diff --git a/boards/ek-lm4f120xl/Makefile.features b/boards/ek-lm4f120xl/Makefile.features index 0ce7768d2b..e7ffe1be3b 100644 --- a/boards/ek-lm4f120xl/Makefile.features +++ b/boards/ek-lm4f120xl/Makefile.features @@ -1,6 +1,7 @@ # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_gpio +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart diff --git a/boards/ek-lm4f120xl/include/periph_conf.h b/boards/ek-lm4f120xl/include/periph_conf.h index 610a403ffc..818c8e097a 100644 --- a/boards/ek-lm4f120xl/include/periph_conf.h +++ b/boards/ek-lm4f120xl/include/periph_conf.h @@ -19,6 +19,8 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif @@ -99,6 +101,68 @@ extern "C" { #define ADC_NUMOF (12) /** @} */ +/** + * @name SPI configuration + * @{ + */ +static const spi_conf_t spi_confs[] = { + { + .ssi_sysctl = SYSCTL_PERIPH_SSI0, + .ssi_base = SSI0_BASE, + .gpio_sysctl = SYSCTL_PERIPH_GPIOA, + .gpio_port = GPIO_PORTA_BASE, + .pins = { + .clk = GPIO_PA2_SSI0CLK, + .fss = GPIO_PA3_SSI0FSS, + .rx = GPIO_PA4_SSI0RX, + .tx = GPIO_PA5_SSI0TX, + .mask = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 + } + }, + { + .ssi_sysctl = SYSCTL_PERIPH_SSI1, + .ssi_base = SSI1_BASE, + .gpio_sysctl = SYSCTL_PERIPH_GPIOF, + .gpio_port = GPIO_PORTF_BASE, + .pins = { + .clk = GPIO_PF2_SSI1CLK, + .fss = GPIO_PF3_SSI1FSS, + .rx = GPIO_PF0_SSI1RX, + .tx = GPIO_PF1_SSI1TX, + .mask = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 + } + }, + { + .ssi_sysctl = SYSCTL_PERIPH_SSI2, + .ssi_base = SSI2_BASE, + .gpio_sysctl = SYSCTL_PERIPH_GPIOB, + .gpio_port = GPIO_PORTB_BASE, + .pins = { + .clk = GPIO_PB4_SSI2CLK, + .fss = GPIO_PB5_SSI2FSS, + .rx = GPIO_PB6_SSI2RX, + .tx = GPIO_PB7_SSI2TX, + .mask = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 + } + }, + { + .ssi_sysctl = SYSCTL_PERIPH_SSI3, + .ssi_base = SSI3_BASE, + .gpio_sysctl = SYSCTL_PERIPH_GPIOD, + .gpio_port = GPIO_PORTD_BASE, + .pins = { + .clk = GPIO_PD0_SSI3CLK, + .fss = GPIO_PD1_SSI3FSS, + .rx = GPIO_PD2_SSI3RX, + .tx = GPIO_PD3_SSI3TX, + .mask = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 + } + }, +}; + +#define SPI_NUMOF (sizeof(spi_confs) / sizeof(spi_confs[0])) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/lm4f120/Makefile.include b/cpu/lm4f120/Makefile.include index 17d7b63192..fb2d4cecf2 100644 --- a/cpu/lm4f120/Makefile.include +++ b/cpu/lm4f120/Makefile.include @@ -1,4 +1,8 @@ export CPU_ARCH = cortex-m4f include $(RIOTMAKE)/arch/cortexm.inc.mk + +# use common periph functions +USEMODULE += periph_common + include $(RIOTCPU)/stellaris_common/Makefile.include diff --git a/cpu/lm4f120/cpu.c b/cpu/lm4f120/cpu.c index a4b1598381..2fac948852 100644 --- a/cpu/lm4f120/cpu.c +++ b/cpu/lm4f120/cpu.c @@ -24,6 +24,7 @@ #include "arch/thread_arch.h" #include "arch/irq_arch.h" #include "periph/init.h" +#include "periph_conf.h" /** * @brief Initialize the CPU, set IRQ priorities diff --git a/cpu/lm4f120/include/cpu_conf.h b/cpu/lm4f120/include/cpu_conf.h index 3a0f4f9aa1..094d993e27 100644 --- a/cpu/lm4f120/include/cpu_conf.h +++ b/cpu/lm4f120/include/cpu_conf.h @@ -43,9 +43,9 @@ extern "C" { #include "stellaris_periph/timer.h" #include "stellaris_periph/pin_map.h" #include "stellaris_periph/uart.h" +#include "stellaris_periph/ssi.h" #include "stellaris_periph/fpu.h" #include "stellaris_periph/rom.h" -#include "periph/uart.h" #ifdef CPU_MODEL_LM4F120H5QR #include "vendor/lm4f120h5qr.h" diff --git a/cpu/lm4f120/include/periph_cpu.h b/cpu/lm4f120/include/periph_cpu.h index f0b57d1e39..8ef0b334c9 100644 --- a/cpu/lm4f120/include/periph_cpu.h +++ b/cpu/lm4f120/include/periph_cpu.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Rakendra Thapa + * Copyright (C) 2017 Marc Poulhiès * * 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,14 +15,13 @@ * @brief CPU specific definitions for internal peripheral handling * * @author Rakendra Thapa + * @author Marc Poulhiès */ #ifndef PERIPH_CPU_H #define PERIPH_CPU_H -#include "periph/dev_enums.h" #include "cpu_conf.h" - #ifdef __cplusplus extern "C" { #endif @@ -109,6 +109,70 @@ typedef enum { } adc_res_t; #endif /* ndef DOXYGEN */ +/** + * @brief Override SPI hardware chip select macro + * + * As of now, we do not support HW CS, so we always set it to a fixed value + */ +#define SPI_HWCS(x) (UINT_MAX - 1) + +/** + * @brief SPI configuration data structure + * @{ + */ +typedef struct { + unsigned long ssi_sysctl; /**< SSI device in sysctl */ + unsigned long ssi_base; /**< SSI base address */ + unsigned long gpio_sysctl; /**< GPIO device in sysctl */ + unsigned long gpio_port; /**< GPIO port */ + struct { + unsigned long clk; /**< pin used for SCK */ + unsigned long fss; /**< pin used for FSS */ + unsigned long rx; /**< pin used for MISO */ + unsigned long tx; /**< pin used for MOSI */ + unsigned long mask; /**< Pin mask */ + } pins; /**< Pin setting */ +} spi_conf_t; +/** @} */ + +/** + * @brief declare needed generic SPI functions + * @{ + */ +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE 1 +#define PERIPH_SPI_NEEDS_TRANSFER_REG 1 +#define PERIPH_SPI_NEEDS_TRANSFER_REGS 1 +#define PERIPH_SPI_NEEDS_INIT_CS 1 +/** @} */ + +/** + * @brief Override SPI clock speed values + * @{ + */ +#define HAVE_SPI_CLK_T 1 +typedef enum { + SPI_CLK_100KHZ = 100000, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ = 400000, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ = 1000000, /**< drive the SPI bus with 1MHz */ + SPI_CLK_4MHZ = 4000000, /**< drive the SPI bus with 4MHz */ + SPI_CLK_5MHZ = 5000000, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ = 10000000, /**< drive the SPI bus with 10MHz */ +} spi_clk_t; +/** @} */ + +/** + * @brief Override SPI mode settings + * @{ + */ +#define HAVE_SPI_MODE_T 1 +typedef enum { + SPI_MODE_0 = SSI_FRF_MOTO_MODE_0, /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = SSI_FRF_MOTO_MODE_1, /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = SSI_FRF_MOTO_MODE_2, /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = SSI_FRF_MOTO_MODE_0, /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/lm4f120/periph/spi.c b/cpu/lm4f120/periph/spi.c new file mode 100644 index 0000000000..c43a615050 --- /dev/null +++ b/cpu/lm4f120/periph/spi.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2017 Marc Poulhiès + * + * 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_lm4f120 + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Marc Poulhiès + * + * @} + */ +#include "cpu.h" +#include "mutex.h" +#include "periph/gpio.h" +#include "periph/spi.h" +#include "periph_conf.h" +#include "board.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#ifdef SPI_NUMOF + +/** + * @brief Array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + /* initialize device lock */ + mutex_init(&locks[bus]); + + /* trigger pin initialization */ + spi_init_pins(bus); + + /* enable clock for SSI */ + ROM_SysCtlPeripheralEnable(spi_confs[bus].ssi_sysctl); + + /* configure SSI */ + ROM_SSIDisable(spi_confs[bus].ssi_base); + ROM_SSIClockSourceSet(spi_confs[bus].ssi_base, SSI_CLOCK_SYSTEM); + + /* disable clock for SSI */ + ROM_SysCtlPeripheralDisable(spi_confs[bus].ssi_sysctl); +} + +void spi_init_pins(spi_t bus) +{ + ROM_SysCtlPeripheralEnable(spi_confs[bus].gpio_sysctl); + + ROM_GPIOPinConfigure(spi_confs[bus].pins.clk); + ROM_GPIOPinConfigure(spi_confs[bus].pins.fss); + ROM_GPIOPinConfigure(spi_confs[bus].pins.rx); + ROM_GPIOPinConfigure(spi_confs[bus].pins.tx); + + ROM_GPIOPinTypeSSI(spi_confs[bus].gpio_port, spi_confs[bus].pins.mask); +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable clock for SSI */ + ROM_SysCtlPeripheralEnable(spi_confs[bus].ssi_sysctl); + + /* configure SSI device */ + ROM_SSIConfigSetExpClk(spi_confs[bus].ssi_base, ROM_SysCtlClockGet(), + mode, + SSI_MODE_MASTER, + clk, + 8); + + ROM_SSIEnable(spi_confs[bus].ssi_base); + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and release lock */ + ROM_SSIDisable(spi_confs[bus].ssi_base); + ROM_SysCtlPeripheralDisable(spi_confs[bus].ssi_sysctl); + + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + char *inbuf = in; + unsigned long int tmp_out; + const unsigned char *outbuf = + (out != NULL) ? (const unsigned char *)out : (const unsigned char *)&tmp_out; + + /* make sure at least one input or one output buffer is given */ + assert(in != NULL || out != NULL); + + /* ROM function only works with long int */ + unsigned long long_in; + + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); + } + + for (; len > 0; len--) { + /* casting const away is needed because TI interface is not const-aware */ + ROM_SSIDataPut(spi_confs[bus].ssi_base, (unsigned long int) (*outbuf)); + + /* wait until tx over */ + while (ROM_SSIBusy(spi_confs[bus].ssi_base)) {} + + ROM_SSIDataGet(spi_confs[bus].ssi_base, &long_in); + + /* wait until rx over */ + while (ROM_SSIBusy(spi_confs[bus].ssi_base)) {} + + if (inbuf) { + *inbuf = (char)long_in; + inbuf++; + } + if (out) { + outbuf++; + } + } + if (!cont && cs != SPI_CS_UNDEF) { + gpio_set((gpio_t)cs); + } +} + +#endif /* SPI_NUMOF */ From 11893d8e5f6575ad412c697c13268f6fc15347ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= Date: Wed, 28 Jun 2017 13:07:16 +0200 Subject: [PATCH 2/2] cpu/lm4f120 fix cpuid cleanup remove dangling CPUID_LEN macro left after fe75996c that caused some code to wronlgy believe this cpu has cpuid_get(). --- cpu/lm4f120/include/periph_cpu.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cpu/lm4f120/include/periph_cpu.h b/cpu/lm4f120/include/periph_cpu.h index 8ef0b334c9..bc36fc3685 100644 --- a/cpu/lm4f120/include/periph_cpu.h +++ b/cpu/lm4f120/include/periph_cpu.h @@ -26,11 +26,6 @@ extern "C" { #endif -/** - * @brief Length of the CPU_ID in octets - */ -#define CPUID_LEN (12U) - /** * @brief Overwrite the default gpio_t type definition * @{