I'm having some trouble getting my memory to GPIO DMA circular settings right. The initialization code pasted below has some issues.
I'm trying moving data from a uint16_t array to the GPIO->ODR register. I have the source and destination both configured as halfword since they're both 16-bit registers. My array is 48 bytes long, and I want to transfer 96 bytes (the 48 byte array 2 times). So I want the DMA to shift out the 48 bytes, then go back to the start of the array, and do it again with the same array.
However I'm not clear on how to tell the DMA after how many bytes to circle back. If I set the buffersize to 96 it just keeps reading 48 bytes past my array.
void WS2812_Basic_DMA_Init2(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Enable DMA1 clock
DMA_DeInit(DMA1_Channel2); // Reset DMA1 channe1 to default values;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // M2M Disabled- Peripheral mode (requires timer trigger)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Circular mode
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // High priority
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // Memory to Peripheral
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit Register
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Always write to same register
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOC->ODR; // Output data for GPIO
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 16-bit array
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment through array
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&source16; // 16-bit Source data
DMA_InitStructure.DMA_BufferSize = ARRAYSIZE; // Size of source array x 2
DMA_Init(DMA1_Channel2, &DMA_InitStructure); // Initialize DMA
//Enable DMA1 channel IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable DMA1 Channel Transfer Complete interrupt
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
}
Best Answer
The DMA was set up correctly but I was disabling it on the TC event. If I don't disable it, it will keep moving the specified number of bytes indefinitely.
The buffer size is what tells the DMA how many bytes to transfer before wrapping around, and it will continue to loop through those addresses until explicitly disabled.