mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #9698 from smlng/pr/cc2538/spi
cpu/cc2538: refine periph/spi implementation
This commit is contained in:
commit
25a487e3a9
@ -103,11 +103,11 @@ static const i2c_conf_t i2c_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PA4,
|
||||
.miso_pin = GPIO_PA5,
|
||||
.sck_pin = GPIO_PA2,
|
||||
.cs_pin = GPIO_PD0
|
||||
.num = 0,
|
||||
.mosi_pin = GPIO_PIN(0, 4),
|
||||
.miso_pin = GPIO_PIN(0, 5),
|
||||
.sck_pin = GPIO_PIN(0, 2),
|
||||
.cs_pin = GPIO_PIN(3, 0)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -130,11 +130,11 @@ static const i2c_conf_t i2c_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PA5,
|
||||
.miso_pin = GPIO_PA4,
|
||||
.sck_pin = GPIO_PA2,
|
||||
.cs_pin = GPIO_PA3,
|
||||
.num = 0,
|
||||
.mosi_pin = GPIO_PIN(0, 5),
|
||||
.miso_pin = GPIO_PIN(0, 4),
|
||||
.sck_pin = GPIO_PIN(0, 2),
|
||||
.cs_pin = GPIO_PIN(0, 3)
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -126,11 +126,11 @@ static const i2c_conf_t i2c_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PA5,
|
||||
.miso_pin = GPIO_PA4,
|
||||
.sck_pin = GPIO_PA2,
|
||||
.cs_pin = GPIO_PA3,
|
||||
.num = 0,
|
||||
.mosi_pin = GPIO_PIN(0, 5),
|
||||
.miso_pin = GPIO_PIN(0, 4),
|
||||
.sck_pin = GPIO_PIN(0, 2),
|
||||
.cs_pin = GPIO_PIN(0, 3)
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -51,17 +51,17 @@ static const i2c_conf_t i2c_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PD0,
|
||||
.miso_pin = GPIO_PC4,
|
||||
.sck_pin = GPIO_PD1,
|
||||
.cs_pin = GPIO_PD3
|
||||
.num = 0,
|
||||
.mosi_pin = GPIO_PIN(3, 0),
|
||||
.miso_pin = GPIO_PIN(2, 4),
|
||||
.sck_pin = GPIO_PIN(3, 1),
|
||||
.cs_pin = GPIO_PIN(3, 3)
|
||||
},
|
||||
{
|
||||
.dev = SSI1,
|
||||
.mosi_pin = GPIO_PC7,
|
||||
.miso_pin = GPIO_PA4,
|
||||
.sck_pin = GPIO_PB5,
|
||||
.num = 1,
|
||||
.mosi_pin = GPIO_PIN(2, 7),
|
||||
.miso_pin = GPIO_PIN(0, 4),
|
||||
.sck_pin = GPIO_PIN(1 ,5),
|
||||
.cs_pin = GPIO_UNDEF
|
||||
}
|
||||
};
|
||||
|
@ -51,18 +51,18 @@ static const i2c_conf_t i2c_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PB1,
|
||||
.miso_pin = GPIO_PB3,
|
||||
.sck_pin = GPIO_PB2,
|
||||
.cs_pin = GPIO_PB5
|
||||
.num = 0,
|
||||
.mosi_pin = GPIO_PIN(1, 1),
|
||||
.miso_pin = GPIO_PIN(1, 3),
|
||||
.sck_pin = GPIO_PIN(1, 2),
|
||||
.cs_pin = GPIO_PIN(1, 5)
|
||||
},
|
||||
{
|
||||
.dev = SSI1,
|
||||
.mosi_pin = GPIO_PC5,
|
||||
.miso_pin = GPIO_PC6,
|
||||
.sck_pin = GPIO_PC4,
|
||||
.cs_pin = GPIO_PA7
|
||||
.num = 1,
|
||||
.mosi_pin = GPIO_PIN(2, 5),
|
||||
.miso_pin = GPIO_PIN(2, 6),
|
||||
.sck_pin = GPIO_PIN(2, 4),
|
||||
.cs_pin = GPIO_PIN(0, 7)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -54,18 +54,18 @@ static const i2c_conf_t i2c_config[] = {
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SSI0,
|
||||
.mosi_pin = GPIO_PB1,
|
||||
.miso_pin = GPIO_PB3,
|
||||
.sck_pin = GPIO_PB2,
|
||||
.cs_pin = GPIO_PB5
|
||||
.num = 0,
|
||||
.mosi_pin = GPIO_PIN(1, 1),
|
||||
.miso_pin = GPIO_PIN(1, 3),
|
||||
.sck_pin = GPIO_PIN(1, 2),
|
||||
.cs_pin = GPIO_PIN(1, 5)
|
||||
},
|
||||
{
|
||||
.dev = SSI1,
|
||||
.mosi_pin = GPIO_PC5,
|
||||
.miso_pin = GPIO_PC6,
|
||||
.sck_pin = GPIO_PC4,
|
||||
.cs_pin = GPIO_PA7
|
||||
.num = 1,
|
||||
.mosi_pin = GPIO_PIN(2, 5),
|
||||
.miso_pin = GPIO_PIN(2, 6),
|
||||
.sck_pin = GPIO_PIN(2, 4),
|
||||
.cs_pin = GPIO_PIN(0, 7)
|
||||
}
|
||||
};
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
|
@ -14,6 +14,7 @@
|
||||
* @brief CC2538 SSI interface
|
||||
*
|
||||
* @author Ian Martin <ian@locicontrols.com>
|
||||
* @author Sebastian Meiling <s@mlng.net>
|
||||
*/
|
||||
|
||||
#ifndef CC2538_SSI_H
|
||||
@ -29,92 +30,31 @@ extern "C" {
|
||||
* @brief SSI component registers
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
cc2538_reg_t CR0; /**< SSI Control Register 0 */
|
||||
struct {
|
||||
cc2538_reg_t DSS : 4; /**< SSI data size select */
|
||||
cc2538_reg_t FRF : 2; /**< SSI frame format select */
|
||||
cc2538_reg_t SPO : 1; /**< SSI serial clock polarity */
|
||||
cc2538_reg_t SPH : 1; /**< SSI serial clock phase */
|
||||
cc2538_reg_t SCR : 8; /**< SSI serial clock rate */
|
||||
cc2538_reg_t RESERVED : 16; /**< Reserved bits */
|
||||
} CR0bits;
|
||||
};
|
||||
|
||||
union {
|
||||
cc2538_reg_t CR1; /**< SSI Control Register 1 */
|
||||
struct {
|
||||
cc2538_reg_t LBM : 1; /**< SSI loop-back mode */
|
||||
cc2538_reg_t SSE : 1; /**< SSI synchronous serial port enable */
|
||||
cc2538_reg_t MS : 1; /**< SSI master and slave select */
|
||||
cc2538_reg_t SOD : 1; /**< SSI slave mode output disable */
|
||||
cc2538_reg_t RESERVED : 28; /**< Reserved bits */
|
||||
} CR1bits;
|
||||
};
|
||||
|
||||
cc2538_reg_t DR; /**< SSI Data register */
|
||||
|
||||
union {
|
||||
cc2538_reg_t SR; /**< SSI FIFO/busy Status Register */
|
||||
struct {
|
||||
cc2538_reg_t TFE : 1; /**< SSI transmit FIFO empty */
|
||||
cc2538_reg_t TNF : 1; /**< SSI transmit FIFO not full */
|
||||
cc2538_reg_t RNE : 1; /**< SSI receive FIFO not empty */
|
||||
cc2538_reg_t RFF : 1; /**< SSI receive FIFO full */
|
||||
cc2538_reg_t BSY : 1; /**< SSI busy bit */
|
||||
cc2538_reg_t RESERVED : 27; /**< Reserved bits */
|
||||
} SRbits;
|
||||
};
|
||||
cc2538_reg_t CPSR; /**< SSI Clock Register */
|
||||
cc2538_reg_t IM; /**< SSI Interrupt Mask register */
|
||||
cc2538_reg_t RIS; /**< SSI Raw Interrupt Status register */
|
||||
cc2538_reg_t MIS; /**< SSI Masked Interrupt Status register */
|
||||
cc2538_reg_t ICR; /**< SSI Interrupt Clear Register */
|
||||
cc2538_reg_t DMACTL; /**< SSI uDMA Control Register. */
|
||||
cc2538_reg_t CC; /**< SSI clock configuration */
|
||||
cc2538_reg_t CR0; /**< SSI Control Register 0 */
|
||||
cc2538_reg_t CR1; /**< SSI Control Register 1 */
|
||||
cc2538_reg_t DR; /**< SSI Data register */
|
||||
cc2538_reg_t SR; /**< SSI FIFO/busy Status Register */
|
||||
cc2538_reg_t CPSR; /**< SSI Clock Register */
|
||||
cc2538_reg_t IM; /**< SSI Interrupt Mask register */
|
||||
cc2538_reg_t RIS; /**< SSI Raw Interrupt Status register */
|
||||
cc2538_reg_t MIS; /**< SSI Masked Interrupt Status register */
|
||||
cc2538_reg_t ICR; /**< SSI Interrupt Clear Register */
|
||||
cc2538_reg_t DMACTL; /**< SSI uDMA Control Register. */
|
||||
cc2538_reg_t CC; /**< SSI clock configuration */
|
||||
} cc2538_ssi_t;
|
||||
|
||||
#define SSI0 ( (cc2538_ssi_t*)0x40008000 ) /**< SSI0 Instance */
|
||||
#define SSI1 ( (cc2538_ssi_t*)0x40009000 ) /**< SSI1 Instance */
|
||||
|
||||
/**
|
||||
* @brief Define CR0 register bitfields
|
||||
* @{
|
||||
* @brief Set CR0 data size (bits)
|
||||
*/
|
||||
#define SSI_CR0_DSS(x) ((x - 1) << 0)
|
||||
#define SSI_CR0_SPO (1 << 6)
|
||||
#define SSI_CR0_SPH (1 << 7)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Define CR1 register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_CR1_LBM (1 << 0)
|
||||
#define SSI_CR1_SSE (1 << 1)
|
||||
#define SSI_CR1_MS (1 << 2)
|
||||
#define SSI_CR1_SOD (1 << 3)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Define SR register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_SR_TFE (1 << 0)
|
||||
#define SSI_SR_TNF (1 << 1)
|
||||
#define SSI_SR_RNE (1 << 2)
|
||||
#define SSI_SR_RFF (1 << 3)
|
||||
#define SSI_SR_BSY (1 << 4)
|
||||
/** @} */
|
||||
#define SSI_CR0_DSS(x) (x - 1)
|
||||
|
||||
/**
|
||||
* @brief Define CC register bitfields
|
||||
* @{
|
||||
*/
|
||||
#define SSI_SS_PIOSC (1 << 0)
|
||||
#define SSI_SS_DSEN (1 << 2)
|
||||
#define SSI_SS_SYSDIV (0)
|
||||
#define SSI_SS_IODIV (SSI_SS_PIOSC)
|
||||
#define SSI_CC_CS_SYSDIV (0x0)
|
||||
#define SSI_CC_CS_IODIV (0x1)
|
||||
#define SSI_CC_CS_DSEN (0x4)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "vendor/hw_ssi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -60,6 +61,10 @@ typedef uint32_t gpio_t;
|
||||
*/
|
||||
#define GPIO_UNDEF (0xffffffff)
|
||||
|
||||
/**
|
||||
* @brief Custom value to indicate unused parameter in gpio_init_mux
|
||||
*/
|
||||
#define GPIO_MUX_NONE (0xff)
|
||||
/**
|
||||
* @brief Define a custom GPIO_PIN macro
|
||||
*
|
||||
@ -217,7 +222,7 @@ static const spi_clk_conf_t spi_clk_config[] = {
|
||||
* @{
|
||||
*/
|
||||
typedef struct {
|
||||
cc2538_ssi_t *dev; /**< SSI device */
|
||||
uint8_t num; /**< number of SSI device, i.e. 0 or 1 */
|
||||
gpio_t mosi_pin; /**< pin used for MOSI */
|
||||
gpio_t miso_pin; /**< pin used for MISO */
|
||||
gpio_t sck_pin; /**< pin used for SCK */
|
||||
|
@ -264,13 +264,13 @@ void gpio_init_mux(gpio_t pin, uint8_t over, uint8_t sel, uint8_t func)
|
||||
{
|
||||
assert(pin != GPIO_UNDEF);
|
||||
/* configure pin function and multiplexing */
|
||||
if (over != MODE_NOTSUP) {
|
||||
if (over != GPIO_MUX_NONE) {
|
||||
IOC->OVER[_pp_num(pin)] = over;
|
||||
}
|
||||
if (sel != MODE_NOTSUP) {
|
||||
if (sel != GPIO_MUX_NONE) {
|
||||
IOC->SEL[_pp_num(pin)] = sel;
|
||||
}
|
||||
if (func != MODE_NOTSUP) {
|
||||
if (func != GPIO_MUX_NONE) {
|
||||
IOC->PINS[func] = _pp_num(pin);
|
||||
}
|
||||
/* enable alternative function mode */
|
||||
|
@ -21,11 +21,17 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "vendor/hw_memmap.h"
|
||||
#include "vendor/hw_ssi.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
*/
|
||||
@ -33,33 +39,38 @@ static mutex_t locks[SPI_NUMOF];
|
||||
|
||||
static inline cc2538_ssi_t *dev(spi_t bus)
|
||||
{
|
||||
return spi_config[bus].dev;
|
||||
/* .num is either 0 or 1, return respective base address */
|
||||
return (spi_config[bus].num) ? (cc2538_ssi_t *)SSI1_BASE : (cc2538_ssi_t *)SSI0_BASE;
|
||||
}
|
||||
|
||||
static inline void poweron(spi_t bus)
|
||||
{
|
||||
SYS_CTRL_RCGCSSI |= (1 << bus);
|
||||
SYS_CTRL_SCGCSSI |= (1 << bus);
|
||||
SYS_CTRL_DCGCSSI |= (1 << bus);
|
||||
SYS_CTRL_RCGCSSI |= (1 << spi_config[bus].num);
|
||||
SYS_CTRL_SCGCSSI |= (1 << spi_config[bus].num);
|
||||
SYS_CTRL_DCGCSSI |= (1 << spi_config[bus].num);
|
||||
}
|
||||
|
||||
static inline void poweroff(spi_t bus)
|
||||
{
|
||||
SYS_CTRL_RCGCSSI &= ~(1 << bus);
|
||||
SYS_CTRL_SCGCSSI &= ~(1 << bus);
|
||||
SYS_CTRL_DCGCSSI &= ~(1 << bus);
|
||||
SYS_CTRL_RCGCSSI &= ~(1 << spi_config[bus].num);
|
||||
SYS_CTRL_SCGCSSI &= ~(1 << spi_config[bus].num);
|
||||
SYS_CTRL_DCGCSSI &= ~(1 << spi_config[bus].num);
|
||||
}
|
||||
|
||||
void spi_init(spi_t bus)
|
||||
{
|
||||
assert(bus <= SPI_NUMOF);
|
||||
DEBUG("%s: bus=%u\n", __FUNCTION__, bus);
|
||||
|
||||
assert(bus < SPI_NUMOF);
|
||||
|
||||
/* init mutex for given bus */
|
||||
mutex_init(&locks[bus]);
|
||||
/* temporarily power on the device */
|
||||
poweron(bus);
|
||||
/* configure device to be a master and disable SSI operation mode */
|
||||
dev(bus)->CR1 = 0;
|
||||
/* configure system clock as SSI clock source */
|
||||
dev(bus)->CC = SSI_SS_IODIV;
|
||||
dev(bus)->CC = SSI_CC_CS_IODIV;
|
||||
/* and power off the bus again */
|
||||
poweroff(bus);
|
||||
|
||||
@ -69,37 +80,22 @@ void spi_init(spi_t bus)
|
||||
|
||||
void spi_init_pins(spi_t bus)
|
||||
{
|
||||
switch ((uintptr_t)spi_config[bus].dev) {
|
||||
case (uintptr_t)SSI0:
|
||||
IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI0_TXD;
|
||||
IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI0_CLK_OUT;
|
||||
IOC_PXX_SEL[spi_config[bus].cs_pin ] = SSI0_FSS_OUT;
|
||||
|
||||
IOC_SSIRXD_SSI0 = spi_config[bus].miso_pin;
|
||||
break;
|
||||
|
||||
case (uintptr_t)SSI1:
|
||||
IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI1_TXD;
|
||||
IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI1_CLK_OUT;
|
||||
IOC_PXX_SEL[spi_config[bus].cs_pin ] = SSI1_FSS_OUT;
|
||||
|
||||
IOC_SSIRXD_SSI1 = spi_config[bus].miso_pin;
|
||||
break;
|
||||
}
|
||||
|
||||
IOC_PXX_OVER[spi_config[bus].mosi_pin] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[bus].miso_pin] = IOC_OVERRIDE_DIS;
|
||||
IOC_PXX_OVER[spi_config[bus].sck_pin ] = IOC_OVERRIDE_OE;
|
||||
IOC_PXX_OVER[spi_config[bus].cs_pin ] = IOC_OVERRIDE_OE;
|
||||
|
||||
gpio_hardware_control(spi_config[bus].mosi_pin);
|
||||
gpio_hardware_control(spi_config[bus].miso_pin);
|
||||
gpio_hardware_control(spi_config[bus].sck_pin);
|
||||
gpio_hardware_control(spi_config[bus].cs_pin);
|
||||
DEBUG("%s: bus=%u\n", __FUNCTION__, bus);
|
||||
/* select values according to SPI device */
|
||||
cc2538_ioc_sel_t txd = spi_config[bus].num ? SSI1_TXD : SSI0_TXD;
|
||||
cc2538_ioc_sel_t clk = spi_config[bus].num ? SSI1_CLK_OUT : SSI0_CLK_OUT;
|
||||
cc2538_ioc_sel_t fss = spi_config[bus].num ? SSI1_FSS_OUT : SSI0_FSS_OUT;
|
||||
cc2538_ioc_pin_t rxd = spi_config[bus].num ? SSI1_RXD : SSI0_RXD;
|
||||
/* init pin functions and multiplexing */
|
||||
gpio_init_mux(spi_config[bus].mosi_pin, OVERRIDE_ENABLE, txd, GPIO_MUX_NONE);
|
||||
gpio_init_mux(spi_config[bus].sck_pin, OVERRIDE_ENABLE, clk, GPIO_MUX_NONE);
|
||||
gpio_init_mux(spi_config[bus].cs_pin, OVERRIDE_ENABLE, fss, GPIO_MUX_NONE);
|
||||
gpio_init_mux(spi_config[bus].miso_pin, OVERRIDE_DISABLE, GPIO_MUX_NONE, rxd);
|
||||
}
|
||||
|
||||
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
DEBUG("%s: bus=%u\n", __FUNCTION__, bus);
|
||||
(void) cs;
|
||||
/* lock the bus */
|
||||
mutex_lock(&locks[bus]);
|
||||
@ -117,6 +113,7 @@ int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
DEBUG("%s: bus=%u\n", __FUNCTION__, bus);
|
||||
/* disable and power off device */
|
||||
dev(bus)->CR1 = 0;
|
||||
poweroff(bus);
|
||||
@ -127,6 +124,8 @@ void spi_release(spi_t bus)
|
||||
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
DEBUG("%s: bus=%u, len=%u\n", __FUNCTION__, bus, (unsigned)len);
|
||||
|
||||
const uint8_t *out_buf = out;
|
||||
uint8_t *in_buf = in;
|
||||
|
||||
@ -167,8 +166,8 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
while (!(dev(bus)->SR & SSI_SR_RNE)){}
|
||||
in_buf[i] = dev(bus)->DR;
|
||||
}
|
||||
/* wait until no more busy */
|
||||
while ((dev(bus)->SR & SSI_SR_BSY)) {}
|
||||
/* wait until no more busy */
|
||||
while ((dev(bus)->SR & SSI_SR_BSY)) {}
|
||||
}
|
||||
|
||||
if ((!cont) && (cs != SPI_CS_UNDEF)) {
|
||||
|
Loading…
Reference in New Issue
Block a user