Browse Source

cpu/lm4f120: SPI support

master
Marc Poulhiès 7 years ago
parent
commit
685b42c9a2
  1. 1
      boards/ek-lm4f120xl/Makefile.features
  2. 64
      boards/ek-lm4f120xl/include/periph_conf.h
  3. 4
      cpu/lm4f120/Makefile.include
  4. 1
      cpu/lm4f120/cpu.c
  5. 2
      cpu/lm4f120/include/cpu_conf.h
  6. 68
      cpu/lm4f120/include/periph_cpu.h
  7. 140
      cpu/lm4f120/periph/spi.c

1
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

64
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

4
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

1
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

2
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"

68
cpu/lm4f120/include/periph_cpu.h

@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Rakendra Thapa <rakendrathapa@gmail.com>
* Copyright (C) 2017 Marc Poulhiès <dkm@kataplop.net>
*
* 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 <rakendrathapa@gmail.com>
* @author Marc Poulhiès <dkm@kataplop.net>
*/
#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

140
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 <dkm@kataplop.net>
*
* @}
*/
#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 */
Loading…
Cancel
Save