MEM2MEM mode has three features compared to normal DMA operation when we send any data to or receive anything from a peripheral:
- MEM2MEM mode does not require any request from the peripheral modules. Once the DMA channel is enabled, the transfer process starts immediately.
- The memory address register DMA_CMARx and the peripheral address register DMA_CPARx are populated with memory area addresses.
- MEM2MEM mode and CIRC ring mode cannot be used at the same time.
Code: Select all
uint8_t data[10];
uint8_t buff[sizeof(data)];
for(int i=0; i<sizeof(data); i++)
{
data = i+1;
buff = 0;
}
Don't forget to enable DMA1 clocking and disable the selected DMA channel just in case:
Code: Select all
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //Enable DMA1 clocking
DMA1_Channel1->CCR &= ~DMA_CCR_EN; //Disable the channel before tuning.
Code: Select all
DMA1_Channel1->CNDTR = sizeof(data); //how many elements to copy
DMA1_Channel1->CMAR = (uint32_t)(data); //what we copy (memory address)
DMA1_Channel1->CPAR = (uint32_t)(buff); //where we copy (address of "periphery")
Code: Select all
DMA1_Channel1->CCR =.
DMA_CCR_MEM2MEM //from memory to memory
| DMA_CCR_MINC //memory increment
| DMA_CCR_PINC // peripheral increment
| DMA_CCR_DIR; //direction from "memory" to "peripheral".
You can start the process with this line:
Code: Select all
DMA1_Channel1->CCR |= DMA_CCR_EN; //start the process
Code: Select all
uint8_t data[10];
uint8_t buff[sizeof(data)];
void main()
{
for(int i=0; i<sizeof(data); i++)
{
data[i] = i+1;
buff[i] = 0;
}
RCC->AHBENR |= RCC_AHBENR_DMA1EN; //Enable DMA1 clocking
DMA1_Channel1->CCR &= ~DMA_CCR_EN; //Disable channel before tuning
DMA1_Channel1->CNDTR = sizeof(data); //how many elements to copy
DMA1_Channel1->CMAR = (uint32_t)(data); //what we copy (memory address)
DMA1_Channel1->CPAR = (uint32_t)(buff); //where we copy (address of "periphery")
DMA1_Channel1->CCR = (uint32_t(buff); //where we copy (address of "periphery").
DMA_CCR_MEM2MEM //from memory to memory
| DMA_CCR_MINC //memory increment
| DMA_CCR_PINC // peripheral increment
| DMA_CCR_DIR; //direction from "memory" to "periphery"
DMA1_Channel1->CCR |= DMA_CCR_EN; //start the process
for(;;)
{
}
}
and after the process is complete, it's like this:
It's all working!
It's worth noting that if instead of
Code: Select all
DMA1_Channel1->CMAR = (uint32_t)(data); //what we copy (address of "memory")
DMA1_Channel1->CPAR = (uint32_t)(buff); //where we copy (address of "periphery")
Code: Select all
DMA1_Channel1->CMAR = (uint32_t)(buff); //where we copy (address of "memory")
DMA1_Channel1->CPAR = (uint32_t)(data); //what we copy (address of "periphery")
Code: Select all
DMA1_Channel1->CCR =.
DMA_CCR_MEM2MEM //from memory to memory
| DMA_CCR_MINC //memory increment
| DMA_CCR_PINC; //increment of peripherals.