cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G431 SPI2 (16-bit) DMA (DMAMUX) data transmission is incorrect.

Oleksii
Associate III

Here is the code:

 

 

void DMA_Init_SPI2(void *rxBuffer, void *txBuffer, uint16_t rxSIZE, uint16_t txSIZE) {

    RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMAMUX1EN;

    // DMA1 Channel 1 для SPI2_RX (Peripheral-to-Memory)
    
    DMA1_Channel1->CCR = DMA_CCR_MINC |        // RAM++
                         DMA_CCR_TCIE |        // IRQ_EN
                         DMA_CCR_PSIZE_0 |     // 16-bit
                         DMA_CCR_MSIZE_0 |     // 16-bit
                         DMA_CCR_CIRC
                         ;
    DMA1_Channel1->CNDTR = rxSIZE;              
    DMA1_Channel1->CPAR = (uint32_t)&(SPI2->DR);
    DMA1_Channel1->CMAR = (uint32_t)rxBuffer;   
    DMAMUX1_Channel0->CCR = 12 ;               // SPI2_RX (Table 91 rm440)
    
 // DMA1 Channel 2 для SPI2_RX (Memory to Peripheral)
 
    DMA1_Channel2->CCR = DMA_CCR_MINC 	 |     // RAM++
                         DMA_CCR_DIR     |     // RAM -> SPI
                         DMA_CCR_PSIZE_0 |     // 16-bit
                         DMA_CCR_MSIZE_0       // 16-bit
                         ;

    DMA1_Channel2->CNDTR = txSIZE;              
    DMA1_Channel2->CPAR = (uint32_t)&(SPI2->DR); 
    DMA1_Channel2->CMAR = (uint32_t)txBuffer; 
    DMAMUX1_Channel1->CCR = 13;                // SPI2_TX (Table 91)

    NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

uint8_t dmaComplete;

void DMA1_Channel1_IRQHandler(void) {

    if (DMA1->ISR & DMA_ISR_TCIF1) {

        DMA1->IFCR = DMA_IFCR_CTCIF1;

        //DMA1_Channel1->CCR &= ~DMA_CCR_EN;
        DMA1_Channel2->CCR &= ~DMA_CCR_EN;

        dmaComplete = 1;

    }

//  DMA1->IFCR |= DMA_IFCR_CGIF1;
}
#define SPI2_DMA_enable  SPI2->CR2  |=  3; // 16 BIT
#define SPI2_DMA_disabled SPI2->CR2 |= ~3;

#define SPI2_CS_on   GPIOA->BRR =  1<<10;
#define SPI2_CS_off  GPIOA->BSRR = 1<<10;

void IIM42652_ReadSPI2_DMA(uint8_t startReadCommand,uint16_t* ram,uint16_t size) {

	dmaComplete = 0;

    ram[0] = (uint16_t)startReadCommand << 8; //example 0xAD00

    SPI2_CS_on
    
    DMA1_Channel2->CNDTR = size;
    DMA1_Channel2->CPAR = (uint32_t)&(SPI2->DR);
    DMA1_Channel2->CMAR = (uint32_t*)ram;
    DMA1_Channel2->CCR |= DMA_CCR_EN;
    
 	while (!dmaComplete);
 
    SPI2_CS_off

}
void ConfigSPI2(void) {

	RCC->APB1ENR1 |= RCC_APB1ENR1_SPI2EN;
	SPI2->CR1 = (1 << 2) | (2 << 3) | (3 <<  | 0; // master | clk/8 |  SSM=1 SSI =1 
	SPI2->CR2 |= (0b1111 <<  | 0; // 16 BIT /
	

	//SPI2->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;


	SPI2->CR1 |= (1 << 6);// EN SP2
}
uint16_t spi2_rx_buf[30]={0},spi2rxsize = 12,
	 spi2_tx_buf[30]={0},spi2txsize = 12;

int main(void) {

	// Настройка системного тактирования

	SystemClock_Config();
	GPIO_INIT();
	CAN_Config();

	I2C2_Init();

	ConfigSPI2();
	DMA_Init_SPI2(spi2_rx_buf,spi2_tx_buf,spi2rxsize,spi2txsize);
	init_iim42652(&imu_iim42652);
	
	DMA1_Channel1->CCR |= DMA_CCR_EN; // Rx circle
	SPI2_DMA_enable	
	
    while (1) {
	
	if(readyINT1){readyINT1 = 0; 
		      IIM42652_ReadSPI2_DMA(0xAD,spi2_tx_buf,12);//Read FIFO
		      if((*spi2_rx_buf) &0x04) sendACC = 1;
		      
		      }
	//..........
	
	if (!systick_pause) {
	 	if(sendACC){sendACC =0;
		     CAN_SendMessage(id+1,(uint8_t*) spi2_rx_buf, 8);
		     CAN_SendMessage(id+2,(uint8_t*) spi2_rx_buf+8, 8);
		     };
		systick_pause = 20;
	};
	

    }
}

 

 

 I checked SPI2 the operation using standard methods (in a loop) for sending and receiving data, and everything works as expected; the data is received correctly.

[0C 00 ] 14 00 78 F4 FF EA FF 19 08 02 00 F3 FF FC

 

But as soon as I enable the DMA, everything starts to behave strangely. The first half-word (16 bits) is received correctly, but then there is a change in the data or some garbage.

 

[0C 00] 00 14 DC 78 60 FF 16 00 02 08 F5 00 FD FF

 

Can anyone suggest where I might be missing something or doing it wrong? Unfortunately, the RM440 contains little information on DMA (DMAMUX) and sometimes does not correspond to stm32g431xx.h. I have already asked questions on GROK, DeepSeek, and ChatGPT—none of them could offer anything useful regarding this issue.))

 

 

 

3 REPLIES 3
gbm
Principal

To change SPI DMA settings  in SPI CR2, SPI must be disabled in CR1. RX DMA must be enabled before starting TX.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Oleksii
Associate III
#define SPI2_DMA_enable  SPI2->CR2  |=  3; // 16 BIT
DMA1_Channel1->CCR |= DMA_CCR_EN; // Rx circle
	SPI2_DMA_enable	

Thank you for the response. The datasheet does not specify that SPI needs to be disabled to enable DMA.

However, I have tried both options, and it works either way. Believe me, I have spent more than one day trying to find the problem.

Also, please note that the data is received, but it is incorrect; it is similar to what is expected.
Marker bayt 14 ...78

[0C 00 ]14 00 78 F4 FF EA FF 19 08 02 00 F3 FF FC   

[0C 00] 00 14 DC 78 60 FF 16 00 02 08 F5 00 FD FF

TDK
Guru

How are you determining that the data sent is incorrect? The best source would be to look at a scope or logic analyzer plot.

 

 

In your RX complete handler, you disable the TX DMA and assume it's done. This is an error unless the TX and RX buffers are exactly the same length, always. The TX DMA stream is automatically disabled when it's done.

 

Consider writing a minimal example which only performs the SPI functionality and posting it here.

If you feel a post has answered your question, please click "Accept as Solution".