Skocz do zawartości

Sipeed Tang Nano 4k z ADC - Gowin FPGA Designer


Gieneq

Pomocna odpowiedź

(edytowany)

Cześć @FlyingDutch

Fajnie, że działasz dalej z tematem. Ja w ten weekend też nadrabiam zaległości. Właśnie podłączyłem ADS1256 do ESP32. Widziałem że pisałeś o utrudnieniach i faktycznie jest to trochę zagmatwane. Najpierw dla testów wziąłem ekspander PCM23S08 z kursu STM32L4 i zmarnowałem na nim cały dzień. Obstawiam że nie działa, bo podłączałem do Arduino Nano i nie szło uruchomić, a to nie jest jakieś trudne - raptem 6 bajtów.

Wtedy też przydał się analizator stanów logicznych, pożyczyłem jednak tego klona za 40zł i działa. Sygnał okazał się prawidłowy wiec pewnie układ się wziął i zepsuł.

Wziąłem więc płytkę ADS1256 i bibliotekę o której wspominałeś z fragmentem w pliku nagłówkowym:

// #elif   defined(ARDUINO_ARCH_ESP32)
// 	// Contributions are welcome

Jakoś miałem opory przed podłączaniem tego do ESP32 ale jednak dało radę. Mam płytkę z wyświetlaczem LCD i z wolnych pinów mam HSPI. Dodałem wiec w pliku nagłówkowym obiekt SPI:

#include <esp32-hal-spi.h>

#define pinDRDY 2
#define pinRST  4
#define pinCS   15
  
class ADS1256 {
  //...
float _conversionFactor;

  SPIClass spiobject;
};

#endif

W konstruktorze stworzyłem instancję klasy SPIClass i wszędzie w kodzie zmieniłem domyślny SPI na instancje obiektu:

ADS1256::ADS1256(float clockspdMhz, float vref, bool useResetPin) {
  //...
  // Start SPI on a quarter of ADC clock speed
  spiobject = SPIClass(HSPI);
  spiobject.begin();
  spiobject.beginTransaction(
      SPISettings(clockspdMhz * 1000000 / 4, MSBFIRST, SPI_MODE1));
}

i działa! Także można dorzucić do repozytorium coś od siebie 🙂 

Testowy program zwrócił mi poprawną wartość, a komunikacja faktycznie działa:

image.thumb.png.575a36b7542905766ce6dde082633590.png

Nie wiem tylko dlaczego pomiary nie pasują do czegokolwiek, ale na spokojnie przejrzę kod i myślę, że do czegoś dojdę.

 

9 godzin temu, FlyingDutch napisał:

Program nazywa się "Daqarta"

Super sprawa, na pewno się przyda 🙂 

Przeczytałem co napisałeś i wygląda że jednak I2S byłby lepszym pomysłem, jestem zaskoczony że jest to tańsze i prostsze. Zawsze jakieś doświadczenie 🙂

 

Edytowano przez Gieneq
  • Lubię! 1
Link do komentarza
Share on other sites

Cześć @Gieneq,

fajnie, że udało Ci się podłączyć ADC ADS1256 do płytki ESP32. Mnie udało się zebrać sample przetwornikiem ADC I2S (układ PCM1808) (dla jednego kanału robiłem próby dla ułatwienia) i policzyć  256  punktową FFT na tych samplach. Oczywiście nic nie może działać idealnie i znów napotkałem problemy: polegają one na tym, że gdy włączam program (lub robię reset klawiszem z ESP32) pierwszych kilka tysięcy sampli z układu PCM1808 jest błędne (np. wartości 0 lub bardzo małe). Stąd w głównej pętli programu najpierw zbieram 3000 sampli z którymi nic nie robię, i dopiero jak to się skończy, zaczynam pobierać 256 sampli do tablicy z której jest liczona FFT. Wtedy wszystko jest w jak najlepszym porządku i wygląda na to, że obliczona FFT jest poprawna. Kod z powodu zbierania tych 3000 niepotrzebnych sampli jest koszmarny, jak ustalę co jest przyczyną to postaram się go poprawić. Zrobiłem kilka testów i zmieniałem częstotliwość sinusoidy w badanym kanale, a potem liczyłem FFT  i największa amplituda FFT odpowiadała ustawionej częstotliwości generatora (np. 339 Hz, 12 KHz itp.). Tutaj zrzut ekranu z generatora z f=12 Khz (prawy kanał, bo mam zamienione kanały na wtyczce mini-jack):

Generator12KHz.thumb.png.617d971edbb74d71d84d279745303b8b.png

Tutaj kod głównego programu dla ESP32 (Arduino IDE):

#include "FFT.h" // include the library
#include "FFT_signal.h"
#include "ledc.h"
#include "driver/i2s.h"

#define CLK_PIN (18)
const i2s_port_t I2S_PORT = I2S_NUM_0;

volatile float sensor1;
bool startSampling=false;
bool endSampling=false;
bool meTime=false;
bool startOnly=false;
volatile int licSample=0;
long int t1A=0L;
long int t2A=0L;

void setup() { //---------------------------------------------------------------------------------------
  Serial.begin(115200); // use the serial port
  Serial.println("Starting ...");
  esp_err_t err;

  gpio_reset_pin((gpio_num_t)CLK_PIN);
  /* Set the GPIO as a push/pull output */
  gpio_set_direction((gpio_num_t)CLK_PIN, GPIO_MODE_OUTPUT);
  gpio_set_drive_capability((gpio_num_t)CLK_PIN, GPIO_DRIVE_CAP_3);

  ledc_timer_config_t ledc_timer;
  ledc_channel_config_t ledc_channel;
  
  //params ledc_timer
  ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;//LEDC_HIGH_SPEED_MODE;
  ledc_timer.timer_num  = LEDC_TIMER_0;
  ledc_timer.bit_num    = (ledc_timer_bit_t) LEDC_TIMER_1_BIT; //LEDC_TIMER_2_BIT;
  ledc_timer.freq_hz    = 11289600;
  ledc_timer.clk_cfg    = LEDC_USE_APB_CLK;
  
  //params ledc_channel
  ledc_channel.channel    = LEDC_CHANNEL_0;
  ledc_channel.gpio_num   = 18;  //WAS 18
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
  ledc_channel.timer_sel  = LEDC_TIMER_0;
  ledc_channel.duty       = 1;

  //Generacja zegara dla PCM1808
  ledc_timer_config(&ledc_timer);
  ledc_channel_config(&ledc_channel);
  //---------------------------------------------
  
  // The I2S config as per the example
  const i2s_config_t i2s_config = {
      .mode = i2s_mode_t(I2S_MODE_SLAVE | I2S_MODE_RX), // Receive, not transfer
      .sample_rate = 44100,                         // 44,1KHz
      .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits
      .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,   //I2S_CHANNEL_FMT_RIGHT_LEFT, // use both channel
      .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,     // Interrupt level 1
      .dma_buf_count = 4,                           // number of buffers
      .dma_buf_len = 8                              // 8 samples per buffer (minimum)
  };

    // The pin config as per the setup
  const i2s_pin_config_t pin_config = {
      .bck_io_num = 26,   // Serial Clock (SCK)
      .ws_io_num = 25,    // Word Select (WS)
      .data_out_num = I2S_PIN_NO_CHANGE, // not used (only for speakers)
      .data_in_num = 33   // Serial Data (SD)
  };

  // Configuring the I2S driver and pins.
  // This function must be called before any I2S driver read/write operations.
  err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    Serial.printf("Failed installing driver: %d\n", err);
    while (true);
  }
  err = i2s_set_pin(I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    Serial.printf("Failed setting pin: %d\n", err);
    while (true);
  }
  
  Serial.println("I2S driver installed.");
  Serial.println("Program Started");
  licSample=0;
  startSampling=false;//true; 
  meTime=true;
  startOnly=true;
}//---------------------------------------------------------------------------------------

void loop() {
  // Read a single sample and log it for the Serial Plotter.
  if (startOnly) {
    for(int j=0;j<=3000;j++) {
      int32_t sampleA = 0;
      int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sampleA, portMAX_DELAY); // no timeout
      if (bytes_read > 0) {
        Serial.println(sampleA);
      }
    }
    startOnly=false;
    startSampling=true;
  }
//-------------------------------------------------------------------------------------------
if (startSampling) {
 if (meTime) {
  t1A=micros();
  meTime=false;
 }
 int32_t sample = 0;
 int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout
 if (bytes_read > 0) {
     sensor1 = (float) sample;
     //Serial.println(sensor1,10);
 } 

 //Serial.println(sensor1 , 10); // Print as decimal, 10 decimal places
 fft_signal[licSample]=(double)sensor1;
 licSample++;
 if (licSample>=256) {
   licSample=0;
   startSampling=false;
   endSampling=true;
   t2A=micros();
   Serial.print("Time taken: ");
   Serial.print((t2A-t1A)*1.0/1000);
   Serial.println(" milliseconds!");
 }
}

if (endSampling) {
  char print_buf[300];
  fft_config_t *real_fft_plan = fft_init(FFT_N, FFT_REAL, FFT_FORWARD, fft_input, fft_output);

  for (int k = 0 ; k < FFT_N ; k++)
    real_fft_plan->input[k] = (float)fft_signal[k];

  long int t1 = micros();
  // Execute transformation
  fft_execute(real_fft_plan);

  //sprintf(print_buf,"sizeFFT= %d", real_fft_plan->size);
  //Serial.println(print_buf);

  long int t2 = micros();
  
  // Print the output
  for (int k = 1 ; k < real_fft_plan->size / 2 ; k++)
  {
    /*The real part of a magnitude at a frequency is followed by the corresponding imaginary part in the output*/
    float mag = sqrt(pow(real_fft_plan->output[2*k],2) + pow(real_fft_plan->output[2*k+1],2))/1;
    float freq = k*1.0/(1*TOTAL_TIME);
    sprintf(print_buf,"%f Hz : %f", freq, mag);
    Serial.println(print_buf);
    if(mag > max_magnitude)
    {
        max_magnitude = mag;
        fundamental_freq = freq;
    }
  }   
  
  Serial.println();
  /*Multiply the magnitude of the DC component with (1/FFT_N) to obtain the DC component*/
  sprintf(print_buf,"DC component : %f g\n", (real_fft_plan->output[0])/10000/FFT_N);  // DC is at [0]
  Serial.println(print_buf);

  /*Multiply the magnitude at all other frequencies with (2/FFT_N) to obtain the amplitude at that frequency*/
  sprintf(print_buf,"Fundamental Freq : %f Hz\t Mag: %f g\n", fundamental_freq, (max_magnitude/10000)*2/FFT_N);
  Serial.println(print_buf);

  Serial.print("Time taken: ");Serial.print((t2-t1)*1.0/1000);Serial.println(" milliseconds!");
  
  // Clean up at the end to free the memory allocated
  fft_destroy(real_fft_plan);
  endSampling=false;
  }
}

A tutaj zwrócone wyniki (serial monitor) z liczenia FFT dla f=12KHz:

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
E (138) psram: PSRAM ID read error: 0xffffffff
Starting ...
I2S driver installed.
Program Started

Time taken: 5.18 milliseconds!
169.635284 Hz : 191452416.000000
339.270569 Hz : 109134136.000000
508.905853 Hz : 67720232.000000
678.541138 Hz : 138728464.000000
848.176392 Hz : 177556576.000000
1017.811707 Hz : 185624608.000000
1187.447021 Hz : 146101744.000000
1357.082275 Hz : 173017408.000000
1526.717529 Hz : 216774208.000000
1696.352783 Hz : 227156224.000000
1865.988159 Hz : 217343344.000000
2035.623413 Hz : 240541456.000000
2205.258789 Hz : 253379664.000000
2374.894043 Hz : 258168640.000000
2544.529297 Hz : 274099616.000000
2714.164551 Hz : 280934432.000000
2883.799805 Hz : 281624320.000000
3053.435059 Hz : 275708704.000000
3223.070312 Hz : 289942432.000000
3392.705566 Hz : 303484288.000000
3562.341064 Hz : 296357408.000000
3731.976318 Hz : 287148768.000000
3901.611572 Hz : 323902560.000000
4071.246826 Hz : 276508608.000000
4240.882324 Hz : 270648032.000000
4410.517578 Hz : 267042256.000000
4580.152832 Hz : 272944384.000000
4749.788086 Hz : 250736480.000000
4919.423340 Hz : 223841248.000000
5089.058594 Hz : 283212416.000000
5258.693848 Hz : 335304512.000000
5428.329102 Hz : 309299008.000000
5597.964355 Hz : 237490128.000000
5767.599609 Hz : 120023432.000000
5937.234863 Hz : 118431016.000000
6106.870117 Hz : 146821248.000000
6276.505371 Hz : 160563120.000000
6446.140625 Hz : 133326096.000000
6615.775879 Hz : 123779272.000000
6785.411133 Hz : 162451328.000000
6955.046875 Hz : 194568896.000000
7124.682129 Hz : 211550832.000000
7294.317383 Hz : 222536896.000000
7463.952637 Hz : 257127104.000000
7633.587891 Hz : 305581024.000000
7803.223145 Hz : 346614848.000000
7972.858398 Hz : 344598880.000000
8142.493652 Hz : 394834528.000000
8312.128906 Hz : 437261280.000000
8481.764648 Hz : 483144480.000000
8651.399414 Hz : 522352128.000000
8821.035156 Hz : 587505472.000000
8990.669922 Hz : 629459520.000000
9160.305664 Hz : 670656704.000000
9329.940430 Hz : 729368960.000000
9499.576172 Hz : 787471488.000000
9669.210938 Hz : 855302656.000000
9838.846680 Hz : 932553600.000000
10008.481445 Hz : 987118656.000000
10178.117188 Hz : 1084925952.000000
10347.751953 Hz : 1173533952.000000
10517.387695 Hz : 1277462528.000000
10687.022461 Hz : 1417751168.000000
10856.658203 Hz : 1637444864.000000
11026.293945 Hz : 1873759360.000000
11195.928711 Hz : 2259308800.000000
11365.564453 Hz : 2949163520.000000
11535.199219 Hz : 4422577664.000000
11704.834961 Hz : 10363367424.000000
11874.469727 Hz : 18745341952.000000
12044.105469 Hz : 4416784384.000000
12213.740234 Hz : 2342270464.000000
12383.375977 Hz : 1539607680.000000
12553.010742 Hz : 1125686400.000000
12722.646484 Hz : 878828288.000000
12892.281250 Hz : 758940352.000000
13061.916992 Hz : 652103872.000000
13231.551758 Hz : 596211904.000000
13401.187500 Hz : 576817216.000000
13570.822266 Hz : 549978752.000000
13740.458008 Hz : 523314784.000000
13910.093750 Hz : 537184768.000000
14079.728516 Hz : 533713536.000000
14249.364258 Hz : 529715616.000000
14418.999023 Hz : 514065728.000000
14588.634766 Hz : 517166016.000000
14758.269531 Hz : 511620320.000000
14927.905273 Hz : 498939712.000000
15097.540039 Hz : 492389056.000000
15267.175781 Hz : 479132064.000000
15436.810547 Hz : 483157088.000000
15606.446289 Hz : 460360832.000000
15776.081055 Hz : 448837920.000000
15945.716797 Hz : 448728608.000000
16115.351562 Hz : 444418400.000000
16284.987305 Hz : 310974144.000000
16454.623047 Hz : 380750848.000000
16624.257812 Hz : 340865952.000000
16793.892578 Hz : 351013472.000000
16963.529297 Hz : 324327616.000000
17133.164062 Hz : 313178336.000000
17302.798828 Hz : 289025600.000000
17472.433594 Hz : 270706976.000000
17642.070312 Hz : 252091712.000000
17811.705078 Hz : 243223952.000000
17981.339844 Hz : 236100528.000000
18150.974609 Hz : 219777808.000000
18320.611328 Hz : 208784704.000000
18490.246094 Hz : 197463568.000000
18659.880859 Hz : 182546368.000000
18829.515625 Hz : 193781984.000000
18999.152344 Hz : 183540864.000000
19168.787109 Hz : 175686528.000000
19338.421875 Hz : 181729568.000000
19508.058594 Hz : 179868224.000000
19677.693359 Hz : 192602992.000000
19847.328125 Hz : 194869232.000000
20016.962891 Hz : 199194448.000000
20186.599609 Hz : 205792704.000000
20356.234375 Hz : 205338080.000000
20525.869141 Hz : 214842656.000000
20695.503906 Hz : 238989968.000000
20865.140625 Hz : 225072432.000000
21034.775391 Hz : 228193280.000000
21204.410156 Hz : 232003056.000000
21374.044922 Hz : 235886736.000000
21543.681641 Hz : 231358832.000000

DC component : 80.314697 g

Fundamental Freq : 11874.469727 Hz	 Mag: 14644.798828 g

Time taken: 0.17 milliseconds!
  

Dla innych częstotliwości też się to zgadzało. próbki (256) były zebrane w czasie 5,18 ms a liczenie FFT trwało 0.17 ms. Zaokrąglając do 6 ms, możemy zbierać próbki i liczyć 256 punktową FFT dla jednego kanału 166 razy na sekundę. Zrobię jeszcze próby z 512 punktową FFT i sygnałami sinusoida i prostokąt - dla prostokąta powinno być widać na FFT sporo prążków widma dla wyższych harmonicznych sygnału. W archiwum zip pełny kod projektu (z plikami nagłówkowymi).

FFT_on_ESP32_PCM1808_06.zip

Zmodyfikowałem trochę program główny - w sterowniku I2S (ESP32) zmieniłem rozdzielczość na 24 bity, i zbieram 512 sampli, oraz liczę 512 punktową FFT. Teraz zbieranie 512 sampli trwa 11,1 ms a liczenie FFT 0,26 ms, stąd możemy zbierać sample i liczyć 512-punktową FFT 83 razy na sekundę. Tutaj wyniki programu FFT512 punkt dla f generatora wynoszącej 400 Hz:

Time taken: 11.10 milliseconds!
86.132645 Hz : 9141368832.000000
172.265289 Hz : 11442161664.000000
258.397919 Hz : 17559941120.000000
344.530579 Hz : 43953999872.000000
430.663208 Hz : 78903001088.000000
516.795837 Hz : 20639463424.000000
602.928528 Hz : 11848830976.000000
689.061157 Hz : 8302599168.000000
775.193787 Hz : 6384007680.000000
861.326416 Hz : 5188823040.000000
947.459106 Hz : 4322128384.000000
1033.591675 Hz : 3817713152.000000
1119.724365 Hz : 3246767872.000000
1205.857056 Hz : 2809762816.000000
1291.989624 Hz : 2461610240.000000
1378.122314 Hz : 2155312640.000000
1464.255005 Hz : 1902678400.000000
1550.387573 Hz : 1687403136.000000
1636.520264 Hz : 1523738624.000000
1722.652832 Hz : 1383339392.000000
1808.785522 Hz : 1249201152.000000
1894.918213 Hz : 1109603456.000000
1981.050781 Hz : 974990272.000000
2067.183350 Hz : 861933952.000000
2153.316162 Hz : 757803712.000000
2239.448730 Hz : 668782272.000000
2325.581299 Hz : 578334464.000000
2411.714111 Hz : 512225984.000000
2497.846680 Hz : 477127648.000000
2583.979248 Hz : 433857152.000000
2670.112061 Hz : 411584480.000000
2756.244629 Hz : 392930496.000000
2842.377197 Hz : 384715104.000000
2928.510010 Hz : 382387328.000000
3014.642578 Hz : 444822784.000000
3100.775146 Hz : 434545760.000000
3186.907959 Hz : 465637344.000000
3273.040527 Hz : 501518656.000000
3359.173096 Hz : 523212768.000000
3445.305664 Hz : 545217280.000000
3531.438477 Hz : 584884288.000000
3617.571045 Hz : 614427840.000000
3703.703613 Hz : 630672896.000000
3789.836426 Hz : 655527296.000000
3875.968994 Hz : 661188032.000000
3962.101562 Hz : 695105856.000000
4048.234375 Hz : 766112384.000000
4134.366699 Hz : 772925952.000000
4220.499512 Hz : 798566784.000000
4306.632324 Hz : 804484032.000000
4392.764648 Hz : 812074944.000000
4478.897461 Hz : 831840384.000000
4565.030273 Hz : 835790784.000000
4651.162598 Hz : 842383168.000000
4737.295410 Hz : 860760704.000000
4823.428223 Hz : 865882240.000000
4909.560547 Hz : 887030080.000000
4995.693359 Hz : 871380736.000000
5081.826172 Hz : 843278720.000000
5167.958496 Hz : 813922240.000000
5254.091309 Hz : 784963904.000000
5340.224121 Hz : 766593408.000000
5426.356445 Hz : 787226496.000000
5512.489258 Hz : 1937158784.000000
5598.622070 Hz : 871175872.000000
5684.754395 Hz : 929168512.000000
5770.887207 Hz : 963689856.000000
5857.020020 Hz : 971004096.000000
5943.152344 Hz : 949483456.000000
6029.285156 Hz : 966385280.000000
6115.417969 Hz : 901552576.000000
6201.550293 Hz : 856672512.000000
6287.683105 Hz : 817124224.000000
6373.815918 Hz : 803324928.000000
6459.948242 Hz : 809918784.000000
6546.081055 Hz : 815625152.000000
6632.213379 Hz : 797496320.000000
6718.346191 Hz : 780294784.000000
6804.479004 Hz : 744705472.000000
6890.611328 Hz : 721741632.000000
6976.744141 Hz : 639909056.000000
7062.876953 Hz : 687745344.000000
7149.009277 Hz : 648987072.000000
7235.142090 Hz : 629781632.000000
7321.274902 Hz : 623329920.000000
7407.407227 Hz : 624927680.000000
7493.540039 Hz : 580346560.000000
7579.672852 Hz : 539820992.000000
7665.805176 Hz : 518066240.000000
7751.937988 Hz : 480906944.000000
7838.070801 Hz : 464945280.000000
7924.203125 Hz : 443038240.000000
8010.335938 Hz : 399219168.000000
8096.468750 Hz : 403359552.000000
8182.601074 Hz : 386568160.000000
8268.733398 Hz : 359140000.000000
8354.866211 Hz : 337761568.000000
8440.999023 Hz : 294525216.000000
8527.131836 Hz : 274494304.000000
8613.264648 Hz : 245167680.000000
8699.397461 Hz : 222852512.000000
8785.529297 Hz : 212910144.000000
8871.662109 Hz : 210311056.000000
8957.794922 Hz : 204235840.000000
9043.927734 Hz : 146356880.000000
9130.060547 Hz : 138340944.000000
9216.193359 Hz : 141419376.000000
9302.325195 Hz : 131669808.000000
9388.458008 Hz : 133256080.000000
9474.590820 Hz : 113988824.000000
9560.723633 Hz : 133358080.000000
9646.856445 Hz : 155083712.000000
9732.989258 Hz : 168116640.000000
9819.121094 Hz : 180321840.000000
9905.253906 Hz : 213035968.000000
9991.386719 Hz : 250704112.000000
10077.519531 Hz : 233930736.000000
10163.652344 Hz : 242874112.000000
10249.785156 Hz : 248719424.000000
10335.916992 Hz : 268186864.000000
10422.049805 Hz : 297925504.000000
10508.182617 Hz : 303129184.000000
10594.315430 Hz : 329909376.000000
10680.448242 Hz : 350985824.000000
10766.580078 Hz : 363776032.000000
10852.712891 Hz : 377948160.000000
10938.845703 Hz : 371298368.000000
11024.978516 Hz : 331623072.000000
11111.111328 Hz : 410877088.000000
11197.244141 Hz : 420421024.000000
11283.375977 Hz : 426114912.000000
11369.508789 Hz : 441244320.000000
11455.641602 Hz : 435619456.000000
11541.774414 Hz : 437170880.000000
11627.907227 Hz : 446268096.000000
11714.040039 Hz : 449189600.000000
11800.171875 Hz : 446413472.000000
11886.304688 Hz : 459700992.000000
11972.437500 Hz : 450042016.000000
12058.570312 Hz : 464806816.000000
12144.703125 Hz : 475681408.000000
12230.835938 Hz : 477403072.000000
12316.967773 Hz : 484270048.000000
12403.100586 Hz : 485154848.000000
12489.233398 Hz : 465371072.000000
12575.366211 Hz : 464977184.000000
12661.499023 Hz : 462827040.000000
12747.631836 Hz : 453089056.000000
12833.763672 Hz : 457062464.000000
12919.896484 Hz : 450253568.000000
13006.029297 Hz : 411559456.000000
13092.162109 Hz : 447291648.000000
13178.294922 Hz : 438463904.000000
13264.426758 Hz : 420638816.000000
13350.559570 Hz : 414526912.000000
13436.692383 Hz : 388920480.000000
13522.825195 Hz : 392907424.000000
13608.958008 Hz : 386582016.000000
13695.090820 Hz : 368768160.000000
13781.222656 Hz : 369395424.000000
13867.355469 Hz : 366564320.000000
13953.488281 Hz : 374304480.000000
14039.621094 Hz : 281218944.000000
14125.753906 Hz : 291337184.000000
14211.886719 Hz : 280410752.000000
14298.018555 Hz : 277286592.000000
14384.151367 Hz : 269499616.000000
14470.284180 Hz : 255721504.000000
14556.416992 Hz : 245399696.000000
14642.549805 Hz : 223101168.000000
14728.682617 Hz : 214164304.000000
14814.814453 Hz : 203302304.000000
14900.947266 Hz : 181108912.000000
14987.080078 Hz : 189798688.000000
15073.212891 Hz : 148700768.000000
15159.345703 Hz : 141986208.000000
15245.478516 Hz : 132098304.000000
15331.610352 Hz : 124060240.000000
15417.743164 Hz : 103626080.000000
15503.875977 Hz : 100319352.000000
15590.008789 Hz : 89201088.000000
15676.141602 Hz : 79425960.000000
15762.273438 Hz : 85389720.000000
15848.406250 Hz : 92024312.000000
15934.539062 Hz : 80940288.000000
16020.671875 Hz : 134176088.000000
16106.804688 Hz : 127494800.000000
16192.937500 Hz : 144446048.000000
16279.069336 Hz : 167815824.000000
16365.202148 Hz : 183239008.000000
16451.335938 Hz : 193962000.000000
16537.466797 Hz : 126679520.000000
16623.599609 Hz : 219613008.000000
16709.732422 Hz : 224130464.000000
16795.865234 Hz : 229435360.000000
16881.998047 Hz : 239941568.000000
16968.130859 Hz : 216957552.000000
17054.263672 Hz : 269503904.000000
17140.396484 Hz : 259196048.000000
17226.529297 Hz : 267311696.000000
17312.662109 Hz : 286268608.000000
17398.794922 Hz : 302883296.000000
17484.927734 Hz : 303634336.000000
17571.058594 Hz : 318956736.000000
17657.191406 Hz : 326156608.000000
17743.324219 Hz : 334837440.000000
17829.457031 Hz : 344002080.000000
17915.589844 Hz : 340860000.000000
18001.722656 Hz : 322950816.000000
18087.855469 Hz : 350027200.000000
18173.988281 Hz : 353387616.000000
18260.121094 Hz : 366410912.000000
18346.253906 Hz : 369161408.000000
18432.386719 Hz : 365175168.000000
18518.517578 Hz : 384044992.000000
18604.650391 Hz : 367130752.000000
18690.783203 Hz : 373451168.000000
18776.916016 Hz : 383362016.000000
18863.048828 Hz : 377482624.000000
18949.181641 Hz : 382090720.000000
19035.314453 Hz : 355031392.000000
19121.447266 Hz : 357656096.000000
19207.580078 Hz : 371207328.000000
19293.712891 Hz : 361327232.000000
19379.845703 Hz : 362330432.000000
19465.978516 Hz : 350333408.000000
19552.109375 Hz : 334586784.000000
19638.242188 Hz : 345290400.000000
19724.375000 Hz : 344308128.000000
19810.507812 Hz : 331108704.000000
19896.640625 Hz : 326780672.000000
19982.773438 Hz : 356569920.000000
20068.906250 Hz : 291068224.000000
20155.039062 Hz : 303582336.000000
20241.171875 Hz : 284261088.000000
20327.304688 Hz : 270258528.000000
20413.437500 Hz : 254429872.000000
20499.570312 Hz : 261809056.000000
20585.701172 Hz : 245236592.000000
20671.833984 Hz : 231506240.000000
20757.966797 Hz : 221063200.000000
20844.099609 Hz : 213076752.000000
20930.232422 Hz : 200788960.000000
21016.365234 Hz : 201769008.000000
21102.498047 Hz : 171253072.000000
21188.630859 Hz : 165943488.000000
21274.763672 Hz : 151917744.000000
21360.896484 Hz : 148159168.000000
21447.029297 Hz : 128343256.000000
21533.160156 Hz : 113991704.000000
21619.292969 Hz : 106053936.000000
21705.425781 Hz : 92115712.000000
21791.558594 Hz : 76886800.000000
21877.691406 Hz : 68215016.000000
21963.824219 Hz : 62225192.000000

DC component : 1820.613403 g

Fundamental Freq : 430.663208 Hz	 Mag: 30821.484375 g

Time taken: 0.26 milliseconds!

Jak widać wyniki są poprawne. Na wyjściu karty dźwiękowej występuje szum o częstotliwości kilka KHz i on też wpływa na wyniki obliczonej FFT. Teraz pozostaje ustalić dlaczego przetwornik I2S (układ PCM1808) po restarcie/włączeniu ma pewien okres czasu dla którego zbierane sample są błędne, oraz ulepszyć kod programu. Właściwie główne cele zostały osiągnięte - widać, że przetwornik ADC I2S (układ PCM1808) i ESP32 tworzą tandem, który śmiało może zbierać próbki sygnału audio w paśmie 0 Hz do 20 KHz i liczyć 512 punktową FFT w zadanym czasie i z dużą rozdzielczością (24 bity).

Tutaj kod głównego programu (po modyfikacji FFT 512 punktów):

#include "FFT.h" // include the library
#include "FFT_signal.h"
#include "ledc.h"
#include "driver/i2s.h"

#define CLK_PIN (18)
const i2s_port_t I2S_PORT = I2S_NUM_0;

volatile double sensor1;
bool startSampling=false;
bool endSampling=false;
bool meTime=false;
bool startOnly=false;
volatile int licSample=0;
long int t1A=0L;
long int t2A=0L;

void setup() { //---------------------------------------------------------------------------------------
  Serial.begin(115200); // use the serial port
  Serial.println("Starting ...");
  esp_err_t err;

  gpio_reset_pin((gpio_num_t)CLK_PIN);
  /* Set the GPIO as a push/pull output */
  gpio_set_direction((gpio_num_t)CLK_PIN, GPIO_MODE_OUTPUT);
  gpio_set_drive_capability((gpio_num_t)CLK_PIN, GPIO_DRIVE_CAP_3);

  ledc_timer_config_t ledc_timer;
  ledc_channel_config_t ledc_channel;
  
  //params ledc_timer
  ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;//LEDC_HIGH_SPEED_MODE;
  ledc_timer.timer_num  = LEDC_TIMER_0;
  ledc_timer.bit_num    = (ledc_timer_bit_t) LEDC_TIMER_1_BIT; //LEDC_TIMER_2_BIT;
  ledc_timer.freq_hz    = 11289600;
  ledc_timer.clk_cfg    = LEDC_USE_APB_CLK;
  
  //params ledc_channel
  ledc_channel.channel    = LEDC_CHANNEL_0;
  ledc_channel.gpio_num   = 18;  //WAS 18
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
  ledc_channel.timer_sel  = LEDC_TIMER_0;
  ledc_channel.duty       = 1;

  //Generacja zegara dla PCM1808
  ledc_timer_config(&ledc_timer);
  ledc_channel_config(&ledc_channel);
  //---------------------------------------------
  
  // The I2S config as per the example
  const i2s_config_t i2s_config = {
      .mode = i2s_mode_t(I2S_MODE_SLAVE | I2S_MODE_RX), // Receive, not transfer
      .sample_rate = 44100,                         // 44,1KHz
      .bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT, // could only get it to work with 32bits
      .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,   //I2S_CHANNEL_FMT_RIGHT_LEFT, // use both channel
      .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,     // Interrupt level 1
      .dma_buf_count = 4,                           // number of buffers
      .dma_buf_len = 8                              // 8 samples per buffer (minimum)
  };

    // The pin config as per the setup
  const i2s_pin_config_t pin_config = {
      .bck_io_num = 26,   // Serial Clock (SCK)
      .ws_io_num = 25,    // Word Select (WS)
      .data_out_num = I2S_PIN_NO_CHANGE, // not used (only for speakers)
      .data_in_num = 33   // Serial Data (SD)
  };

  // Configuring the I2S driver and pins.
  // This function must be called before any I2S driver read/write operations.
  err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    Serial.printf("Failed installing driver: %d\n", err);
    while (true);
  }
  err = i2s_set_pin(I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    Serial.printf("Failed setting pin: %d\n", err);
    while (true);
  }
  
  Serial.println("I2S driver installed.");
  Serial.println("Program Started");
  licSample=0;
  startSampling=false;//true; 
  meTime=true;
  startOnly=true;
}//---------------------------------------------------------------------------------------

void loop() {
  // Read a single sample and log it for the Serial Plotter.
  if (startOnly) {
    for(int j=0;j<=3000;j++) {
      int32_t sampleA = 0;
      int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sampleA, portMAX_DELAY); // no timeout
      if (bytes_read > 0) {
        Serial.println(sampleA);
      }
    }
    startOnly=false;
    startSampling=true;
  }
//-------------------------------------------------------------------------------------------
if (startSampling) {
 if (meTime) {
  t1A=micros();
  meTime=false;
 }
 int32_t sample = 0;
 int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout
 if (bytes_read > 0) {
     sensor1 = (double) sample;
     //Serial.println(sensor1,10);
 } 

 //Serial.println(sensor1 , 10); // Print as decimal, 10 decimal places
 fft_signal[licSample]=sensor1;
 licSample++;
 if (licSample>=512) {
   licSample=0;
   startSampling=false;
   endSampling=true;
   t2A=micros();
   Serial.print("Time taken: ");
   Serial.print((t2A-t1A)*1.0/1000);
   Serial.println(" milliseconds!");
 }
}

if (endSampling) {
  char print_buf[300];
  fft_config_t *real_fft_plan = fft_init(FFT_N, FFT_REAL, FFT_FORWARD, fft_input, fft_output);

  for (int k = 0 ; k < FFT_N ; k++)
    real_fft_plan->input[k] = (float)fft_signal[k];

  long int t1 = micros();
  // Execute transformation
  fft_execute(real_fft_plan);

  //sprintf(print_buf,"sizeFFT= %d", real_fft_plan->size);
  //Serial.println(print_buf);

  long int t2 = micros();
  
  // Print the output
  for (int k = 1 ; k < real_fft_plan->size / 2 ; k++)
  {
    /*The real part of a magnitude at a frequency is followed by the corresponding imaginary part in the output*/
    float mag = sqrt(pow(real_fft_plan->output[2*k],2) + pow(real_fft_plan->output[2*k+1],2))/1;
    float freq = k*1.0/(1*TOTAL_TIME);
    sprintf(print_buf,"%f Hz : %f", freq, mag);
    Serial.println(print_buf);
    if(mag > max_magnitude)
    {
        max_magnitude = mag;
        fundamental_freq = freq;
    }
  }   
  
  Serial.println();
  /*Multiply the magnitude of the DC component with (1/FFT_N) to obtain the DC component*/
  sprintf(print_buf,"DC component : %f g\n", (real_fft_plan->output[0])/10000/FFT_N);  // DC is at [0]
  Serial.println(print_buf);

  /*Multiply the magnitude at all other frequencies with (2/FFT_N) to obtain the amplitude at that frequency*/
  sprintf(print_buf,"Fundamental Freq : %f Hz\t Mag: %f g\n", fundamental_freq, (max_magnitude/10000)*2/FFT_N);
  Serial.println(print_buf);

  Serial.print("Time taken: ");Serial.print((t2-t1)*1.0/1000);Serial.println(" milliseconds!");
  
  // Clean up at the end to free the memory allocated
  fft_destroy(real_fft_plan);
  endSampling=false;
  }
}

A tutaj kod pliku "FFT_signal.h", który także był zmodyfikowany:

#define FFT_N 512 // Must be a power of 2
#define TOTAL_TIME  0.01161  //The time in which data was captured. This is equal to FFT_N/sampling_freq 0.008533333
//9.391904 was time

float fft_input[FFT_N];
float fft_output[FFT_N];

float max_magnitude = 0;
float fundamental_freq = 0;


/* Dummy data (Output of an accelerometer)
 * Frequency: 5 Hz
 * Amplitude: 0.25g
*/
double fft_signal[FFT_N];

Jako ostatnią próbę, podałem na wejście przetwornika I2S sygnał prostokątny o f = 4 KHz, w wyniku obliczonej FFT pojawiły się prążki wyższych nieparzystych harmonicznych tej częstotliwości (4Khz) w widmie sygnału (np. mocno podwyższona amplituda prążka o f=12 KHz : trzecia harmoniczna i f =20Khz: piąta harmoniczna), tak jak można się było tego spodziewać. Tutaj wyniki - obliczona FFT tekstowo:

Time taken: 11.07 milliseconds!
86.132645 Hz : 408293280.000000
172.265289 Hz : 380586752.000000
258.397919 Hz : 409515456.000000
344.530579 Hz : 440767712.000000
430.663208 Hz : 529739840.000000
516.795837 Hz : 627410304.000000
602.928528 Hz : 718427136.000000
689.061157 Hz : 808271744.000000
775.193787 Hz : 895133248.000000
861.326416 Hz : 966536000.000000
947.459106 Hz : 1053998400.000000
1033.591675 Hz : 1066186112.000000
1119.724365 Hz : 1186865280.000000
1205.857056 Hz : 1301008256.000000
1291.989624 Hz : 1400085248.000000
1378.122314 Hz : 1519175936.000000
1464.255005 Hz : 1625729408.000000
1550.387573 Hz : 1713407616.000000
1636.520264 Hz : 1819180032.000000
1722.652832 Hz : 1912047488.000000
1808.785522 Hz : 2029090816.000000
1894.918213 Hz : 2140813440.000000
1981.050781 Hz : 2275709696.000000
2067.183350 Hz : 2390953984.000000
2153.316162 Hz : 2537329408.000000
2239.448730 Hz : 2682446592.000000
2325.581299 Hz : 2830460160.000000
2411.714111 Hz : 2977613312.000000
2497.846680 Hz : 3144946688.000000
2583.979248 Hz : 3341127936.000000
2670.112061 Hz : 3547421952.000000
2756.244629 Hz : 3759941888.000000
2842.377197 Hz : 4023924736.000000
2928.510010 Hz : 4294814976.000000
3014.642578 Hz : 4574524416.000000
3100.775146 Hz : 4974773248.000000
3186.907959 Hz : 5412062208.000000
3273.040527 Hz : 5956078080.000000
3359.173096 Hz : 6618698752.000000
3445.305664 Hz : 7478651392.000000
3531.438477 Hz : 8649086976.000000
3617.571045 Hz : 10295028736.000000
3703.703613 Hz : 12892574720.000000
3789.836426 Hz : 17588123648.000000
3875.968994 Hz : 28775542784.000000
3962.101562 Hz : 90601717760.000000
4048.234375 Hz : 68374339584.000000
4134.366699 Hz : 23441127424.000000
4220.499512 Hz : 13599793152.000000
4306.632324 Hz : 9270361088.000000
4392.764648 Hz : 6833225216.000000
4478.897461 Hz : 5260700160.000000
4565.030273 Hz : 4180043264.000000
4651.162598 Hz : 3364445696.000000
4737.295410 Hz : 2729316864.000000
4823.428223 Hz : 2218638336.000000
4909.560547 Hz : 1817226880.000000
4995.693359 Hz : 1482218368.000000
5081.826172 Hz : 1231075968.000000
5167.958496 Hz : 1016959040.000000
5254.091309 Hz : 827169024.000000
5340.224121 Hz : 661439552.000000
5426.356445 Hz : 502713248.000000
5512.489258 Hz : 907886912.000000
5598.622070 Hz : 303772416.000000
5684.754395 Hz : 319899712.000000
5770.887207 Hz : 402728064.000000
5857.020020 Hz : 497565408.000000
5943.152344 Hz : 576873216.000000
6029.285156 Hz : 652826816.000000
6115.417969 Hz : 707570816.000000
6201.550293 Hz : 752119936.000000
6287.683105 Hz : 804130304.000000
6373.815918 Hz : 850382144.000000
6459.948242 Hz : 907687232.000000
6546.081055 Hz : 964701632.000000
6632.213379 Hz : 1006233536.000000
6718.346191 Hz : 1051661696.000000
6804.479004 Hz : 1085285248.000000
6890.611328 Hz : 1112073984.000000
6976.744141 Hz : 1156359680.000000
7062.876953 Hz : 1141037440.000000
7149.009277 Hz : 1181207936.000000
7235.142090 Hz : 1206009856.000000
7321.274902 Hz : 1234120960.000000
7407.407227 Hz : 1254292736.000000
7493.540039 Hz : 1273686400.000000
7579.672852 Hz : 1273214720.000000
7665.805176 Hz : 1278683008.000000
7751.937988 Hz : 1289632000.000000
7838.070801 Hz : 1297243776.000000
7924.203125 Hz : 1308710656.000000
8010.335938 Hz : 1298717696.000000
8096.468750 Hz : 1317596928.000000
8182.601074 Hz : 1318697728.000000
8268.733398 Hz : 1310319744.000000
8354.866211 Hz : 1301061504.000000
8440.999023 Hz : 1299535360.000000
8527.131836 Hz : 1270433408.000000
8613.264648 Hz : 1273693952.000000
8699.397461 Hz : 1270876416.000000
8785.529297 Hz : 1263771776.000000
8871.662109 Hz : 1252880896.000000
8957.794922 Hz : 1248206208.000000
9043.927734 Hz : 1196622336.000000
9130.060547 Hz : 1179914368.000000
9216.193359 Hz : 1163208832.000000
9302.325195 Hz : 1137695232.000000
9388.458008 Hz : 1118046848.000000
9474.590820 Hz : 1080700160.000000
9560.723633 Hz : 1079216128.000000
9646.856445 Hz : 1048332288.000000
9732.989258 Hz : 1013176448.000000
9819.121094 Hz : 973087808.000000
9905.253906 Hz : 943776000.000000
9991.386719 Hz : 917044416.000000
10077.519531 Hz : 858685568.000000
10163.652344 Hz : 828215296.000000
10249.785156 Hz : 782355584.000000
10335.916992 Hz : 738688128.000000
10422.049805 Hz : 684618816.000000
10508.182617 Hz : 646526528.000000
10594.315430 Hz : 580540288.000000
10680.448242 Hz : 520964800.000000
10766.580078 Hz : 459492192.000000
10852.712891 Hz : 410082208.000000
10938.845703 Hz : 364540288.000000
11024.978516 Hz : 338826720.000000
11111.111328 Hz : 352749088.000000
11197.244141 Hz : 429281632.000000
11283.375977 Hz : 552253696.000000
11369.508789 Hz : 740534464.000000
11455.641602 Hz : 992724160.000000
11541.774414 Hz : 1371656320.000000
11627.907227 Hz : 1901877376.000000
11714.040039 Hz : 2747869952.000000
11800.171875 Hz : 4313456128.000000
11886.304688 Hz : 8216051200.000000
11972.437500 Hz : 36275232768.000000
12058.570312 Hz : 18224908288.000000
12144.703125 Hz : 7777150976.000000
12230.835938 Hz : 5111212032.000000
12316.967773 Hz : 3882990336.000000
12403.100586 Hz : 3167514112.000000
12489.233398 Hz : 2694308352.000000
12575.366211 Hz : 2350506496.000000
12661.499023 Hz : 2085567872.000000
12747.631836 Hz : 1882536448.000000
12833.763672 Hz : 1713207680.000000
12919.896484 Hz : 1568141824.000000
13006.029297 Hz : 1444735872.000000
13092.162109 Hz : 1340146176.000000
13178.294922 Hz : 1242595072.000000
13264.426758 Hz : 1163019904.000000
13350.559570 Hz : 1081374848.000000
13436.692383 Hz : 1012613696.000000
13522.825195 Hz : 940885696.000000
13608.958008 Hz : 885604352.000000
13695.090820 Hz : 826839744.000000
13781.222656 Hz : 775246976.000000
13867.355469 Hz : 722131904.000000
13953.488281 Hz : 689703296.000000
14039.621094 Hz : 608234752.000000
14125.753906 Hz : 580383488.000000
14211.886719 Hz : 545053056.000000
14298.018555 Hz : 510988736.000000
14384.151367 Hz : 475507424.000000
14470.284180 Hz : 446134944.000000
14556.416992 Hz : 410951680.000000
14642.549805 Hz : 379628544.000000
14728.682617 Hz : 364948864.000000
14814.814453 Hz : 347281312.000000
14900.947266 Hz : 328105120.000000
14987.080078 Hz : 316639040.000000
15073.212891 Hz : 297384192.000000
15159.345703 Hz : 287581376.000000
15245.478516 Hz : 281325568.000000
15331.610352 Hz : 277506944.000000
15417.743164 Hz : 280306944.000000
15503.875977 Hz : 282546560.000000
15590.008789 Hz : 285367392.000000
15676.141602 Hz : 289609792.000000
15762.273438 Hz : 299996416.000000
15848.406250 Hz : 307019904.000000
15934.539062 Hz : 314902624.000000
16020.671875 Hz : 353931008.000000
16106.804688 Hz : 339039936.000000
16192.937500 Hz : 346807616.000000
16279.069336 Hz : 354902784.000000
16365.202148 Hz : 357639008.000000
16451.335938 Hz : 375153600.000000
16537.466797 Hz : 536939840.000000
16623.599609 Hz : 383292928.000000
16709.732422 Hz : 402282240.000000
16795.865234 Hz : 416327744.000000
16881.998047 Hz : 430192096.000000
16968.130859 Hz : 438749824.000000
17054.263672 Hz : 442028288.000000
17140.396484 Hz : 447770688.000000
17226.529297 Hz : 454473440.000000
17312.662109 Hz : 453005472.000000
17398.794922 Hz : 457402336.000000
17484.927734 Hz : 449943616.000000
17571.058594 Hz : 469420064.000000
17657.191406 Hz : 466934976.000000
17743.324219 Hz : 471360608.000000
17829.457031 Hz : 469294240.000000
17915.589844 Hz : 464179328.000000
18001.722656 Hz : 480258592.000000
18087.855469 Hz : 455845728.000000
18173.988281 Hz : 460382272.000000
18260.121094 Hz : 448051968.000000
18346.253906 Hz : 446943456.000000
18432.386719 Hz : 441915328.000000
18518.517578 Hz : 443220768.000000
18604.650391 Hz : 426555168.000000
18690.783203 Hz : 424576640.000000
18776.916016 Hz : 414091040.000000
18863.048828 Hz : 410781152.000000
18949.181641 Hz : 405568224.000000
19035.314453 Hz : 407728768.000000
19121.447266 Hz : 419237344.000000
19207.580078 Hz : 430601312.000000
19293.712891 Hz : 466494688.000000
19379.845703 Hz : 521243872.000000
19465.978516 Hz : 613582272.000000
19552.109375 Hz : 757928256.000000
19638.242188 Hz : 992379264.000000
19724.375000 Hz : 1395421312.000000
19810.507812 Hz : 2178366208.000000
19896.640625 Hz : 4297061376.000000
19982.773438 Hz : 27569408000.000000
20068.906250 Hz : 7477797888.000000
20155.039062 Hz : 3555265024.000000
20241.171875 Hz : 2433805568.000000
20327.304688 Hz : 1901287552.000000
20413.437500 Hz : 1594971904.000000
20499.570312 Hz : 1384900224.000000
20585.701172 Hz : 1247371136.000000
20671.833984 Hz : 1140868608.000000
20757.966797 Hz : 1057831296.000000
20844.099609 Hz : 989689280.000000
20930.232422 Hz : 933467008.000000
21016.365234 Hz : 904325632.000000
21102.498047 Hz : 851899776.000000
21188.630859 Hz : 818414592.000000
21274.763672 Hz : 791978048.000000
21360.896484 Hz : 771969792.000000
21447.029297 Hz : 745353664.000000
21533.160156 Hz : 741109888.000000
21619.292969 Hz : 729386112.000000
21705.425781 Hz : 703444480.000000
21791.558594 Hz : 698118528.000000
21877.691406 Hz : 690122624.000000
21963.824219 Hz : 683873152.000000

DC component : -36.215302 g

Fundamental Freq : 3962.101562 Hz	 Mag: 35391.296875 g

Time taken: 0.26 milliseconds!

BTW: Zbieranie sampli z układu PCM1808 (ADC I2S) powinno być stosunkowo proste do zaimplementowania w języku Verilog (na płytce FPGA "Tang Nano 4K"). Z zebranych próbek sygnału audio będzie liczona FFT za pomocą Ip Core firmy Gowin. Dzisiaj muszę się zająć innym pilnym dla mnie tematem, ale powrócę do tego zadania w najbliższym czasie/

Pozdrawiam

Edytowano przez FlyingDutch
  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

9 godzin temu, FlyingDutch napisał:

widać, że przetwornik ADC I2S (układ PCM1808) i ESP32 tworzą tandem, który śmiało może zbierać próbki sygnału audio w paśmie 0 Hz do 20 KHz i liczyć 512 punktową FFT w zadanym czasie i z dużą rozdzielczością (24 bity).

@FlyingDutch super, że pomimo problemów udaje Ci się 🙂 

Z tymi błędnymi samplami to nie ma w dokumentacji jakiegoś czasu "rozgrzania" albo kalibracji? Dla ADS jest coś takiego i właśnie chcę zaimplementować kalibrację, bo nie ma tego w kodzie z repozytorium. 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

32 minuty temu, Gieneq napisał:

@FlyingDutch super, że pomimo problemów udaje Ci się 🙂 

Z tymi błędnymi samplami to nie ma w dokumentacji jakiegoś czasu "rozgrzania" albo kalibracji? Dla ADS jest coś takiego i właśnie chcę zaimplementować kalibrację, bo nie ma tego w kodzie z repozytorium. 

@Gieneq,

Poszukałem w karcie katalogowej układu PCM1808 i znalazłem taki parametr - cytat z dokumentacji:

Cytat

FADE-IN AND FADE-OUT FUNCTIONS
The PCM1808-Q1 has fade-in and fade-out functions on DOUT (pin 9) to avoid pop noise, and the functions
come into operation in some cases as described in several following sections. The level changes from 0 dB to
mute or mute to 0 dB are performed using calculated pseudo S-shaped characteristics with zero-cross detection.
Because of the zero-cross detection, the time needed for the fade in and fade out depends on the analog input
frequency (fin). It takes 48/fin until processing is completed. If there is no zero cross during 8192/fS, DOUT is
faded in or out by force during 48/fS (TIME OUT). Figure 18 illustrates the fade-in and fade-out operation
processing.

48/fs = 48/44100=10,8844 ms czas FADE-IN to by się zgadzało. Ten czas narastania wzmocnienia jest, aby nie było pików sygnału po włączeniu Przetwornika PCM1806. FADE-IN jest uruchamiany przy włączaniu przetwornika i restarcie układu - no i się wyjaśniło.

Tutaj link do karty katalogowej układu PCM1808:

https://www.ti.com/lit/ds/symlink/pcm1808-q1.pdf?ts=1647798656922&ref_url=https%3A%2F%2Fwww.ti.com%2Fproduct%2FPCM1808-Q1

Pozdrawiam

Edytowano przez FlyingDutch
update
  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)

Podjąłem wyzwanie użycia Arduino IDE 2. Zapowiada się dobrze, ale jeszcze potrzeba kilka iteracji.

Żeby nie być marudą to zacznę od plusów:

  • podpowiedź składni,
  • lepsze kolorowanie,
  • poruszanie się po definicjach funkcji z ctrl+click i podpowiedź wartości stałych, podgląd prototypu funkcji i komentarza,

image.thumb.png.61a8b1793d9c03406049ba2582a8b281.png

  • monitor portu na dole obok logu,
  • menadżer bibliotek/płytek w wygodnym miejscu - fajny pomysł (nie testowałem ale chyba działa),
  • debuger! Ciekawe czy działa...
  • jakaś usługa chmurowa, kiedyś robiłęm podejście do edytora webowego i był całkiem ciekawy, raczej w kierunku IoT,
  • szybsza kompilacja (tak mi się wydaje)

image.thumb.png.dfebf54136701b451146485bbd72c502.png

Ogólnie robi dobre wrażenie, wreszcie fajnie działają zakładki, tworzenie nowych plików, edycja istniejących.

image.thumb.png.eff17ad420f2c8546d8e881ac4153989.png

Środowisko wygląda jak Platformio W VSC/Atomie i za to wielki plus. Tylko...

  • nie nalazłem drzewa katalogów, niestety powyżej kilku plików pojawia się problem, mogę sobie otworzyć w eksploratorze -.-

image.thumb.png.775e4da98d4b703fe66f616a50c48a1c.png

  • pomimo dodania szczegółów kompilacji, pojawiają się kwiatki takie jak ten na screenshocie, że nie wiem gdzie jest błąd. Dla porównania w VSC wykrywanie tak trywialnych błędów działa bez kompilacji, a nawet jeżeli to jest wskazane miejsce.

image.thumb.png.3483d3cc641f8b7a95604491a31e3fa3.png

  • i chyba najbardziej poważne - niestabilność. Po kilku godzinach podpowiedź składni zaczęła zamulać aż przestała działać. Ctrl+clik odmówił współpracy, podobnie po najechaniu na jakąś funkcję już nie miałem podglądu... cóż.

Także w końcu mając dość rzuciłem to środowisko i wróciłem do sprawdzonego. VSC też mi się nie podoba, ale działa. Trochę posiedzaiłem nad dokumentacją ADS1256 i trochę lepiej rozumiem temat. Udało mi się uzyskać pomiaru, a pobrane dane wyglądają poprawnie:

image.thumb.png.0294d290ee205f855ea126fe599b29f0.png

image.thumb.png.02e56372634cd4ed0dbbd80d16e6687b.png

Zastanawiałem się tylko skąd taki błąd. Skorzystałem z dokumentacji gdzie opisano że najmniej znaczący bit to:

image.thumb.png.934b8658727a2138497bae0b7a5e3689.png

Czyli ze wzoru: 2*2.5*ads/(1*0x7FFFF) można uzyskać wynik. Tylko i dla 0V miałem dryft 7mV i dla 3,3 V tylko 3,1 V. Podłączyłem więc do 2,5 V REF i tu znowu coś za mało - patrz screenshot. Podłączyłem woltomierz i wyszło że ultraprecyzyjne źródło odniesienia ma 2,47 V. Czyli wynik był zawyżony o 0,7%.

IMG_8905.thumb.jpg.e5b27a0eec22e1f3a08cbb15c4b25714.jpg

Dodając ten fakt w kodzie, nowe pomiary są zaniżone ale błąd to -0,48%.

Myślę że to jest i tak super pomiar ale na pewno da się to poprawić. Dla tego ustawienia czyli 2000 sps, PGA = 1 i wyłączonego bufora tracę 3 bity czyli 4 uV - nie jest to dużo, na pewno więcej brudu mam przez używanie płytki stykowej

image.thumb.png.62633c355ada5e94f53816615f8e5357.png

Włączenie bufora poprawia sytuację, ale dopiero dla wyższych ustawień PGA i sampling rate

image.thumb.png.8c6a6c6f055b34f40258cf1574c1f8bf.png

Ustawiłem 3 ksps i używając wyzwalania poleceniem RDATA oczywiście transmisja się nie wyrabia:

image.thumb.png.1cf592d3436cd68e67414fd22ed897ce.png

Dodałem więc polecenie RDATAC tuż po kalibracji i śmiga 30kHz:

image.thumb.png.04b575a724ef70e8b83a0dd6ce8d033c.png

spiobject->transfer(ADS1256_CMD_RDATAC);

Tak z ciekawości Ctrl+click na funkcję transfer i przecież jest wariant dla bufora danych:

image.thumb.png.98e1b201f744da471e1a98c54ef1e45d.png

Informacyjnie: funkcja działa destruktywnie - nadpisuje bufor wejściowy, w tym przypadku nie ma to znaczenia.

 Więc zamiast tego:

    unsigned char _highByte, _midByte, _lowByte;
    unsigned long value;

    _highByte = spiobject->transfer(0);
    _midByte  = spiobject->transfer(0);
    _lowByte  = spiobject->transfer(0);
    value = ((long)_highByte << 16) + ((long)_midByte << 8) + ((long)_lowByte);

    float voltage = 2*2.47 * value / (1*0x7FFFFF);

czyli 3 funkcji transfer można dać:

    uint8_t buff[] = {0,0,0}; 
    unsigned long value;

    spiobject->transfer(buff, 3);
    value = ((long)buff[2] << 16) + ((long)buff[1] << 8) + ((long)buff[0]);

i teraz nie ma zbędnych przerw:

image.thumb.png.10374ebdea22c03cf601af5e2e723c01.png

Tego autor biblioteki chyba nie wiedział, cóż.

 

W dokumentacji zaznaczono, że częstotliwość SPI ma być 4x mniejsza (okres 4x większy) niż zegar taktujący:

image.thumb.png.c0b909c8a58111594b1fa3047c915611.png

Ciekaw byłem co się stanie jak to zignoruję. Dla 2x większego okresu częstotliwość jest 60 kHz, pomiary są ok (tu około 2,46 V) ale zaczynają się dublować:

image.thumb.png.4ec7c7e12c8dc2ee238e4a805f12b447.png

Więc zostaję przy 30kHz, trudno, nie będzie całego spectrum audio ale i tak jest 6x szersze. Dopracuję bibliotekę, wrzucę na githuba i biorę się za testy FFT.

 

Edytowano przez Gieneq
  • Lubię! 2
Link do komentarza
Share on other sites

(edytowany)

@FlyingDutch bardzo dziękuję 🙂 ale nie chwalmy dnia przed zachodem słońca. Dziś pracy z motyką w polu było mnóstwo, a słońce wysoko nad horyzontem 😞 także... klątwa na tym projekcie daje o sobie znać. Dziś przeleciały mi ponad 3h, bo z obserwacji wynikło, że komendy i wpisy do rejestrów nie przynoszą efektów. Waj!?

Pomijając wysypujący się loger:

image.thumb.png.f069fda04c9029d504cdad8e71bd9eea.png

Płytka ESP niechętnie przechodzi w tryb programowania wiec trzeba zazwyczaj pomóc klikając przycisk. Dochodzi do tego jednak inne utrudnienie - takie powiedzmy 3/5 przypadków kończy się błędem programowania, muszę odpiąć płytkę, wgrać kod i włożyć na miejsce.

image.thumb.png.71d4b3347e5cc28ec7285e36d743d573.png

Płytka jest tak skonstruowana, że zasilanie jest na skrajnej stronie. Więc wkładając ESP do płytki stykowej uruchamiałem program, tam cały setup() przelatywał i bez wstępnej konfiguracji lądowałem w takiej sytuacji:

image.thumb.png.ac082861079084eb0fa1d87a3b997d09.png

Zdziwiony kombinowałem z częstotliwością, opóźnieniami, zboczami, zasilaniem, setną częścią wartości referencyjnej, a wystarczyło odpiąć kabel i podłączyć na nowo:

image.thumb.png.903c2a6e30e170d6a747b11eae552649.png

Kiedy na to wpadłem? Gdy źle podłączyłem ESP i na laptopie dostałem ostrzeżenie o zwarciu zasilania USB 😧 Wpadłem wtedy na pomysł, że może przy podłączaniu coś się dzieje. Na szczęście wszystko przeżyło to starcie.

Cieszę się, że wrzuciłem projekt na gita, bo rozgrzebałem cały kod. Wyewidencjonuj do... origin/master i sytuacja uratowana 🙂 

Na tym jednak nie koniec wrażeń. Pomęczyłem się jeszcze, bo okazało się, że po wgraniu programu nie następuje reset ustawień - np żeby zmienić częstotliwość próbkowania trzeba odłączyć i podłączyć na nowo zasilanie do ESP.

Mam jeszcze jeden błąd, ale to już nie na dziś bo mam tego dosyć. Przyjrzałem się wysyłaniu danych na UART:

image.thumb.png.fdc6756282acc0cceb9579dbaed7bf1f.png

i nie wiem dlaczego po pobraniu 24 bitów MISO nie wraca do stanu wysokiego i to nawet po przejściu ~DRDY (na wykresach poniżej) który informuje o zakończeniu wysyłania danych dalej jest stan niski.

image.thumb.png.3113a9491b8ab49d24e41736f437a85d.png

Mam nadzieję, że to tylko moje niedopatrzenia, ale zestaw nieszczególnie ładnego ESP za 30zł i modułu z Ali coraz mniej budzą moje zaufanie.

Edytowano przez Gieneq
  • Lubię! 1
Link do komentarza
Share on other sites

11 godzin temu, Gieneq napisał:

@FlyingDutch bardzo dziękuję 🙂 ale nie chwalmy dnia przed zachodem słońca. Dziś pracy z motyką w polu było mnóstwo, a słońce wysoko nad horyzontem 😞 także... klątwa na tym projekcie daje o sobie znać. Dziś przeleciały mi ponad 3h, bo z obserwacji wynikło, że komendy i wpisy do rejestrów nie przynoszą efektów. Waj!?

Płytka ESP niechętnie przechodzi w tryb programowania wiec trzeba zazwyczaj pomóc klikając przycisk. Dochodzi do tego jednak inne utrudnienie - takie powiedzmy 3/5 przypadków kończy się błędem programowania, muszę odpiąć płytkę, wgrać kod i włożyć na miejsce.

image.thumb.png.71d4b3347e5cc28ec7285e36d743d573.png

 

Kiedy na to wpadłem? Gdy źle podłączyłem ESP i na laptopie dostałem ostrzeżenie o zwarciu zasilania USB 😧 Wpadłem wtedy na pomysł, że może przy podłączaniu coś się dzieje. Na szczęście wszystko przeżyło to starcie.

Cieszę się, że wrzuciłem projekt na gita, bo rozgrzebałem cały kod. Wyewidencjonuj do... origin/master i sytuacja uratowana 🙂 

Na tym jednak nie koniec wrażeń. Pomęczyłem się jeszcze, bo okazało się, że po wgraniu programu nie następuje reset ustawień - np żeby zmienić częstotliwość próbkowania trzeba odłączyć i podłączyć na nowo zasilanie do ESP.

Cześć,

coś jest na rzeczy, z tymi płytkami ESP32 ja mam dwie sztuki "ESP32 Wrover" (nówki z Aliexpress) i jedna się w ogóle nie daje zaprogramować (port wirtualny COM pojawia się i znika w Windowsie). Druga jest w miarę OK i na tej działam. zgadzam się z tobą, że jest to bardzo frustrujące, gdy sprzęt nie działa w stabilny i przewidywalny sposób.

BTW: @Gieneq, jaki jest adres twojego repozytorium Github z kodem dla ADS1256? Z chęcią użyłbym twoich funkcji do kalibracji dla tego układu.

Pozdrawiam

Edytowano przez FlyingDutch
Link do komentarza
Share on other sites

14 godzin temu, Gieneq napisał:

Płytka ESP niechętnie przechodzi w tryb programowania wiec trzeba zazwyczaj pomóc klikając przycisk

Miałem podobny objaw na Ubuntu 18.04, na 20.04 wszystko działa normalnie.

2 godziny temu, FlyingDutch napisał:

ja mam dwie sztuki "ESP32 Wrover" (nówki z Aliexpress) i jedna się w ogóle nie daje zaprogramować (port wirtualny COM pojawia się i znika w Windowsie).

No cóż, ja używałem "gołych" wroverów, programator FTDI i zerżnięty z devkita układ na dwóch tranzystorach do reset/boot. Na trzy sztuki (z Botlandu) wszystko działało...

  • Lubię! 1
Link do komentarza
Share on other sites

Niestety okazało się, że cały bałagan był po stronie ESP. Muszę na spróbowanie kupić jakiś oryginalniejszy z Botlandu, bo z takim czymś się nie da pracować.

5 minut temu, ethanak napisał:

Na trzy sztuki (z Botlandu) wszystko działało...

No właśnie...

Tu wyraźnie widać działanie trybu one-shot, niestety ale na Arduino UNO:

image.thumb.png.8a20932fae4907d3983475e5d35d6d21.png

i wszystko działa!

image.thumb.png.4fbd338cebae027ea1650ad743b062f7.png

Ciekawa sprawa, bez zmiany ustawienia kolejności bitów, mam nagle odwrotną kolejność. Okazało się że w kodzie miałem błąd, ale tak się zgrał z błędem transmisji ESP, że zazwyczaj wychodziło poprawnie.

 

Link do komentarza
Share on other sites

1 minutę temu, Gieneq napisał:

No właśnie...

Tyle że jak wspomniałem to były same moduły WROVER a nie płytki.

A wszelkie DevKity i Loliny po prostu kupuję na Aledrogo, u któregoś ze sprawdzonych (msalomon, modulosy i takie tam) i nigdy nie miałem problemów.

Link do komentarza
Share on other sites

41 minut temu, ethanak napisał:

Miałem podobny objaw na Ubuntu 18.04, na 20.04 wszystko działa normalnie.

No cóż, ja używałem "gołych" wroverów, programator FTDI i zerżnięty z devkita układ na dwóch tranzystorach do reset/boot. Na trzy sztuki (z Botlandu) wszystko działało...

Cześć,

ja mam te płytki kupione na Aliexpress.com, może tu leży różnica. Na razie nie chciało mi się używać zewnętrznego układu FTDI, ale jak będę potrzebował drugiej płytki z ESP32, to może spróbuję.

Pozdrawiam

Link do komentarza
Share on other sites

(edytowany)

Podłączyłem płytkę ESP z wyświetlacza i na niej wszystko działa! Więc przejechałem się na Ali. Bywa.

@FlyingDutch uzupełniłem repozytorium i scaliłem gałąź w której rozgrzebałem kod: https://github.com/Gieneq/ADS1256_ESP32

Co do kalibracji to tam wiele nie ma, komenda autokalibracji i tyle. W dokumentacji można przeczytać jak to się odbywa. Przy autokalibracji są 3 komendy, przy czym ta której używam odpala jakby te 2 poprzednie jedna po drugiej. Polega to na podaniu sygnału kalibrującego na przetwornik dla wartości minimalnej i max 0x7FFFFF, która powinna dla wzmocnienia 1 wynieść 5V.

Jest też opcja kalibracji ręcznej, w której samemu trzeba podać te 2 sygnały ale to nie jest warte zachodu w tym projekcie. Ale czytając o tym pomyślałem, że do tego można użyć 3 GPIO jakie dostępne są w wersji xxx6 układu i wysterować jakieś klucze/przekaźniki, którymi dostarczane byłyby sygnały kalibrujące. Na pewno będzie to ciekawsze niż miganie diodą, które uwzględniłem w przykładach w repozytorium:

void loop()
{
  adc.digitalWriteADS(1, HIGH);
  delay(250);
  adc.digitalWriteADS(1, LOW);
  delay(250);
}

pomysł zostawiam na później.

1726206058_ADS1256_Arduino_ESP32_Devmodulekopia.thumb.jpg.fb80f03cf3e0bda3d828c641169d856b.jpg

Jedno z GPIO ma na wyjściu sygnał zegarowy i tu wpadłem na pomysł, że skoro w dokumentacji są opisane czasy w liczbie taktów zegara np t6 - odstęp pomiędzy wysłaniem zapytania o odczyt pomiaru a rozpoczęciem czytania wynosi około 7us a jest to konkretnie 50 CLKIN, to może by skorzystać w tego sygnału - pewnie do tego miał służyć. Ale to też nie ma wielkiego priorytetu.

A teraz w tej gałęzi zabieram się za dodanie FFT, oby te ESP nie sprawiało problemów https://github.com/Gieneq/ADS1256_ESP32/tree/FFT-introduce

Edytowano przez Gieneq
  • Lubię! 1
Link do komentarza
Share on other sites

Znowu mam problem, ale chyba do się coś z tym zrobić. Gdy ustawiam częstotliwość na 1/4 czyli max jaką się da to przy 30ksps komunikacja przestaje działać. Przy częstotliwości 1/8 działa, ale transmisja wypełnia prawie cały okres:

image.thumb.png.d2cdbee01e07dadb48cfeb11b2771f6b.png

A na MISO i tak jest jakiś dziwny sygnał wchodzący nie dość że na CS to jeszcze na DRDY którego stan wysokie powinien oznaczać, że jest to koniec transmisji 24 bitów... gdzieś wyczytałem że te problemy mogą pochodzić od płytki stykowej. Sprawdzę, ale na razie mam pilniejszą sprawę, bo nawet przy dzielniku 4, rdzeń jest praktycznie cały czas zajęty blokującą komunikacją. Poczytam czy da się dodać przerwanie od DRDY i DMA, w końcu jest coś o tym w dokumentacji:

image.thumb.png.a2f1b1a80e82b387324cb2cf0c5834f7.png

Znalazłem taką bibliotekę, sprawdzę jak działa: https://github.com/hideakitai/ESP32DMASPI

  • Lubię! 1
Link do komentarza
Share on other sites

Cześć,

w końcu wziąłem się za podłączenie przetwornika analogowo-cyfrowego I2S (PCM1808) do układu FPGA "Sipeed Tang Nano 4K". Tak jak mi się wydawało po analizie protokołu I2S, kod do odczytu danych z przetwornika PCM1808 w języku VHDL jest bardzo prosty. Znalzłem na stronie WWW Opencores.org taki projekt:

https://opencores.org/projects/i2s_to_parallel

Projekt składa się z jednego bardzo prosto napisanego pliku w języku VHDL. Stwierdziłem, że napisałbym to praktycznie bardzo podobnie, a ponieważ nie chciało mi się tracić czasu na symulację i weryfikację nowo pisanego kodu, użyłem tego z tego projektu.  Utworzyłem nowy projekt w "Gowin EDA", dodałem kod entity "i2s_to_parallel" do projektu - oto kod źródłowy pliku "i2s_to_parallel.vhd":

---------------------------------------------------------------------------------
-- Engineer:      Fabio Gravina <fabio.gravina@gmail.com>
--                                                       http://www.fgravina.net
--                Primiano Tucci <p.tucci@gmail.com>
--                                                  http://www.primianotucci.com
--
-- Create Date:   17:26:41 12/19/2008
-- Design Name:   i2s_to_parallel
--
-- Description:   
-- 
-- This module provides a bridge between an I2S serial device (audio ADC, S/PDIF 
-- Decoded data) and a parallel device (microcontroller, IP block).
--
-- It's coded as a generic VHDL entity, so developer can choose the proper signal
-- width (8/16/24 bit)
--
-- Input takes:
-- -I2S Bit Clock
-- -I2S LR Clock (Left/Right channel indication)
-- -I2S Data
--
-- Output provides:
-- -DATA_L / DATA_R parallel outputs
-- -STROBE and STROBE_LR output ready signals.
-- 
-- As soon as data is read from the serial I2S line, it's written on the proper
-- parallel output and a rising edge of the STROBE signal indicates that new
-- data is ready.
-- STROBE_LR signal tells if the strobe signal was relative to the
-- Left or Right channel.
--
--------------------------------------------------------------------------------
-- I2S Waveform summary
--
-- BIT_CK     __    __   __    __    __            __    __    __    __   
--           | 1|__| 2|_| 3|__| 4|__| 5|__... ... |32|__| 1|__| 2|__| 3| ...
--
-- LR_CK                                  ... ...      _________________
--           ____________R_Channel_Data______________|   L Channel Data ...
--
-- DATA      x< 00 ><D24><D22><D21><D20>  ... ...     < 00 ><D24><D23>  ...
--
--
-- Each time enough ('width' bits of) data is collected from the serial input
-- it is outputed on the corresponding DATA_R/L port and the proper
-- STROBE signals are emitted
-- A rising edge of the STROBE signal tells that parallel data is ready
-- STROBE_LR signal tells which of the DATA_L / DATA_R has been generated
-- DATA_L/R remain valid for the whole cycle (until next data is processed)
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity i2s_to_parallel is 
-- width: How many bits (from MSB) are gathered from the serial I2S input
generic(width : integer := 16);
port(
	--  I2S Input ports
	LR_CK : in std_logic;    --Left/Right indicator clock
	BIT_CK : in std_logic;   --Bit clock
	DIN : in std_logic;      --Data Input
	-- Control ports
	RESET : in std_logic;    --Asynchronous Reset (Active Low)
	-- Parallel Output ports
	DATA_L : out std_logic_vector(width-1 downto 0);
	DATA_R : out std_logic_vector(width-1 downto 0);
	-- Output status ports
	STROBE : out std_logic;  --Rising edge means data is ready
	STROBE_LR : out std_logic
);
end i2s_to_parallel;

architecture Behavioral of i2s_to_parallel  is
	signal current_lr : std_logic;
	signal counter : integer range 0 to width;
	signal shift_reg : std_logic_vector(width-1 downto 0);
	signal output_strobed : std_logic;
	
begin
	process(RESET, BIT_CK, LR_CK, DIN)
	begin
		if(RESET = '0') then
			DATA_L <= (others => '0');
			DATA_R <= (others => '0');
			shift_reg <= (others => '0');
			current_lr <= '0';
			STROBE_LR <= '0';
			STROBE <= '0';
			counter <= width;
			output_strobed <= '0';
		elsif rising_edge(BIT_CK) then
			-- Note: LRCK changes on the falling edge of BCK
			-- We notice of the first LRCK transition only on the
			-- next rising edge of BCK
			-- In this way we discard the first data bit as we start pushing
			-- data into the shift register only on the next BCK rising edge
			-- This is right for I2S standard (data starts on the 2nd clock)
			if(LR_CK /= current_lr) then
				current_lr <= LR_CK;
				counter <= width;
				--clear the shift register
				shift_reg <= (others => '0');
				STROBE <= '0';
				output_strobed <= '0';
			elsif(counter > 0) then
				-- Push data into the shift register
				shift_reg <= shift_reg(width-2 downto 0) & DIN;
				-- Decrement counter
				counter <= counter - 1;		
			elsif(counter = 0) then
				--TODO Optimization
				-- Data could be written one clock behind
				-- when counter = 1 (step down counter)
				-- We're wasting a cycle here
				if(output_strobed = '0') then
					if(current_lr = '1') then
						--Output Right Channel
						DATA_R <= shift_reg;
					else
						--Output Left Channel					
						DATA_L <= shift_reg;
					end if;
					STROBE_LR <= current_lr;
					output_strobed <= '1';
				else
					STROBE <= '1';
				end if; --(output_strobed = '0')
			end if;	-- (counter = 0)
		
		end if; -- reset / rising_edge
		
	end process;

end Behavioral;

Do projektu dodałem trzy IP cores z "Gowin EDA": pętlę PLL, aby wygenerować zewnętrzny zegar o f= 11,2896 Mhz (256*Fs) dla układu PCM1808, dwu portową pamięć BRAM o ilości komórek 512 i 24-bitowej magistrali danych oraz moduł liczący FFT (512 punktową) o 24bitach danych I/O. Dodałem też główny moduł projektu o nazwie  "i2s_top.vhd" - poniżej jego kod źródłowy:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity i2s_top is
    -- widthI2S: How many bits (from MSB) are gathered from the serial I2S input
    generic(widthI2S : integer := 12);
    Port ( clk_27Mhz : in  STD_LOGIC;
           RST_LOW : in  STD_LOGIC;
           btn_Start : in  STD_LOGIC; --button start FFT
           led_DoneFFT : out std_logic; -- FFT done
           --  I2S Input ports	       
	       BIT_CK_I2S : in std_logic;   --Bit clock
	       DIN_I2S : in std_logic;      --Data 
           LR_CK_I2S : in std_logic;    --Left/Right indicator clock
           --  I2S Output ports
           SCKI_11Mhz : out std_logic; --SCKI 11,57Mhz clock for PCM1808 IC (256*Fs)
           --
           DATA_I2S_CH_R : out std_logic_vector(widthI2S-1 downto 0);
           	-- Output status ports
	       STROBE : out std_logic  --Rising edge means data is ready
	   );
end i2s_top;

architecture Behavioral of i2s_top is

    component Gowin_PLLVR
    port (
        clkout: out std_logic;
        reset: in std_logic;
        clkin: in std_logic
    );
    end component;

    component i2s_to_parallel
    -- width: How many bits (from MSB) are gathered from the serial I2S input
    generic(width : integer := 12);
    port(
	    --  I2S Input ports
	    LR_CK : in std_logic;    --Left/Right indicator clock
	    BIT_CK : in std_logic;   --Bit clock
	    DIN : in std_logic;      --Data Input
	    -- Control ports
	    RESET : in std_logic;    --Asynchronous Reset (Active Low)
	    -- Parallel Output ports
	    DATA_L : out std_logic_vector(width-1 downto 0);
	    DATA_R : out std_logic_vector(width-1 downto 0);
	    -- Output status ports
	    STROBE : out std_logic;  --Rising edge means data is ready
	    STROBE_LR : out std_logic
    );
    end component;


    -- internal signals
    signal DATA_L_INT : std_logic_vector(11 downto 0);
    signal STROBE_LR_INT : std_logic;

begin

  I2S_Clock: Gowin_PLLVR
    port map (
        clkout => SCKI_11Mhz,
        reset => not RST_LOW,
        clkin => clk_27Mhz
    );

  I2S_Driver: i2s_to_parallel
    port map(
	    --  I2S Input ports
	    LR_CK => LR_CK_I2S,   --Left/Right indicator clock
	    BIT_CK => BIT_CK_I2S, --Bit clock
	    DIN => DIN_I2S,       --Data Input
	    -- Control ports
	    RESET => RST_LOW,     --Asynchronous Reset (Active Low)
	    -- Parallel Output ports
	    DATA_L => DATA_L_INT,
	    DATA_R => DATA_I2S_CH_R,
	    -- Output status ports
	    STROBE => STROBE ,
	    STROBE_LR => STROBE_LR_INT
    );


end Behavioral;

Aktualnie w module głównym użyłem dwóch komponentów: "Gowin_PLLVR" (pętla PLL zegara) i "i2s_to_pararell" moduł do odbioru po protokole I2S sampli z przetwornika PCM1808. Porty modułu głównego są tak dobrane, aby za pomocą analizatora stanów logicznych można było obserwować sample z ADC I2S.

Tutaj zrzut ekranu z "Gowin EDA" z tym projektem:

gowinEda_I2S_01_.thumb.png.5caafc02f9e69ecec66063603ab38ad3.png

Synteza i implementacja projektu przebiega bez błędów. Tutaj plik "user constraints "I2S_Tang4K_Simple01.cst" (dla płytki Sipeed Tang Nano 4K):

//Copyright (C)2014-2022 Gowin Semiconductor Corporation.
//All rights reserved. 
//File Title: Physical Constraints file
//GOWIN Version: 1.9.8.03
//Part Number: GW1NSR-LV4CQN48PC7/I6
//Device: GW1NSR-4C
//Created Time: Thu 03 24 13:05:17 2022

IO_LOC "STROBE" 40;
IO_PORT "STROBE" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[11]" 22;
IO_PORT "DATA_I2S_CH_R[11]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[10]" 21;
IO_PORT "DATA_I2S_CH_R[10]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[9]" 20;
IO_PORT "DATA_I2S_CH_R[9]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[8]" 19;
IO_PORT "DATA_I2S_CH_R[8]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[7]" 18;
IO_PORT "DATA_I2S_CH_R[7]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[6]" 17;
IO_PORT "DATA_I2S_CH_R[6]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[5]" 13;
IO_PORT "DATA_I2S_CH_R[5]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[4]" 16;
IO_PORT "DATA_I2S_CH_R[4]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[3]" 23;
IO_PORT "DATA_I2S_CH_R[3]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[2]" 8;
IO_PORT "DATA_I2S_CH_R[2]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[1]" 33;
IO_PORT "DATA_I2S_CH_R[1]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "DATA_I2S_CH_R[0]" 27;
IO_PORT "DATA_I2S_CH_R[0]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "SCKI_11Mhz" 43;
IO_PORT "SCKI_11Mhz" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "led_DoneFFT" 10;
IO_PORT "led_DoneFFT" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8;
IO_LOC "LR_CK_I2S" 42;
IO_PORT "LR_CK_I2S" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "DIN_I2S" 41;
IO_PORT "DIN_I2S" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "BIT_CK_I2S" 44;
IO_PORT "BIT_CK_I2S" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "RST_LOW" 31;
IO_PORT "RST_LOW" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "clk_27Mhz" 45;
IO_PORT "clk_27Mhz" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "btn_Start" 15;
IO_PORT "btn_Start" PULL_MODE=UP;

Teraz mam zamiar fizycznie połączyć płytkę z przetwornikiem I2S do zestawu FPGA "Sipeed Tang Nano 4K" i sprawdzić, czy zbieranie sampli przebiega poprawnie (tak jak wcześniej robiłem to z płytką ESP32).

CDN..

Pozdrawiam

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.