AnsweredAssumed Answered

Anomalous high ADC rate at stm32f103cb

Question asked by kudryashov.dmitry on Mar 11, 2016
Latest reply on Mar 13, 2016 by kudryashov.dmitry
Hello! I need an advice. My stm32f103cb chip has ADC with 0.39 us per point conversion rate on one channel. But datasheet says its max rate is 1 Msps (1us). I checked sampling rate with external oscillograph (1 Gsps Tektronics) and external signal generator (Tektronics). I sent to ADC square wave with width of 10 us ON and of 10 us OFF (0-3V) and recieve with my delphi programm also square signal with flat level ON and OFF for 26 points of each. Also I was able to view sine wave signal up to 200 kHz (0-3V) with good resolution. The code is below. The basis was USB-CDC loop example from latest stmm32f1xx perif library. On EP3 event my parser starts GetData function where firstly resets DMA to set Memory base address to start of data array and then starts ADC conversion with direct DMA to record adc data to my array [992 elements] (dma mode is normal, not cyclic). After transfer is done - all data sends to usb-com and my delphi programm recieve it and plots a graph.
The code:
// Variant with 0.39 us sampling rate - read freq up to 20o kHz
 
#include "hw_config.h"
#include "usb_lib.h"
#include "usb_desc.h" //
#include "usb_pwr.h" //
 
#define ADC1_DR_Address    ((uint32_t)0x4001244C)
 
uint32_t packet_sent=1;
uint32_t packet_receive=1;
extern __IO uint8_t Receive_Buffer[64];
extern __IO  uint32_t Receive_length ;
 
uint16_t ADC_Buffer[992];
uint8_t TxBuffer[64];
uint32_t i,j,d;
 
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
 
void ADC_settings(void);   
void parser(void);  // need to declare
void getFirmware(void);
void GetData(void);
void SendError(void);
void delay(uint32_t delayValue);
void init_pwm(void);
 
int main()
{
    init_pwm();
     
  Set_System();
  Set_USBClock();
  USB_Interrupts_Config();
  USB_Init();
    ADC_settings();
     
  while(1) {    }
}
 
 
void ADC_settings() {
     
 
     
  /* ADCCLK = PCLK2/4 */
  RCC_ADCCLKConfig(RCC_PCLK2_Div4);    
 
  /* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
     
  /* Enable ADC1 and GPIOC clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
 
  /* Configure PA.01 (ADC Channel_1) as analog input -------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
     
  /* DMA1 channel1 configuration ----------------------------------------------*/
  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Buffer[0];
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 992;
  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_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
   
  /* Enable DMA1 channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE);  
     
     
  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);
 
  /* ADC1 regular channel1 configuration */ //- PIN10 Mapple Mini
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_1Cycles5);
 
  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
 
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
 
  /* Enable ADC1 reset calibration register */  
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));
 
  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));   
}
 
 
 
void parser() {
    // executes at EP3 irq at incoming packet in file usb_endp.c
    if ( Receive_Buffer[0] == 0xAA) {
      switch ( Receive_Buffer[1] )
      {
         case 0xCB:  
                            getFirmware();
                            break;
         case 0x01:
                            GetData();
                            break;          
                 default:
                            break;
             }
         else
                    {
                        SendError();
                         
                    }
 
  packet_receive = 0;
}
 
void getFirmware() {
     
    TxBuffer[0] = 0xAA;
    TxBuffer[1] =   0xBC;  
 
    CDC_Send_DATA ((unsigned char*)TxBuffer,2);
}
 
void SendError() {
 
    TxBuffer[0] = 0xAA;
    TxBuffer[1] =   0xEE;
 
    CDC_Send_DATA ((unsigned char*)TxBuffer,2);        
}
 
 
void GetData() {
             
    DMA_Cmd(DMA1_Channel1, DISABLE); 
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Buffer[0];   
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);   
    DMA_Cmd(DMA1_Channel1, ENABLE);
     
    ADC1->CR2 |= ((uint32_t)0x00500000);        // start ADC                       
        while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));
    ADC1->CR2 &= ((uint32_t)0xFFAFFFFF);        // stop ADC
    DMA_ClearFlag(DMA1_FLAG_TC1);
             
         
    for(j=0;j<32;j++) {
        for(i=0;i<31;i++) {
            TxBuffer[i*2] = (ADC_Buffer[i+31*j] & 0x0000FF00) >> 8;
            TxBuffer[i*2+1] = (ADC_Buffer[i+31*j] & 0x000000FF);           
        }
        CDC_Send_DATA ((unsigned char*)TxBuffer,62);            // 63 bytes max!
        delay(10000);
}
 
}
 
void delay(uint32_t delayValue) {
     
    for( d = 0 ; d < delayValue ; d++) {};
     
}
 
 
void init_pwm() {
    GPIO_InitTypeDef pwmGPIO;  
    TIM_TimeBaseInitTypeDef pwm;
    TIM_OCInitTypeDef pwmOC;
     
    // enable
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
 
    // init gpio
    pwmGPIO.GPIO_Pin = GPIO_Pin_0;
    pwmGPIO.GPIO_Mode = GPIO_Mode_AF_PP;
    pwmGPIO.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &pwmGPIO);
 
    // init TIM3 ch.3 - PIN3 Mapple Mini
    /* Time base configuration */
    pwm.TIM_Prescaler = 36 - 1;
    pwm.TIM_Period = 19;    // 0 - also 1 tick - now 50 us ON and 50 us OFF
    pwm.TIM_ClockDivision = 0;
    pwm.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &pwm);
    // for 3600-1 and 2000 and 50 = T=1sec Pulse = 25 ms
     
    /* PWM1 Mode configuration: Channel3 */
    pwmOC.TIM_OCMode = TIM_OCMode_PWM1;
    pwmOC.TIM_OutputState = TIM_OutputState_Enable; // ON first
    pwmOC.TIM_Pulse = 10; // go to 50 pulses and LED OFF
    pwmOC.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC3Init(TIM3, &pwmOC);
    TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
 
    TIM_ARRPreloadConfig(TIM3, ENABLE);
 
    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);
}
 
 
#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****/

Outcomes