2015-10-08 07:23 AM
I'm trying to understand DMA usage by testing a simple application. The idea is to allow USART peripheral to access read and write from and to memory directly, by using DMA technique. I'm testing this on
http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF253215?sc=internet/evalboard/product/253jsp
. After reading some generic literature on DMA and reference manual of this particular SOC (STM32F051XX), my understanding on DMA capable, USART operation for data reception (i.e. Data transfer direction is from Peripheral to Memory) is as follows:H/W = Handled by Hardware
S/W = Handled by SoftwareBased on above understanding and some sample code DMA related code distributed by STM and in this forum, Below is my simple application. The idea is to transfer some characters over USART1 interface, transfer this data into memory using DMA and toggle the LED on evaluation board to indicate the completion of transfer.
Below is the code snip:
#include <stddef.h>
#include <stdint.h>
#include ''stm32f0xx.h''
#include ''stm32f0xx_it.h''
static
__IO uint32_t val;
__INLINE
void
Configure_GPIOC(
void
)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* configure pins */
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
__INLINE
void
Configure_GPIOA(
void
)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* configure pins */
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void
USART1_Configuration(
void
)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
USART_InitTypeDef USART_InitStructure;
/* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/* Enable USART1 */
USART_Cmd(USART1, ENABLE);
}
void
DMA1_Configure(
void
)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel3);
/* Configure Channel Parameters */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->RDR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)val;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 4;
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_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
/* Initialize the DMA Channel */
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
/* Enable the USART's DMA receive request interface */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
}
void
DMA1_Channel2_3_IRQHandler(
void
)
{
/* Test on DMA Transfer Complete interrupt */
if
(DMA_GetITStatus(DMA1_IT_TC3))
{
/* Toggle the Blue LED */
GPIOC->ODR ^= GPIO_ODR_9;
/* Clear DMA Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA1_IT_TC3);
}
}
int
main(
void
)
{
RCC_ClocksTypeDef RCC_Clocks;
/* SysTick end of count event each 1ms */
RCC_GetClocksFreq(&RCC_Clocks);
/* initialize the System Timer and its interrupt, and start the
* System Tick Timer. Refer SysTick_Handler in startup_stm32fs
* and stm32f0xx_it.c
*/
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
/* Configure GPIOC port and pins: Green and Blue LED On evaluation board */
Configure_GPIOC();
/* Configure GPIOA port and pins: PA.9 and PA.1O as USART On evaluation board */
Configure_GPIOA();
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
/* Configure USART1 */
USART1_Configuration();
DMA1_Configure();
/* Reference manual, pg 176:
* Bit 10 USART1_RX_DMA_RMP
* 0: No remap (USART1_RX DMA request mapped on DMA channel 3)
*/
SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_USART1Rx, DISABLE);
while
(1)
{
__WFI();
}
}
Compilation happens fine, but it seems that the
DMA1_Channel2_3_IRQHandler
is not getting invoked and hence I do not see the LED getting Toggled :( Also attach here is the Screenshot of RealTerm Settings (1) and thesend tab in RealTerm, where I try to send a character (2). (1) (2) Thank you for your help. #solved #stm322015-10-08 08:41 AM
The C++ syntax has me asking if this is in a .cpp file? That could cause interrupt issues.
The biggest issue I can see is that you're not enabling the USART1 clock.2015-10-08 09:06 AM
Aha, the Camel Case, the inspiration came from the library routines (USART_Cmd etc)
And yes, I missed enabling the clock for USART1, but now even after enabling it, things still don't work. Updated USART1 setup routine:void USART1_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_InitTypeDef USART_InitStructure;
/* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/* Enable USART1 */
USART_Cmd(USART1, ENABLE);
}
2015-10-08 09:19 AM
I'm not using the F0, or looking to work through the references here.
I will caution you not to do the GPIO initialization the way you are, enable the clock earlier, fill the structure in, then initialize the pin. There is a hazard related to enabling the clock and immediately touching the peripheral. You need to send at least 4 characters to ''complete'' the DMA transfer as specified. If using C++, watch the naming of the IRQ handler.2015-10-09 02:01 AM
Thank you so much for your help. Finally got itworking :)
1: Changed GPIO Initialization as yousuggested, i.e. Now I, (i) enable theclock, (ii) Fill in the structure, (iii) Initialize the pin 2:The DMA Memory base address was incorrect, Previously, in theDMA1_Configure
routine, it was as below:DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)val;
Where, val was declared as,
static
__IO uint32_t val;
Now, Changed the above two as:
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&val;
and val as,
static
__IO uint8_t val[4];
And, as expected, the DMA ISR gets invoked and I see the LED toggling :)
Please comment, if you have any other guidelines, suggestions.
Thanks again.
2015-10-09 04:41 AM
For the completion purposes, I should mention thesetting up DMAISR that I forgot to mention in my previouspost. This routine shouldbe called inthe beginningbefore setting up DMA channel.
void
NVIC_Configuration(
void
)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the USART1 RX DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}