Skip to main content
Graduate
August 5, 2025
Solved

SPI DMA Memory to peripheral

  • August 5, 2025
  • 6 replies
  • 483 views

Hello everyone,

I'm currently working on an SPI bus on an STM32U031C6 + S2LP.

I'd like to use my SPI with DMA mode.

The SPI bus I used previously worked on this board. As this is my first time using DMA, I'm simply trying to send data without necessarily performing a read, but rather by analyzing the bytes using a logic analyzer.

 

My SPI configuration is defined as follows:

//-----------------------------------------------------------------------------
void S2LP_InitIO (void)
//-----------------------------------------------------------------------------
{
	RCC->APBENR2 |= RCC_APBENR2_SPI1EN;

	GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE11)) | (GPIO_MODER_MODE11_0); //-- Select output mode (01)

	//--- PA15 en sortie (pour Spirit-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 )); //-- Select input mode (00)
	GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPD0 )); //-- Input Floating (00)


	//======= Bus SPI : PA5,6,7 (SCLK, MISO, MOSI) ==========
	//--- Mode Alternate Function
	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
	);

	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_SPE;					//--- Enable SPI1

	if (!(SPI1->CR1 & SPI_CR1_SPE)) {
	 Error_Handler(); // ou breakpoint
	}

}

 

Here my function for try DMA Mode :

//-----------------------------------------------------------------------------
uint8_t SpiritDeviceVersion (void)
//-----------------------------------------------------------------------------
{
	S2LP_CS_DEBUT;

	uint8_t aTxBuffer[3] = {0x01, 0xF1, 0x00};
	RCC->AHBENR |= RCC_AHBENR_DMA1EN;	// Horloge DMA1 ON

	DMA1_Channel1->CPAR = (uint32_t) &(SPI1->DR);
	DMA1_Channel1->CMAR = (uint32_t) &(aTxBuffer[0]);

	DMA1_Channel1->CCR = 0;
	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);		// Haute priorite
	DMA1_Channel1->CNDTR = 0x03;			//3 data

	DMA1_Channel1->CCR |= DMA_CCR_EN;
	DMAMUX1_Channel1->CCR = 37; // SPI_TX
	while(DMA1_Channel1->CNDTR != 0) asm("nop");

	S2LP_CS_FIN;
	return toto;

}

 

I'm currently stuck in the While CNDTR != 0 condition.

I think my counter should be decrementing, but it never does, and I don't see any information on the SPI bus...

If you have any ideas ?

Thank you for your time.

    This topic has been closed for replies.
    Best answer by waclawek.jan

    > Is correct to configure and/or enable DMA after SPI clock ?

    Probably yes.

    As I've said and gave a link above, your problem may be incorrect DMAMUX channel - for DMA channel 1 you need to set up DMAMUX channel 0.

    JW

    6 replies

    Super User
    August 5, 2025

    Where do you enable SPI (SPIx_CR1->SPE=1)?

    If in doubts, always start by reading out and checking content of relevant peripherals (SPI, DMAMUX, DMA, GPIO).

    JW

    Graduate
    August 5, 2025

     

    Sorry,

    Before posting my message, I tried moving: SPI1->CR1 |= SPI_CR1_SPE;

    I'm enabeling SPI after configuration of SPI-> CRx registers

    I've corrected my message, and will add a capture of my DMACCR1 Register.

    Super User
    August 5, 2025

    Read out and check/post content of registers of relevant peripherals (SPI, DMAMUX, DMA, GPIO).

    JW

    PS.I would set up DMAMUX before enabling DMA; and also the DMAMUX channel assignment may be wrong:

    JW

    Graduate
    August 5, 2025

    So,

    I have checked my peripherals, the SPI is runing and the DMA1 too.
    But i'm still struck in while DMA1_Channel1->CNDTR != 0.

    Is correct to configure and/or enable DMA after SPI clock ?

     

    Regards.

    Super User
    August 5, 2025

    > Is correct to configure and/or enable DMA after SPI clock ?

    Probably yes.

    As I've said and gave a link above, your problem may be incorrect DMAMUX channel - for DMA channel 1 you need to set up DMAMUX channel 0.

    JW

    Graduate
    August 5, 2025

    Thanks, for your reply,
    Now it's work,

    Quentin_27_1-1754405483444.png

    I just haven't understand the channel0_DMAMUX1 was on DMA1...

    Quentin_27_0-1754405424506.png

    I will now set the rx method, if I can help anyone my code below:

    	volatile uint8_t	toto;
    
    
    
    	uint8_t aTxBuffer[3] = {0x01, 0xF1, 0x00};
    
    	RCC->AHBENR |= RCC_AHBENR_DMA1EN;	// Horloge DMA1 ON
    	DMA1_Channel1->CPAR = (uint32_t) &(SPI1->DR);
    	DMA1_Channel1->CMAR = (uint32_t) &(aTxBuffer[0]);
    
    	DMA1_Channel1->CCR = 0;
    	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);		// Haute priorite
    
    	DMA1_Channel1->CNDTR = 0x03;			//3 data
    
    
    	DMAMUX1_Channel0->CCR = 37;
    	DMA1_Channel1->CCR |= DMA_CCR_EN;
    
    	S2LP_CS_DEBUT;
    	while(DMA1_Channel1->CNDTR != 0) asm("nop");
    
    	S2LP_CS_FIN;
    

    Thanks for your time.