mirror of https://github.com/ARMmbed/mbed-os.git
Introduce SPI_ENABLE_SYNC/SPI_DISABLE_SYNC to simplify enable/disable control
parent
54ce719b71
commit
24496cb162
|
@ -60,6 +60,34 @@ static struct nu_spi_var spi2_var = {
|
||||||
#endif
|
#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
|
#if DEVICE_SPI_ASYNCH
|
||||||
static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
|
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);
|
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);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE 1: All configurations should be ready before enabling SPI peripheral.
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
// NOTE 2: Re-configuration is allowed only as SPI peripheral is idle.
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_Open(spi_base,
|
SPI_Open(spi_base,
|
||||||
slave ? SPI_SLAVE : SPI_MASTER,
|
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.
|
// 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)
|
void spi_frequency(spi_t *obj, int hz)
|
||||||
{
|
{
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
|
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);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE: Data in receive FIFO can be read out via ICE.
|
// 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
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
while(! spi_writeable(obj));
|
||||||
|
@ -236,7 +260,7 @@ int spi_master_write(spi_t *obj, int value)
|
||||||
while (! spi_readable(obj));
|
while (! spi_readable(obj));
|
||||||
int value2 = SPI_READ_RX(spi_base);
|
int value2 = SPI_READ_RX(spi_base);
|
||||||
|
|
||||||
SPI_DISABLE(spi_base);
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
|
|
||||||
return value2;
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
return spi_readable(obj);
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for rx buffer full
|
// Wait for rx buffer full
|
||||||
while (! spi_readable(obj));
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for tx buffer empty
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
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_enable_event(obj, event, 1);
|
||||||
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
|
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) {
|
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
||||||
// Interrupt way
|
// Interrupt way
|
||||||
|
@ -426,9 +450,8 @@ void spi_abort_asynch(spi_t *obj)
|
||||||
spi_enable_vector_interrupt(obj, 0, 0);
|
spi_enable_vector_interrupt(obj, 0, 0);
|
||||||
spi_master_enable_interrupt(obj, 0);
|
spi_master_enable_interrupt(obj, 0);
|
||||||
|
|
||||||
// FIXME: SPI H/W may get out of state without the busy check.
|
/* Necessary for accessing FIFOCTL below */
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_ClearRxFIFO(spi_base);
|
SPI_ClearRxFIFO(spi_base);
|
||||||
SPI_ClearTxFIFO(spi_base);
|
SPI_ClearTxFIFO(spi_base);
|
||||||
|
|
|
@ -71,6 +71,34 @@ static struct nu_spi_var spi4_var = {
|
||||||
#endif
|
#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
|
#if DEVICE_SPI_ASYNCH
|
||||||
static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
|
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);
|
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);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE 1: All configurations should be ready before enabling SPI peripheral.
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
// NOTE 2: Re-configuration is allowed only as SPI peripheral is idle.
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_Open(spi_base,
|
SPI_Open(spi_base,
|
||||||
slave ? SPI_SLAVE : SPI_MASTER,
|
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.
|
// 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)
|
void spi_frequency(spi_t *obj, int hz)
|
||||||
{
|
{
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
|
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);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE: Data in receive FIFO can be read out via ICE.
|
// 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
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
while(! spi_writeable(obj));
|
||||||
|
@ -241,7 +265,7 @@ int spi_master_write(spi_t *obj, int value)
|
||||||
while (! spi_readable(obj));
|
while (! spi_readable(obj));
|
||||||
int value2 = SPI_READ_RX(spi_base);
|
int value2 = SPI_READ_RX(spi_base);
|
||||||
|
|
||||||
SPI_DISABLE(spi_base);
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
|
|
||||||
return value2;
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
return spi_readable(obj);
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for rx buffer full
|
// Wait for rx buffer full
|
||||||
while (! spi_readable(obj));
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for tx buffer empty
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
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_enable_event(obj, event, 1);
|
||||||
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
|
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) {
|
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
||||||
// Interrupt way
|
// Interrupt way
|
||||||
|
@ -428,9 +452,8 @@ void spi_abort_asynch(spi_t *obj)
|
||||||
spi_enable_vector_interrupt(obj, 0, 0);
|
spi_enable_vector_interrupt(obj, 0, 0);
|
||||||
spi_master_enable_interrupt(obj, 0);
|
spi_master_enable_interrupt(obj, 0);
|
||||||
|
|
||||||
// NOTE: SPI H/W may get out of state without the busy check.
|
/* Necessary for accessing FIFOCTL below */
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_ClearRxFIFO(spi_base);
|
SPI_ClearRxFIFO(spi_base);
|
||||||
SPI_ClearTxFIFO(spi_base);
|
SPI_ClearTxFIFO(spi_base);
|
||||||
|
|
|
@ -75,6 +75,38 @@ static struct nu_spi_var spi2_var = {
|
||||||
#endif
|
#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
|
#if DEVICE_SPI_ASYNCH
|
||||||
static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
|
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);
|
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);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE: All configurations should be ready before enabling SPI peripheral.
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
// 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_Open(spi_base,
|
SPI_Open(spi_base,
|
||||||
slave ? SPI_SLAVE : SPI_MASTER,
|
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
|
// NANO130: Configure slave select signal to edge-trigger rather than level-trigger
|
||||||
spi_base->SSR |= SPI_SSR_SS_LTRIG_Msk;
|
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)
|
void spi_frequency(spi_t *obj, int hz)
|
||||||
{
|
{
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
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_DISABLE_SYNC(spi_base);
|
||||||
SPI_DisableFIFO(spi_base);
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
|
||||||
|
|
||||||
SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
|
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,6 +286,7 @@ int spi_master_write(spi_t *obj, int value)
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// NUC472/M453/M487: SPI_CTL.SPIEN is controlled by software (in FIFO mode).
|
// 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.
|
// NANO130: SPI_CTL.GO_BUSY is controlled by hardware in FIFO mode.
|
||||||
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for tx buffer empty
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
while(! spi_writeable(obj));
|
||||||
|
@ -303,9 +320,9 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
|
||||||
#if DEVICE_SPISLAVE
|
#if DEVICE_SPISLAVE
|
||||||
int spi_slave_receive(spi_t *obj)
|
int spi_slave_receive(spi_t *obj)
|
||||||
{
|
{
|
||||||
// NOTE:
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
// 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);
|
||||||
|
|
||||||
return spi_readable(obj);
|
return spi_readable(obj);
|
||||||
};
|
};
|
||||||
|
@ -314,9 +331,7 @@ int spi_slave_read(spi_t *obj)
|
||||||
{
|
{
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE:
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
// 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.
|
|
||||||
|
|
||||||
// Wait for rx buffer full
|
// Wait for rx buffer full
|
||||||
while (! spi_readable(obj));
|
while (! spi_readable(obj));
|
||||||
|
@ -329,9 +344,7 @@ void spi_slave_write(spi_t *obj, int value)
|
||||||
{
|
{
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE:
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
// 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.
|
|
||||||
|
|
||||||
// Wait for tx buffer empty
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
while(! spi_writeable(obj));
|
||||||
|
@ -365,9 +378,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
|
||||||
spi_enable_event(obj, event, 1);
|
spi_enable_event(obj, event, 1);
|
||||||
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
|
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
|
||||||
|
|
||||||
// NOTE:
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
// 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.
|
|
||||||
|
|
||||||
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
||||||
// Interrupt way
|
// Interrupt way
|
||||||
|
@ -473,8 +484,8 @@ void spi_abort_asynch(spi_t *obj)
|
||||||
spi_enable_vector_interrupt(obj, 0, 0);
|
spi_enable_vector_interrupt(obj, 0, 0);
|
||||||
spi_master_enable_interrupt(obj, 0, SPI_FIFO_RX_INTEN_MASK | SPI_FIFO_TX_INTEN_MASK);
|
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.
|
/* Necessary for accessing FIFOCTL below */
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
|
|
||||||
SPI_ClearRxFIFO(spi_base);
|
SPI_ClearRxFIFO(spi_base);
|
||||||
SPI_ClearTxFIFO(spi_base);
|
SPI_ClearTxFIFO(spi_base);
|
||||||
|
|
|
@ -66,6 +66,34 @@ static struct nu_spi_var spi3_var = {
|
||||||
#endif
|
#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
|
#if DEVICE_SPI_ASYNCH
|
||||||
static void spi_enable_vector_interrupt(spi_t *obj, uint32_t handler, uint8_t enable);
|
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);
|
static void spi_master_enable_interrupt(spi_t *obj, uint8_t enable);
|
||||||
|
@ -181,10 +209,7 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
|
||||||
|
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE 1: All configurations should be ready before enabling SPI peripheral.
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
// NOTE 2: Re-configuration is allowed only as SPI peripheral is idle.
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_Open(spi_base,
|
SPI_Open(spi_base,
|
||||||
slave ? SPI_SLAVE : SPI_MASTER,
|
slave ? SPI_SLAVE : SPI_MASTER,
|
||||||
|
@ -211,14 +236,16 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
|
||||||
spi_base->SSCTL &= ~SPI_SSCTL_SSACTPOL_Msk;
|
spi_base->SSCTL &= ~SPI_SSCTL_SSACTPOL_Msk;
|
||||||
// NOTE: SPI_SS0 is defined as the slave select input in Slave mode.
|
// 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)
|
void spi_frequency(spi_t *obj, int hz)
|
||||||
{
|
{
|
||||||
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_SetBusClock((SPI_T *) NU_MODBASE(obj->spi.spi), hz);
|
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);
|
SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
// NOTE: Data in receive FIFO can be read out via ICE.
|
// 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
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
while(! spi_writeable(obj));
|
||||||
|
@ -239,7 +266,7 @@ int spi_master_write(spi_t *obj, int value)
|
||||||
while (! spi_readable(obj));
|
while (! spi_readable(obj));
|
||||||
int value2 = SPI_READ_RX(spi_base);
|
int value2 = SPI_READ_RX(spi_base);
|
||||||
|
|
||||||
SPI_DISABLE(spi_base);
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
|
|
||||||
return value2;
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
return spi_readable(obj);
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for rx buffer full
|
// Wait for rx buffer full
|
||||||
while (! spi_readable(obj));
|
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_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi);
|
||||||
|
|
||||||
SPI_ENABLE(spi_base);
|
SPI_ENABLE_SYNC(spi_base);
|
||||||
|
|
||||||
// Wait for tx buffer empty
|
// Wait for tx buffer empty
|
||||||
while(! spi_writeable(obj));
|
while(! spi_writeable(obj));
|
||||||
|
@ -319,7 +346,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
|
||||||
spi_enable_event(obj, event, 1);
|
spi_enable_event(obj, event, 1);
|
||||||
spi_buffer_set(obj, tx, tx_length, rx, rx_length);
|
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) {
|
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
||||||
// Interrupt way
|
// Interrupt way
|
||||||
|
@ -425,9 +452,8 @@ void spi_abort_asynch(spi_t *obj)
|
||||||
spi_enable_vector_interrupt(obj, 0, 0);
|
spi_enable_vector_interrupt(obj, 0, 0);
|
||||||
spi_master_enable_interrupt(obj, 0);
|
spi_master_enable_interrupt(obj, 0);
|
||||||
|
|
||||||
// FIXME: SPI H/W may get out of state without the busy check.
|
/* Necessary for accessing FIFOCTL below */
|
||||||
while (SPI_IS_BUSY(spi_base));
|
SPI_DISABLE_SYNC(spi_base);
|
||||||
SPI_DISABLE(spi_base);
|
|
||||||
|
|
||||||
SPI_ClearRxFIFO(spi_base);
|
SPI_ClearRxFIFO(spi_base);
|
||||||
SPI_ClearTxFIFO(spi_base);
|
SPI_ClearTxFIFO(spi_base);
|
||||||
|
|
Loading…
Reference in New Issue