mirror of https://github.com/ARMmbed/mbed-os.git
[Nuvoton] Introduce SPI_ENABLE_SYNC/SPI_DISABLE_SYNC to simplify enable/disable control
parent
f6bcbfe1f0
commit
643d772cf9
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue