This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit cb024f41e2c9c5e3042f98d70329e84a7ec03ed0 Author: Jorge Guzman <[email protected]> AuthorDate: Sun Oct 25 00:57:09 2026 -0300 arch/risc-v/gd32vw55x: do not end an SPI DMA early The SPI driver enabled every DMA channel interrupt, and its callback wakes the waiter on any of them: the half transfer interrupt ended the exchange while the second half was still on the wire, and the single data mode exception, raised when a receive request waits for the bus, ended it at a random point. These exceptions have no effect on the transfer (user manual 10.5.2). - spi: enable only the full transfer finish and access error interrupts. Also indent the case labels of the SPI mode switch as nxstyle expects (no functional change). - dma: clear the exception flags but call back only along with another event. Tested on the GD32VW553K-START with MOSI wired to MISO (PA0-PA1): 24-byte exchanges through spitool returned the sent data 9 times out of 50 before, with the end of the data missing, and 50 times out of 50 now. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Jorge Guzman <[email protected]> --- arch/risc-v/src/gd32vw55x/gd32vw55x_dma.c | 8 +++++-- arch/risc-v/src/gd32vw55x/gd32vw55x_spi.c | 38 ++++++++++++++++++------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/arch/risc-v/src/gd32vw55x/gd32vw55x_dma.c b/arch/risc-v/src/gd32vw55x/gd32vw55x_dma.c index 761457e441b..34b09e63d9a 100644 --- a/arch/risc-v/src/gd32vw55x/gd32vw55x_dma.c +++ b/arch/risc-v/src/gd32vw55x/gd32vw55x_dma.c @@ -436,9 +436,13 @@ static int gd32_dma_interrupt(int irq, void *context, void *arg) { gd32_dma_interrupt_flag_clear(dmachan->chan_num, status); - /* Invoke the DMA callback */ + /* Invoke the DMA callback. The single data mode and FIFO exceptions + * have no effect on the transfer (user manual 10.5.2): they are only + * reported along with another event. + */ - if (dmachan->callback != NULL) + if (dmachan->callback != NULL && + (status & ~(DMA_INTF_SDEIF | DMA_INTF_FEEIF)) != 0) { dmachan->callback(dmachan, (uint16_t)status, dmachan->arg); } diff --git a/arch/risc-v/src/gd32vw55x/gd32vw55x_spi.c b/arch/risc-v/src/gd32vw55x/gd32vw55x_spi.c index c6080d9dce5..1f4723c1094 100644 --- a/arch/risc-v/src/gd32vw55x/gd32vw55x_spi.c +++ b/arch/risc-v/src/gd32vw55x/gd32vw55x_spi.c @@ -98,9 +98,15 @@ #ifdef CONFIG_GD32VW55X_SPI_DMA -/* The DMA interrupts that are enabled while an SPI DMA is in progress */ +/* The DMA interrupts that are enabled while an SPI DMA is in progress: + * the end of the transfer and the access error. The callback wakes the + * waiter on any interrupt, so the half transfer interrupt must stay off, + * or the exchange would end while the second half is still on the wire, + * and so must the single data mode exception, which a receive request + * raises when it waits for the bus and which does not stop the transfer. + */ -# define SPI_DMA_INTEN (DMA_INT_MASK) +# define SPI_DMA_INTEN (DMA_CHXCTL_FTFIE | DMA_CHXCTL_TAEIE) /* SPI DMA priority */ @@ -627,24 +633,24 @@ static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) { switch (mode) { - case SPIDEV_MODE0: /* CKPL=0, CKPH=0 */ - setbits = 0; - break; + case SPIDEV_MODE0: /* CKPL=0, CKPH=0 */ + setbits = 0; + break; - case SPIDEV_MODE1: /* CKPL=0, CKPH=1 */ - setbits = SPI_CTL0_CKPH; - break; + case SPIDEV_MODE1: /* CKPL=0, CKPH=1 */ + setbits = SPI_CTL0_CKPH; + break; - case SPIDEV_MODE2: /* CKPL=1, CKPH=0 */ - setbits = SPI_CTL0_CKPL; - break; + case SPIDEV_MODE2: /* CKPL=1, CKPH=0 */ + setbits = SPI_CTL0_CKPL; + break; - case SPIDEV_MODE3: /* CKPL=1, CKPH=1 */ - setbits = SPI_CTL0_CKPH | SPI_CTL0_CKPL; - break; + case SPIDEV_MODE3: /* CKPL=1, CKPH=1 */ + setbits = SPI_CTL0_CKPH | SPI_CTL0_CKPL; + break; - default: - return; + default: + return; } /* The clock configuration can only be changed while the SPI is
