AnsweredAssumed Answered

Sampling Freqeuncy for the ADC STM32F4

Question asked by mansour.mahmoud on Aug 28, 2013
Latest reply on Aug 28, 2013 by Clive One
Hallo my dear forum-mates,
1- Briefly about what i'm doing:
 
i'm working on project which utilizes the board STM32F4 Discovery. i want to do some measurements for biosignals " Analog Signals " which has a freqeuncy spectrum 10 - 500 Hz. To measure these signals i need to use one of the ADC modules and one of the USART modules of the Discovery board. i'm using COOCOX IDE to write the needed codes.

2- My Inquiry is :

How to define the sampling frequncy of the ADC and how to tune it ?
for frequencies up to 100 HZ everything is running fine and the signal is recontructred well,
but for frequecies > 100 Hz, it is noticable that there is data lost .

So please how can i determine the sampling freqeuncy and how can i increase it :)

here is the code i'm using :

/* Description:
 * The code will be applied in converting analoge signal and sending it using a serial port interface to the PC
 */


/*
Hinweis zum Clock fuer 8MHz Quarz, damit er auf 168MHz läuft (betrifft das stm32F4Discovery):


in der system_stm32f4xx.c muss eingetragen sein:
PLL_M = 8


in der stm32f4xx.h muss eingetragen sein:
HSE_VALUE = 8000000
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "misc.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_adc.h"
//#include "stm32f4xx_conf.h"


#define READ_BUFFER_SIZE 20


volatile char read_buffer[READ_BUFFER_SIZE];
volatile char read_buffer_single;
volatile char string_complete;
volatile int  uart_str_count;




void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
  }
}




void ADC_INIT_EXAMPLE(void)
{
  /* Creating The ADC and GPIO Initialization Structures -------------------------------------------*/


  // Creating ADC Initialization structure
  ADC_InitTypeDef       ADC_InitStructure;
  //Creating ADC Common Init structure
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  // Creating GPIO Init structure
  GPIO_InitTypeDef      GPIO_InitStructure;


  /* ADC and GPIO Clock configuration --------------------------------------------------------------*/


  // The GPIO's" including Port A " is connected to the Advanced High-Performance Bus AHB1
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  // The ADC's is connected the Advanced Peripheral Bus APB2
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3,  ENABLE);


  /* Setting PortA-Pin1 as an Analog input for the ADC   ------------------------------------------*/


  //Specifies the GPIO pins to be configured " Pin 1 in Port A "
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;
  /*Specifies the operating mode for the selected pins:
    1-GPIO_Mode_IN   = 0x00,  GPIO Input Mode
    2-GPIO_Mode_OUT  = 0x01,  GPIO Output Mode
    3-GPIO_Mode_AF   = 0x02,  GPIO Alternate function Mode
    4-GPIO_Mode_AN   = 0x03   GPIO Analog Mode// 0x03 = 0000 0011*/
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  //No pull up/down is the choice when no digital inputs is applied
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  //Applying the new Configurations to the selected port
  GPIO_Init(GPIOA, &GPIO_InitStructure);


  /* ADC Common Initialization structure configuration  ------------------------------------------*/


  //Specifying if the ADC is working in  independent "Single", dual or Triple mode.
  //Independent means : Using one of the three ADC modules during conversion "All the ADCs independent"
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  //Specifying the Clock for the analog circuitry ADDCLK which is common to all ADCs. This clock is
  //generated from the APB2 clock divided by a programmable prescaler that allows
  //the ADC to work at fPCLK2/2, /4, /6 or /8.
  /* 1- HCLK = 168MHz
     2- PCLK2 = HCLK/2 = 84MHz (typical 1:4 setup)
     3- ADCCLK = PCLK2/2 = 42MHz (default ADC prescaler after reset 1:2) */
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  // Enables or Disables Direct Access Memory mode
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  //Configures the Delay between 2 sampling phases
  //The delay can vary from 5-20 cycle between two samples
  //This means and for this case 5 cycles = 5*tADCCLK = 5*(1/fPCLK2)
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  //Assigning the common Configurations to each ADC
  ADC_CommonInit(&ADC_CommonInitStructure);


  /* ADC3 Initialization Structure Configuration ------------------------------------------------*/


  /*Specifying the ADC Resolution into one of the following :
    1- ADC_Resolution_12b                         ((uint32_t)0x00000000)
    2- ADC_Resolution_10b                         ((uint32_t)0x01000000)
    3- ADC_Resolution_8b                          ((uint32_t)0x02000000)
    4- ADC_Resolution_6b                          ((uint32_t)0x03000000)*/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  //Specifying whether the conversion  is performed in Scan (multichannels) or Single (one channel) mode.
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;//DISABLE;
  //Specifying whether the conversion is performed in Continuous or Single mode.
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  //Specifying whether the ADC data is "Left" or "Right" aligned in the Data register
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //Specifying the number of conversions that will be done using the sequencer for regular channel group
  //The number of Conversions can vary from 1-16
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  //Assigning the previous configuration to ADCx "In this case ADC3"
  ADC_Init(ADC3, &ADC_InitStructure);


  /* ADC3 regular channel(1) configuration --------------------------------------------------------*/


  //Configures for the selected ADC regular channel its corresponding rank in the sequencer
  //and its sample time.
  //1- ADC Channel(0-15)
  //2- rank (1-16), rank=1 since i'm using single"Independent" mode. This will be used to
  //help the sequencer in case of group regular channel conversion.
  //3- ADC_SampleTime is one of [3,15,28,56,84,112,144,480] cycle.
  // umso höher die SampleTime desto genauer der Wert und desto weniger Crosstalk
  ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 1, ADC_SampleTime_480Cycles);


  /* Enable ADC3 -----------------------------------------------------------------------------------*/
  ADC_Cmd(ADC3, ENABLE);


}


void USART_INIT_EXAMPLE(void)
{
  /* USARTx configured as follow:
        - BaudRate = 19200 baud
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
  */


  /* Creating The USART and GPIO Initialization Structures -------------------------------------------*/


  // Creating GPIO Initialization structure
  GPIO_InitTypeDef GPIO_InitStructure;
  // Creating USART Initialization structure
  USART_InitTypeDef USART_InitStructure;


  /* USART and GPIO Clock configuration --------------------------------------------------------------*/


  // The GPIO-Port C is connected to the Advanced High-Performance Bus AHB1
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  // The USARTS's is connected the Advanced Peripheral Bus APB1
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);


  /* Configuring Pin 10-Port C to it's Alternate function " namely : USART3_Tx " ----------------------*/
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);


  /* Configuring Pin 11-Port C to it's Alternate function " namely : USART3_Rx " ----------------------*/
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);


  /* Configure USART3-Tx as alternate function --------------------------------------------------------*/


  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);


  /* Configure USART3-Rx as alternate function  -------------------------------------------------------*/


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_Init(GPIOC, &GPIO_InitStructure);


  /* Configuration of USART Module to be used  ---------------------------------------------------------*/


  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_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;


  /* Assigning the previous configurations to USART3 ----------------------------------------------------*/
  USART_Init(USART3, &USART_InitStructure);


  /* Receive/read Data register not empty interrupt is enabled ------------------------------------------*/
  USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);


  /* Enable USART */
  USART_Cmd(USART3, ENABLE);
}


void UART_SEND_EXAMPLE(char byte)
{
       USART_SendData(USART3,byte);
       /* Loop until the end of transmission */
       while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET)
       {


       }
}


void UART_SEND_TEXT_EXAMPLE(char *buffer)
{
     while (*buffer)
     {
          UART_SEND_EXAMPLE(*buffer);
          buffer++;
     }
}




void NVIC_INIT_EXAMPLE(uint16_t IRQ)
{
     NVIC_InitTypeDef NVIC_InitStructure;


     NVIC_InitStructure.NVIC_IRQChannel = IRQ;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ Channel wird enabled
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // Die Priorität --> kleine Zahlen = hohe Priorität
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
     NVIC_Init(&NVIC_InitStructure);
}




void USART3_IRQHandler(void)
{
     if (USART_GetITStatus(USART3,USART_IT_RXNE) == SET)
     {
       USART_ClearITPendingBit(USART3,USART_IT_RXNE);
       // Daten aus dem Puffer lesen
       read_buffer_single = (USART3->DR & (uint16_t)0x01FF);


            if ( string_complete == 0 )
            {
                    if (read_buffer_single!='\n' && read_buffer_single!='\r' && uart_str_count<READ_BUFFER_SIZE-1)
                    {
                      read_buffer[uart_str_count] = read_buffer_single;
                      uart_str_count++;
                    }
                    else
                    {
                      read_buffer[uart_str_count] = '\0';
                      uart_str_count = 0;
                      string_complete = 1;
                    }
            }
     }
}




int main(void)
   {
     uint16_t result;
     uint16_t voltage;
     char text[20];


     SystemInit();


     USART_INIT_EXAMPLE();


     // ist für die USART Empfangsroutine (wird in diesem Beispiel nicht gebraucht)
     // USART3_IRQn = 39,     /*!< USART3 global Interrupt
     NVIC_INIT_EXAMPLE(USART3_IRQn);


     ADC_INIT_EXAMPLE();


     while(1)
    {
          // Starte eine Conversion
           ADC_SoftwareStartConv(ADC3);


          // wenn die Conversion fertig ist...
           if (ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC))
           {
               // holt sich den Wandelwert
               result = ADC_GetConversionValue(ADC3);


               // rechnet den Wandelwert in Spannung(mV) um
               voltage =(float)2954/(float)4095 * result;


               // in einen String wandeln
               sprintf (text,"%d",voltage);


               // Wert auf der ser. Schnittst. ausgeben
               UART_SEND_TEXT_EXAMPLE(text);
               UART_SEND_TEXT_EXAMPLE("\n\r");
               Delay(10000000);
           }


    }
}


Outcomes