2025-09-10 2:48 AM
Hi everyone,
Im currently trying to use SPI with DMA mode on STM32U031G6 with an S2LP,
In this specific case I want to obtain the number of bytes present in my FIFO (10 bytes here), but the problem is that my reading through DMA mode does not work.
Below is the data that I analyze in SPI using a logic analyzer :
we have the read command (0x01) + the FIFO status command (0x90) + the command (0x00) where I get my response 0x0A or my 10 bytes.
What I don't understand is that the read_1_registre_DMA function returns 1 on the 3rd data item that I want to read as below :
Below is the function where I give my 3 Tx commands and where I expect 3 responses in return for Rx but the data is not correct for RX[2] (3rd element, or for me I should find my 0xA):
//-----------------------------------------------------------------------------
uint8_t S2LP_Read1Registre (uint8_t address)
//-----------------------------------------------------------------------------
{
S2LP_Init_DMA_Mode();
// Préparer les commandes SPI (HEADER + adresse FIFO)
g_SPI_DMA_TxBuffer[0] = (HEADER_READ | HEADER_ADDRESS);
g_SPI_DMA_TxBuffer[1] = address;
g_SPI_DMA_TxBuffer[2] = (0x00);
// Sélection du S2LP
S2LP_CS_DEBUT;
// Setup CNDTR
DMA1_Channel2->CNDTR = 0x03; // RX
DMA1_Channel1->CNDTR = 0x03; // TX
// Lancer RX puis TX
DMA1_Channel2->CCR |= DMA_CCR_EN;
DMA1_Channel1->CCR |= DMA_CCR_EN;
// Attente fin TX (canal 1), puis RX (canal 2)
while(DMA1_Channel1->CNDTR != 0) asm("nop");
while(DMA1_Channel2->CNDTR != 0) asm("nop");
// Fin de communication
S2LP_CS_FIN;
// Désactiver les DMA
DMA1_Channel1->CCR &= ~DMA_CCR_EN;
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
uint8_t toto = g_SPI_DMA_RxBuffer[2]; //--- lecture data recue
return toto;
}
And the init_DMA Function:
uint8_t g_SPI_DMA_TxBuffer[BUF_SIZE] = {0};
uint8_t g_SPI_DMA_RxBuffer[BUF_SIZE] = {0};
void S2LP_Init_DMA_Mode (void)
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Horloge DMA1 ON
//Config Tx
DMA1_Channel1->CPAR = (uint32_t) &(SPI1->DR); // Definie l'adresse SPI.DR comme adresse peripherique
DMA1_Channel1->CMAR = (uint32_t) &(g_SPI_DMA_TxBuffer[0]); // Definie l'adresse tableau comme buffer Tx
DMA1_Channel1->CCR = 0; // Pour etre sur de commencer la config à vide
DMA1_Channel1->CCR |= (DMA_CCR_DIR); // Direction vers peripherique (TX)
DMA1_Channel1->CCR |= (DMA_CCR_MINC); // MEM increment mode
DMA1_Channel1->CCR |= (DMA_CCR_PL_1); // Haute priorite pour le SPI gere uniquement les operations faites en DMA
//DMA1_Channel1->CNDTR = 0x03; // 3 data
//Config Rx
DMA1_Channel2->CPAR = (uint32_t) &(SPI1->DR); // Definie l'adresse SPI.DR comme adresse peripherique
DMA1_Channel2->CMAR = (uint32_t) &(g_SPI_DMA_RxBuffer[0]); // Definie l'adresse tableau comme buffer Rx
DMA1_Channel2->CCR = 0; // Pour etre sur de commencer la config à vide
// Attention ici on active pas DMA_CCR_DIR car on va dans le sens inverse justement !
DMA1_Channel2->CCR |= (DMA_CCR_MINC); //MEM increment mode
DMA1_Channel2->CCR |= (DMA_CCR_PL_0 | DMA_CCR_PL_1); // Haute priorite pour le SPI gere uniquement les opérations faites en DMA
//DMA1_Channel2->CNDTR = 0x01; //1 data
// -- Usage DMA MUX --
// Selection du MUX DMAMUX1 channel_x <=HARD=> DMA_Channel_x+1
//----------------------------------------------------------
DMAMUX1_Channel0->CCR = 37; // Selection du MUX DMAMUX1 channel_0 <=HARD=> DMA_Channel_1
DMAMUX1_Channel1->CCR = 36; // Selection du MUX DMAMUX1 channel_1 <=HARD=> DMA_Channel_2
// ... ...
}
Thanks for your time !
Solved! Go to Solution.
2025-09-11 2:51 AM
My guess is that what you see is the SPI Rx FIFO in action.
I would clear that SPI Rx FIFO "manually" before starting DMA, by something like
while (SPI1->SR & SPI_SR_RXNE) (void)SPI1->DR; // dummy read
It's not clear to me why would that FIFO be not empty, but the answer may be hidden in other parts of your program which we don't see.
JW
2025-09-10 5:38 AM
RX[2] does not have the expected value.
Do you know that RX[0] and RX[1] are being received correctly?
You observe RX[0] and RX[1] have the expected values after the transfer. But might they have had those values before the transfer? Can you put e.g. 0xff into all of them prior to the transfer to test this?
Understanding if any bytes are received correctly will help diagnose where the problem might be. For example, do you set SPI_CR2_RXDMAEN as well as SPI_CR2_TXDMAEN ?
2025-09-10 6:15 AM
Thank you for your reply,
I try to add as you say Rx[0 - 2] = 0xFF
but i have the same result :
Bellow the SPI_IO_init code where I enable DMA for SPI-Rx and SPI-Tx
//-----------------------------------------------------------------------------
void S2LP_InitIO (void)
//-----------------------------------------------------------------------------
{
//--- PA11 -CSn) ---
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE11)) | (GPIO_MODER_MODE11_0); //-- Select output mode (01)
//--- PA15 -SDn) ---
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE15)) | (GPIO_MODER_MODE15_0); //-- Select output mode (01)
//--- PA0 en entree sans pull-up/down (pour Spirit-GPIO0) ---
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE0 ));
GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPD0 )); //-- Input Floating (00)
//======= Bus SPI : PA5,6,7 (SCLK, MISO, MOSI) ==========
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE5 | GPIO_MODER_MODE6 | GPIO_MODER_MODE7)) |
(GPIO_MODER_MODE5_1 | GPIO_MODER_MODE6_1 | GPIO_MODER_MODE7_1);
GPIOA->AFR[0] &= ~(
(0xF << (5 * 4)) | // Clear PA5
(0xF << (6 * 4)) | // Clear PA6
(0xF << (7 * 4)) // Clear PA7
);
GPIOA->AFR[0] |= (
(0x5 << (5 * 4)) | // PA5 -> AF5
(0x5 << (6 * 4)) | // PA6 -> AF5
(0x5 << (7 * 4)) // PA7 -> AF5
);
//--- Pull-down sur PA6, PA2 pour SDO, GPIO0 en mode StandBy
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD6); //-- (00)
GPIOA->PUPDR |= (GPIO_PUPDR_PUPD6_1); //-- Pull down (10)
SPI1->CR1 &= ~SPI_CR1_SPE; // <-- Désactiver SPI
SPI1->CR2 = SPI_CR2_FRXTH | SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_BR_0 | SPI_CR1_SSM | SPI_CR1_SSI ; //--- Master, BR:Fpclk/4, CPOL et CPHA a zero
//SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_SSM | SPI_CR1_SSI;
SPI1->CR1 |= SPI_CR1_SPE; //--- Enable SPI1
if (!(SPI1->CR1 & SPI_CR1_SPE))
{
Error_Handler();
}
S2LP_Init_DMA_Mode();
}
Thanks
2025-09-10 11:32 PM
Anyone get this trouble ?
2025-09-11 12:34 AM
Simple byte-by-byte polled transfer works?
JW
2025-09-11 1:01 AM
Hi, thanks for you reply,
In fact, I actually switched to DMA because of the addition of the SPI FIFO on the microprocessor I'm using, which I didn't have before (where I just read my SPI->DR register and checked my FLAGs), but I was actually able to test the SPI's operation in polling.
What makes me doubt my implementation of DMA is that after reading my 0xFD register, which contains the number of elements in my FIFO (which I can see on the logic analyzer...),
I set the number of elements read to 10 and called my DMA function, which reads my FIFO. And surprise:
My orange data corresponds to what I would have wanted while reading 0xFD (number of elements and the blue data are indeed the data I would like to have in my FIFO..)
There's a sort of offset, but I don't understand the reason because I call my "S2LP DMA INIT" function every time before using my DMA functions, which initializes the DMA with the addresses of the arrays to be used.
Thanks for your time.
Q.M
2025-09-11 2:51 AM
My guess is that what you see is the SPI Rx FIFO in action.
I would clear that SPI Rx FIFO "manually" before starting DMA, by something like
while (SPI1->SR & SPI_SR_RXNE) (void)SPI1->DR; // dummy read
It's not clear to me why would that FIFO be not empty, but the answer may be hidden in other parts of your program which we don't see.
JW