[spi] spi slave mode for general interface and lpc arch

This commit is contained in:
Gautier Hattenberger
2012-11-09 23:15:13 +01:00
parent dc01c7f1a8
commit 3c97058ae4
5 changed files with 246 additions and 101 deletions
+139 -70
View File
@@ -304,6 +304,63 @@ __attribute__ ((always_inline)) static inline void SpiAutomaton(struct spi_perip
}
}
__attribute__ ((always_inline)) static inline void SpiSlaveStart(struct spi_periph* p, struct spi_transaction* t) {
p->status = SPIRunning;
t->status = SPITransRunning;
// callback function before transaction
if (t->before_cb != 0) t->before_cb(t);
// start spi transaction
SpiEnable(p);
SpiInitBuf(p,t);
SpiEnableTxi(p); // enable tx fifo half empty interrupt
//SpiEnableRti(p); // enable rx timeout interrupt
}
__attribute__ ((always_inline)) static inline void SpiSlaveAutomaton(struct spi_periph* p) {
struct spi_transaction* trans = p->trans[p->trans_extract_idx];
/* Tx fifo is half empty */
if (bit_is_set(((sspRegs_t *)(p->reg_addr))->mis, TXMIS)) {
SpiTransmit(p, trans);
SpiReceive(p, trans);
SpiEnableRti(p);
}
/* Rx fifo is not empty and no receive took place in the last 32 bits period */
if (bit_is_set(((sspRegs_t *)(p->reg_addr))->mis, RTMIS)) {
SpiReceive(p, trans);
SpiClearRti(p); /* clear interrupt */
SpiDisableRti(p);
// callback function after transaction
if (trans->after_cb != 0) trans->after_cb(trans);
SpiDisable(p);
// end transaction with success
trans->status = SPITransSuccess;
p->status = SPIIdle;
}
}
/* SSP (SPI1) pins (UM10120_1.pdf page 76)
P0.17 SCK PINSEL1 2 << 2
P0.18 MISO PINSEL1 2 << 4
P0.19 MOSI PINSEL1 2 << 6
P0.20 SS PINSEL1 2 << 8
*/
#define SSP_PINSEL1_SCK (2 << 2)
#define SSP_PINSEL1_MISO (2 << 4)
#define SSP_PINSEL1_MOSI (2 << 6)
#define SSP_PINSEL1_SSEL (2 << 8)
/** default initial settings */
#ifndef SPI1_VIC_SLOT
#define SPI1_VIC_SLOT 7
#endif
/*
*
* SPI Master code
@@ -311,7 +368,7 @@ __attribute__ ((always_inline)) static inline void SpiAutomaton(struct spi_perip
*
*/
#ifdef SPI_MASTER
#if SPI_MASTER
#if USE_SPI0
@@ -339,34 +396,18 @@ void spi0_arch_init(void) {
#if USE_SPI1
/** default initial settings */
#ifndef SPI1_VIC_SLOT
#define SPI1_VIC_SLOT 7
#endif
/* SSP (SPI1) pins (UM10120_1.pdf page 76)
P0.17 SCK PINSEL1 2 << 2
P0.18 MISO PINSEL1 2 << 4
P0.19 MOSI PINSEL1 2 << 6
P0.20 SS PINSEL1 2 << 8
*/
#define PINSEL1_SCK (2 << 2)
#define PINSEL1_MISO (2 << 4)
#define PINSEL1_MOSI (2 << 6)
#define PINSEL1_SSEL (2 << 8)
/* SSPCR0 settings */
#define SSP_DSS 0x07 << 0 /* data size : 8 bits */
#define SSP_FRF 0x00 << 4 /* frame format : SPI */
#define SSP_CPOL 0x00 << 6 /* clock polarity : SCK idles low */
#define SSP_CPHA 0x00 << 7 /* clock phase : data captured on first clock transition */
#define SSP_SCR 0x0F << 8 /* serial clock rate : divide by 16 */
#define MASTER_SSP_DSS 0x07 << 0 /* data size : 8 bits */
#define MASTER_SSP_FRF 0x00 << 4 /* frame format : SPI */
#define MASTER_SSP_CPOL 0x00 << 6 /* clock polarity : SCK idles low */
#define MASTER_SSP_CPHA 0x00 << 7 /* clock phase : data captured on first clock transition */
#define MASTER_SSP_SCR 0x0F << 8 /* serial clock rate : divide by 16 */
/* SSPCR1 settings */
#define SSP_LBM 0x00 << 0 /* loopback mode : disabled */
#define SSP_SSE 0x00 << 1 /* SSP enable : disabled */
#define SSP_MS 0x00 << 2 /* master slave mode : master */
#define SSP_SOD 0x00 << 3 /* slave output disable : don't care when master */
#define MASTER_SSP_LBM 0x00 << 0 /* loopback mode : disabled */
#define MASTER_SSP_SSE 0x00 << 1 /* SSP enable : disabled */
#define MASTER_SSP_MS 0x00 << 2 /* master slave mode : master */
#define MASTER_SSP_SOD 0x00 << 3 /* slave output disable : don't care when master */
/** Clock prescaler.
* SPI clock rate = PCLK / (CPSR*(SCR+1))
@@ -396,11 +437,11 @@ void spi1_arch_init(void) {
spi1.init_struct = (void*)(&spi1_vic_slot);
/* setup pins for SSP (SCK, MISO, MOSI) */
PINSEL1 |= PINSEL1_SCK | PINSEL1_MISO | PINSEL1_MOSI;
PINSEL1 |= SSP_PINSEL1_SCK | SSP_PINSEL1_MISO | SSP_PINSEL1_MOSI;
/* setup SSP */
SSPCR0 = SSP_DSS | SSP_FRF | SSP_CPOL | SSP_CPHA | SSP_SCR;
SSPCR1 = SSP_LBM | SSP_MS | SSP_SOD;
SSPCR0 = MASTER_SSP_DSS | MASTER_SSP_FRF | MASTER_SSP_CPOL | MASTER_SSP_CPHA | MASTER_SSP_SCR;
SSPCR1 = MASTER_SSP_LBM | MASTER_SSP_MS | MASTER_SSP_SOD;
SSPCPSR = SSPCPSR_VAL; /* Prescaler */
/* initialize interrupt vector */
@@ -516,12 +557,7 @@ bool_t spi_resume(struct spi_periph* p, uint8_t slave) {
* FIXME it is probably not working at all right now
*
*/
#ifdef SPI_SLAVE
volatile uint8_t spi_tx_idx;
volatile uint8_t spi_rx_idx;
void SPI1_ISR(void) __attribute__((naked));
#if SPI_SLAVE
/* set SSP input clock, PCLK / CPSDVSR = 468.75kHz */
@@ -542,57 +578,90 @@ void SPI1_ISR(void) __attribute__((naked));
#endif
#endif
#if USE_SPI0_SLAVE
#error SPI0 in slave mode is not implemented yet, sorry
#endif
#if USE_SPI1_SLAVE
/* SSPCR0 settings */
#define SSP_DSS 0x07 << 0 /* data size : 8 bits */
#define SSP_FRF 0x00 << 4 /* frame format : SPI */
#define SSP_CPOL 0x00 << 6 /* clock polarity : idle low */
#define SSP_CPHA 0x01 << 7 /* clock phase : 1 */
#define SSP_SCR 0x0F << 8 /* serial clock rate : 29.3kHz, SSP input clock / 16 */
#define SLAVE_SSP_DSS 0x07 << 0 /* data size : 8 bits */
#define SLAVE_SSP_FRF 0x00 << 4 /* frame format : SPI */
#define SLAVE_SSP_CPOL 0x00 << 6 /* clock polarity : idle low */
#define SLAVE_SSP_CPHA 0x01 << 7 /* clock phase : 1 */
#define SLAVE_SSP_SCR 0x0F << 8 /* serial clock rate : 29.3kHz, SSP input clock / 16 */
/* SSPCR1 settings */
#define SSP_LBM 0x00 << 0 /* loopback mode : disabled */
#define SSP_SSE 0x00 << 1 /* SSP enable : disabled */
#define SSP_MS 0x01 << 2 /* master slave mode : slave */
#define SSP_SOD 0x00 << 3 /* slave output disable : disabled */
#define SLAVE_SSP_LBM 0x00 << 0 /* loopback mode : disabled */
#define SLAVE_SSP_SSE 0x00 << 1 /* SSP enable : disabled */
#define SLAVE_SSP_MS 0x01 << 2 /* master slave mode : slave */
#define SLAVE_SSP_SOD 0x00 << 3 /* slave output disable : disabled */
void spi1_slave_ISR(void) __attribute__((naked));
void spi1_slave_ISR(void) {
ISR_ENTRY();
SpiSlaveAutomaton(&spi1);
VICVectAddr = 0x00000000; /* clear this interrupt from the VIC */
ISR_EXIT();
}
void spi1_slave_arch_init(void) {
spi1.reg_addr = SPI1;
void spi_slave_init( void ) {
/* setup pins for SSP (SCK, MISO, MOSI, SS) */
PINSEL1 |= PINSEL1_SCK | PINSEL1_MISO | PINSEL1_MOSI | PINSEL1_SSEL;
PINSEL1 |= SSP_PINSEL1_SCK | SSP_PINSEL1_MISO | SSP_PINSEL1_MOSI | SSP_PINSEL1_SSEL;
/* setup SSP */
SSPCR0 = SSP_DSS | SSP_FRF | SSP_CPOL | SSP_CPHA | SSP_SCR;
SSPCR1 = SSP_LBM | SSP_MS | SSP_SOD;
SSPCR0 = SLAVE_SSP_DSS | SLAVE_SSP_FRF | SLAVE_SSP_CPOL | SLAVE_SSP_CPHA | SLAVE_SSP_SCR;
SSPCR1 = SLAVE_SSP_LBM | SLAVE_SSP_MS | SLAVE_SSP_SOD;
SSPCPSR = CPSDVSR; /* Prescaler, UM10120_1.pdf page 167 */
/* initialize interrupt vector */
VICIntSelect &= ~VIC_BIT(VIC_SPI1); // SPI1 selected as IRQ
VICIntEnable = VIC_BIT(VIC_SPI1); // SPI1 interrupt enabled
VICVectCntl7 = VIC_ENABLE | VIC_SPI1;
VICVectAddr7 = (uint32_t)SPI1_ISR; // address of the ISR
VICIntSelect &= ~VIC_BIT(VIC_SPI1); /* SPI1 selected as IRQ */
VICIntEnable = VIC_BIT(VIC_SPI1); /* SPI1 interrupt enabled */
_VIC_CNTL(SPI1_VIC_SLOT) = VIC_ENABLE | VIC_SPI1;
_VIC_ADDR(SPI1_VIC_SLOT) = (uint32_t)spi1_slave_ISR; /* address of the ISR */
/* enable SPI */
// SpiEnable();
}
void SPI1_ISR(void) {
ISR_ENTRY();
#endif
if (bit_is_set(SSPMIS, TXMIS)) { /* Tx half empty */
SpiTransmit();
SpiReceive();
SpiEnableRti();
}
/* Register one (and only one) transaction to use spi as slave */
bool_t spi_slave_register(struct spi_periph* p, struct spi_transaction* t) {
if ( bit_is_set(SSPMIS, RTMIS)) { /* Rx timeout */
SpiReceive();
SpiClearRti(); /* clear interrupt */
SpiDisableRti();
SpiDisable();
spi_message_received = TRUE;
}
if (p->trans_insert_idx >= 1) {
t->status = SPITransFailed;
return FALSE;
}
t->status = SPITransPending;
p->status = SPIIdle;
p->trans[p->trans_insert_idx] = t; // No need to disable interrupts, only one transaction
p->trans_insert_idx = 1;
VICVectAddr = 0x00000000; /* clear this interrupt from the VIC */
ISR_EXIT();
// handle spi options (CPOL, CPHA, data size,...)
if (t->cpol == SPICpolIdleHigh) SpiSetCPOL(p);
else SpiClearCPOL(p);
if (t->cpha == SPICphaEdge2) SpiSetCPHA(p);
else SpiClearCPHA(p);
SpiSetDataSize(p, t->dss);
return TRUE;
}
bool_t spi_slave_wait(struct spi_periph* p) {
if (p->trans_insert_idx == 0) {
// no transaction registered
return FALSE;
}
// Start waiting
SpiSlaveStart(p, p->trans[p->trans_extract_idx]);
return TRUE;
}
#endif /* SPI_SLAVE */
@@ -33,8 +33,6 @@
#include "LPC21xx.h"
#include BOARD_CONFIG
// SSP is on SPI1 on lpc
#if defined USE_SSP & !USE_SPI1
#define USE_SP11 1
@@ -44,19 +42,4 @@
#define SPI1_VIC_SLOT SSP_VIC_SLOT
#endif
#ifdef SPI_SLAVE
extern volatile uint8_t spi_tx_idx;
extern volatile uint8_t spi_rx_idx;
#endif /* SPI_SLAVE */
#ifdef SPI_MASTER
#endif /* SPI_MASTER */
#endif /* SPI_ARCH_H */
+10 -1
View File
@@ -46,7 +46,7 @@
#ifdef USE_USB_SERIAL
#include "mcu_periph/usb_serial.h"
#endif
#if USE_SPI0 || USE_SPI1 || USE_SPI2
#if USE_SPI0 || USE_SPI1 || USE_SPI2 || USE_SPI0_SLAVE || USE_SPI1_SLAVE || USE_SPI2_SLAVE
#include "mcu_periph/spi.h"
#endif
#ifdef USE_DAC
@@ -109,6 +109,15 @@ void mcu_init(void) {
#if USE_SPI2
spi2_init();
#endif
#if USE_SPI0_SLAVE
spi0_slave_init();
#endif
#if USE_SPI1_SLAVE
spi1_slave_init();
#endif
#if USE_SPI2_SLAVE
spi2_slave_init();
#endif
#ifdef USE_DAC
dac_init();
#endif
+41 -6
View File
@@ -28,7 +28,7 @@
#include "std.h"
#include "mcu_periph/spi.h"
#ifdef SPI_MASTER
#if SPI_MASTER
#if USE_SPI0
struct spi_periph spi0;
@@ -64,16 +64,51 @@ void spi_init(struct spi_periph* p) {
p->trans_insert_idx = 0;
p->trans_extract_idx = 0;
p->status = SPIIdle;
p->mode = SPIMaster;
p->suspend = FALSE;
}
#endif /* SPI_MASTER */
#ifdef SPI_SLAVE
#if SPI_SLAVE
uint8_t* spi_buffer_input;
uint8_t* spi_buffer_output;
uint8_t spi_buffer_length;
volatile bool_t spi_message_received;
#if USE_SPI0_SLAVE
struct spi_periph spi0;
void spi0_slave_init(void) {
spi_slave_init(&spi0);
spi0_slave_arch_init();
}
#endif
#if USE_SPI1_SLAVE
struct spi_periph spi1;
void spi1_slave_init(void) {
spi_slave_init(&spi1);
spi1_slave_arch_init();
}
#endif
#if USE_SPI2_SLAVE
struct spi_periph spi2;
void spi2_slave_init(void) {
spi_slave_init(&spi2);
spi2_slave_arch_init();
}
#endif
extern void spi_slave_init(struct spi_periph* p) {
p->trans_insert_idx = 0;
p->trans_extract_idx = 0;
p->status = SPIIdle;
p->mode = SPISlave;
p->suspend = FALSE;
}
#endif /* SPI_SLAVE */
+56 -7
View File
@@ -167,7 +167,7 @@ struct spi_periph {
volatile uint8_t suspend;
};
#ifdef SPI_MASTER
#if SPI_MASTER
#define SPI_SLAVE0 0
#define SPI_SLAVE1 1
@@ -260,16 +260,65 @@ extern bool_t spi_resume(struct spi_periph* p, uint8_t slave);
#endif /* SPI_MASTER */
#ifdef SPI_SLAVE
#if SPI_SLAVE
extern uint8_t* spi_buffer_input;
extern uint8_t* spi_buffer_output;
extern uint8_t spi_buffer_length;
#if USE_SPI0_SLAVE
extern volatile bool_t spi_message_received;
extern struct spi_periph spi0;
extern void spi0_slave_init(void);
void spi_slave_init(void);
/** Architecture dependant SPI1 initialization.
* Must be implemented by underlying architecture
*/
extern void spi0_slave_arch_init(void);
#endif
#if USE_SPI1_SLAVE
extern struct spi_periph spi1;
extern void spi1_slave_init(void);
/** Architecture dependant SPI1 initialization.
* Must be implemented by underlying architecture
*/
extern void spi1_slave_arch_init(void);
#endif
#if USE_SPI2_SLAVE
extern struct spi_periph spi2;
extern void spi2_slave_init(void);
/** Architecture dependant SPI1 initialization.
* Must be implemented by underlying architecture
*/
extern void spi2_slave_arch_init(void);
#endif
/** Initialize a spi peripheral in slave mode.
* @param p spi peripheral to be configured
*/
extern void spi_slave_init(struct spi_periph* p);
/** Register a spi transaction in slave mode (only one transaction can be registered).
* Must be implemented by the underlying architecture
* @param p spi peripheral to be used
* @param t spi transaction
* @return return true if registered with success
*/
extern bool_t spi_slave_register(struct spi_periph* p, struct spi_transaction* t);
/** Initialized and wait for the next transaction.
* If a transaction is registered for this peripheral, the spi will be
* waiting for a communication from the master
* @param p spi peripheral to be used
* @return return true if a transaction was register for this peripheral
*/
extern bool_t spi_slave_wait(struct spi_periph* p);
#endif /* SPI_SLAVE */
#endif /* SPI_H */