Arduino Polska Forum

Pełna wersja: Nieznana przyczyna opóźnień MCP4725
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Stron: 1 2
Witam wszystkich, mam problem z identyfikacją opóźnień w prostym układzie, w którym generuję falę trójkątną za pomocą DAC 7425. DAC podłączony jest po i2c. Wygenerowanie wykresu zajmuje mniej niż 1 ms jednak w pętli programu powstaje nieznane opóźnienie ok 600ms po każdym cyklu. Co może być przyczyną?
Kod:
#include <Wire.h>
#include <Adafruit_MCP4725.h>
int timee=0;
Adafruit_MCP4725 dac;
void setup()
{  
Serial.begin(9600);
dac.begin(0x60);
}
void loop()
{
timee = millis();
Serial.println(timee);
  for (int counter = 0; counter < 4096; counter++)
  {
    dac.setVoltage(counter, false);
  }
 
  for (int counter = 1; counter > 4096; counter--)//4095
  {
    dac.setVoltage(counter, false);
  }
timee = millis();
Serial.println(timee);
}

Wynik na monitorze:
...
4673
4673
5258
5258
5841
5841
6426
6426
7011
7011
7595
7595
8179
8179
8763
8763
9348
9348
...
(int counter = 1; counter > 4096; counter--) ale wiesz, że to będzie dłuuugo powtarzał?
(06-02-2019, 22:31)kaczakat napisał(a): [ -> ](int counter = 1; counter > 4096; counter--) ale wiesz, że to będzie dłuuugo powtarzał?

Jak widać na znaczniku czasowym te dwie pętle for przetwarza w mniej niż 1 ms.
(int counter = 4095; counter > 0; counter--) powinno być ale to nie rozwiązuje problemu

posta pisałem zmęczony
To jeszcze kawka przed analizą, ja np. nie widzę by to gdzieś trwało poniżej 1ms, ale może teraz z kolei ja jestem zmęczony. Wszędzie jest >600ms. Nawet jeśli masz już pętle poprawnie to wywołujesz funkcje 8000x. Byle jaka funkcja w Arduino to czas kilku us. Wcześniej to było zliczanie od 1 przez wszystkie ujemne, czyli jakieś 20000x, czyli jedna trwała gdzieś z 30us. Teraz powinno zejść do 240ms, ale jeśli to była tylko pomyłka przy prezentacji kodu tutaj, to funkcja trwa 80us.   No poniżej 1ms to miałbyś 1000FPS, nieźle, jak na Arduino z Atmegą wyciągniesz kilkanaście to będzie dobrze napisany kod. I ustaw sobie serial na 115200, działa szybciej.
Jak chcesz sprawdzić długość trwania funkcji to wpisz sobie dwie zmienne uint32_t i wydrukuj różnicę rzutowaną na uint32_t.

Kod:
uint32_t poczatek, koniec;
poczatek=micros();
mierzonaFunkcja();
koniec=micros();
Serial.println((uint32_t )(koniec-poczatek));

Ten sam kod robi się z millis, nie ma wtedy problemu z działaniami na swojej pamięci.
Pewny pomiar zapewni tylko oscyloskop, ewentualnie analizator logiczny (też symulator w AS7/debugger) wystawiasz pin na wysoki/niski przed funkcją, to samo po funkcji i sprawdzasz odległość pików. Te wewnętrzne z millis()/micros() mogą być niepoprawne, zależy kto na to patrzy, jak wygląda cały program, przerwania, itp.
Przerobiłem kod, poprawiłem błędy wyliczam czas:
Mam Arduino mega

Kod:
#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
uint32_t poczatek, koniec;

void setup(void) {
  Serial.begin(9600);
}

void loop(void) {
    poczatek=micros();
    uint32_t counter;
    // Run through the full 12-bit scale for a triangle wave
    for (counter = 0; counter < 4095; counter++)
    {
      dac.setVoltage(counter, false);
    }
    for (counter = 4095; counter > 0; counter--)
    {
      dac.setVoltage(counter, false);
    }
   koniec=micros();
   Serial.println((uint32_t )(koniec-poczatek));

}


Wynik:
743132
743144
743144
743144
743152
743156
743128
743128
743128
743128
743128
743128
743140


Wygląda, że wygenerowanie dwóch zboczy narastającego i opadającego zajmuje 0,74 sekundy więc 1,5 Hz????
To jest I2C, nie oczekuj cudu, jak ma to być z 4000 punktów to tak to wygląda. To bardziej prawdopodobny wynik niż 1000Hz. Jak podkręcisz zegar I2C to będzie x4 lub x8 (to już poza specyfikacją). No i jak druga strona da radę, 400kHz jest w bibliotece, którą właśnie znalazłem po tym nagłówku w załączonym kodzie, ale nie wiem jak masz to ustawione. Nie wiem co to ma robić, jakbyś wysyłał 100 000 bitów w jednym otwarciu magistrali to jest to 1s, ale jak 8000x otwierasz magistralę, wysyłasz coś, zamykasz, rozpoczęcie i zamknięcie funkcji, do tego paru w środku do I2C, a jeszcze coś mają zrobić, wszystko trwa.
Chciałbym zrobić po prostu generator, na filmach w internecie takie układy (gotowe Dace) generują przebiegi w kHz u mnie ledwo jeden Hz
To może źle to używasz, nie wiem czemu robisz coś 4000, no właśnie o tym myślałem, że jak to jest generator to powinieneś mu wysłać co ma wygenerować, a nie generować z Arduino.
Edit:
Zajrzałem do przykładu, oni to robią tak, że w jedną funkcję wrzucają cała tablicę próbek i jest 32-no max 512 iteracji, ale każda iteracja to jakiś przebieg z gotowca (dalej nie wiem co to ma robić), a nie wyliczany, tak to może zadziałać.
Przykład z biblioteki oryginalny:

Kod:
/**************************************************************************/
/*!
    @file     trianglewave.pde
    @author   Adafruit Industries
    @license  BSD (see license.txt)

    This example will generate a triangle wave with the MCP4725 DAC.  

    This is an example sketch for the Adafruit MCP4725 breakout board
    ----> http://www.adafruit.com/products/935

    Adafruit invests time and resources providing this open source code,
    please support Adafruit and open-source hardware by purchasing
    products from Adafruit!
*/
/**************************************************************************/
#include <Wire.h>
#include <Adafruit_MCP4725.h>

Adafruit_MCP4725 dac;

void setup(void) {
  Serial.begin(9600);
  Serial.println("Hello!");

  // For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
  // For MCP4725A0 the address is 0x60 or 0x61
  // For MCP4725A2 the address is 0x64 or 0x65
  dac.begin(0x62);
    
  Serial.println("Generating a triangle wave");
}

void loop(void) {
    uint32_t counter;
    // Run through the full 12-bit scale for a triangle wave
    for (counter = 0; counter < 4095; counter++)
    {
      dac.setVoltage(counter, false);
    }
    for (counter = 4095; counter > 0; counter--)
    {
      dac.setVoltage(counter, false);
    }
}
No i ich kod zadziała szybciej, a Twój wolniej.
Wysyłka bufora po UART jest naprawdę czasochłonna.
Nie lepiej zapisywać dane gdzieś w pamięci i wysyłać hurtowo w przerwaniu?
Albo obliczyć wartości w Excelu, zapisać do tablicy i wywoływać w przerwaniu?
A poza tym, to ich demo jest o dupę potłuc.
Stron: 1 2