mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
Merge pull request #13246 from benpicco/lpc23xx-spi
cpu/lpc2387: make SPI configurable
This commit is contained in:
commit
b44cf48a87
@ -65,7 +65,19 @@ static const uart_conf_t uart_config[] = {
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SPI0,
|
||||
.pinsel_mosi = 3,
|
||||
.pinsel_miso = 3,
|
||||
.pinsel_clk = 3,
|
||||
.pinsel_msk_mosi = (BIT16 | BIT17),
|
||||
.pinsel_msk_miso = (BIT14 | BIT15),
|
||||
.pinsel_msk_clk = (BIT8 | BIT9),
|
||||
},
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (1)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -71,11 +71,20 @@ static const uart_conf_t uart_config[] = {
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
*
|
||||
* The SPI implementation is very much fixed, so we don't need to configure
|
||||
* anything besides the mandatory SPI_NUMOF.
|
||||
* @{
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SPI0,
|
||||
.pinsel_mosi = 3,
|
||||
.pinsel_miso = 3,
|
||||
.pinsel_clk = 3,
|
||||
.pinsel_msk_mosi = (BIT16 | BIT17), /* P1.24 */
|
||||
.pinsel_msk_miso = (BIT14 | BIT15), /* P1.23 */
|
||||
.pinsel_msk_clk = (BIT8 | BIT9), /* P1.20 */
|
||||
},
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (1)
|
||||
/** @} */
|
||||
|
||||
|
@ -113,11 +113,20 @@ static const uart_conf_t uart_config[] = {
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
*
|
||||
* The SPI implementation is very much fixed, so we don't need to configure
|
||||
* anything besides the mandatory SPI_NUMOF.
|
||||
* @{
|
||||
*/
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.dev = SPI0,
|
||||
.pinsel_mosi = 3,
|
||||
.pinsel_miso = 3,
|
||||
.pinsel_clk = 3,
|
||||
.pinsel_msk_mosi = (BIT16 | BIT17),
|
||||
.pinsel_msk_miso = (BIT14 | BIT15),
|
||||
.pinsel_msk_clk = (BIT8 | BIT9),
|
||||
},
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (1)
|
||||
/** @} */
|
||||
|
||||
|
@ -110,6 +110,19 @@ typedef struct {
|
||||
uint32_t pinsel_msk_tx; /**< TX PINSEL Mask */
|
||||
} uart_conf_t;
|
||||
|
||||
/**
|
||||
* @brief SPI device configuration
|
||||
*/
|
||||
typedef struct {
|
||||
lpc23xx_spi_t *dev; /**< pointer to the SPI device */
|
||||
uint8_t pinsel_mosi; /**< PINSEL# of the MOSI pin */
|
||||
uint8_t pinsel_miso; /**< PINSEL# of the MISO pin */
|
||||
uint8_t pinsel_clk; /**< PINSEL# of the CLK pin */
|
||||
uint32_t pinsel_msk_mosi; /**< MOSI PINSEL Mask */
|
||||
uint32_t pinsel_msk_miso; /**< MISO PINSEL Mask */
|
||||
uint32_t pinsel_msk_clk; /**< CLK PINSEL Mask */
|
||||
} spi_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Number of available timer channels
|
||||
*/
|
||||
|
18
cpu/lpc2387/include/vendor/lpc23xx.h
vendored
18
cpu/lpc2387/include/vendor/lpc23xx.h
vendored
@ -809,8 +809,25 @@ typedef struct {
|
||||
#define S0SPCCR (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x0C))
|
||||
#define S0SPINT (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x1C))
|
||||
|
||||
/**
|
||||
* @brief Generic SPI register map
|
||||
*/
|
||||
typedef struct {
|
||||
REG32 CR0; /**< Control Register 0 */
|
||||
REG32 CR1; /**< Control Register 1 */
|
||||
REG32 DR; /**< Data Register */
|
||||
REG32 SR; /**< Status Register */
|
||||
REG32 CPSR; /**< Clock Prescale Register */
|
||||
REG32 IMSC; /**< Interrupt Mask Set/Clear Register */
|
||||
REG32 RIS; /**< Raw Interrupt Status Register */
|
||||
REG32 MIS; /**< Masked Interrupt Status Register */
|
||||
REG32 ICR; /**< Interrupt Clear Register */
|
||||
REG32 DMACR; /**< DMA Control Register */
|
||||
} lpc23xx_spi_t;
|
||||
|
||||
/* SSP0 Controller */
|
||||
#define SSP0_BASE_ADDR 0xE0068000
|
||||
#define SPI0 ((lpc23xx_spi_t *)SSP0_BASE_ADDR)
|
||||
#define SSP0CR0 (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x00))
|
||||
#define SSP0CR1 (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x04))
|
||||
#define SSP0DR (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x08))
|
||||
@ -824,6 +841,7 @@ typedef struct {
|
||||
|
||||
/* SSP1 Controller */
|
||||
#define SSP1_BASE_ADDR 0xE0030000
|
||||
#define SPI1 ((lpc23xx_spi_t *)SSP1_BASE_ADDR)
|
||||
#define SSP1CR0 (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x00))
|
||||
#define SSP1CR1 (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x04))
|
||||
#define SSP1DR (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x08))
|
||||
|
@ -34,90 +34,137 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define SPI_TX_EMPTY (SSP0SR & SSPSR_TFE)
|
||||
#define SPI_BUSY (SSP0SR & SSPSR_BSY)
|
||||
#define SPI_RX_AVAIL (SSP0SR & SSPSR_RNE)
|
||||
/**
|
||||
* @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 lpc23xx_spi_t *get_dev(spi_t dev)
|
||||
{
|
||||
return spi_config[dev].dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each SPI device
|
||||
*/
|
||||
static mutex_t lock = MUTEX_INIT;
|
||||
static mutex_t lock[SPI_NUMOF];
|
||||
|
||||
static void _power_off(spi_t bus)
|
||||
{
|
||||
switch ((uint32_t) get_dev(bus)) {
|
||||
case SSP0_BASE_ADDR:
|
||||
PCONP &= ~PCSSP0;
|
||||
break;
|
||||
case SSP1_BASE_ADDR:
|
||||
PCONP &= ~PCSSP1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _power_on(spi_t bus)
|
||||
{
|
||||
switch ((uint32_t) get_dev(bus)) {
|
||||
case SSP0_BASE_ADDR:
|
||||
PCONP |= PCSSP0;
|
||||
break;
|
||||
case SSP1_BASE_ADDR:
|
||||
PCONP |= PCSSP1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void spi_init(spi_t bus)
|
||||
{
|
||||
assert(bus == SPI_DEV(0));
|
||||
assert(bus < SPI_NUMOF);
|
||||
|
||||
/* configure pins */
|
||||
spi_init_pins(bus);
|
||||
|
||||
/* power off the bus (default is on) */
|
||||
PCONP &= ~(PCSSP0);
|
||||
_power_off(bus);
|
||||
}
|
||||
|
||||
void spi_init_pins(spi_t bus)
|
||||
{
|
||||
(void) bus;
|
||||
const spi_conf_t *cfg = &spi_config[bus];
|
||||
|
||||
PINSEL3 |= (BIT8 | BIT9); /* SCLK */
|
||||
PINSEL3 |= (BIT14 | BIT15); /* MISO */
|
||||
PINSEL3 |= (BIT16 | BIT17); /* MOSI */
|
||||
*(&PINSEL0 + cfg->pinsel_mosi) |= cfg->pinsel_msk_mosi;
|
||||
*(&PINSEL0 + cfg->pinsel_miso) |= cfg->pinsel_msk_miso;
|
||||
*(&PINSEL0 + cfg->pinsel_clk) |= cfg->pinsel_msk_clk;
|
||||
}
|
||||
|
||||
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
(void) bus;
|
||||
(void) cs;
|
||||
|
||||
uint32_t pclksel;
|
||||
uint32_t cpsr;
|
||||
|
||||
lpc23xx_spi_t *dev = get_dev(bus);
|
||||
|
||||
/* only support for mode 0 at the moment */
|
||||
if (mode != SPI_MODE_0) {
|
||||
return SPI_NOMODE;
|
||||
}
|
||||
|
||||
/* lock bus */
|
||||
mutex_lock(&lock);
|
||||
mutex_lock(&lock[bus]);
|
||||
|
||||
/* power on */
|
||||
PCONP |= (PCSSP0);
|
||||
_power_on(bus);
|
||||
|
||||
/* interface setup */
|
||||
SSP0CR0 = 7;
|
||||
dev->CR0 = 7;
|
||||
|
||||
/* configure bus clock */
|
||||
lpc2387_pclk_scale(CLOCK_CORECLOCK / 1000, (uint32_t)clk, &pclksel, &cpsr);
|
||||
PCLKSEL1 &= ~(BIT10 | BIT11); /* CCLK to PCLK divider*/
|
||||
PCLKSEL1 |= pclksel << 10;
|
||||
SSP0CPSR = cpsr;
|
||||
|
||||
switch ((uint32_t)dev) {
|
||||
case SSP0_BASE_ADDR:
|
||||
PCLKSEL1 &= ~(BIT10 | BIT11); /* CCLK to PCLK divider*/
|
||||
PCLKSEL1 |= pclksel << 10;
|
||||
break;
|
||||
case SSP1_BASE_ADDR:
|
||||
PCLKSEL0 &= ~(BIT20 | BIT21); /* CCLK to PCLK divider*/
|
||||
PCLKSEL0 |= pclksel << 20;
|
||||
break;
|
||||
}
|
||||
|
||||
dev->CPSR = cpsr;
|
||||
|
||||
/* enable the bus */
|
||||
SSP0CR1 |= BIT1;
|
||||
dev->CR1 |= BIT1;
|
||||
|
||||
/* clear RxFIFO */
|
||||
int dummy;
|
||||
while (SPI_RX_AVAIL) { /* while RNE (Receive FIFO Not Empty)...*/
|
||||
dummy = SSP0DR; /* read data*/
|
||||
while (dev->SR & SSPSR_RNE) { /* while RNE (Receive FIFO Not Empty)...*/
|
||||
dev->DR; /* read data*/
|
||||
}
|
||||
(void) dummy; /* to suppress unused-but-set-variable */
|
||||
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
(void) bus;
|
||||
lpc23xx_spi_t *dev = get_dev(bus);
|
||||
|
||||
/* disable, power off, and release the bus */
|
||||
SSP0CR1 &= ~(BIT1);
|
||||
PCONP &= ~(PCSSP0);
|
||||
mutex_unlock(&lock);
|
||||
dev->CR1 &= ~BIT1;
|
||||
|
||||
_power_off(bus);
|
||||
|
||||
mutex_unlock(&lock[bus]);
|
||||
}
|
||||
|
||||
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
(void) bus;
|
||||
|
||||
const uint8_t *out_buf = out;
|
||||
uint8_t *in_buf = in;
|
||||
|
||||
lpc23xx_spi_t *dev = get_dev(bus);
|
||||
|
||||
assert(out_buf || in_buf);
|
||||
|
||||
if (cs != SPI_CS_UNDEF) {
|
||||
@ -126,11 +173,13 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t tmp = (out_buf) ? out_buf[i] : 0;
|
||||
while (!SPI_TX_EMPTY) {}
|
||||
SSP0DR = tmp;
|
||||
while (SPI_BUSY) {}
|
||||
while (!SPI_RX_AVAIL) {}
|
||||
tmp = (uint8_t)SSP0DR;
|
||||
/* wait for TX buffer empty */
|
||||
while (!(dev->SR & SSPSR_TFE)) {}
|
||||
dev->DR = tmp;
|
||||
while (dev->SR & SSPSR_BSY) {}
|
||||
/* wait for RX not empty */
|
||||
while (!(dev->SR & SSPSR_RNE)) {}
|
||||
tmp = (uint8_t)dev->DR;
|
||||
if (in_buf) {
|
||||
in_buf[i] = tmp;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user