From 24496cb162feda3182f70a41be96c1a2837bf2ac Mon Sep 17 00:00:00 2001 From: ccli8 Date: Mon, 26 Mar 2018 10:34:22 +0800 Subject: [PATCH] Introduce SPI_ENABLE_SYNC/SPI_DISABLE_SYNC to simplify enable/disable control --- targets/TARGET_NUVOTON/TARGET_M451/spi_api.c | 55 +++++++---- targets/TARGET_NUVOTON/TARGET_M480/spi_api.c | 55 +++++++---- .../TARGET_NUVOTON/TARGET_NANO100/spi_api.c | 93 +++++++++++-------- .../TARGET_NUVOTON/TARGET_NUC472/spi_api.c | 66 +++++++++---- 4 files changed, 176 insertions(+), 93 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c index 5d035ccf99..f07a935976 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c @@ -60,6 +60,34 @@ static struct nu_spi_var spi2_var = { #endif }; +/* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros + * + * The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI + * control logic is enabled/disabled, this bit indicates the real status of SPI controller. + * + * NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC(). + * NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers, + * user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0 + * (by SPI_DISABLE_SYNC here). + */ +__STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base) +{ + if (! (spi_base->CTL & SPI_CTL_SPIEN_Msk)) { + SPI_ENABLE(spi_base); + } + while (! (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk)); +} +__STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base) +{ + if (spi_base->CTL & SPI_CTL_SPIEN_Msk) { + // NOTE: SPI H/W may get out of state without the busy check. + while (SPI_IS_BUSY(spi_base)); + + SPI_DISABLE(spi_base); + } + while (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk); +} + #if DEVICE_SPI_ASYNCH static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable); static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable); @@ -177,10 +205,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - // NOTE 1: All configurations should be ready before enabling SPI peripheral. - // NOTE 2: Re-configuration is allowed only as SPI peripheral is idle. - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); SPI_Open(spi_base, slave ? SPI_SLAVE : SPI_MASTER, @@ -207,15 +232,14 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) } // NOTE: M451's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk). This will violate judgement of spi_active(). Disable it. - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); } void spi_frequency(spi_t *obj, int hz) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz); } @@ -226,7 +250,7 @@ int spi_master_write(spi_t *obj, int value) SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); // NOTE: Data in receive FIFO can be read out via ICE. - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for tx buffer empty while(! spi_writeable(obj)); @@ -236,7 +260,7 @@ int spi_master_write(spi_t *obj, int value) while (! spi_readable(obj)); int value2 = SPI_READ_RX(spi_base); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); return value2; } @@ -261,7 +285,7 @@ int spi_slave_receive(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); return spi_readable(obj); }; @@ -270,7 +294,7 @@ int spi_slave_read(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for rx buffer full while (! spi_readable(obj)); @@ -282,7 +306,7 @@ void spi_slave_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for tx buffer empty while(! spi_writeable(obj)); @@ -316,7 +340,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, spi_enable_event(obj, event, 1); spi_buffer_set(obj, tx, tx_length, rx, rx_length); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); if (obj->spi.dma_usage == DMA_USAGE_NEVER) { // Interrupt way @@ -426,9 +450,8 @@ void spi_abort_asynch(spi_t *obj) spi_enable_vector_interrupt(obj, 0, 0); spi_master_enable_interrupt(obj, 0); - // FIXME: SPI H/W may get out of state without the busy check. - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + /* Necessary for accessing FIFOCTL below */ + SPI_DISABLE_SYNC(spi_base); SPI_ClearRxFIFO(spi_base); SPI_ClearTxFIFO(spi_base); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c index 79e6818d28..035c1c8663 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c @@ -71,6 +71,34 @@ static struct nu_spi_var spi4_var = { #endif }; +/* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros + * + * The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI + * control logic is enabled/disabled, this bit indicates the real status of SPI controller. + * + * NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC(). + * NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers, + * user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0 + * (by SPI_DISABLE_SYNC here). + */ +__STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base) +{ + if (! (spi_base->CTL & SPI_CTL_SPIEN_Msk)) { + SPI_ENABLE(spi_base); + } + while (! (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk)); +} +__STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base) +{ + if (spi_base->CTL & SPI_CTL_SPIEN_Msk) { + // NOTE: SPI H/W may get out of state without the busy check. + while (SPI_IS_BUSY(spi_base)); + + SPI_DISABLE(spi_base); + } + while (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk); +} + #if DEVICE_SPI_ASYNCH static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable); static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable); @@ -184,10 +212,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - // NOTE 1: All configurations should be ready before enabling SPI peripheral. - // NOTE 2: Re-configuration is allowed only as SPI peripheral is idle. - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); SPI_Open(spi_base, slave ? SPI_SLAVE : SPI_MASTER, @@ -212,15 +237,14 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) } // NOTE: M451's/M480's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk). This will violate judgement of spi_active(). Disable it. - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); } void spi_frequency(spi_t *obj, int hz) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz); } @@ -231,7 +255,7 @@ int spi_master_write(spi_t *obj, int value) SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); // NOTE: Data in receive FIFO can be read out via ICE. - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for tx buffer empty while(! spi_writeable(obj)); @@ -241,7 +265,7 @@ int spi_master_write(spi_t *obj, int value) while (! spi_readable(obj)); int value2 = SPI_READ_RX(spi_base); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); return value2; } @@ -266,7 +290,7 @@ int spi_slave_receive(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); return spi_readable(obj); }; @@ -275,7 +299,7 @@ int spi_slave_read(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for rx buffer full while (! spi_readable(obj)); @@ -287,7 +311,7 @@ void spi_slave_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for tx buffer empty while(! spi_writeable(obj)); @@ -320,7 +344,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, spi_enable_event(obj, event, 1); spi_buffer_set(obj, tx, tx_length, rx, rx_length); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); if (obj->spi.dma_usage == DMA_USAGE_NEVER) { // Interrupt way @@ -428,9 +452,8 @@ void spi_abort_asynch(spi_t *obj) spi_enable_vector_interrupt(obj, 0, 0); spi_master_enable_interrupt(obj, 0); - // NOTE: SPI H/W may get out of state without the busy check. - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + /* Necessary for accessing FIFOCTL below */ + SPI_DISABLE_SYNC(spi_base); SPI_ClearRxFIFO(spi_base); SPI_ClearTxFIFO(spi_base); diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c index 0bc47ae67f..f7209c4a65 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c @@ -75,6 +75,38 @@ static struct nu_spi_var spi2_var = { #endif }; +/* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros + * + * The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI + * control logic is enabled/disabled, this bit indicates the real status of SPI controller. + * + * NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC(). + * NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers, + * user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0 + * (by SPI_DISABLE_SYNC here). + * + * NOTE: + * 1. NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode). + * 2. NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode. + */ +__STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base) +{ + /* NOTE: On NANO130, FIFO mode defaults to disabled. */ + if (! (spi_base->CTL & SPI_CTL_FIFOM_Msk)) { + SPI_EnableFIFO(spi_base, NU_SPI_FIFO_DEPTH / 2, NU_SPI_FIFO_DEPTH / 2); + } +} +__STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base) +{ + /* NOTE: On NANO130, SPI_CTL.GO_BUSY always reads as 1 in slave/FIFO mode. So disable FIFO first. */ + if (spi_base->CTL & SPI_CTL_FIFOM_Msk) { + SPI_DisableFIFO(spi_base); + } + + /* NOTE: SPI H/W may get out of state without the busy check */ + while (SPI_IS_BUSY(spi_base)); +} + #if DEVICE_SPI_ASYNCH static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable); static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable, uint32_t mask); @@ -191,13 +223,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - // NOTE: All configurations should be ready before enabling SPI peripheral. - // NOTE: Re-configuration is allowed only as SPI peripheral is idle. - // NOTE: - // NANO130, SPI_CTL.GO_BUSY always reads as 1 in slave/FIFO mode. So disable FIFO first. - SPI_DisableFIFO(spi_base); - while (SPI_IS_BUSY(spi_base)); - + SPI_DISABLE_SYNC(spi_base); SPI_Open(spi_base, slave ? SPI_SLAVE : SPI_MASTER, @@ -240,25 +266,15 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) // NANO130: Configure slave select signal to edge-trigger rather than level-trigger spi_base->SSR |= SPI_SSR_SS_LTRIG_Msk; } - - // NOTE: - // NANO130: FIFO mode defaults to disabled. - SPI_EnableFIFO(spi_base, NU_SPI_FIFO_DEPTH / 2, NU_SPI_FIFO_DEPTH / 2); } void spi_frequency(spi_t *obj, int hz) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - // NANO130, SPI_CTL.GO_BUSY always reads as 1 in slave/FIFO mode. So disable FIFO first. - SPI_DisableFIFO(spi_base); - while (SPI_IS_BUSY(spi_base)); + SPI_DISABLE_SYNC(spi_base); SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz); - - // NOTE: - // NANO130: FIFO mode defaults to disabled. - SPI_EnableFIFO(spi_base, NU_SPI_FIFO_DEPTH / 2, NU_SPI_FIFO_DEPTH / 2); } @@ -270,7 +286,8 @@ int spi_master_write(spi_t *obj, int value) // NOTE: // NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode). // NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode. - + SPI_ENABLE_SYNC(spi_base); + // Wait for tx buffer empty while(! spi_writeable(obj)); uint32_t TX = (NU_MODSUBINDEX(obj->spi.spi) == 0) ? ((uint32_t) &spi_base->TX0) : ((uint32_t) &spi_base->TX1); @@ -303,21 +320,19 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, #if DEVICE_SPISLAVE int spi_slave_receive(spi_t *obj) { - // NOTE: - // NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode). - // NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode. - + SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + + SPI_ENABLE_SYNC(spi_base); + return spi_readable(obj); }; int spi_slave_read(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - - // NOTE: - // NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode). - // NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode. - + + SPI_ENABLE_SYNC(spi_base); + // Wait for rx buffer full while (! spi_readable(obj)); uint32_t RX = (NU_MODSUBINDEX(obj->spi.spi) == 0) ? ((uint32_t) &spi_base->RX0) : ((uint32_t) &spi_base->RX1); @@ -328,11 +343,9 @@ int spi_slave_read(spi_t *obj) void spi_slave_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - - // NOTE: - // NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode). - // NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode. - + + SPI_ENABLE_SYNC(spi_base); + // Wait for tx buffer empty while(! spi_writeable(obj)); uint32_t TX = (NU_MODSUBINDEX(obj->spi.spi) == 0) ? ((uint32_t) &spi_base->TX0) : ((uint32_t) &spi_base->TX1); @@ -364,11 +377,9 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, // SPI IRQ is necessary for both interrupt way and DMA way spi_enable_event(obj, event, 1); spi_buffer_set(obj, tx, tx_length, rx, rx_length); - - // NOTE: - // NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode). - // NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode. - + + SPI_ENABLE_SYNC(spi_base); + if (obj->spi.dma_usage == DMA_USAGE_NEVER) { // Interrupt way spi_master_write_asynch(obj, NU_SPI_FIFO_DEPTH / 2); @@ -473,9 +484,9 @@ void spi_abort_asynch(spi_t *obj) spi_enable_vector_interrupt(obj, 0, 0); spi_master_enable_interrupt(obj, 0, SPI_FIFO_RX_INTEN_MASK | SPI_FIFO_TX_INTEN_MASK); - // NOTE: SPI H/W may get out of state without the busy check. - while (SPI_IS_BUSY(spi_base)); - + /* Necessary for accessing FIFOCTL below */ + SPI_DISABLE_SYNC(spi_base); + SPI_ClearRxFIFO(spi_base); SPI_ClearTxFIFO(spi_base); } diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c index 1ab0704fc2..5b063782ca 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c @@ -66,6 +66,34 @@ static struct nu_spi_var spi3_var = { #endif }; +/* Synchronous version of SPI_ENABLE()/SPI_DISABLE() macros + * + * The SPI peripheral clock is asynchronous with the system clock. In order to make sure the SPI + * control logic is enabled/disabled, this bit indicates the real status of SPI controller. + * + * NOTE: All configurations shall be ready before calling SPI_ENABLE_SYNC(). + * NOTE: Before changing the configurations of SPIx_CTL, SPIx_CLKDIV, SPIx_SSCTL and SPIx_FIFOCTL registers, + * user shall clear the SPIEN (SPIx_CTL[0]) and confirm the SPIENSTS (SPIx_STATUS[15]) is 0 + * (by SPI_DISABLE_SYNC here). + */ +__STATIC_INLINE void SPI_ENABLE_SYNC(SPI_T *spi_base) +{ + if (! (spi_base->CTL & SPI_CTL_SPIEN_Msk)) { + SPI_ENABLE(spi_base); + } + while (! (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk)); +} +__STATIC_INLINE void SPI_DISABLE_SYNC(SPI_T *spi_base) +{ + if (spi_base->CTL & SPI_CTL_SPIEN_Msk) { + // NOTE: SPI H/W may get out of state without the busy check. + while (SPI_IS_BUSY(spi_base)); + + SPI_DISABLE(spi_base); + } + while (spi_base->STATUS & SPI_STATUS_SPIENSTS_Msk); +} + #if DEVICE_SPI_ASYNCH static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable); static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable); @@ -180,12 +208,9 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) MBED_ASSERT(bits >= NU_SPI_FRAME_MIN && bits <= NU_SPI_FRAME_MAX); SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - - // NOTE 1: All configurations should be ready before enabling SPI peripheral. - // NOTE 2: Re-configuration is allowed only as SPI peripheral is idle. - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); - + + SPI_DISABLE_SYNC(spi_base); + SPI_Open(spi_base, slave ? SPI_SLAVE : SPI_MASTER, (mode == 0) ? SPI_MODE_0 : (mode == 1) ? SPI_MODE_1 : (mode == 2) ? SPI_MODE_2 : SPI_MODE_3, @@ -211,15 +236,17 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) spi_base->SSCTL &= ~SPI_SSCTL_SSACTPOL_Msk; // NOTE: SPI_SS0 is defined as the slave select input in Slave mode. } + + // NOTE: M451's/M480's SPI_Open() will enable SPI transfer (SPI_CTL_SPIEN_Msk). This will violate judgement of spi_active(). Disable it. + SPI_DISABLE_SYNC(spi_base); } void spi_frequency(spi_t *obj, int hz) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); - + + SPI_DISABLE_SYNC(spi_base); + SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz); } @@ -229,7 +256,7 @@ int spi_master_write(spi_t *obj, int value) SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); // NOTE: Data in receive FIFO can be read out via ICE. - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for tx buffer empty while(! spi_writeable(obj)); @@ -239,7 +266,7 @@ int spi_master_write(spi_t *obj, int value) while (! spi_readable(obj)); int value2 = SPI_READ_RX(spi_base); - SPI_DISABLE(spi_base); + SPI_DISABLE_SYNC(spi_base); return value2; } @@ -264,7 +291,7 @@ int spi_slave_receive(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); return spi_readable(obj); }; @@ -273,7 +300,7 @@ int spi_slave_read(spi_t *obj) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for rx buffer full while (! spi_readable(obj)); @@ -285,7 +312,7 @@ void spi_slave_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); - SPI_ENABLE(spi_base); + SPI_ENABLE_SYNC(spi_base); // Wait for tx buffer empty while(! spi_writeable(obj)); @@ -318,8 +345,8 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, // SPI IRQ is necessary for both interrupt way and DMA way spi_enable_event(obj, event, 1); spi_buffer_set(obj, tx, tx_length, rx, rx_length); - - SPI_ENABLE(spi_base); + + SPI_ENABLE_SYNC(spi_base); if (obj->spi.dma_usage == DMA_USAGE_NEVER) { // Interrupt way @@ -425,9 +452,8 @@ void spi_abort_asynch(spi_t *obj) spi_enable_vector_interrupt(obj, 0, 0); spi_master_enable_interrupt(obj, 0); - // FIXME: SPI H/W may get out of state without the busy check. - while (SPI_IS_BUSY(spi_base)); - SPI_DISABLE(spi_base); + /* Necessary for accessing FIFOCTL below */ + SPI_DISABLE_SYNC(spi_base); SPI_ClearRxFIFO(spi_base); SPI_ClearTxFIFO(spi_base);