diff --git a/conf/autopilot/rotorcraft.makefile b/conf/autopilot/rotorcraft.makefile index 6db166a9df..5bbb95a122 100644 --- a/conf/autopilot/rotorcraft.makefile +++ b/conf/autopilot/rotorcraft.makefile @@ -144,7 +144,7 @@ ap.CFLAGS += -DUSE_I2C2 else ifeq ($(BOARD), navgo) include $(CFG_ROTORCRAFT)/spi.makefile ap.CFLAGS += -DUSE_SPI_SLAVE0 -ap.CFLAGS += -DSPI_NO_UNSELECT_SLAVE +ap.CFLAGS += -DUSE_SPI1 ap.CFLAGS += -DSPI_MASTER ap.srcs += peripherals/mcp355x.c endif diff --git a/sw/airborne/arch/lpc21/include/LPC21xx.h b/sw/airborne/arch/lpc21/include/LPC21xx.h index b57c5d2d22..4ec0f651d0 100644 --- a/sw/airborne/arch/lpc21/include/LPC21xx.h +++ b/sw/airborne/arch/lpc21/include/LPC21xx.h @@ -207,27 +207,59 @@ /////////////////////////////////////////////////////////////////////////////// // Serial Peripheral Interface 1 (SPI1) -#define SPI1 ((spiRegs_t *)0xE0030000) +#define SPI1 ((sspRegs_t *)0xE0068000) // SPI1 Registers -#define S1SPCR SPI1->cr /* Control Register */ -#define S1SPSR SPI1->sr /* Status Register */ -#define S1SPDR SPI1->dr /* Data Register */ -#define S1SPCCR SPI1->ccr /* Clock Counter Register */ -#define S1SPINT SPI1->flag /* Interrupt Flag Register */ +//#define S1SPCR SPI1->cr /* Control Register */ +//#define S1SPSR SPI1->sr /* Status Register */ +//#define S1SPDR SPI1->dr /* Data Register */ +//#define S1SPCCR SPI1->ccr /* Clock Counter Register */ +//#define S1SPINT SPI1->flag /* Interrupt Flag Register */ /* S1SPINT bits definition */ #define SPI1IF 0 -#define SSPCR0 (*(REG16*) 0xE0068000) /* Control Register 0 */ -#define SSPCR1 (*(REG_8*) 0xE0068004) /* Control Register 1 */ -#define SSPDR (*(REG16*) 0xE0068008) /* Data register */ -#define SSPSR (*(REG_8*) 0xE006800C) /* Status register */ -#define SSPCPSR (*(REG_8*) 0xE0068010) /* Clock prescale register */ -#define SSPIMSC (*(REG_8*) 0xE0068014) /* Interrupt mask register */ -#define SSPRIS (*(REG_8*) 0xE0068018) /* Raw interrupt status register */ -#define SSPMIS (*(REG_8*) 0xE006801C) /* Masked interrupt status register */ -#define SSPICR (*(REG_8*) 0xE0068020) /* Interrupt clear register */ +#define SSPCR0 SPI1->cr0 /* Control Register 0 */ +#define SSPCR1 SPI1->cr1 /* Control Register 1 */ +#define SSPDR SPI1->dr /* Data register */ +#define SSPSR SPI1->sr /* Status register */ +#define SSPCPSR SPI1->cpsr /* Clock prescale register */ +#define SSPIMSC SPI1->imsc /* Interrupt mask register */ +#define SSPRIS SPI1->ris /* Raw interrupt status register */ +#define SSPMIS SPI1->mis /* Masked interrupt status register */ +#define SSPICR SPI1->icr /* Interrupt clear register */ + +//#define SSPCR0 (*(REG16*) 0xE0068000) /* Control Register 0 */ +//#define SSPCR1 (*(REG_8*) 0xE0068004) /* Control Register 1 */ +//#define SSPDR (*(REG16*) 0xE0068008) /* Data register */ +//#define SSPSR (*(REG_8*) 0xE006800C) /* Status register */ +//#define SSPCPSR (*(REG_8*) 0xE0068010) /* Clock prescale register */ +//#define SSPIMSC (*(REG_8*) 0xE0068014) /* Interrupt mask register */ +//#define SSPRIS (*(REG_8*) 0xE0068018) /* Raw interrupt status register */ +//#define SSPMIS (*(REG_8*) 0xE006801C) /* Masked interrupt status register */ +//#define SSPICR (*(REG_8*) 0xE0068020) /* Interrupt clear register */ + +/* SSPCR0 bits definition */ +#define DSS 0 +#define FRF 4 +#define CPOL 6 +#define CPHA 7 +#define SCR 8 + +/* SSPDSS values definition */ +#define DSS_VAL4 0x3 +#define DSS_VAL5 0x4 +#define DSS_VAL6 0x5 +#define DSS_VAL7 0x6 +#define DSS_VAL8 0x7 +#define DSS_VAL9 0x8 +#define DSS_VAL10 0x9 +#define DSS_VAL11 0xA +#define DSS_VAL12 0xB +#define DSS_VAL13 0XC +#define DSS_VAL14 0xD +#define DSS_VAL15 0xE +#define DSS_VAL16 0xF /* SSPCR1 bits definition */ #define LBM 0 diff --git a/sw/airborne/arch/lpc21/include/lpcSPI.h b/sw/airborne/arch/lpc21/include/lpcSPI.h index bc089c2038..6faee84fcc 100644 --- a/sw/airborne/arch/lpc21/include/lpcSPI.h +++ b/sw/airborne/arch/lpc21/include/lpcSPI.h @@ -35,4 +35,27 @@ typedef struct REG_8 _pad7[3]; } spiRegs_t; +// Serial Serial Port Registers (SSP/SPI) +typedef struct +{ + REG_8 cr0; // Control Register 0 + REG_8 _pad0[3]; + REG_8 cr1; // Control Register 1 + REG_8 _pad1[3]; + REG_8 dr; // Data Register + REG_8 _pad2[3]; + REG_8 sr; // Status Register + REG_8 _pad3[3]; + REG_8 cpsr; // Clock Prescale Register + REG_8 _pad4[3]; + REG_8 imsc; // Interrupt Mask Set and Clear Register + REG_8 _pad5[3]; + REG_8 ris; // Raw Interrupt Status Register + REG_8 _pad6[3]; + REG_8 mis; // Masked Interrupt Status Register + REG_8 _pad7[3]; + REG_8 icr; // Interrupt Clear Register + REG_8 _pad8[3]; +} sspRegs_t; + #endif diff --git a/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c b/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c index d7286e6dcd..c50865dac8 100644 --- a/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c +++ b/sw/airborne/arch/lpc21/mcu_periph/spi_arch.c @@ -29,10 +29,272 @@ #include "std.h" #include "LPC21xx.h" +#include "interrupt_hw.h" #include "armVIC.h" +#include BOARD_CONFIG -volatile uint8_t spi_tx_idx; -volatile uint8_t spi_rx_idx; +// FIXME +// current implementation only works for SPI1 (SSP) + +/** Slave selection functions and macros + * + * + * Slave0 select : P0.20 PINSEL1 00 << 8 + * Slave1 select : P1.20 + * + */ + +#define SPI_SELECT_SLAVE_IO__(port, reg) IO ## port ## reg +#define SPI_SELECT_SLAVE_IO_(port, reg) SPI_SELECT_SLAVE_IO__(port, reg) + +#define SPI_SELECT_SLAVE0_IODIR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE0_PORT, DIR) +#define SPI_SELECT_SLAVE0_IOCLR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE0_PORT, CLR) +#define SPI_SELECT_SLAVE0_IOSET SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE0_PORT, SET) + +#define SPI_SELECT_SLAVE1_IODIR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE1_PORT, DIR) +#define SPI_SELECT_SLAVE1_IOCLR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE1_PORT, CLR) +#define SPI_SELECT_SLAVE1_IOSET SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE1_PORT, SET) + +__attribute__ ((always_inline)) static inline void SpiSlaveSelect(uint8_t slave) { + switch (slave) { +#if USE_SPI_SLAVE0 + case SPI_SLAVE0: + SetBit(SPI_SELECT_SLAVE0_IOCLR, SPI_SELECT_SLAVE0_PIN); + break; +#endif +#if USE_SPI_SLAVE1 + case SPI_SLAVE0: + SetBit(SPI_SELECT_SLAVE1_IOCLR, SPI_SELECT_SLAVE1_PIN); + break; +#endif + default: + break; + } +} + +__attribute__ ((always_inline)) static inline void SpiSlaveUnselect(uint8_t slave) { + switch (slave) { +#if USE_SPI_SLAVE0 + case SPI_SLAVE0: + SetBit(SPI_SELECT_SLAVE0_IOSET, SPI_SELECT_SLAVE0_PIN); + break; +#endif +#if USE_SPI_SLAVE1 + case SPI_SLAVE0: + SetBit(SPI_SELECT_SLAVE1_IOSET, SPI_SELECT_SLAVE1_PIN); + break; +#endif + default: + break; + } +} + +/** Spi clock polarity and phase functions + */ + +__attribute__ ((always_inline)) static inline void SpiSetCPOL(struct spi_periph* p) { + SetBit(((sspRegs_t *)(p->reg_addr))->cr0, CPOL); +} + +__attribute__ ((always_inline)) static inline void SpiClearCPOL(struct spi_periph* p) { + ClearBit(((sspRegs_t *)(p->reg_addr))->cr0, CPOL); +} + +__attribute__ ((always_inline)) static inline void SpiSetCPHA(struct spi_periph* p) { + SetBit(((sspRegs_t *)(p->reg_addr))->cr0, CPHA); +} + +__attribute__ ((always_inline)) static inline void SpiClearCPHA(struct spi_periph* p) { + ClearBit(((sspRegs_t *)(p->reg_addr))->cr0, CPHA); +} + +/** Spi data size functions + */ + +__attribute__ ((always_inline)) static inline void SpiSetDataSize(struct spi_periph* p, enum SPIDataSizeSelect dss) { + switch (dss) { + default: + case DSS8bit: + ((sspRegs_t *)(p->reg_addr))->cr0 = (((sspRegs_t *)(p->reg_addr))->cr0 & ~(0xF<reg_addr))->cr0 = (((sspRegs_t *)(p->reg_addr))->cr0 & ~(0xF<reg_addr))->cr1, SSE); +} + +__attribute__ ((always_inline)) static inline void SpiDisable(struct spi_periph* p) { + ClearBit(((sspRegs_t *)(p->reg_addr))->cr1, SSE); +} + +__attribute__ ((always_inline)) static inline void SpiEnableRti(struct spi_periph* p) { + SetBit(((sspRegs_t *)(p->reg_addr))->imsc, RTIM); +} + +__attribute__ ((always_inline)) static inline void SpiDisableRti(struct spi_periph* p) { + ClearBit(((sspRegs_t *)(p->reg_addr))->imsc, RTIM); +} + +__attribute__ ((always_inline)) static inline void SpiClearRti(struct spi_periph* p) { + SetBit(((sspRegs_t *)(p->reg_addr))->icr, RTIC); +} + +__attribute__ ((always_inline)) static inline void SpiEnableTxi(struct spi_periph* p) { + SetBit(((sspRegs_t *)(p->reg_addr))->imsc, TXIM); +} + +__attribute__ ((always_inline)) static inline void SpiDisableTxi(struct spi_periph* p) { + ClearBit(((sspRegs_t *)(p->reg_addr))->imsc, TXIM); +} + +__attribute__ ((always_inline)) static inline void SpiEnableRxi(struct spi_periph* p) { + SetBit(((sspRegs_t *)(p->reg_addr))->imsc, RXIM); +} + +__attribute__ ((always_inline)) static inline void SpiDisableRxi(struct spi_periph* p) { + ClearBit(((sspRegs_t *)(p->reg_addr))->imsc, RXIM); +} + +__attribute__ ((always_inline)) static inline void SpiSend(struct spi_periph* p, uint8_t c) { + ((sspRegs_t *)(p->reg_addr))->dr = c; +} + +__attribute__ ((always_inline)) static inline void SpiRead(struct spi_periph* p, uint8_t* c) { + *c = ((sspRegs_t *)(p->reg_addr))->dr; +} + +__attribute__ ((always_inline)) static inline void SpiTransmit(struct spi_periph* p, struct spi_transaction* t) { + while (p->tx_idx_buf < t->length && bit_is_set(((sspRegs_t *)(p->reg_addr))->sr, TNF)) { + SpiSend(p, t->output_buf[p->tx_idx_buf]); + p->tx_idx_buf++; + } + if (p->tx_idx_buf == t->length) { + SpiDisableTxi(p); + } +} + +__attribute__ ((always_inline)) static inline void SpiReceive(struct spi_periph* p, struct spi_transaction* t) { + while (bit_is_set(((sspRegs_t *)(p->reg_addr))->sr, RNE)) { + if (p->rx_idx_buf < t->length) { + uint8_t r; + SpiRead(p, &r); + t->input_buf[p->rx_idx_buf] = r; + p->rx_idx_buf++; + } + else { + uint8_t foo; + SpiRead(p, &foo); + } + } +} + +__attribute__ ((always_inline)) static inline void SpiInitBuf(struct spi_periph* p, struct spi_transaction* t) { + p->rx_idx_buf = 0; + p->tx_idx_buf = 0; + SpiTransmit(p,t); // fill fifo +} + + +__attribute__ ((always_inline)) static inline void SpiStart(struct spi_periph* p, struct spi_transaction* t) { + p->status = SPIRunning; + t->status = SPITransRunning; + // handle spi options (CPOL, CPHA, data size,...) + if (t->cpol == SPICPOL_Mode1) SpiSetCPOL(p); + else SpiClearCPOL(p); + if (t->cpha == SPICPHA_Mode1) SpiSetCPHA(p); + else SpiClearCPHA(p); + SpiSetDataSize(p, t->dss); + // handle slave select + if (t->select == SPISelectUnselect || t->select == SPISelect) { + SpiSlaveSelect(t->slave_idx); + } + // start spi transaction + SpiEnable(p); + SpiInitBuf(p,t); + SpiEnableTxi(p); // enable tx fifo half empty interrupt +} + + +__attribute__ ((always_inline)) static inline void SpiAutomaton(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)) { + // handle slave unselect + if (trans->select == SPISelectUnselect || trans->select == SPIUnselect) { + SpiSlaveUnselect(trans->slave_idx); + } + SpiReceive(p, trans); + SpiDisableRti(p); + SpiClearRti(p); /* clear interrupt */ + SpiDisable(p); + // end transaction with success + trans->status = SPITransSuccess; + // handle transaction fifo here + p->trans_extract_idx++; + if (p->trans_extract_idx >= SPI_TRANSACTION_QUEUE_LEN) + p->trans_extract_idx = 0; + // if no more transaction to process, stop here, else start next transaction + if (p->trans_extract_idx == p->trans_insert_idx) { + p->status = SPIIdle; + } + else { + SpiStart(p,p->trans[p->trans_extract_idx]); + } + } +} + +/* + * + * SPI Master code + * + * + */ + +#ifdef SPI_MASTER + +//#include "led.h" /* FIXME remove that */ + +#if USE_SPI0 + +// void spi0_ISR(void) __attribute__((naked)); +// +// void spi0_ISR(void) { +// ISR_ENTRY(); +// VICVectAddr = 0x00000000; +// ISR_EXIT(); +// } + +void spi0_arch_init(void) { + + spi0.reg_addr = SPI0; + + // TODO set spi0 and interrupt vector +} + +#endif + + +#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 @@ -45,7 +307,130 @@ volatile uint8_t spi_rx_idx; #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 0x01 << 7 /* clock phase : data captured on second clock transition */ +#define SSP_SCR 0x00 << 8 /* serial clock rate */ + +/* 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 */ + +#ifndef SSPCPSR_VAL +#define SSPCPSR_VAL 0x20 +#endif + +void spi1_ISR(void) __attribute__((naked)); + +void spi1_ISR(void) { + ISR_ENTRY(); + + SpiAutomaton(&spi1); + + VICVectAddr = 0x00000000; /* clear this interrupt from the VIC */ + ISR_EXIT(); +} + +void spi1_arch_init(void) { + + spi1.reg_addr = SPI1; + + /* setup pins for SSP (SCK, MISO, MOSI) */ + PINSEL1 |= PINSEL1_SCK | PINSEL1_MISO | PINSEL1_MOSI; + + /* setup SSP */ + SSPCR0 = SSP_DSS | SSP_FRF | SSP_CPOL | SSP_CPHA | SSP_SCR; + SSPCR1 = SSP_LBM | SSP_MS | SSP_SOD; + SSPCPSR = SSPCPSR_VAL; /* Prescaler */ + + /* initialize interrupt vector */ + 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_ISR; /* address of the ISR */ + +} + +#endif + + +bool_t spi_submit(struct spi_periph* p, struct spi_transaction* t) { + + uint8_t idx; + idx = p->trans_insert_idx + 1; + if (idx >= SPI_TRANSACTION_QUEUE_LEN) idx = 0; + if (idx == p->trans_extract_idx) { + t->status = SPITransFailed; + return FALSE; /* queue full */ + } + t->status = SPITransPending; + //*(t->ready) = 0; ??? + // Disable interrupts + int_disable(); + p->trans[p->trans_insert_idx] = t; + p->trans_insert_idx = idx; + /* if peripheral is idle, start the transaction */ + if (p->status == SPIIdle) { + SpiStart(p,p->trans[p->trans_extract_idx]); + } + int_enable(); + + return TRUE; +} + + +void spi_init_slaves(void) { +#if USE_SPI_SLAVE0 + /* setup slave0_select pin + * slave0_select is output + */ + SPI_SELECT_SLAVE0_IODIR |= 1 << SPI_SELECT_SLAVE0_PIN; + SpiSlaveUnselect(SPI_SLAVE0); +#endif + +#if USE_SPI_SLAVE1 + /* setup slave1_select pin + * P1.25-16 are used as GPIO + * FIXME SLAVEX_PINSEL should be defined in airframe header + * slave1_select is output + */ + PINSEL2 &= ~(_BV(3)); + SPI_SELECT_SLAVE1_IODIR |= 1 << SPI_SELECT_SLAVE1_PIN; + SpiSlaveUnselect(SPI_SLAVE1); +#endif + +#if USE_SPI_SLAVE2 +#error SPI_SLAVE2 is not implemented yet, sorry +#endif +} + +void spi_slave_select(uint8_t slave) { + SpiSlaveSelect(slave); +} + +void spi_slave_unselect(uint8_t slave) { + SpiSlaveUnselect(slave); +} + +#endif /** SPI_MASTER */ + + +/* + * + * SPI Slave code + * + * 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)); /* set SSP input clock, PCLK / CPSDVSR = 468.75kHz */ @@ -80,7 +465,7 @@ void SPI1_ISR(void) __attribute__((naked)); #define SSP_MS 0x01 << 2 /* master slave mode : slave */ #define SSP_SOD 0x00 << 3 /* slave output disable : disabled */ -void spi_init( void ) { +void spi_slave_init( void ) { /* setup pins for SSP (SCK, MISO, MOSI, SS) */ PINSEL1 |= PINSEL1_SCK | PINSEL1_MISO | PINSEL1_MOSI | PINSEL1_SSEL; @@ -121,90 +506,3 @@ void SPI1_ISR(void) { } #endif /* SPI_SLAVE */ - - -/* - * - * SPI Master code - * - * - */ - -#ifdef SPI_MASTER - -#include "led.h" /* FIXME remove that */ - -/* interrupt handler */ -void SPI1_ISR(void) __attribute__((naked)); - -/* 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 0x01 << 7 /* clock phase : data captured on second clock transition */ -#define SSP_SCR 0x00 << 8 /* serial clock rate */ - -/* 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 */ - -#ifndef SSPCPSR_VAL -#define SSPCPSR_VAL 0x20 -#endif - -void spi_init( void ) { - /* setup pins for SSP (SCK, MISO, MOSI) */ - PINSEL1 |= PINSEL1_SCK | PINSEL1_MISO | PINSEL1_MOSI; - -#if defined USE_SPI_SLAVE0 - /* setup slave0_select pin */ - SPI_SELECT_SLAVE0_IODIR |= 1 << SPI_SELECT_SLAVE0_PIN; /* slave0_select is output */ - SpiUnselectSlave0(); /* slave0 is unselected */ -#endif - -#if defined USE_SPI_SLAVE1 - /* setup slave1_select pin */ - PINSEL2 &= ~(_BV(3)); /* P1.25-16 are used as GPIO */ - SPI_SELECT_SLAVE1_IODIR |= 1 << SPI_SELECT_SLAVE1_PIN; /* slave1_select is output */ - SpiUnselectSlave1(); /* slave1 is unselected */ -#endif - - /* setup SSP */ - SSPCR0 = SSP_DSS | SSP_FRF | SSP_CPOL | SSP_CPHA | SSP_SCR; - SSPCR1 = SSP_LBM | SSP_MS | SSP_SOD; - SSPCPSR = SSPCPSR_VAL; /* Prescaler */ - - /* 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 */ -} - -void SPI1_ISR(void) { - ISR_ENTRY(); - - if (bit_is_set(SSPMIS, TXMIS)) { /* Tx fifo is half empty */ - SpiTransmit(); - SpiReceive(); - SpiEnableRti(); - } - - if (bit_is_set(SSPMIS, RTMIS)) { /* Rx fifo is not empty and no receive took place in the last 32 bits period */ -#if !SPI_NO_UNSELECT_SLAVE - SpiUnselectCurrentSlave(); -#endif - SpiReceive(); - SpiDisableRti(); - SpiClearRti(); /* clear interrupt */ - SpiDisable(); - spi_message_received = TRUE; - } - - VICVectAddr = 0x00000000; /* clear this interrupt from the VIC */ - ISR_EXIT(); -} - -#endif /** SPI_MASTER */ diff --git a/sw/airborne/arch/lpc21/mcu_periph/spi_arch.h b/sw/airborne/arch/lpc21/mcu_periph/spi_arch.h index 6e05e44168..7798901bd1 100644 --- a/sw/airborne/arch/lpc21/mcu_periph/spi_arch.h +++ b/sw/airborne/arch/lpc21/mcu_periph/spi_arch.h @@ -32,89 +32,19 @@ #include "LPC21xx.h" #include BOARD_CONFIG -extern volatile uint8_t spi_tx_idx; -extern volatile uint8_t spi_rx_idx; -#define SpiInitBuf() { \ - spi_rx_idx = 0; \ - spi_tx_idx = 0; \ - spi_message_received = FALSE; \ - SpiTransmit(); /* fill fifo */ \ -} -#define SpiTransmit() { \ - while (spi_tx_idx < spi_buffer_length \ - && bit_is_set(SSPSR, TNF)) { \ - SpiSend(spi_buffer_output[spi_tx_idx]); \ - spi_tx_idx++; \ - } \ - if (spi_tx_idx == spi_buffer_length) \ - SpiDisableTxi(); \ -} +// SSP is on SPI1 on lpc +#if defined USE_SSP & !USE_SPI1 +#define USE_SP11 1 +// TODO other defines ? +#endif -#define SpiReceive() { \ - while (bit_is_set(SSPSR, RNE)) { \ - if (spi_rx_idx < spi_buffer_length) { \ - SpiRead(spi_buffer_input[spi_rx_idx]) \ - spi_rx_idx++; \ - } \ - else { \ - uint8_t foo; \ - SpiRead(foo); \ - } \ - } \ - } - -#define SpiEnable() { \ - SetBit(SSPCR1, SSE); \ - } - -#define SpiDisable() { \ - ClearBit(SSPCR1, SSE); \ - } - -#define SpiEnableRti() { \ - SetBit(SSPIMSC, RTIM); \ - } - -#define SpiDisableRti() { \ - ClearBit(SSPIMSC, RTIM); \ - } - -#define SpiClearRti() { \ - SetBit(SSPICR, RTIC); \ - } - -#define SpiEnableTxi() { \ - SetBit(SSPIMSC, TXIM); \ - } - -#define SpiDisableTxi() { \ - ClearBit(SSPIMSC, TXIM); \ - } - -#define SpiEnableRxi() { \ - SetBit(SSPIMSC, RXIM); \ - } - -#define SpiDisableRxi() { \ - ClearBit(SSPIMSC, RXIM); \ - } - -#define SpiSend(a) { \ - SSPDR = a; \ - } - -#define SpiRead(a) { \ - a = SSPDR; \ - } #ifdef SPI_SLAVE -#define SpiStart() { \ - SpiEnable(); \ - SpiInitBuf(); \ - SpiEnableTxi(); /* enable tx fifo half empty interrupt */ \ - } + +extern volatile uint8_t spi_tx_idx; +extern volatile uint8_t spi_rx_idx; #endif /* SPI_SLAVE */ @@ -123,73 +53,7 @@ extern volatile uint8_t spi_rx_idx; #ifdef SPI_MASTER -/* !!!!!!!!!!!!! Code for one single slave at a time !!!!!!!!!!!!!!!!! */ -#if defined SPI_SELECT_SLAVE1_PIN && defined SPI_SELECT_SLAVE0_PIN -#error "SPI: one single slave, please" -#endif - - -#define SpiStart() { \ - SpiEnable(); \ - SpiInitBuf(); \ - SpiEnableTxi(); /* enable tx fifo half empty interrupt */ \ -} - -/* - * Slave0 select : P0.20 PINSEL1 00 << 8 - * Slave1 select : P1.20 - * - */ - -#define SPI_SELECT_SLAVE_IO__(port, reg) IO ## port ## reg -#define SPI_SELECT_SLAVE_IO_(port, reg) SPI_SELECT_SLAVE_IO__(port, reg) - -#define SPI_SELECT_SLAVE0_IODIR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE0_PORT, DIR) -#define SPI_SELECT_SLAVE0_IOCLR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE0_PORT, CLR) -#define SPI_SELECT_SLAVE0_IOSET SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE0_PORT, SET) - -#define SPI_SELECT_SLAVE1_IODIR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE1_PORT, DIR) -#define SPI_SELECT_SLAVE1_IOCLR SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE1_PORT, CLR) -#define SPI_SELECT_SLAVE1_IOSET SPI_SELECT_SLAVE_IO_(SPI_SELECT_SLAVE1_PORT, SET) - - -#define SpiSelectSlave0() { \ - spi_cur_slave = SPI_SLAVE0; \ - SetBit(SPI_SELECT_SLAVE0_IOCLR, SPI_SELECT_SLAVE0_PIN); \ - } - -#define SpiUnselectSlave0() { \ - spi_cur_slave = SPI_NONE; \ - SetBit(SPI_SELECT_SLAVE0_IOSET, SPI_SELECT_SLAVE0_PIN); \ - } - - -#define SpiSelectSlave1() { \ - spi_cur_slave = SPI_SLAVE1; \ - SetBit(SPI_SELECT_SLAVE1_IOCLR, SPI_SELECT_SLAVE1_PIN); \ - } - -#define SpiUnselectSlave1() { \ - spi_cur_slave = SPI_NONE; \ - SetBit(SPI_SELECT_SLAVE1_IOSET, SPI_SELECT_SLAVE1_PIN); \ - } - -#ifdef SPI_SELECT_SLAVE0_PIN -#define SpiUnselectCurrentSlave() SpiUnselectSlave0() -#endif - -#ifdef SPI_SELECT_SLAVE1_PIN -#define SpiUnselectCurrentSlave() SpiUnselectSlave1() -#endif - #endif /* SPI_MASTER */ -#define SpiSetCPOL() (SSPCR0 |= _BV(6)) -#define SpiClrCPOL() (SSPCR0 &= ~(_BV(6))) - -#define SpiSetCPHA() (SSPCR0 |= _BV(7)) -#define SpiClrCPHA() (SSPCR0 &= ~(_BV(7))) - - #endif /* SPI_ARCH_H */ diff --git a/sw/airborne/arch/stm32/mcu_periph/spi_arch.c b/sw/airborne/arch/stm32/mcu_periph/spi_arch.c index dd18b3ff3a..b8fdbae148 100644 --- a/sw/airborne/arch/stm32/mcu_periph/spi_arch.c +++ b/sw/airborne/arch/stm32/mcu_periph/spi_arch.c @@ -1,4 +1,3 @@ -#include "subsystems/imu.h" #include #include @@ -9,9 +8,62 @@ #include "mcu_periph/spi.h" +struct spi_transaction* slave0; + // SPI2 Slave Selection -#define Spi2Slave0Unselect() GPIO_BSRR(GPIOB) = GPIO12 -#define Spi2Slave0Select() GPIO_BRR(GPIOB) = GPIO12 + +#define SPI2_SLAVE0_PORT GPIOB +#define SPI2_SLAVE0_PIN GPIO12 + +#define SPI2_SLAVE1_PORT GPIOB +#define SPI2_SLAVE1_PIN GPIO5 + +#define SPI2_SLAVE2_PORT GPIOB +#define SPI2_SLAVE2_PIN GPIO3 + +static inline void Spi2SlaveUnselect(uint8_t slave) +{ + switch(slave) { + case 0: + GPIO_BSRR(SPI2_SLAVE0_PORT) = SPI2_SLAVE0_PIN; + break; +#if USE_SPI2_SLAVE1 + case 1: + GPIO_BSRR(SPI2_SLAVE1_PORT) = SPI2_SLAVE1_PIN; + break; +#endif //USE_SPI2_SLAVE1 +#if USE_SPI2_SLAVE2 + case 2: + GPIO_BSRR(SPI2_SLAVE2_PORT) = SPI2_SLAVE2_PIN; + break; +#endif //USE_SPI2_SLAVE2 + + default: + break; + } +} + + +static inline void Spi2SlaveSelect(uint8_t slave) +{ + switch(slave) { + case 0: + GPIO_BRR(SPI2_SLAVE0_PORT) = SPI2_SLAVE0_PIN; + break; +#if USE_SPI2_SLAVE1 + case 1: + GPIO_BRR(SPI2_SLAVE1_PORT) = SPI2_SLAVE1_PIN; + break; +#endif //USE_SPI2_SLAVE1 +#if USE_SPI2_SLAVE2 + case 2: + GPIO_BRR(SPI2_SLAVE2_PORT) = SPI2_SLAVE2_PIN; + break; +#endif //USE_SPI2_SLAVE2 + default: + break; + } +} // spi dma end of rx handler // XXX: should be provided by libopencm3? @@ -72,41 +124,40 @@ void spi_init(void) { // SLAVE 0 // set accel slave select as output and assert it ( on PB12) - Spi2Slave0Unselect(); + Spi2SlaveUnselect(0); rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, - GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); + GPIO_CNF_OUTPUT_PUSHPULL, SPI2_SLAVE0_PIN); + + // SLAVE 1 + Spi2SlaveUnselect(1); + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, SPI2_SLAVE1_PIN); + + // SLAVE 2 + Spi2SlaveUnselect(1); + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, SPI2_SLAVE2_PIN); +//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //Slave2 is on JTDO pin, so disable JTAG DP + + + spi2.trans_insert_idx = 0; + spi2.trans_extract_idx = 0; + spi2.status = SPIIdle; spi_arch_int_enable(); - } -/* -void adxl345_write_to_reg(uint8_t addr, uint8_t val) { - - Adxl345Select(); - SPI_I2S_SendData(SPI2, addr); - while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); - SPI_I2S_SendData(SPI2, val); - while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); - while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET); - Adxl345Unselect(); -} - -void spi_clear_rx_buf(void) { - uint8_t __attribute__ ((unused)) ret = SPI_I2S_ReceiveData(SPI2); -} -*/ - -struct spi_transaction* slave0; void spi_rw(struct spi_transaction * _trans) { // Store local copy to notify of the results slave0 = _trans; slave0->status = SPITransRunning; - - Spi2Slave0Select(); + spi2.status = SPIRunning; + Spi2SlaveSelect(slave0->slave_idx); // SPI2_Rx_DMA_Channel configuration ------------------------------------ @@ -151,11 +202,37 @@ void spi_rw(struct spi_transaction * _trans) } +bool_t spi_submit(struct spi_periph* p, struct spi_transaction* t) +{ + uint8_t idx; + idx = p->trans_insert_idx + 1; + if (idx >= SPI_TRANSACTION_QUEUE_LEN) idx = 0; + if (idx == p->trans_extract_idx) { + t->status = SPITransFailed; + return FALSE; /* queue full */ + } + t->status = SPITransPending; + // FIXME: still needed? + //*(t->ready) = 0; + //Disable interrupts to avoid race conflict with end of DMA transfer interrupt + __disable_irq(); + p->trans[p->trans_insert_idx] = t; + p->trans_insert_idx = idx; + + /* if peripheral is idle, start the transaction */ + if (p->status == SPIIdle) { + spi_rw(p->trans[p->trans_extract_idx]); + } + __enable_irq(); + return TRUE; +} + + // Accel end of DMA transferred void dma1_channel4_isr(void) { - Spi2Slave0Unselect(); + Spi2SlaveUnselect(spi2.trans[spi2.trans_extract_idx]->slave_idx); if ((DMA1_ISR & DMA_ISR_TCIF4) != 0) { // clear int pending bit @@ -164,7 +241,6 @@ void dma1_channel4_isr(void) // mark as available spi_message_received = TRUE; } - // disable DMA Channel dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL4); @@ -178,7 +254,15 @@ void dma1_channel4_isr(void) slave0->status = SPITransSuccess; *(slave0->ready) = 1; + spi2.trans_extract_idx++; + // Check if there is another pending SPI transaction + if (spi2.trans_extract_idx >= SPI_TRANSACTION_QUEUE_LEN) + spi2.trans_extract_idx = 0; + if (spi2.trans_extract_idx == spi2.trans_insert_idx) + spi2.status = SPIIdle; + else + spi_rw(spi2.trans[spi2.trans_extract_idx]); } diff --git a/sw/airborne/arch/stm32/mcu_periph/spi_arch.h b/sw/airborne/arch/stm32/mcu_periph/spi_arch.h index 9f89261551..635efafa01 100644 --- a/sw/airborne/arch/stm32/mcu_periph/spi_arch.h +++ b/sw/airborne/arch/stm32/mcu_periph/spi_arch.h @@ -37,7 +37,6 @@ extern void spi_arch_int_disable(void); extern void spi_clear_rx_buf(void); void spi_rw(struct spi_transaction * _trans); - /* ////////// diff --git a/sw/airborne/link_mcu.h b/sw/airborne/link_mcu.h index 7c87a946a1..47a2a7c825 100644 --- a/sw/airborne/link_mcu.h +++ b/sw/airborne/link_mcu.h @@ -51,8 +51,8 @@ extern bool_t link_mcu_received; extern void link_mcu_event_task( void ); -#if defined MCU_SPI_LINK && ! defined USE_SPI -#define USE_SPI +#if defined MCU_SPI_LINK && !USE_SPI +#define USE_SPI 1 #endif diff --git a/sw/airborne/mcu.c b/sw/airborne/mcu.c index 4e2b0890c6..833cf7096a 100644 --- a/sw/airborne/mcu.c +++ b/sw/airborne/mcu.c @@ -46,7 +46,7 @@ #ifdef USE_USB_SERIAL #include "mcu_periph/usb_serial.h" #endif -#ifdef USE_SPI +#if USE_SPI0 || USE_SPI1 || USE_SPI2 #include "mcu_periph/spi.h" #endif #ifdef USE_DAC @@ -100,8 +100,17 @@ void mcu_init(void) { #ifdef USE_USB_SERIAL VCOM_init(); #endif -#ifdef USE_SPI - spi_init(); +#if USE_SPI0 + spi0_init(); +#endif +#if USE_SPI1 + spi1_init(); +#endif +#if USE_SPI2 + spi2_init(); +#endif +#if USE_SPI0 || USE_SPI1 || USE_SPI2 + spi_init_slaves(); #endif #ifdef USE_DAC dac_init(); diff --git a/sw/airborne/mcu_periph/spi.c b/sw/airborne/mcu_periph/spi.c index 2451ed7e79..6f706a9c54 100644 --- a/sw/airborne/mcu_periph/spi.c +++ b/sw/airborne/mcu_periph/spi.c @@ -25,14 +25,54 @@ #include "std.h" #include "mcu_periph/spi.h" +#ifdef SPI_MASTER + +#if USE_SPI0 + +struct spi_periph spi0; + +void spi0_init(void) { + spi_init(&spi0); + spi0_arch_init(); +} + +#endif + +#if USE_SPI1 + +struct spi_periph spi1; + +void spi1_init(void) { + spi_init(&spi1); + spi1_arch_init(); +} + +#endif + +#if USE_SPI2 + +struct spi_periph spi2; + +void spi2_init(void) { + spi_init(&spi2); + spi2_arch_init(); +} + +#endif + +void spi_init(struct spi_periph* p) { + p->trans_insert_idx = 0; + p->trans_extract_idx = 0; + p->status = SPIIdle; +} + +#endif /* SPI_MASTER */ + +#ifdef SPI_SLAVE + uint8_t* spi_buffer_input; uint8_t* spi_buffer_output; uint8_t spi_buffer_length; volatile bool_t spi_message_received; -#ifdef SPI_MASTER - -volatile uint8_t spi_cur_slave; -uint8_t spi_nb_ovrn; - -#endif /* SPI_MASTER */ +#endif diff --git a/sw/airborne/mcu_periph/spi.h b/sw/airborne/mcu_periph/spi.h index 31580a537b..86744026c6 100644 --- a/sw/airborne/mcu_periph/spi.h +++ b/sw/airborne/mcu_periph/spi.h @@ -29,27 +29,188 @@ #ifndef SPI_H #define SPI_H -#ifdef USE_SPI +//#if USE_SPI #include "std.h" +#include "mcu_periph/spi_arch.h" + +// FIXME how to use this properly ? +enum SPIMode { + SPIMaster, + SPISlave +}; + +/** SPI slave selection behavior. + * SelectUnselect: slave is selected before transaction and unselected after + * Select: slave is selected before transaction but not unselected + * Unselect: slave is not selected but unselected after transaction + * NoSelect: slave is not selected nor unselected + * + * Default operation should be SelectUnselected, but some peripherals + * might need some special control + * Use non-default control only if you know what you're doing + */ +enum SPISlaveSelect { + SPISelectUnselect, + SPISelect, + SPIUnselect, + SPINoSelect +}; + +/** SPI clock phase control. + * control when data are sampled (rising or falling edge of clock) + * depending of the clock polarity + * Mode 0: data sampled on first clock edge + * Mode 1: data sampled on second clock edge + */ +enum SPIClockPhase { + SPICPHA_Mode0, + SPICPHA_Mode1 +}; + +/** SPI clock polarity control. + * Mode 0: clock idle low + * Mode 1: clock idle high + */ +enum SPIClockPolarity { + SPICPOL_Mode0, + SPICPOL_Mode1 +}; + +/** SPI Data size transfer. + */ +enum SPIDataSizeSelect { + DSS8bit, + DSS16bit +}; + +/** SPI transaction status. + */ enum SPITransactionStatus { SPITransPending, SPITransRunning, SPITransSuccess, - SPITransFailed + SPITransFailed, + SPITransDone }; +/** SPI peripheral status. + */ +enum SPIStatus { + SPIIdle, + SPIRunning +}; + +#ifndef SPI_BUF_LEN +#define SPI_BUF_LEN 32 +#endif + struct spi_transaction { - volatile uint8_t* mosi_buf; - volatile uint8_t* miso_buf; - volatile uint8_t* ready; + volatile uint8_t input_buf[SPI_BUF_LEN]; + volatile uint8_t output_buf[SPI_BUF_LEN]; + volatile uint8_t* ready; // FIXME what is the difference with status ? uint8_t length; + uint8_t slave_idx; + enum SPISlaveSelect select; + enum SPIClockPolarity cpol; + enum SPIClockPhase cpha; + enum SPIDataSizeSelect dss; // Architecture dependant options (LPC21) ? volatile enum SPITransactionStatus status; }; -#include "mcu_periph/spi_arch.h" +#ifndef SPI_TRANSACTION_QUEUE_LEN +#define SPI_TRANSACTION_QUEUE_LEN 8 +#endif +struct spi_periph { + /* circular buffer holding transactions */ + struct spi_transaction* trans[SPI_TRANSACTION_QUEUE_LEN]; + uint8_t trans_insert_idx; + uint8_t trans_extract_idx; + /* internal state of the peripheral */ + volatile enum SPIStatus status; + volatile uint8_t tx_idx_buf; + volatile uint8_t rx_idx_buf; + void* reg_addr; + enum SPIMode mode; +}; + +#ifdef SPI_MASTER + +#define SPI_SLAVE0 0 +#define SPI_SLAVE1 1 +#define SPI_SLAVE2 2 + +//extern uint8_t spi_nb_ovrn; //TODO SPI error struct + +#if USE_SPI0 + +extern struct spi_periph spi0; +extern void spi0_init(void); + +/** Architecture dependant SPI0 initialization. + * Must be implemented by underlying architecture + */ +extern void spi0_arch_init(void); + +#endif + +#if USE_SPI1 + +extern struct spi_periph spi1; +extern void spi1_init(void); + +/** Architecture dependant SPI1 initialization. + * Must be implemented by underlying architecture + */ +extern void spi1_arch_init(void); + +#endif + +#if USE_SPI2 + +extern struct spi_periph spi2; +extern void spi2_init(void); + +/** Architecture dependant SPI2 initialization. + * Must be implemented by underlying architecture + */ +extern void spi2_arch_init(void); + + +#endif + +/** Initialize a spi peripheral. + * @param p spi peripheral to be configured + */ +extern void spi_init(struct spi_periph* p); + +/** Initialize all used slaves and uselect them. + */ +extern void spi_init_slaves(void); + +/** Submit a spi transaction. + * Must be implemented by the underlying architecture + * @param p spi peripheral to be used + * @param t spi transaction + * @return return true if insertion to the transaction queue succed + */ +extern bool_t spi_submit(struct spi_periph* p, struct spi_transaction* t); + +/** Select a slave. + * @param slave slave id + */ +void spi_slave_select(uint8_t slave); + +/** Unselect a slave. + * @param slave slave id + */ +void spi_slave_unselect(uint8_t slave); + +#endif /* SPI_MASTER */ + +#ifdef SPI_SLAVE extern uint8_t* spi_buffer_input; extern uint8_t* spi_buffer_output; @@ -57,23 +218,10 @@ extern uint8_t spi_buffer_length; extern volatile bool_t spi_message_received; -void spi_init(void); +void spi_slave_init(void); -#ifdef SPI_MASTER +#endif -#define SPI_NONE 0 -#define SPI_SLAVE0 1 -#define SPI_SLAVE1 2 -#define SPI_SLAVE2 3 - -extern volatile uint8_t spi_cur_slave; -extern uint8_t spi_nb_ovrn; - -#define SpiCheckAvailable() (spi_cur_slave == SPI_NONE) -#define SpiOverRun() {spi_nb_ovrn++;} - -#endif /* SPI_MASTER */ - -#endif /* USE_SPI */ +//#endif /* USE_SPI */ #endif /* SPI_H */ diff --git a/sw/airborne/peripherals/mcp355x.c b/sw/airborne/peripherals/mcp355x.c index 3eec8438ab..13404cc06d 100644 --- a/sw/airborne/peripherals/mcp355x.c +++ b/sw/airborne/peripherals/mcp355x.c @@ -28,34 +28,40 @@ bool_t mcp355x_data_available; int32_t mcp355x_data; -uint8_t mcp355x_spi_buf[4]; + +struct spi_transaction mcp355x_spi_trans; void mcp355x_init(void) { mcp355x_data_available = FALSE; mcp355x_data = 0; - SpiClrCPOL(); - SpiClrCPHA(); + mcp355x_spi_trans.length = 4; + mcp355x_spi_trans.slave_idx = SPI_SLAVE0; + mcp355x_spi_trans.select = SPISelect; + mcp355x_spi_trans.cpol = SPICPOL_Mode0; + mcp355x_spi_trans.cpha = SPICPHA_Mode0; + mcp355x_spi_trans.dss = DSS8bit; + } void mcp355x_read(void) { - spi_buffer_length = 4; - spi_buffer_input = mcp355x_spi_buf; - //SpiSelectSlave0(); - SpiStart(); + spi_submit(&spi1, &mcp355x_spi_trans); } void mcp355x_event(void) { - if (spi_message_received) { - spi_message_received = FALSE; - if ((mcp355x_spi_buf[0]>>4) == 0) { + if (mcp355x_spi_trans.status == SPITransSuccess) { + if ((mcp355x_spi_trans.input_buf[0]>>4) == 0) { mcp355x_data = (int32_t)( - ((uint32_t)mcp355x_spi_buf[0]<<17) | - ((uint32_t)mcp355x_spi_buf[1]<<9) | - ((uint32_t)mcp355x_spi_buf[2]<<1) | - (mcp355x_spi_buf[3]>>7)); + ((uint32_t)mcp355x_spi_trans.input_buf[0]<<17) | + ((uint32_t)mcp355x_spi_trans.input_buf[1]<<9) | + ((uint32_t)mcp355x_spi_trans.input_buf[2]<<1) | + (mcp355x_spi_trans.input_buf[3]>>7)); mcp355x_data_available = TRUE; } + mcp355x_spi_trans.status = SPITransDone; + } + if (mcp355x_spi_trans.status == SPITransFailed) { + mcp355x_spi_trans.status = SPITransDone; } }