Connect with us

STM32F4 ADC to FFT help

Discussion in 'Microcontrollers, Programming and IoT' started by J.W, Jul 7, 2016.

  1. J.W

    J.W

    5
    0
    Jul 7, 2016
    Hi,

    I am very new in the computer architecture field or anything related to it. I am given a task to feed the data from ADC to FFT and i am very confuse how to set it up. I am currently using the stm32f429i discovery board. Can anyone give me some heardstart on how to setup the procedures.
     
  2. Harald Kapp

    Harald Kapp Moderator Moderator

    9,416
    1,925
    Nov 17, 2011
    Is this homework or an assignment?
     
  3. J.W

    J.W

    5
    0
    Jul 7, 2016
    Assignment i have to program the stm32f429i discovery board to perform the ADC to FFT function.
     
  4. Harald Kapp

    Harald Kapp Moderator Moderator

    9,416
    1,925
    Nov 17, 2011
    What have you done so far to tackle the task? How are you going to split it into sub-tasks?
    Do you have a flow chart for your program? Consider which tasks are relevant with respect to functions such as:
    - input of data
    - processing of data
    - output of data
     
  5. J.W

    J.W

    5
    0
    Jul 7, 2016
    I have read through some tutorials and a little on the St reference manual for the chip.
    Right now i am programming to activate the ADC peripheral and i noticed that some tutorials used timers to trigger ADC and was wondering why do we have to do it?

    Input of data is form the function generator which will be received by the input of the ADC periheral have configure the GPIO pin for ADC peripheral.
     
  6. Harald Kapp

    Harald Kapp Moderator Moderator

    9,416
    1,925
    Nov 17, 2011
    But what is your overall program flow?
    With repect to
    the actual programming of a function, subroutine etc. is a minor detail.
    For the architecture it is important to know and/or define the flow of the data from the source (analog input) to the output (e.g. digital display) as well as to define the required data structures (e.g. how are you going to represent the input data and output data within the computer's memory?).
    Also considerations like e.g.:
    • Is data going to be copied between routines or are pointers (addresses) used? Both of which have advantages and disadvantages.
    • Does the data qcquissition have to be continuous or can it be intermittently? Continuous operation will require additional buffering to be able to store new data without overwriting old data which is still being processed.
    If you want help in programming the peripheral components of the stm32f429i, that's not architecture. You will find lots of sample code by Googling with the right keywords.
     
  7. J.W

    J.W

    5
    0
    Jul 7, 2016
    Currently I do not have time to learn about programming or the architecture of it as due to the timing given to complete the project all i can do is learn a few basics and try to implement it.

    I am now trying to trigger ADC conversion using timer 2 every 125us and also to feed the data into DAC as i want to check if the ADC waveform is the same as the signal input. However there i an error in getting the DAC signal as the oscilloscope does not display the signal.

    Below shows the code that i used:
    #include "main.h"
    #include "stlogo.h"

    /** @addtogroup STM32F4xx_HAL_Examples
    * @{
    */

    /** @addtogroup BSP
    * @{
    */

    /* Private typedef -----------------------------------------------------------*/
    /* Private define ------------------------------------------------------------*/
    /* Private macro -------------------------------------------------------------*/
    /* Private variables ---------------------------------------------------------*/
    static uint8_t DemoIndex = 0;
    #ifdef EE_M24LR64
    uint8_t NbLoop = 1;
    #endif /* EE_M24LR64 */
    __IO uint8_t ubKeyPressed = RESET;

    BSP_DemoTypedef BSP_examples[] = {
    { Touchscreen_demo, "TOUCHSCREEN", 0 },
    { LCD_demo, "LCD", 0 },
    { Log_demo, "LCD LOG", 0 },
    { MEMS_demo, "MEMS", 0 },
    #ifdef EE_M24LR64
    { EEPROM_demo, "EEPROM", 0},
    #endif /* EE_M24LR64 */
    };
    TIM_HandleTypeDef timhandle;
    ADC_HandleTypeDef adchandle;
    DAC_HandleTypeDef dachandle;
    DMA_HandleTypeDef dmahandle;
    uint32_t AdcBuf[ADC_BUFFER_LENGTH];

    /* Private function prototypes -----------------------------------------------*/
    static void SystemClock_Config(void);
    void ADC_IRQHandler(void);
    static void Error_Handler(void);
    static void Init_Timer(void);
    static void Init_ADC(void);
    static void Init_DAC(void);
    static void Init_DMA(void);
    static void Init_LCD(void);

    /* Private functions ---------------------------------------------------------*/

    static void Init_Timer()
    {
    __TIM2_CLK_ENABLE();
    timhandle.Instance = TIM2;
    timhandle.Init.Prescaler = 0;
    timhandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    timhandle.Init.Period = HAL_RCC_GetHCLKFreq() / (2*ADC_BUFFER_LENGTH);
    timhandle.Init.CounterMode = TIM_COUNTERMODE_UP;
    timhandle.Init.RepetitionCounter = 0;
    HAL_TIM_Base_Init(&timhandle);

    TIM_MasterConfigTypeDef masterConfig;
    masterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
    masterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&timhandle, &masterConfig);
    }

    static void Init_ADC(void)
    {
    __GPIOB_CLK_ENABLE();
    GPIO_InitTypeDef gpioInit;
    gpioInit.Pin = GPIO_PIN_0;
    gpioInit.Mode = GPIO_MODE_ANALOG;
    gpioInit.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &gpioInit);

    HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC_IRQn);

    __ADC1_CLK_ENABLE();
    adchandle.Instance = ADC1;
    adchandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
    adchandle.Init.Resolution = ADC_RESOLUTION_12B;
    adchandle.Init.ScanConvMode = DISABLE;
    adchandle.Init.ContinuousConvMode = DISABLE;
    adchandle.Init.DiscontinuousConvMode = DISABLE;
    adchandle.Init.NbrOfDiscConversion = 0;
    adchandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
    adchandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
    adchandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    adchandle.Init.NbrOfConversion = 1;
    adchandle.Init.DMAContinuousRequests = ENABLE;
    adchandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //DISABLE;

    if (HAL_ADC_Init(&adchandle) != HAL_OK)
    {
    Error_Handler();
    }

    /*##-2- Configure ADC regular channel ######################################*/
    /* Note: Considering IT occurring after each number of size of */
    /* "uhADCxConvertedValue" ADC conversions (IT by DMA end */
    /* of transfer), select sampling time and ADC clock with sufficient */
    /* duration to not create an overhead situation in IRQHandler. */
    ADC_ChannelConfTypeDef sAdcConfig;
    sAdcConfig.Channel = ADC_CHANNEL_8;
    sAdcConfig.Rank = 1;
    sAdcConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
    sAdcConfig.Offset = 0;

    if (HAL_ADC_ConfigChannel(&adchandle, &sAdcConfig) != HAL_OK)
    {
    /* Channel Configuration Error */
    Error_Handler();
    }
    }

    static void Init_DAC(void)
    {
    __GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef gpioInit;
    gpioInit.Pin = GPIO_PIN_4;
    gpioInit.Mode = GPIO_MODE_ANALOG;
    gpioInit.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &gpioInit);

    __DAC_CLK_ENABLE();
    dachandle.Instance = DAC;
    if (HAL_DAC_Init(&dachandle) != HAL_OK)
    {
    /* Initialization Error */
    Error_Handler();
    }

    DAC_ChannelConfTypeDef sDacConfig;
    sDacConfig.DAC_Trigger = DAC_TRIGGER_NONE;
    sDacConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

    if (HAL_DAC_ConfigChannel(&dachandle, &sDacConfig, DAC_CHANNEL_1) != HAL_OK)
    {
    Error_Handler();
    }
    }

    static void Init_DMA(void)
    {
    __DMA2_CLK_ENABLE();
    dmahandle.Instance = DMA2_Stream4;
    dmahandle.Init.Channel = DMA_CHANNEL_0;
    dmahandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
    dmahandle.Init.PeriphInc = DMA_PINC_DISABLE;
    dmahandle.Init.MemInc = DMA_MINC_ENABLE;
    dmahandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    dmahandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    dmahandle.Init.Mode = DMA_CIRCULAR;
    dmahandle.Init.Priority = DMA_PRIORITY_HIGH;
    dmahandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    dmahandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    dmahandle.Init.MemBurst = DMA_MBURST_SINGLE;
    dmahandle.Init.PeriphBurst = DMA_PBURST_SINGLE;

    HAL_DMA_Init(&dmahandle);

    __HAL_LINKDMA(&adchandle, DMA_Handle, dmahandle);

    HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
    }

    static void Init_LCD(void)
    {
    BSP_LCD_Init();
    BSP_LCD_Clear(LCD_COLOR_WHITE);
    BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
    BSP_LCD_DrawRect(20, 20, 320, 200 );
    }

    static void Error_Handler(void)
    {
    /* Turn LED5 on */
    while (1)
    {
    }
    }

    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* padchandle)
    {
    uint32_t adc_value = HAL_ADC_GetValue(&adchandle);
    __HAL_ADC_DISABLE_IT(&adchandle, ADC_IT_EOC);
    HAL_DAC_SetValue(&dachandle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, adc_value);

    static unsigned int index = 0;

    AdcBuf[index] = adc_value;

    index++;

    if (index >= ADC_BUFFER_LENGTH)
    {
    index = 0;
    }

    if (index != 0) return;

    BSP_LCD_FillRect(21, 21, 318, 198 );

    for (int i = 0; i < 319; i++)
    {
    unsigned long y1 = 0, y2 = 0;

    for (int j = i*25; j < (i+1)*25; j++)
    {
    y1 += AdcBuf[j];
    y2 += AdcBuf[j+25];
    }

    y1 /= 512;
    y2 /= 512;

    BSP_LCD_DrawLine(20+i, y1, 20+i+1, y2);
    }
    }

    void ADC_IRQHandler(void)
    {
    HAL_ADC_IRQHandler(&adchandle);
    }

    void DMA2_Stream4_IRQHandler()
    {
    HAL_DMA_IRQHandler(&dmahandle);
    }

    /**
    * @brief Main program
    * @param None
    * @retval None
    */
    int main(void)
    {
    HAL_Init();
    SystemClock_Config();
    BSP_LED_Init(LED3);
    BSP_LED_Init(LED4);
    Init_LCD();
    Init_Timer();
    Init_ADC();
    Init_DAC();
    Init_DMA();

    HAL_ADC_Start_IT(&adchandle);
    HAL_DAC_Start(&dachandle, DAC_CHANNEL_1);
    HAL_TIM_Base_Start(&timhandle);

    while (1)
    {
    }

    return 0;
    }

    /**
    * @brief System Clock Configuration
    * The system Clock is configured as follow :
    * System Clock source = PLL (HSE)
    * SYSCLK(Hz) = 180000000
    * HCLK(Hz) = 180000000
    * AHB Prescaler = 1
    * APB1 Prescaler = 4
    * APB2 Prescaler = 2
    * HSE Frequency(Hz) = 8000000
    * PLL_M = 8
    * PLL_N = 360
    * PLL_P = 2
    * PLL_Q = 7
    * VDD(V) = 3.3
    * Main regulator output voltage = Scale1 mode
    * Flash Latency(WS) = 5
    * @param None
    * @retval None
    */
    static void SystemClock_Config(void)
    {
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_OscInitTypeDef RCC_OscInitStruct;

    /* Enable Power Control clock */
    __HAL_RCC_PWR_CLK_ENABLE()
    ;

    /* The voltage scaling allows optimizing the power consumption when the device is
    clocked below the maximum system frequency, to update the voltage scaling value
    regarding system frequency refer to product datasheet. */
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /* Enable HSE Oscillator and activate PLL with HSE as source */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 360;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    /* Activate the Over-Drive mode */
    HAL_PWREx_EnableOverDrive();

    /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
    clocks dividers */
    RCC_ClkInitStruct.ClockType =
    (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
    }

    /**
    * @brief Display main demo messages
    * @param None
    * @retval None
    */
    static void Display_DemoDescription(void)
    {
    uint8_t desc[50];

    /* Set LCD Foreground Layer */
    BSP_LCD_SelectLayer(1);

    BSP_LCD_SetFont(&LCD_DEFAULT_FONT);

    /* Clear the LCD */
    BSP_LCD_SetBackColor(LCD_COLOR_WHITE);
    BSP_LCD_Clear(LCD_COLOR_WHITE);

    /* Set the LCD Text Color */
    BSP_LCD_SetTextColor(LCD_COLOR_DARKBLUE);

    /* Display LCD messages */
    BSP_LCD_DisplayStringAt(0, 10, (uint8_t*)"STM32F429I BSP", CENTER_MODE);
    BSP_LCD_SetFont(&Font16);
    BSP_LCD_DisplayStringAt(0, 35, (uint8_t*)"Drivers examples", CENTER_MODE);

    /* Draw Bitmap */
    BSP_LCD_DrawBitmap((BSP_LCD_GetXSize() - 80) / 2, 65, (uint8_t *)stlogo);

    BSP_LCD_SetFont(&Font8);
    BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() - 20, (uint8_t*)"Copyright (c) STMicroelectronics 2014", CENTER_MODE);

    BSP_LCD_SetFont(&Font12);
    BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
    BSP_LCD_FillRect(0, BSP_LCD_GetYSize() / 2 + 15, BSP_LCD_GetXSize(), 60);
    BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
    BSP_LCD_SetBackColor(LCD_COLOR_BLUE);
    BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() / 2 + 30, (uint8_t*)"Press USER Button to start:", CENTER_MODE);
    sprintf((char *)desc, "%s example", BSP_examples[DemoIndex].DemoName);
    BSP_LCD_DisplayStringAt(0, BSP_LCD_GetYSize() / 2 + 45, (uint8_t *)desc, CENTER_MODE);
    }

    /**
    * @brief Check for user input
    * @param None
    * @retval Input state (1 : active / 0 : Inactive)
    */
    uint8_t CheckForUserInput(void)
    {
    if (BSP_PB_GetState(BUTTON_KEY) == RESET)
    {
    while (BSP_PB_GetState(BUTTON_KEY) == RESET)
    ;
    return 1;
    }
    return 0;
    }

    /**
    * @brief Toggle LEDs
    * @param None
    * @retval None
    */
    void Toggle_Leds(void)
    {
    static uint8_t ticks = 0;

    if (ticks++ > 100)
    {
    BSP_LED_Toggle(LED3);
    BSP_LED_Toggle(LED4);
    ticks = 0;
    }
    }

    /**
    * @brief EXTI line detection callbacks.
    * @param GPIO_Pin: Specifies the pins connected EXTI line
    * @retval None
    */
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    if (GPIO_Pin == KEY_BUTTON_PIN)
    {
    ubKeyPressed = SET;
    }
    }

    #ifdef USE_FULL_ASSERT
    /**
    * @brief Reports the name of the source file and the source line number
    * where the assert_param error has occurred.
    * @param file: pointer to the source file name
    * @param line: assert_param error line source number
    * @retval None
    */
    void assert_failed(uint8_t* file, uint32_t line)
    {
    /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

    /* Infinite loop */
    while (1)
    {
    }
    }
    #endif

    /**
    * @}
    */

    /**
    * @}
    */

    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
     
  8. Harald Kapp

    Harald Kapp Moderator Moderator

    9,416
    1,925
    Nov 17, 2011
    That's too bad. You need to lay the foundations before you start building an application. You may get a working program without these, but understanding it, changing or maintaining it or adding new functionality in the future will not be easy without a good structure.

    I'm sorry not to be able to help you with the actual code.
     
  9. J.W

    J.W

    5
    0
    Jul 7, 2016
    Ok no prob thanks for the help!
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-