2025-02-28 12:52 AM - last edited on 2025-02-28 1:01 AM by Andrew Neil
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.))
2025-02-28 1:17 AM
To change SPI DMA settings in SPI CR2, SPI must be disabled in CR1. RX DMA must be enabled before starting TX.
2025-02-28 1:46 AM
#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
2025-02-28 6:14 AM - edited 2025-02-28 6:15 AM
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.