mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-05-29 19:17:28 +08:00
[spi] spi slave mode for general interface and lpc arch
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user