2015-10-26 06:47 AM
On an stm32f411 Nucleo, I'm trying to generate a DMA request to transfer data from memory to the USART2 data register at every compare event (when CCR1 matches TIM3_CNT). To this end, I have, in order:
Configured the NVIC, enabled the TIM3_IRQ
Configured the GPIO pins for the user LED and USART2
Configured the USART2.
Configured the DMA1, Stream 4, Channel 5 (for accepting DMA requests from TIM3_CH1 as per the ref. manual).
Configured the TIM3 and OC1 so that a compare yields true every 1 second.
Enabled the interrupt and DMA requests at every compare TRUE event.
Enabled the timer.
The main function is as under:
int
main(
void
)
{
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
files before to branch to application main.
To reconfigure the default setting of SystemInit() function,
refer to system_stm32f4xx.c file */
/* SysTick end of count event each 10ms */
RCC_GetClocksFreq(&RCC_Clocks);
SystemCoreClockUpdate();
SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);
/* Add your application code here */
userLedInit(LED_DIMMING_DISABLE);
const
uint8_t datum[7] =
''NUCLEO ''
;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
/* IRQ configuration */
NVIC_SetPriorityGrouping(0x4);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* GPIO Configuration for USART2 through STLink VCP COM3 on Nucleo 411 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_TIM3);
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Medium_Speed;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART2 Initialization */
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = (USART_Mode_Tx | USART_Mode_Rx);
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_OverSampling8Cmd(USART2, DISABLE);
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
/* DMA Configuration */
DMA_DeInit(DMA1_Stream4);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_5;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&datum;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_Init(DMA1_Stream4, &DMA_InitStructure);
DMA_Cmd(DMA1_Stream4, ENABLE);
/* Configure TIM3 at 1 Hz */
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_Prescaler = 49999;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 1000;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_UpdateRequestConfig(TIM3, TIM_UpdateSource_Regular);
/* OC Configuration */
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM3, ENABLE);
cliPrintf(
''Greetings from USART2.''
);
/* Infinite loop */
while
(1)
{
;
}
}
And the interrupt handler like this:
1.
void
TIM3_IRQHandler(
void
)
2.
{
3.
TIM_ClearFlag(TIM3, TIM_FLAG_CC1);
4.
5.
userLedToggle();
6.
}
The LED toggles fine every one second but the DMA doesn't seem to work beyond one character. The USART is working since I get the greeting from line 95 above on Realterm, but after that, I just get one character and nothing afterwards while the LED continues to blink at 1 second.
What could be wrong? What should I try next? Thanks...2015-10-26 03:14 PM
I can't see anything wrong.
Do you have a debugger? Can you please post the content of relevant DMA registers? JW2015-10-26 10:56 PM
Thanks JW!
For pointing me in the right direction. I am using gdb + openocd + stlink for debugging. I read the contents of the DMA registers and the DMA_SxCR control register always held garbage values even after the DMA_Init() function exited. I think this is because some members of the DMA_InitStructure, declared INSIDE the main function and used to initialize the DMA, held garbage values. I used DMA_InitStruct() to initialize the variable itself and then initialized the DMA. Now it all works fine. Thanks again.