2015-08-11 05:12 PM
I have the example from the library showing DMA (mem to mem) working with the following initialization:
/* Configure DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aDST_Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;
DMA_InitStructure.DMA_BufferSize = (uint32_t)BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA_STREAM, &DMA_InitStructure);
I'm trying to adapt it to write to GPIOC, as follows but it's not working. Is there anything else I need to change? I can write to GPIOC->ODR manually and I see the lines toggle.
/* Configure DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOC->ODR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aSRC_Const_Buffer2;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = (uint32_t)BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA_STREAM, &DMA_InitStructure);
2015-08-11 05:17 PM
I don't have an F446
Is the DMA flagging an error?Does it like byte transfers? Tried HalfWord or Word?2015-08-11 06:37 PM
2015-08-11 07:21 PM
The sample seems to sit waiting for the stream to be done and the interrupt never triggers
while (DMA_GetCmdStatus(DMA_STREAM) != DISABLE)2015-08-11 08:50 PM
The IRQ is hardly likely to occur if the transfers are not occurring, and you're enabling HT/TC
The DMA should have status bits related to FIFO errors, direct mode errors, etc in the DMA_LISR/DMA_HISR registers.http://www.st.com/web/en/resource/technical/document/reference_manual/DM00135183.pdf
2015-08-12 08:32 AM
Thanks Clive, that's helpful. I just realized my SFR view wasn't working properly because Atollic hadn't linked to the correct .svd file, but I've got that fixed now and I see the transfer error flag set, although it's not clear to me from the description what this means.
Bits 24, 18, 8, 2DMEIFx: Stream x direct mode error interrupt flag (x=7..4)
This bit is set by hardware. It is cleared by software writing 1 to the corresponding bit in the DMA_HIFCR register. 0: No Direct mode error on stream x 1: A Direct mode error occurred on stream x Here is my full source code. Can you see anything that I'm doing wrong or perhaps help me understand why the error is occurring? I can see the GPIOB.0 toggling everytime TIM2-UP triggers, and GPIOC[7:0] are high when I manually write to them but don't change after that./* Includes */
#include ''stm32f4xx.h''
/* Private Definitions */
#define LEDG_PIN GPIO_Pin_5
#define DEBUG_PIN GPIO_Pin_0
#define ARRAYSIZE 16
void GPIO_Initialization(void);
void Timer_Initialization(void);
void DMA_Initialization(void);
void TIM2_IRQHandler(void);
/* Private variables */
uint8_t dmaBuffer[ARRAYSIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
RCC_ClocksTypeDef RCC_Clocks;
int main(void)
{
RCC_GetClocksFreq(&RCC_Clocks);
SystemCoreClockUpdate();
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
GPIO_Initialization();
Timer_Initialization();
DMA_Initialization();
/* Set high */
GPIOC->BSRRL = 0xFF;
GPIOA->BSRRL = LEDG_PIN;
/* Start DMA & TIMER */
DMA_Cmd(DMA1_Stream7, ENABLE);
TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
while (1)
{
}
}
void GPIO_Initialization()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the GPIO Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Configure the GPIO pin */
GPIO_InitStructure.GPIO_Pin = 0xFF;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//Timer interrupt check
GPIO_InitStructure.GPIO_Pin = DEBUG_PIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//LED
GPIO_InitStructure.GPIO_Pin = LEDG_PIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Timer_Initialization(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Disable Timer 2 */
TIM_Cmd(TIM2, DISABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 5000;
TIM_TimeBaseStructure.TIM_Prescaler = 4;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
}
void DMA_Initialization(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable DMA clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_DeInit(DMA1_Stream7);
DMA_InitStructure.DMA_Channel = DMA_Channel_3; //TIM2-UP
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOC->ODR;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&dmaBuffer;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_BufferSize = (uint32_t)ARRAYSIZE;
DMA_Init(DMA1_Stream7, &DMA_InitStructure);
/* Enable Transfer Complete interrupt */
DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE);
//Enable DMA channel IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
GPIOB->ODR ^= DEBUG_PIN; //Toggle pin 0
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
void DMA1_Stream7_IRQHandler(void)
{
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);
/* Turn LED off: End of Transfer */
GPIOA->BSRRH = LEDG_PIN;
DMA_Cmd(DMA1_Stream7, DISABLE);
}
}
2015-08-12 09:58 AM
Like I said, I don't have any F446 parts
Try it with DMA2 Stream1 Channel7 against TIM8 CH1, see this F4 thread[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/DMA%20MemoryToMemory%20using%20Timer%20for%20delivery%20rate&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=557]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FDMA%20MemoryToMemory%20using%20Timer%20for%20delivery%20rate&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=5572015-08-12 03:09 PM
Hmmm, for whatever reason this one works fine but if I switch to Tim2 it breaks. I'm trying to adapt TIM8 to work like TIM2 in my example with the output compare, but I'm not sure how to get the interrupt handler for TIM8. Am I supposed to use
void TIM8_UP_TIM13_IRQHandler(void)This doesn't seem to be triggering even when I enable the interrupt like so: TIM_ITConfig(TIM8, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2, ENABLE);Do I need to do something different for TIM8?2015-08-12 03:35 PM
The Updates would go there, the Capture/Compare got to
TIM8_CC_IRQHandlerAlso remember the Period and Prescaler are N-1 valuesDMA2 supports the kind of memory operations you want and uses APB2 based TIM2015-08-12 03:40 PM
I forgot to enable the NVIC, but that's good to know about the TIM8_CC_IRQHandler being separate.
I guess I'll just adapt my code to use TIM8, but I still don't understand why DMA1 wont work for this. From what I understand I should be able to do it, and in fact had this all working on the STM32F302, but had to move over to the F4 for the faster clock and increased RAM.Could it be because TIM2 is on APB1?