Parallel data transmission using GPIO and DMA STM32F051xx
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-08-13 10:25 AM
Hi all! I'm trying to create a parallel synchronous data transmission using DMA and GPIO on a STM32F051 MCU. I've been following the AN4666 document that ST released, but is set up for STM32F4 MCUs. I also don't use HAL drivers, unlike the example code ST has for that document.
I'm having issues with getting the DMA to output data to the pins. I see only 0 on the pins. I should see all 1s as I set the data buffer to 0xFFFF for all location in the buffer. I'm guessing I don't have DMA set up properly or have it tied correctly up to TIM1. TIM1 is currently outputting a 20KHz PWM signal as expected.
#include ''base_lib.h''
/* Private typedef -----------------------------------------------------------*/
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
static uint16_t asrc_buffer[FULL_FRAME_SIZE];
uint32_t counter=0;
/* Private function prototypes -----------------------------------------------*/
static void Data_GPIO_Config(void);
static void Timer_GPIO_Config(void);
static void ConfigureTIMxAsPWM_withDMA(void);
//static void SetupTimer(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
//Create data to be sent
for (counter = 0; counter <
FULL_FRAME_SIZE
- 1 ; counter++)
{
asrc_buffer[counter] &= 0xFFFF;
}
/* Configure the Data GPIO in output mode */
Data_GPIO_Config();
//Set up timer GPIO
Timer_GPIO_Config();
/* Start TIM PWM with DMA1 channel 5 */
ConfigureTIMxAsPWM_withDMA();
while (1){}
}
/**
* @brief Configure the Data GPIO in output mode
*
* @note None
* @param None
* @retval None
*/
void Data_GPIO_Config(void)
{
RCC->AHBENR |=RCC_AHBENR_GPIOCEN; // Enable GPIO port C
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**
* @brief Configure the Timer GPIO
*
* @note None
* @param None
* @retval None
*/
void Timer_GPIO_Config(void)
{
RCC->AHBENR |=RCC_AHBENR_GPIOAEN; // Enable GPIO port A
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//place before GPIO_Init to avoid pin being connected
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_2);
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void ConfigureTIMxAsPWM_withDMA(void)
{
/* TIM1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
/* DMA1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
uint16_t Period;
Period = 1000000 / 20000; // 20 KHz for 1MHz prescaled
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 48-1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
// Channel 2
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = Period/2 ; //50%
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
//reset DMA1 channel5 to default values
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&asrc_buffer; //Data source, aka our data buffer
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST; // Memory to peripheral
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Always write to same register
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(GPIOC->ODR); //Where we want to output the data
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Increment through data buffer
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit register
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 16-bit array
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //not circular
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
// Enable DMA1 Channel5 Transfer Complete interrupt
DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);
//Enable DMA1 channel IRQ Channel5 */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_5_IRQn; //DMA1_Channel4 and Channel5 interrupts
NVIC_InitStructure.NVIC_IRQChannelPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//Enable the TIM1 compare capture 1 dma requests
TIM_DMACmd(TIM1,TIM_DMA_CC1,ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
// turning on TIM1 and PWM outputs
TIM_Cmd(TIM1, ENABLE);
}
void DMA1_Channel5_IRQHandler(void)
{
//stop the clock cycles. TODO: use bare metal register instead
TIM_Cmd(TIM1,DISABLE);
if(DMA_GetITStatus(DMA1_IT_TC5))
{
//Clear DMA1 Channel5 Half Transfer, Transfer Complete and Global interrupt pending bits
DMA_ClearITPendingBit(DMA1_IT_GL5);
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-08-13 12:14 PM
Use = 0xFFFF, not &= 0xFFFF, the array is probably already zero.
Check if DMA1 supports M2M operation, not sufficiently familiar with the F051, check RMUp vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-08-13 2:47 PM
Changed to =0xFFFF. From what the RM says, DMA1 should support M2M. My attempt is to go from memory-to-peripheral, which it also supports.
I did see in the RM on table 29 that for TIM1, I should be using Channel 3. It says for TIM1_CH2 the DMA request should be channel 3. I have changed that as well.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2016-08-13 3:28 PM
Still not working, but I did find some potential help from an older forum post with a similar problem.
