cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F446 DMA Mem to GPIO

daniel2
Associate II
Posted on August 12, 2015 at 02:12

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);

14 REPLIES 14
Posted on August 12, 2015 at 02:17

I don't have an F446

Is the DMA flagging an error?

Does it like byte transfers? Tried HalfWord or Word?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
daniel2
Associate II
Posted on August 12, 2015 at 03:37

I don't see the IRQ handler trigger at all with all triggers enabled. Is there anywhere else to check for errors?

I've tried different data sizes as well with no luck.

daniel2
Associate II
Posted on August 12, 2015 at 04:21

The sample seems to sit waiting for the stream to be done and the interrupt never triggers

while (DMA_GetCmdStatus(DMA_STREAM) != DISABLE)

Posted on August 12, 2015 at 05:50

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

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
daniel2
Associate II
Posted on August 12, 2015 at 17:32

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);
}
}

Posted on August 12, 2015 at 18:58

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&currentviews=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=557

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
daniel2
Associate II
Posted on August 13, 2015 at 00:09

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?

Posted on August 13, 2015 at 00:35

The Updates would go there, the Capture/Compare got to

TIM8_CC_IRQHandler

Also remember the Period and Prescaler are N-1 values

DMA2 supports the kind of memory operations you want and uses APB2 based TIM

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
daniel2
Associate II
Posted on August 13, 2015 at 00:40

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?