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.