mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/lm4f120: SPI support
This commit is contained in:
parent
786baac055
commit
685b42c9a2
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
Normal file
140
cpu/lm4f120/periph/spi.c
Normal file
@ -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…
Reference in New Issue
Block a user