Тестирование АЦП ардуино, ENOB, разгон и усреднение.

Волшебник
Offline
Зарегистрирован: 22.12.2016

Ставилась задача проверки эффективности и целесообразности разгона АЦП. Для прецезионного измерения битового разрешения АЦП в разных режимах использовался метод БПФ.

Аппаратные ресурсы;

1. ардуино МЕГА2560. АЦП на всех атмегах один и тот-же, мега выбрана из за размера памяти для БПФ.

2. генератор сигналов внутренний DSO Hantek (12-bit ). За неименеем лучшего, возможно результаты завалены при >12 битах.

3. буфферный усилитель - фильтр ФНЧ на MCP6022. Необязательно, два резистора и конденсатор может быть достаточно.

Результаты БЕЗ усреднения - аверейжинга.

/* averaging "u1"
  Single Ended A-0: 
  9.6 ksps, default 
  125 k clock: a7a w11101111 Input 299 Hz
  Peak number:  32  magnitude:  240171.70 Total:  194.1609802246  SINAD:  61.847  ENOB: 9.981
  Peak number:  32  magnitude:  240183.71 Total:  199.3041534423  SINAD:  61.621  ENOB: 9.944
  Peak number:  32  magnitude:  240184.25 Total:  194.2451019287  SINAD:  61.844  ENOB: 9.981
  Peak number:  32  magnitude:  240144.79 Total:  196.1327209472  SINAD:  61.758  ENOB: 9.967
    
  250 k clock: a7a w11101110 Input 599 Hz
  Peak number:  32  magnitude:  239964.40 Total:  199.7442169189  SINAD:  61.593  ENOB: 9.939
  Peak number:  32  magnitude:  239939.14 Total:  195.4058380126  SINAD:  61.783  ENOB: 9.971
  Peak number:  32  magnitude:  239921.18 Total:  201.1040802001  SINAD:  61.533  ENOB: 9.929
  Peak number:  32  magnitude:  239960.48 Total:  198.1329498291  SINAD:  61.664  ENOB: 9.951
    
  500 k clock:  a7a w11101101 Input 1198 Hz
  Peak number:  32  magnitude:  239571.87 Total:  219.0831146240  SINAD:  60.777  ENOB: 9.803
  Peak number:  32  magnitude:  239586.81 Total:  223.4446868896  SINAD:  60.606  ENOB: 9.775
  Peak number:  32  magnitude:  239582.04 Total:  210.8227691650  SINAD:  61.111  ENOB: 9.859
  Peak number:  32  magnitude:  239564.92 Total:  205.2021331787  SINAD:  61.345  ENOB: 9.898
  
  1 M  clock:  a7a w11101100 Input 2396 Hz
  Peak number:  32  magnitude:  232223.76 Total:  280.3315429687  SINAD:  58.365  ENOB: 9.403
  Peak number:  32  magnitude:  232196.04 Total:  274.4304199218  SINAD:  58.548  ENOB: 9.433
  Peak number:  32  magnitude:  232206.81 Total:  272.7705383300  SINAD:  58.602  ENOB: 9.442
  Peak number:  32  magnitude:  232200.46 Total:  277.9204711914  SINAD:  58.439  ENOB: 9.415
 
Как видим, исходные почти 10 падают до 9.4 на 1МГц оверклока (х8). Совсем немного, часто приходиться читать что зависимость чуть ли не бит на каждое х2, т.е. на х8 где-то -4 бита. НЕ правда. АЦП хороший.
 
 
Усреднение на 8, вытягиваем 11-й  бит 
 
*********************************************************************************************  
  Averaging : u8
  125 k clock: a7a w11101111 Input 38 Hz
  Peak number:  32  magnitude:  1990554.87  Total:  894.6037597656  SINAD:  66.947  ENOB: 10.828
  Peak number:  32  magnitude:  1990505.50  Total:  848.9946899414  SINAD:  67.401  ENOB: 10.904
  Peak number:  32  magnitude:  1990401.37  Total:  873.2562866210  SINAD:  67.156  ENOB: 10.863
  Peak number:  32  magnitude:  1990372.00  Total:  861.5628662109  SINAD:  67.273  ENOB: 10.883  
  
  250 k clock: a7a w11101110 Input 74 Hz
  Peak number:  32  magnitude:  1995603.12  Total:  813.4340209960  SINAD:  67.795  ENOB: 10.969
  Peak number:  32  magnitude:  1995438.75  Total:  813.6396484375  SINAD:  67.792  ENOB: 10.969
  Peak number:  32  magnitude:  1995528.50  Total:  829.5065917968  SINAD:  67.625  ENOB: 10.941
  Peak number:  32  magnitude:  1995513.25  Total:  805.1755371093  SINAD:  67.883  ENOB: 10.984
      
  500 k clock:  a7a w11101101 Input 149 Hz
  Peak number:  32  magnitude:  1997099.12  Total:  818.8202514648  SINAD:  67.744  ENOB: 10.961
  Peak number:  32  magnitude:  1997197.87  Total:  847.3858642578  SINAD:  67.447  ENOB: 10.911
  Peak number:  32  magnitude:  1997172.75  Total:  850.2013549804  SINAD:  67.418  ENOB: 10.907
  Peak number:  32  magnitude:  1997167.62  Total:  855.7623291015  SINAD:  67.361  ENOB: 10.897
    
  1 M  clock:  a7a w11101100 Input 299 Hz
  Peak number:  32  magnitude:  1997380.50  Total:  1038.3681640625 SINAD:  65.682  ENOB: 10.618
  Peak number:  32  magnitude:  1997360.00  Total:  1056.1708984375 SINAD:  65.534  ENOB: 10.594
  Peak number:  32  magnitude:  1997487.00  Total:  1018.9625244140 SINAD:  65.847  ENOB: 10.646
  Peak number:  32  magnitude:  1997276.50  Total:  1013.6557006835 SINAD:  65.891  ENOB: 10.653
 
11 бит легко, но понятно что результаты до 1 МГц за счёт снижения сэмплинг рейта. Но 10.6 бит полученые на 1 МГц это лучше чем исходные 9.9.
Разгон АЦП увеличивает разрядность, но затраты процессора тоже немного растут.
 
И напоследок, 12-бит (и более) при снижении рейта. Проверка статистических методов.
 
*********************************************************************************************  
  Averaging : u64
  125 k clock: a7a w11101111 Input 37 Hz
  Peak number:  252 magnitude:  14582499.00 Total:  2508.2463378906 SINAD:  75.289  ENOB: 12.214
  Peak number:  252 magnitude:  14582683.00 Total:  2400.3217773437 SINAD:  75.671  ENOB: 12.278
  Peak number:  252 magnitude:  14582477.00 Total:  2438.2145996093 SINAD:  75.535  ENOB: 12.255
  Peak number:  252 magnitude:  14582293.00 Total:  2494.9956054687 SINAD:  75.335  ENOB: 12.222
      
  250 k clock: a7a w11101110 Input 37 Hz
  Peak number:  126 magnitude:  15749849.00 Total:  3190.2336425781 SINAD:  73.869  ENOB: 11.978
  Peak number:  126 magnitude:  15749567.00 Total:  3170.6799316406 SINAD:  73.922  ENOB: 11.987
  Peak number:  126 magnitude:  15749587.00 Total:  3187.1323242187 SINAD:  73.877  ENOB: 11.980
  Peak number:  126 magnitude:  15749524.00 Total:  3273.5866699218 SINAD:  73.645  ENOB: 11.941
          
  500 k clock:  a7a w11101101 Input 149 Hz
  Peak number:  254 magnitude:  14624333.00 Total:  2407.5144042968 SINAD:  75.670  ENOB: 12.277
  Peak number:  254 magnitude:  14624361.00 Total:  2361.1406250000 SINAD:  75.839  ENOB: 12.305
  Peak number:  254 magnitude:  14624002.00 Total:  2536.6623535156 SINAD:  75.216  ENOB: 12.202
  Peak number:  254 magnitude:  14623783.00 Total:  2483.3261718750 SINAD:  75.401  ENOB: 12.233
        
  1 M  clock:  a7a w11101100 Input 149 Hz
  Peak number:  127 magnitude:  15809414.00 Total:  3351.8518066406 SINAD:  73.473  ENOB: 11.912
  Peak number:  127 magnitude:  15809325.00 Total:  3369.1030273437 SINAD:  73.428  ENOB: 11.905
  Peak number:  127 magnitude:  15809365.00 Total:  3308.0595703125 SINAD:  73.587  ENOB: 11.931
  Peak number:  127 magnitude:  15809180.00 Total:  3314.6928710937 SINAD:  73.569  ENOB: 11.928    
 
64 должна теоретически дать 3-бита, т.е. 12.9 ожидаемый результат. Не хватает, варианты разные, низкое качество генератора сигналов как основной подозреваемый. Надо будет разобраться. Частоты использовались не те, надо бы 4.7 Гц - генератор завалил, поэтому только 2 частоты вместо сетки из 4-х, и более высокие чем /8 если для сравнительного анализа.
 
Код для всех желающих перепроверить результаты на след. посте. Там скорость АЦП через регистры выставлять надо,  знание архитектуры и битов обязательно. Читайте дата шит.
Волшебник
Offline
Зарегистрирован: 22.12.2016

Вкладка основная

/* averaging "u1"
  Single Ended A-0: 
  9.6 ksps, default 
  125 k clock: a7a w11101111 Input 299 Hz
  Peak number:  32  magnitude:  240171.70 Total:  194.1609802246  SINAD:  61.847  ENOB: 9.981
  Peak number:  32  magnitude:  240183.71 Total:  199.3041534423  SINAD:  61.621  ENOB: 9.944
  Peak number:  32  magnitude:  240184.25 Total:  194.2451019287  SINAD:  61.844  ENOB: 9.981
  Peak number:  32  magnitude:  240144.79 Total:  196.1327209472  SINAD:  61.758  ENOB: 9.967
    
  250 k clock: a7a w11101110 Input 599 Hz
  Peak number:  32  magnitude:  239964.40 Total:  199.7442169189  SINAD:  61.593  ENOB: 9.939
  Peak number:  32  magnitude:  239939.14 Total:  195.4058380126  SINAD:  61.783  ENOB: 9.971
  Peak number:  32  magnitude:  239921.18 Total:  201.1040802001  SINAD:  61.533  ENOB: 9.929
  Peak number:  32  magnitude:  239960.48 Total:  198.1329498291  SINAD:  61.664  ENOB: 9.951
    
  500 k clock:  a7a w11101101 Input 1198 Hz
  Peak number:  32  magnitude:  239571.87 Total:  219.0831146240  SINAD:  60.777  ENOB: 9.803
  Peak number:  32  magnitude:  239586.81 Total:  223.4446868896  SINAD:  60.606  ENOB: 9.775
  Peak number:  32  magnitude:  239582.04 Total:  210.8227691650  SINAD:  61.111  ENOB: 9.859
  Peak number:  32  magnitude:  239564.92 Total:  205.2021331787  SINAD:  61.345  ENOB: 9.898
  
  1 M  clock:  a7a w11101100 Input 2396 Hz
  Peak number:  32  magnitude:  232223.76 Total:  280.3315429687  SINAD:  58.365  ENOB: 9.403
  Peak number:  32  magnitude:  232196.04 Total:  274.4304199218  SINAD:  58.548  ENOB: 9.433
  Peak number:  32  magnitude:  232206.81 Total:  272.7705383300  SINAD:  58.602  ENOB: 9.442
  Peak number:  32  magnitude:  232200.46 Total:  277.9204711914  SINAD:  58.439  ENOB: 9.415

*********************************************************************************************  
  Averaging : u8
  125 k clock: a7a w11101111 Input 38 Hz
  Peak number:  32  magnitude:  1990554.87  Total:  894.6037597656  SINAD:  66.947  ENOB: 10.828
  Peak number:  32  magnitude:  1990505.50  Total:  848.9946899414  SINAD:  67.401  ENOB: 10.904
  Peak number:  32  magnitude:  1990401.37  Total:  873.2562866210  SINAD:  67.156  ENOB: 10.863
  Peak number:  32  magnitude:  1990372.00  Total:  861.5628662109  SINAD:  67.273  ENOB: 10.883  
  
  250 k clock: a7a w11101110 Input 74 Hz
  Peak number:  32  magnitude:  1995603.12  Total:  813.4340209960  SINAD:  67.795  ENOB: 10.969
  Peak number:  32  magnitude:  1995438.75  Total:  813.6396484375  SINAD:  67.792  ENOB: 10.969
  Peak number:  32  magnitude:  1995528.50  Total:  829.5065917968  SINAD:  67.625  ENOB: 10.941
  Peak number:  32  magnitude:  1995513.25  Total:  805.1755371093  SINAD:  67.883  ENOB: 10.984
      
  500 k clock:  a7a w11101101 Input 149 Hz
  Peak number:  32  magnitude:  1997099.12  Total:  818.8202514648  SINAD:  67.744  ENOB: 10.961
  Peak number:  32  magnitude:  1997197.87  Total:  847.3858642578  SINAD:  67.447  ENOB: 10.911
  Peak number:  32  magnitude:  1997172.75  Total:  850.2013549804  SINAD:  67.418  ENOB: 10.907
  Peak number:  32  magnitude:  1997167.62  Total:  855.7623291015  SINAD:  67.361  ENOB: 10.897
    
  1 M  clock:  a7a w11101100 Input 299 Hz
  Peak number:  32  magnitude:  1997380.50  Total:  1038.3681640625 SINAD:  65.682  ENOB: 10.618
  Peak number:  32  magnitude:  1997360.00  Total:  1056.1708984375 SINAD:  65.534  ENOB: 10.594
  Peak number:  32  magnitude:  1997487.00  Total:  1018.9625244140 SINAD:  65.847  ENOB: 10.646
  Peak number:  32  magnitude:  1997276.50  Total:  1013.6557006835 SINAD:  65.891  ENOB: 10.653

*********************************************************************************************  
  Averaging : u64
  125 k clock: a7a w11101111 Input 37 Hz
  Peak number:  252 magnitude:  14582499.00 Total:  2508.2463378906 SINAD:  75.289  ENOB: 12.214
  Peak number:  252 magnitude:  14582683.00 Total:  2400.3217773437 SINAD:  75.671  ENOB: 12.278
  Peak number:  252 magnitude:  14582477.00 Total:  2438.2145996093 SINAD:  75.535  ENOB: 12.255
  Peak number:  252 magnitude:  14582293.00 Total:  2494.9956054687 SINAD:  75.335  ENOB: 12.222
      
  250 k clock: a7a w11101110 Input 37 Hz
  Peak number:  126 magnitude:  15749849.00 Total:  3190.2336425781 SINAD:  73.869  ENOB: 11.978
  Peak number:  126 magnitude:  15749567.00 Total:  3170.6799316406 SINAD:  73.922  ENOB: 11.987
  Peak number:  126 magnitude:  15749587.00 Total:  3187.1323242187 SINAD:  73.877  ENOB: 11.980
  Peak number:  126 magnitude:  15749524.00 Total:  3273.5866699218 SINAD:  73.645  ENOB: 11.941
          
  500 k clock:  a7a w11101101 Input 149 Hz
  Peak number:  254 magnitude:  14624333.00 Total:  2407.5144042968 SINAD:  75.670  ENOB: 12.277
  Peak number:  254 magnitude:  14624361.00 Total:  2361.1406250000 SINAD:  75.839  ENOB: 12.305
  Peak number:  254 magnitude:  14624002.00 Total:  2536.6623535156 SINAD:  75.216  ENOB: 12.202
  Peak number:  254 magnitude:  14623783.00 Total:  2483.3261718750 SINAD:  75.401  ENOB: 12.233
        
  1 M  clock:  a7a w11101100 Input 149 Hz
  Peak number:  127 magnitude:  15809414.00 Total:  3351.8518066406 SINAD:  73.473  ENOB: 11.912
  Peak number:  127 magnitude:  15809325.00 Total:  3369.1030273437 SINAD:  73.428  ENOB: 11.905
  Peak number:  127 magnitude:  15809365.00 Total:  3308.0595703125 SINAD:  73.587  ENOB: 11.931
  Peak number:  127 magnitude:  15809180.00 Total:  3314.6928710937 SINAD:  73.569  ENOB: 11.928    
  */

#include <avr/pgmspace.h>

#define ADMUX  (*(uint8_t*)0x7C)
#define ADCSRB (*(uint8_t*)0x7B)
#define ADCSRA (*(uint8_t*)0x7A)

#define FFT_SIZE      1024
#define MIRROR        FFT_SIZE / 2

#define INBUF         FFT_SIZE

         String       in_String         =   "";        
         boolean      end_input         = false;  
         uint8_t      debug_osm         =    0;

         int16_t      inp[INBUF]        = {0};
         float        f_r[INBUF]        = {0};

volatile uint8_t      flag      =    0;

         uint8_t      adres_reg =    0;         
         int16_t      bin_numbr =    0;
         float        max_magnt =    0;
         float        tot_magnt =    0;

         int16_t      dc_offset =  512;

         float        sinad     =  0.0;
         float        enobs     =  0.0;

const    uint8_t      int_cntrl = 0x01;     //PORT D mask, Digital 21
//const    uint8_t      averaging =    0;         
         uint8_t      averaging =    0;         

void setup()
{
  Serial.begin(115200);
  in_String.reserve(200);

  adc_init();

  pinMode( 21, OUTPUT); // ADC-test
  pinMode( 20, OUTPUT); //flag-test
  pinMode( 19, OUTPUT); //float-fft
  pinMode( 18, OUTPUT); //get-magnt
}

void loop()
{
  int16_t  temp = 0;
  char *   pEnd;

  if( flag ) { 
    digitalWrite(20, HIGH);
    for( uint16_t i = 0; i < INBUF; i++) {
      int16_t tempr = inp[i];
        f_r[i] = tempr;// -4096;// -512;
      }
// Test float
// Peak:41 magnitude: 261632.40  Tot:  0.4767234802  SINAD:  114.789 ENOB: 18.775 Bl-Hr Wnd

  if(debug_osm) {
    for(int i = 0; i < FFT_SIZE; i++){
      double wave = cos(( i *41.0 *( 2 *3.1415926535) /FFT_SIZE));
      f_r[i] = 511.0 * wave;
      }        
    }
// 2.Windowing BlackMan-Harris 4-term
     double base_angle = 2.0 *M_PI / (FFT_SIZE -1);
     for( uint16_t i = 0; i < FFT_SIZE; i++ ) {
        double angle = i *base_angle;
        float temp = 0.35875 -(0.48829*cos(angle)) +(0.14128*cos(2*angle)) -(0.01168*cos(3*angle));
       f_r[i] *= temp;
       }

  digitalWrite(19, HIGH);
  rev_bin( f_r, (int16_t) FFT_SIZE);
  rfft33( f_r, FFT_SIZE);
  digitalWrite(19, LOW);

  digitalWrite(18, HIGH);
  get_MagnitF( f_r);
  digitalWrite(18, LOW);

  flag = 0;
  ADCSRA |= ((1<< ADIF) | (1<< ADIE));
  digitalWrite(20, LOW);
  }
  
  serialEvent(); 

  if( end_input) {
    char cmd = in_String[0];
    in_String[0] = '+';
    
    if( cmd == 'd' ) {
      debug_osm = 1 - debug_osm;
      if(debug_osm) Serial.print(F("\nDebug aktiv."));
      else          Serial.print(F("\nDebug de-aktiv."));
      }

    if( cmd == 'u' ) {
      temp = strtol( in_String.c_str(), &pEnd, 10);
      averaging = temp;
      Serial.print(F("\n\taveraging: "));
      Serial.print(averaging, DEC);
      dc_offset = 512UL * averaging;
      }      
/*    
    if( cmd == 'u' ) { // averaging 8
      averaging = 8 - averaging;
      if(averaging) {
        dc_offset = 4096;
        Serial.print(F("\naveraging ON."));
        }
      else {
        dc_offset = 512;
        Serial.print(F("\naveraging Off"));
        }
      }
*/  
          
    // "x" command - print a table of incomming buffer.
    if( cmd == 'x' ) {
      Serial.print("\n\t");  
        for( uint16_t i = 0; i < INBUF; i++) {  
          int16_t tempr = inp[i];  
            Serial.print(tempr, DEC);       
            Serial.print("\t");    
            if ((i+1)%16 == 0) Serial.print("\n\t");
            }
        Serial.println("\n\t");
      }
    // "f" command - print a table of fft results.
    if( cmd == 'f' ) {
      Serial.print("\n\t");  
        for( uint16_t i = 0; i < MIRROR; i++) {  
          Serial.print(f_r[i], 1);       
          Serial.print("\t");    
          if ((i+1)%16 == 0) Serial.print("\n\t");
          }
        Serial.println("\n\t");
      }
    // "e" command.
    if( cmd == 'e' ) {
      enob(f_r);
      Serial.print(F("\n\tPeak number:\t"));
      Serial.print(bin_numbr, DEC);
      Serial.print(F("\tmagnitude:\t"));
      Serial.print(max_magnt, 2);
      Serial.print(F("\tTotal:\t"));
      Serial.print(tot_magnt, 10);
      Serial.print(F("\tSINAD:\t"));
      Serial.print(sinad, 3);
      Serial.print(F("\tENOB:\t"));
      Serial.print(enobs, 3);
      }

    if( cmd == 'a' ) {
      adres_reg = strtol( in_String.c_str(), &pEnd, 16);
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      temp =   (*(uint8_t*)adres_reg);
      Serial.print(temp, BIN);
      }
    if( cmd == 'r' ) {
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      temp =   (*(uint8_t*)adres_reg);
      Serial.print(temp, BIN);
      }
    if( cmd == 'w' ) {
      Serial.print(F("\n\tReg: "));
      Serial.print(adres_reg, HEX);
      Serial.print(F("\tvalue: "));
      temp =   (*(uint8_t*)adres_reg);
      Serial.print(temp, BIN);
      temp = strtol( in_String.c_str(), &pEnd, 2);      
      (*(uint8_t*)adres_reg) = temp;
      Serial.print(F("\tnew  value: "));
      temp =   (*(uint8_t*)adres_reg);
      Serial.print( temp, BIN);      
      }
      
          
    in_String = "";
    end_input= false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    in_String += inChar;
    if (inChar == '\n') {
      end_input= true;
    }
  }
}

Вторая таб - называется АЦП

//ISR(TIMER1_COMPB_vect)
ISR(ADC_vect) 
{ 
  static uint16_t n_sampl  = 0;

  static uint8_t n_sampl2  = 0;
  static uint16_t accum  = 0;

//  digitalWrite(21, HIGH);
  PORTD  |= int_cntrl;       // pin High         

  int16_t temp  = ADCL;  
          temp += (ADCH << 8);  

   accum += temp;

//   uint8_t last = 0;
//   if(averaging) 
   if(++n_sampl2 >= averaging) {
//   if(++n_sampl2 > 31) {
//   if(++n_sampl2 > 0) {
//   if(++n_sampl2 > 15) {
//   if(++n_sampl2 > 63) {
     temp = accum -dc_offset; // /8;   

     n_sampl2 = 0;
     accum = 0;

     inp[n_sampl++]  = temp;
     if( n_sampl >= INBUF ) {
       flag = 1;
       n_sampl  = 0;
       ADCSRA &= ~(1<< ADIE);
       }
   }
//  digitalWrite(21, LOW);
  PORTD  &= ~(int_cntrl);       // pin Low         
}

void adc_init(void)
{ 
  ADMUX  = 0x40; //temp_reg;
  /*
  ADMUX  = ((1<<REFS1)| // Reference Selection Bits
            (1<<REFS0)| // 2.56V Internal
            (0<<ADLAR)| // ADC Left Adjust Result
            (1<< MUX4)| 
            (0<< MUX3)| // Gain / Channel Selection Bits 
            (0<< MUX2)|
            (0<< MUX1)| // (1) 10000 ADC8<->ADC9 Gain = 1x.   
            (0<< MUX0));    
  */

  ADCSRA = ((1<< ADEN)|   // 1 = ADC Enable
            (1<< ADSC)| // ADC Start Conversion 
            (1<<ADATE)| // 1 = ADC Auto Trigger Enable
            (1<< ADIF)| // ADC Interrupt Flag
            (1<< ADIE)| // ADC Interrupt Enable
            (1<<ADPS2)|
            (1<<ADPS1)| // ADC Prescaler :  MHz.
            (1<<ADPS0));  
  
  ADCSRB = ((0<< MUX5)| //=1 for 8-15 channels   
            (0<<ADTS2)|   // Sets Auto Trigger source Timer/Counter1 Compare Match B
            (0<<ADTS1)|
            (0<<ADTS0));

  DIDR1  = 0xFF;
  DIDR2  = 0xFF;
}
/*
void tmr_init()
{
  // Set up TIMER 1 - ADC sampler 
  TIMSK1  = 0x00;
  TCCR1A  = 0;
  TCCR1B  = 0;
  TCCR1C  = 0;
  TCCR1A  = ((1<<WGM11) | (1<<WGM10));       // Mode 15, Fast PWM
  TCCR1B  = ((1<<WGM13) | (1<<WGM12));       // Mode 15, Fast PWM

  TCCR1B |=  (1<<CS10);                      // clk/1 prescaling.
  OCR1A   = SMP_TMR1;
  OCR1B   = SMP_TMR1;

  TCNT1   = 0;
  TIFR1  |= (1<<OCF1B); 
  TIMSK1 |= (1<<OCIE1B);
}
*/

Третья - ДСП

#define Leakage 10

void enob(float data[])
{
  float temp = 0.0;

  bin_numbr = 0;
  max_magnt = 0;
  tot_magnt = 0;

  for ( int i = Leakage; i < MIRROR; i++) {
    temp = f_r[i];
    if (temp > max_magnt) {
      max_magnt = temp;
      bin_numbr = i;
      }
    }
  max_magnt = 0;
  if ((bin_numbr > Leakage) && (bin_numbr < (MIRROR - Leakage))) {
    int16_t lefts = bin_numbr - Leakage;
    int16_t right = bin_numbr + Leakage;
    for ( int i = Leakage; i < MIRROR; i++) {
      temp = f_r[i];
      if ((i > lefts) && (i < right)) {
        max_magnt += temp;
        }
      else {
        tot_magnt += (temp * temp);
        }
      }
    tot_magnt = sqrt(tot_magnt /0.35875); 
    // RSS vs RMS + Noise Shaping by Windowing MUST be accounted.
    // root-sum-square (rss)
    
    if (tot_magnt == 0) tot_magnt = 0.000001;
    
    sinad = (20.0 * log10(max_magnt / (tot_magnt))); 
    // -10 *log(FFT_SIZE /2); IF RMS calculated, than process GAIN must be subtructed.
    
    enobs = (sinad - 1.76) / 6.02;
    }
  else {
    sinad = 0.0;
    enobs = 0.0;
  }
}

/* fft-gain dB = 10 *log(M /2) = 10 *log(256) = 24.082399653; */

4-я флоат ФФТ

void rfft33(float X[], int N)
{
    /****************************************************************************
    *   rfft(float X[],int N)                                                   *
    *     A real-valued, in-place, split-radix FFT program                      *
    *     Decimation-in-time, cos/sin in second loop                            *
    *     Length is N=2**M (i.e. N must be power of 2--no error checking)       *
    *                                                                           *
    * Original Fortran code by Sorensen; published in H.V. Sorensen, D.L. Jones,*
    * M.T. Heideman, C.S. Burrus (1987) Real-valued fast fourier transform      *
    * algorithms.  IEEE Trans on Acoustics, Speech, & Signal Processing, 35,    *
    * 849-863.  Adapted to C by Bill Simpson, 1995  wsimpson@uwinnipeg.ca       *
    * --------------------------------------------------------------------------*
    * C/C++ language bugs fixing & correction:                                  *
    * 1. C-style array start adress [0];                                        *
    * 2. SIN() and COS tweed factors change place;                              *
    * 3. Rev Bin - replaced by new fastest version.                             *
    * made by Anatoly Kuzmenko, 2017,  anatolyk69@gmail.com                     *
    ****************************************************************************/

  int I, I0, I1, I2, I3, I4, I5, I6, I7, I8, IS, ID;
  int J, K, M, N2, N4, N8;
  float A, A3, CC1, SS1, CC3, SS3, E, R1;
  float T1, T2, T3, T4, T5, T6;

  M = (int)(log(N) / log(2.0));             /* N=2^M */

  /* ----Length two butterflies--------------------------------------------- */
  IS = 0;
  ID = 4;
  do {
    for (I0 = IS; I0 < N; I0 += ID) {
      I1    = I0 + 1;
      R1    = X[I0];
      X[I0] = R1 + X[I1];
      X[I1] = R1 - X[I1];
    }
    IS = 2 * ID - 2;
    ID = 4 * ID;
  } while (IS < N);

  /* ----L shaped butterflies----------------------------------------------- */
  N2 = 2;
  for (K = 1; K < M; K++) {
    N2    = N2 * 2;
    N4    = N2 / 4;
    N8    = N2 / 8;
    E     = (float) 6.2831853071719586f / N2;
    IS    = 0;
    ID    = N2 * 2;
    do {
      for ( I = IS; I < N; I += ID) {
        I1 = I; // + 1;
        I2 = I1 + N4;
        I3 = I2 + N4;
        I4 = I3 + N4;
        T1 = X[I4] + X[I3];
        X[I4] = X[I4] - X[I3];
        X[I3] = X[I1] - T1;
        X[I1] = X[I1] + T1;
        if (N4 != 1) {
          I1 += N8;
          I2 += N8;
          I3 += N8;
          I4 += N8;
          T1 = (X[I3] + X[I4]) * .7071067811865475244f;
          T2 = (X[I3] - X[I4]) * .7071067811865475244f;
          X[I4] = X[I2] - T1;
          X[I3] = -X[I2] - T1;
          X[I2] = X[I1] - T2;
          X[I1] = X[I1] + T2;
        }
      }
      IS = 2 * ID - N2;
      ID = 4 * ID;
    } while ( IS < N );
    A = E;
    for ( J = 1; J < N8; J++) {
      //, A s4itat Do trigonometrii !!!
      A = (float)J * E;
      A3 = 3.0 * A;
      CC1   = cos( A);
      SS1   = sin( A);
      CC3   = cos(A3);
      SS3   = sin(A3);
      IS = 0;
      ID = 2 * N2;
      do {
        for ( I = IS; I < N; I += ID) {
          I1 = I + J;
          I2 = I1 + N4;
          I3 = I2 + N4;
          I4 = I3 + N4;
          I5 = I + N4 - J;// + 2;
          I6 = I5 + N4;
          I7 = I6 + N4;
          I8 = I7 + N4;
          T1 = X[I3] * CC1 + X[I7] * SS1;
          T2 = X[I7] * CC1 - X[I3] * SS1;
          T3 = X[I4] * CC3 + X[I8] * SS3;
          T4 = X[I8] * CC3 - X[I4] * SS3;
          T5 = T1 + T3;
          T6 = T2 + T4;
          T3 = T1 - T3;
          T4 = T2 - T4;
          T2 = X[I6] + T6;
          X[I3] = T6 - X[I6];
          X[I8] = T2;
          T2    = X[I2] - T3;
          X[I7] = -X[I2] - T3;
          X[I4] = T2;
          T1    = X[I1] + T5;
          X[I6] = X[I1] - T5;
          X[I1] = T1;
          T1    = X[I5] + T4;
          X[I5] = X[I5] - T4;
          X[I2] = T1;
        }
        IS = 2 * ID - N2;
        ID = 4 * ID;
      } while ( IS < N );
    }
  }
}

void rev_bin( float *fr, int16_t fft_n)
{
  int m, mr, nn, l;
  float tr;

  mr = 0;
  nn = fft_n - 1;

  for (m = 1; m <= nn; ++m) {
    l = fft_n;
    do {
      l >>= 1;
    } while (mr + l > nn);

    mr = (mr & (l - 1)) + l;

    if (mr <= m)
      continue;
    tr = fr[m];
    fr[m] = fr[mr];
    fr[mr] = tr;
  }
}

void get_MagnitF(float *fr)
{
  for (int  i = 1; i < MIRROR; i++) {
    float real = fr[i];
    float imag = fr[FFT_SIZE - i];
    float Magnit = (float) (sqrt((real * real) + (imag * imag)));
    fr[i] = Magnit;
  }
}

5-я - справка, создайте если надо для основных регистров, проще чем по дата шиту туда-сюда шариться 

/*
Single Ended
  1-0 0000 ADC  8
  1-0 0001 ADC  9  // 41 -ref=5, 
  1-0 0010 ADC 10
  1-0 0011 ADC 11
  1-0 0100 ADC 12
  1-0 0101 ADC 13
  1-0 0110 ADC 14
  1-0 0111 ADC 15

Diff.      "+"     "-"     Gain
  1-1 0000 ADC  8  ADC  9     1x
  1-0 1001 ADC  9  ADC  8    10x
  1-0 1011 ADC  9  ADC  8   200x
  1-1 1011 ADC 11  ADC 10     1x  
  1-0 1101 ADC 11  ADC 10    10x
  1-0 1111 ADC 11  ADC 10   200x
*/

Инструкция по применению;

подать переменку 5В пик-пик центрованую на 2.5 постоянки на пин А0. Проверить коммандой х, чем ближе к +-512 тем лучше, но не клиппить.

комманды f e u  сами разберётесь зачем.  a w r тоже, а7а - установить указатель на ADCSRA, w11101100  записать ну и так далее. 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Падение на 1бит точности при росте скорости х2 идет ПОСЛЕ частоты АЦП в 1Мгц. Попробуйте свой тест на делителях 1:2 (Если ваша мега его вообще потянет) - скорость АЦП = 8Мгц, 1:4, 1:8 .. и убедитесь, что потеря нехилая даже для последовательных замеров с одной единственной ноги и даже не в режиме "диф х200".

Да, и на таких скоростях чтение АЦП в обработчике прерывания - безнадежно. Только в основном коде, только "free running mode" .. в общем поиграйтесь.

Частота оцифровки 592кГц при тактовой камня 16Мгц (1:2) вполне достижима. Проверено. :)

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

Тесторовал АЦП AtMega328 (arduino nano) две штуки.

Вход ADC0, резисторный делитель 1/3 (от А0 на минус 5кОм, на вход 10кОм)(что было под рукой), на AREF конденсатор 470нФ, опорное AVCC.

Программа визуализации http://out.arduino.ru/?redirect=https%3A%2F%2Fyadi.sk%2Fd%2Fp-BCHLQFs2kdB&baseU=http%3A%2F%2Farduino.ru%2Fforum%2Fproekty%2Fvyzhimaem-maksimum-usb-ostsillograf-na-arduino

Взято отсюда http://arduino.ru/forum/proekty/vyzhimaem-maksimum-usb-ostsillograf-na-arduino

Ардуиновский код переписан на Си, компилировался в Proteus 8.5 (плагин arduino 1.0.5), оптимизация -О0 (иначе глюки), там же дебажился и от туда же заливался.

В результате в одной Mega328 делитель 1/2 работает и получается 615384 семпла/секунду, эффективных 7 бит. Во второй меге работает только начиная с делителя 1/4, на 1/2 выдает код FF с редким мусором, почему непонятно.

После ~30Кгц входного сигнала (генерировался функцией tone(); arduino Mega2560), видно что полоса пропускания входа АЦП начинает хромать, график становится похожим на кривую пилу.

код:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//******************************************************
byte oldADC, newADC;
byte ADC_BUF[270];	//буфер обьявляем с запасом
byte Rb = 255;
byte count = 0;
//******************************************************
void uSend (byte data);
//*****************************************************
int main (void)
{
     volatile register byte *N asm ("r28");  //указатель на адрес буфера АЦП оже регистровая пара Y
    volatile register byte adcTemp asm ("r9");	//не используется (его не видит компилятор(кричит Warning!) 
						//нужен для ассемблерной вставки (чтобы компилятор не использовал)
  
     ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIF) | (0 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
     ADMUX =  (0 << REFS1) | (1 << REFS0) | (1 << ADLAR)  | (0 << MUX3) | (0 << MUX2)  | (0 << MUX1)  | (0 << MUX0) ;
	DIDR0 = (1<<ADC0D);
    //  REFS1:REFS0
    //00    AREF
    //01    AVcc, с внешним конденсатором на AREF
    //10    Резерв
    //11    Внутренний 2.56В  источник, с внешним конденсатором на AREF
//настройка UART 256000 бод 8-N-1
    UBRR0H=0x0;					//256000=0x00;	
    UBRR0L=0x03;					//256000=0x03;	
    UCSR0B=(1<<RXEN0|1<<TXEN0);
    UCSR0C=(1<<UCSZ01|1<<UCSZ00);
//**********************************************************************
    asm ("sei");

  while(1)
  {   
      ADCSRA |= (1<<ADSC);  //запуск АЦП без прерываний
      while (ADCSRA & (1<<ADSC)) {}   //ждем пока АЦП закончит
      oldADC = ADCH;        //делаем старое значение АЦП
      ADCSRA |=(1<<ADSC);     //запуск преобразования
      while (ADCSRA& (1<<ADSC)){}   //ждем пока АЦП закончит
      newADC = ADCH;        //делаем новое значение АЦП        
      
      while (newADC>oldADC)     //ждем пока закончится фронт
      {
         ADCSRA |=(1<<ADSC);
         while (ADCSRA& (1<<ADSC)){}
        oldADC=newADC;
        newADC=ADCH; 
      }
      while (newADC<=oldADC)      //ждем пока закончится спад
      {
         ADCSRA |=(1<<ADSC);
         while (ADCSRA& (1<<ADSC)){}
        oldADC=newADC;
         newADC=ADCH;
      }
   
     N = ADC_BUF;				//передаем адрес начала буфера
     ADCSRA |= (1<<ADSC|1<<ADATE|1<<ADIE);   //разрешаем прерывания АЦП free running mode
                 
      while (N<(ADC_BUF+255))       //ждем пока соберется буфер АЦП
      {      }
      ADCSRA &=~(1<<ADATE|1<<ADIE); //останавливаем АЦП
 
uSend(15); uSend(0); uSend(15) ;
  for (count = 0; count<255; count++)
  {
  uSend (ADC_BUF[count]);
  }
 
  uSend(OCR1A); //Не используются по видимому в проге ПК
    uSend(OCR1B); //Не используются по видимому в проге ПК
    uSend(0);  //Начальная точка
    uSend(1); uSend(15);uSend(1);
    
  if (UCSR0A&(1<<RXC0))					//читаем и меняем предделитель тактирования АЦП
  {
     Rb = UDR0;
     ADCSRA = (ADCSRA >> 3) << 3 | Rb ;
   }
//*******************************************************  
  }
}


ISR(ADC_vect, ISR_NAKED)
{   					//вход 7 тактов
 
  asm volatile (
      "LDS R9, 0x0079  \n" //забираем из ADCH	//3 такта
      "ST Y+, R9  \n" //ложим в массив ADC_BUF	//2 такта
      "RETI \n"   //сваливаем					//4 такта
   );       //итого 16тактов 
}

void uSend (byte data)					//отправка в UART
{
  while (!(UCSR0A & (1<<UDRE0)))
  {}
  UDR0=data;
}





 

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

Может кому понадобится, код для Mega2560 (другой не было под рукой), в принципе пойдет любая Ардуина.

Отправка частоты (точнее F/255) использовалась терминалка программы FlProg (отправка в DEC).

В ответ  придет "I recived" и отправленное число, и частота генерации. 

Компилировалась в ARDUINO 1.8.1

byte incomingByte = 1;   // для данных, поступающих через последовательный порт

void setup() {  
  Serial.begin(9600);
}
void loop() {
    if (Serial.available() > 0) {
                
        incomingByte = Serial.read(); // считываем входящий байт 
        // показываем, что именно мы получили:
         Serial.print("I received: ");
         Serial.println(incomingByte, DEC);
         Serial.print("\n");
         Serial.println((unsigned int)incomingByte*255);  //показываем частоту генерации
        }
tone(8,(unsigned int)incomingByte*255);
}