zoukankan      html  css  js  c++  java
  • Data transfer from GPIO port to RAM buffer using DMA upon receiving a trigger signal on the timer capture input channel.

    Data transfer from GPIO port to RAM buffer using DMA upon receiving a trigger signal on the timer capture input channel.
    1. Our requirement is to configure the DMA so that it transfers data from the GPIO lines (8 bit data lines) to the RAM buffer upon receiving a trigger signal on the timer capture input channel.
    2. We had received an example code from ST for the F1 series controllers and the  code is attached. The code works fine with the F1 discovery board. Now we are trying to do the same thing on the F4 board. We have implemented the same configurations for F4 board and tried with F4 discovery board but the DMA data transfer doesn’t happen.The code for F4 is also attached.
    3. The code file is attached. Please note that we have used standard peripheral library functions from ST. Can you please go through our configurations and point out errors? Or send the useful example which can fulfill our requirements.

    Indeed, looks like you need DMA2, as DMA1 can only access peripherals on APB1

    // STM32F4 DMA GPIO - sourcer32@gmail.com
     
    // Per RM0090 DMA2, Channel0, Stream6 correlates to TIM1_CH1(PA8) source
    // 2 KHz clock generated on TIM3_CH1 (PB4)
    // Externally strap PA8 to PB4
    // PC0 conflicts, adapt as required
     
    #include "stm32f4_discovery.h"
     
    #define BufferSize 1000
     
    uint8_t GPIO_DATA[BufferSize];
     
    /*******************************************************************************
    * Function Name  : GPIOC Configuration
    * Description    : GPIO PORT configurations in such a way that so it status can be read
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void GPIOC_Configuration (void)
    {
      GPIO_InitTypeDef   GPIO_InitStructure;
     
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); /* GPIOC clock enable */
     
        // I'd prefer inputs, but going with original example...
         
      GPIO_InitStructure.GPIO_Pin = 0xFF; // Pin0 .. Pin7
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOC, &GPIO_InitStructure);
     
      GPIO_SetBits(GPIOC, 0xFF); // Set High-Z
    }
     
    /*******************************************************************************
    * Function Name  : Timer1 configurations
    * Description    : Configure Timer1 in such a way that it can initiate data transfer using DMA on rising edge of clock signal received on port pin.
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void TIM1_Configuration(void)
    {
        GPIO_InitTypeDef   GPIO_InitStructure;
        TIM_ICInitTypeDef  TIM_ICInitStructure;
     
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);  /* TIM1 clock enable */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
     
      /* TIM1 channel 1 pin (PA8) configuration */
      GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
     
      GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1); // PB3 TIM1_CH1
     
      TIM_ICInitStructure.TIM_Channel     = TIM_Channel_1;
      TIM_ICInitStructure.TIM_ICPolarity  = TIM_ICPolarity_Rising;
      TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
      TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
      TIM_ICInitStructure.TIM_ICFilter    = 0x0;
      TIM_ICInit(TIM1, &TIM_ICInitStructure);
     
        TIM_CtrlPWMOutputs(TIM1, ENABLE);               /* TIM Main Inputs/Output Enable    */
      TIM_Cmd(TIM1, ENABLE);                  /* TIM enable counter               */
      TIM_DMACmd(TIM1, TIM_DMA_CC1, ENABLE ); /* Enable TIM1_CC1 DMA Requests     */
    }
     
    /*******************************************************************************
    * Function Name  : DMA2 configuration
    * Description    : Transfer Data from peripheral port (GPIOC) to RAM buffer
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void DMA2_Configuration(void)
    {
        /***************************************************************************************************************************************/
        DMA_InitTypeDef  DMA_InitStructure;
     
        /* Enable the DMA clock */
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
     
        /* Configure the DMA Stream */
        DMA_Cmd(DMA2_Stream6, DISABLE);
        DMA_DeInit(DMA2_Stream6);
     
      /* Set the parameters to be configured */
      DMA_InitStructure.DMA_Channel = DMA_Channel_0;
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOC->IDR;  /* Read fron GPIO input data register */
      DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&GPIO_DATA[0]; /* Send the data to the  RAM buffer */
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
        DMA_InitStructure.DMA_BufferSize = BufferSize;
        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_High;
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        DMA_Init(DMA2_Stream6, &DMA_InitStructure);
     
      /* Enable DMA Transfer Complete interrupt */
      DMA_ITConfig(DMA2_Stream6, DMA_IT_TC, ENABLE);
     
        DMA_Cmd(DMA2_Stream6, ENABLE);
     
        /***************************************************************************************************************************************/
    }
     
    /*******************************************************************************
    * Function Name  : TIM3_Configuration
    * Description    : Configure TIM3 to generate a PWM signal. Used for test purpose
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void TIM3_Configuration (void)
    {
    #define TIM3_PERIOD      (500-1)             /* Timer 3 PWM period 2 KHz */
    #define TIM3CH1_PULSE    ((TIM3_PERIOD+1)/2) /* Timer 3 PWM pulse period */
    #define TIM3_PRESCALER   (84-1)              /* Timer 3 prescaler  1 MHz */
     
      GPIO_InitTypeDef         GPIO_InitStructure;
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
      TIM_OCInitTypeDef        TIM_OCInitStructure;
     
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  /* TIM3 clock enable */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* GPIOB clock enable */
     
      /* GPIOB Configuration: TIM3 channel 1 as alternate function push-pull */
      GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4;
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
     
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_TIM3); // PB4 TIM3_CH1
     
      TIM_TimeBaseStructure.TIM_Period        = TIM3_PERIOD;
      TIM_TimeBaseStructure.TIM_Prescaler     = TIM3_PRESCALER;
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
     
      TIM_OCInitStructure.TIM_OCMode      = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse       = TIM3CH1_PULSE;
      TIM_OCInitStructure.TIM_OCPolarity  = TIM_OCPolarity_High;
     
      TIM_TimeBaseInit    (TIM3, &TIM_TimeBaseStructure);    /* Time base configuration             */
      TIM_OC1Init         (TIM3, &TIM_OCInitStructure);      /* PWM1 Mode configuration: Channel1   */
      TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);      /* Enable the timer preload            */
      TIM_ARRPreloadConfig(TIM3, ENABLE);                    /* Enable the time autoreload register */
      TIM_Cmd             (TIM3, ENABLE);                    /* Start the timer                     */
    }
     
    /**************************************************************************************/
     
    void NVIC_Configuration(void)
    {
      NVIC_InitTypeDef NVIC_InitStructure;
     
      /* Enable the DMA Stream IRQ Channel */
      NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
    }
     
    /**************************************************************************************/
     
    void DMA2_Stream6_IRQHandler(void) // 2 Hz
    {
      /* Test on DMA Stream Transfer Complete interrupt */
      if (DMA_GetITStatus(DMA2_Stream6, DMA_IT_TCIF6))
      {
        /* Clear DMA Stream Transfer Complete interrupt pending bit */
        DMA_ClearITPendingBit(DMA2_Stream6, DMA_IT_TCIF6);
     
        /* Toggle LED3 : End of Transfer */
        STM_EVAL_LEDToggle(LED3);
     
            // Add code here to process things
      }
    }
     
    /**************************************************************************************/
     
    /**
      * @brief   Main program
      * @param  None
      * @retval None
      */
    int main(void)
    {
      int i;
      for(i=0;i<BufferSize; i++)
      {
            if((i % 2) == 0)
                GPIO_DATA[i] = 0;
            else
                GPIO_DATA[i] = 0xFF;
      }
      GPIOC_Configuration();
        NVIC_Configuration();
      TIM1_Configuration();
      TIM3_Configuration();
      DMA2_Configuration();
     
      STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
     
      STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 1 Hz means it working */
     
      while(1); // Don't want to exit
    }

    Hello Clive, I used your code and changed it to memorry to peripheral out.

    The code given below. Now when i try to send the data out what i am seeing is

    when i sample the data at constant rate then some bytes of data gets repeated

    which is giving an indication that the data is getting sampled twice.

    My conclusion says that the particular data remains on GPIO port for longer duration.

    #include "stm32f4xx.h"
    #include "stm32f4xx_gpio.h"
    #include "stm32f4xx_dma.h"
    #include "stm32f4xx_tim.h"
    #include "stm32f4xx_rcc.h"
    #include "misc.h"
    
    #define BufferSize 8008 
    
    uint16_t GPIO_DATA[ BufferSize ];
    volatile uint8_t count = 0;
    
    /*******************************************************************************
     * Function Name  : GPIOE Configuration
     * Description    : GPIO PORT configurations for sending out the data received via DMA transfer
     * Input          : None
     * Output         : None
     * Return         : None
     *******************************************************************************/
    void GPIOE_Configuration( void )
    {
      GPIO_InitTypeDef GPIO_InitStruct;
      
      //RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); /* GPIOE clock enable */
      RCC->AHB1ENR |= RCC_AHB1Periph_GPIOE;
      
      GPIO_InitStruct.GPIO_Pin = 0xFFFF; // Pin0 .. Pin15
      GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
      GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
      
      GPIO_Init( GPIOE, &GPIO_InitStruct );
      
    }
    
    /*******************************************************************************
     * Function Name  : Timer8 configurations
     * Description    : Configure Timer8 in such a way that it can initiate data transfer using DMA
     * Input          : None
     * Output         : None
     * Return         : None
     * Remark     : Prescaler and Period can vary from 1 and 2 respectively
     *******************************************************************************/
    void TIM8_Configuration( void )
    {
    #define TIM8_PERIOD      (3-1)             /* Timer 8 PWM period 90,10 MHz */
    #define TIM8_PRESCALER   (6-1)             /* Timer 8 prescaler 180, 30 MHz */
      
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      
      // RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);  /* TIM8 clock enable */
      RCC->APB2ENR |= RCC_APB2Periph_TIM8;
      
      TIM_TimeBaseStructure.TIM_Period = TIM8_PERIOD;
      TIM_TimeBaseStructure.TIM_Prescaler = TIM8_PRESCALER;
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      
      TIM_TimeBaseInit( TIM8, &TIM_TimeBaseStructure ); /* Time base configuration */
      TIM_ARRPreloadConfig( TIM8, ENABLE ); /* Enable the time autoreload register */
      TIM_Cmd( TIM8, ENABLE ); /* TIM enable counter */
      TIM_DMACmd( TIM8, TIM_DMA_Update, ENABLE ); /* Enable TIM8_UP DMA Requests */
      TIM_ITConfig( TIM8, TIM_IT_Update, ENABLE ); /* Enable TIM8 Update interrupt*/
    }
    /*******************************************************************************
     * Function Name  : Timer1 configurations
     * Description    : Configure Timer1 in such a way that it enables data transfer using DMA
     * Input          : None
     * Output         : None
     * Return         : None
     *******************************************************************************/
    void TIM1_Configuration( void )
    {
    #define TIM1_PERIOD      (500-1)             /* Timer 1 PWM period 1 KHz */
    #define TIM1_PRESCALER   (360-1)             /* Timer 1 prescaler  500 KHz */
      
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      
      // RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);  /* TIM1 clock enable */
      RCC->APB2ENR |= RCC_APB2Periph_TIM1;
      
      TIM_TimeBaseStructure.TIM_Period = TIM1_PERIOD;
      TIM_TimeBaseStructure.TIM_Prescaler = TIM1_PRESCALER;
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      
      TIM_TimeBaseInit( TIM1, &TIM_TimeBaseStructure ); /* Time base configuration */
      TIM_ARRPreloadConfig( TIM1, ENABLE ); /* Enable the time autoreload register */
      TIM_ITConfig( TIM1, TIM_IT_Update, ENABLE ); /* Enable TIM1 Update interrupt*/
      TIM_Cmd( TIM1, ENABLE ); /* TIM enable counter */
      
    }
    
    /*******************************************************************************
     * Function Name  : DMA2 configuration
     * Description    : Transfer Data to peripheral port (GPIOE) from RAM buffer
     * Input          : None
     * Output         : None
     * Return         : None
     *******************************************************************************/
    void DMA2_Configuration( void )
    {
      DMA_InitTypeDef DMA_InitStructure;
      
      /* Enable the DMA clock */
      // RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
      RCC->AHB1ENR |= RCC_AHB1Periph_DMA2;
      
      /* Configure the DMA Stream */
      DMA_Cmd( DMA2_Stream1, DISABLE );
      DMA_DeInit( DMA2_Stream1 );
      
      /* Set the parameters to be configured */
      DMA_InitStructure.DMA_Channel = DMA_Channel_7;
      DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &GPIO_DATA[ 0 ]; /* Read the data from the RAM buffer */
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &GPIOE->ODR; /* Send GPIO output data register */
      DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
      DMA_InitStructure.DMA_BufferSize = BufferSize;
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
      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( DMA2_Stream1, &DMA_InitStructure );
      
      /* Enable DMA Transfer Complete interrupt */
      DMA_ITConfig( DMA2_Stream1, DMA_IT_TC, ENABLE );
      
      DMA_Cmd( DMA2_Stream1, ENABLE );
    }
    
    /**************************************************************************************/
    /*******************************************************************************
     * Function Name  : NVIC configuration
     * Description    : configures 2 interrupt channels. 1st reads end of data transfer and disables DMA,2nd enables dma after every 1ms
     * Input          : None
     * Output         : None
     * Return         : None
     *******************************************************************************/
    void NVIC_Configuration( void )
    {
      NVIC_InitTypeDef NVIC_InitStructure;
      
      /* Enable the DMA Stream IRQ Channel */
      NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init( &NVIC_InitStructure );
      
      //enables DMA stream IRQ Channel after 1ms
      NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init( &NVIC_InitStructure );
      
    }
    
    /**************************************************************************************/
    
    void TIM1_UP_TIM10_IRQHandler( void )
    {
      if ( TIM_GetFlagStatus( TIM1, TIM_FLAG_Update ) )
      {
        DMA_Cmd( DMA2_Stream1, ENABLE );
        //GPIOG->ODR ^= GPIO_Pin_11;        //chip enable
        GPIOG->BSRRL = GPIO_Pin_11;
        // Clear update interrupt bit
        TIM_ClearITPendingBit( TIM1, TIM_IT_Update );
      }
    }
    
    void DMA2_Stream1_IRQHandler( void ) // 1 KHz
    {
      /* Test on DMA Stream Transfer Complete interrupt */
      if ( DMA_GetITStatus( DMA2_Stream1, DMA_IT_TCIF1 ) )
      {
        /* Clear DMA Stream Transfer Complete interrupt pending bit */
        DMA_ClearITPendingBit( DMA2_Stream1, DMA_IT_TCIF1 );
        
        //Indicating end of transfer
        GPIOG->BSRRH = GPIO_Pin_11;
        
        // Add code here to process things
        // DMA_Cmd(DMA2_Stream1, DISABLE);      //for pausing/restarting DMA transfer
      }
    }
    
    void LED_Init( )
    {
      GPIO_InitTypeDef GPIO_InitDef;
      RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOG, ENABLE );
      
      GPIO_InitDef.GPIO_Pin = GPIO_Pin_All;
      GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
      GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
      GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
      //Initialize pins
      GPIO_Init( GPIOG, &GPIO_InitDef );
      
    }
    /**************************************************************************************/
    
    /**
     * @brief  Main program
     * @param  None
     * @retval None
     */
    int main( void )
    {
      SystemInit( );
      int i;
      //writing data to memory
      
      for ( i = 0; i < BufferSize; i++ )
      {
        GPIO_DATA[ i ] = i;    
      }
      
      //Initializing components
      GPIOE_Configuration( );
      LED_Init( );
      NVIC_Configuration( );
      DMA2_Configuration( );
      TIM8_Configuration( );
      TIM1_Configuration( );    //used for setting a clock with 1ms sample rate
      
      while ( 1 )
        ; // Don't want to exit
    }

    Don't enable the TIM8 interrupt, 10 MHz isn't viable. Check the repetition count setting for TIM8

  • 相关阅读:
    转 intent常用功能
    Android 中Activity生命周期分析(二):从AActivity 到BActivity过程分析
    Android 面试题(经典)
    Android 中Activity生命周期分析:Android中横竖屏切换时的生命周期过程
    ios 开发中 developer tools access 总是要输入密码问题的解决
    【转】android 自定义控件
    【转】项目管理
    程序员的出路
    第一章 Actionscript学习基本知识笔记及flashdevelop软件的安装问题
    第十五章 php时区报错 We selected the timezone 'UTC'
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4749332.html
Copyright © 2011-2022 走看看