From 8df96ec50a33f163f4be624ee13ac6228b82da25 Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Mon, 17 Feb 2020 15:00:09 +0800 Subject: [PATCH] Nuvoton: Make SPI inter-frame (delay match configured suspend interval In no MISO case, skip SPI read so that no more write/read delay contribute to SPI inter-frame delay when data is written successively. Update targets: - NUMAKER_PFM_NANO130 - NUMAKER_PFM_NUC472 - NUMAKER_PFM_M453 - NUMAKER_PFM_M487/NUMAKER_IOT_M487 - NU_PFM_M2351_* - NUMAKER_IOT_M263A - NUMAKER_M252KG --- targets/TARGET_NUVOTON/TARGET_M2351/spi_api.c | 29 +++++++++++++--- targets/TARGET_NUVOTON/TARGET_M251/spi_api.c | 29 +++++++++++++--- targets/TARGET_NUVOTON/TARGET_M261/spi_api.c | 29 +++++++++++++--- targets/TARGET_NUVOTON/TARGET_M451/spi_api.c | 29 +++++++++++++--- targets/TARGET_NUVOTON/TARGET_M480/spi_api.c | 29 +++++++++++++--- .../TARGET_NUVOTON/TARGET_NANO100/spi_api.c | 34 ++++++++++++++----- .../TARGET_NUVOTON/TARGET_NUC472/spi_api.c | 29 +++++++++++++--- 7 files changed, 169 insertions(+), 39 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M2351/spi_api.c index 17e0e4e6cc..09745ea3da 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M2351/spi_api.c @@ -285,17 +285,36 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. SPI_ENABLE_SYNC(spi_base); - // Wait for tx buffer empty + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); SPI_WRITE_TX(spi_base, value); - // Wait for rx buffer full - while (! spi_readable(obj)); - int value2 = SPI_READ_RX(spi_base); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + value2 = SPI_READ_RX(spi_base); + } /* We don't call SPI_DISABLE_SYNC here for performance. */ diff --git a/targets/TARGET_NUVOTON/TARGET_M251/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M251/spi_api.c index 7a3dea89ab..d8e9d378ac 100644 --- a/targets/TARGET_NUVOTON/TARGET_M251/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M251/spi_api.c @@ -243,17 +243,36 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. SPI_ENABLE_SYNC(spi_base); - // Wait for tx buffer empty + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); SPI_WRITE_TX(spi_base, value); - // Wait for rx buffer full - while (! spi_readable(obj)); - int value2 = SPI_READ_RX(spi_base); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + value2 = SPI_READ_RX(spi_base); + } /* We don't call SPI_DISABLE_SYNC here for performance. */ diff --git a/targets/TARGET_NUVOTON/TARGET_M261/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M261/spi_api.c index e41583f566..ebf7da50f2 100644 --- a/targets/TARGET_NUVOTON/TARGET_M261/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M261/spi_api.c @@ -264,17 +264,36 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. SPI_ENABLE_SYNC(spi_base); - // Wait for tx buffer empty + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); SPI_WRITE_TX(spi_base, value); - // Wait for rx buffer full - while (! spi_readable(obj)); - int value2 = SPI_READ_RX(spi_base); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + value2 = SPI_READ_RX(spi_base); + } /* We don't call SPI_DISABLE_SYNC here for performance. */ diff --git a/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c index 7930c4aa7d..8b2de0ed2e 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/spi_api.c @@ -257,17 +257,36 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. SPI_ENABLE_SYNC(spi_base); - // Wait for tx buffer empty + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); SPI_WRITE_TX(spi_base, value); - // Wait for rx buffer full - while (! spi_readable(obj)); - int value2 = SPI_READ_RX(spi_base); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + value2 = SPI_READ_RX(spi_base); + } /* We don't call SPI_DISABLE_SYNC here for performance. */ diff --git a/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c b/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c index fbefd3edd8..efcf02bbf1 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/spi_api.c @@ -270,17 +270,36 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. SPI_ENABLE_SYNC(spi_base); - // Wait for tx buffer empty + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); SPI_WRITE_TX(spi_base, value); - // Wait for rx buffer full - while (! spi_readable(obj)); - int value2 = SPI_READ_RX(spi_base); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + value2 = SPI_READ_RX(spi_base); + } /* We don't call SPI_DISABLE_SYNC here for performance. */ diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c index c419d5c99d..3862edf516 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/spi_api.c @@ -303,22 +303,38 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. - // 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 + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); uint32_t TX = (NU_MODSUBINDEX(obj->spi.spi) == 0) ? ((uint32_t) &spi_base->TX0) : ((uint32_t) &spi_base->TX1); M32(TX) = value; - // 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); - int value2 = M32(RX); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + uint32_t RX = (NU_MODSUBINDEX(obj->spi.spi) == 0) ? ((uint32_t) &spi_base->RX0) : ((uint32_t) &spi_base->RX1); + value2 = M32(RX); + } /* We don't call SPI_DISABLE_SYNC here for performance. */ diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c index 7719b71325..ddcf800de5 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/spi_api.c @@ -263,17 +263,36 @@ void spi_frequency(spi_t *obj, int hz) int spi_master_write(spi_t *obj, int value) { SPI_T *spi_base = (SPI_T *) NU_MODBASE(obj->spi.spi); + PinName spi_miso = obj->spi.pin_miso; - // NOTE: Data in receive FIFO can be read out via ICE. SPI_ENABLE_SYNC(spi_base); - // Wait for tx buffer empty + /* Wait for TX FIFO not full */ while(! spi_writeable(obj)); SPI_WRITE_TX(spi_base, value); - // Wait for rx buffer full - while (! spi_readable(obj)); - int value2 = SPI_READ_RX(spi_base); + /* Make inter-frame (SPI data frame) delay match configured suspend interval + * in no MISO case + * + * This API requires data write/read simultaneously. However, it can enlarge + * the inter-frame delay. The data flow for one call of this API would be: + * 1. Write data to TX FIFO when it is not full + * 2. Write delay consisting of TX FIFO to TX Shift Register... + * 3. Actual data transfer on SPI bus + * 4. Read delay consisting of RX FIFO from RX Shift Register... + * 5. Read data from RX FIFO when it is not empty + * Among above, S2&S4 contribute to the inter-frame delay. + * + * To favor no MISO case, we skip S4&S5. Thus, S2 can overlap with S3 and doesn't + * contribute to the inter-frame delay when data is written successively. The solution + * can cause RX FIFO overrun. Ignore it. + */ + int value2 = -1; + if (spi_miso != NC) { + /* Wait for RX FIFO not empty */ + while (! spi_readable(obj)); + value2 = SPI_READ_RX(spi_base); + } /* We don't call SPI_DISABLE_SYNC here for performance. */