Skocz do zawartości

STM32F7 Zbyt mała szybkość zapisu danych z czujników I2C na kartę SD


radek04

Pomocna odpowiedź

Cześć,
od dłuższego czasu pracuję nad projektem o poniższych założeniach:
- odczyt z 4 czujników IMU (24 osie)
- szybkość akwizycji - 400-500 pomiarów na sekundę
- mikrokontroler z serii F7 (wymogi późniejszej rozbudowy)
- zapis na kartę SD lub bezprzewodowe przesłanie danych.

Wpis ten jest tak naprawdę kontynuacją wątku STM32 UART wysyłanie danych typu uint16_t. Okazało się, że pomysł z bezprzewodowym przesyłaniem danych po UART jest trudny/nierealny do zrealizowania, więc postanowiłem wykorzystać zapis na kartę pamięci. Było z tym mnóstwo problemów (z zainteresowanymi chętnie się podzielę), ale koniec końców udało mi się zrealizować zapis w 4-bitowym trybie SDMMC.

Obecnie zmagam się z problemem odpowiedniej szybkości pobierania danych z czterech MPU9250 podłączonych do dwóch linii I2C i ich zapisem na SD. Realizuję to w przerwaniu timera, które odpowiada za stałą szybkość akwizycji. Ustawiając zegary na maksymalne wartości pozwalające na skuteczny zapis na SD, podczas 1-minutowych testów z fs=400 Hz całkowity czas operacji wynosi ok. 65 sekund. Np. dla 100 Hz jest to dokładnie 60 sekund. Zatem program "nie wyrabia" owych 400 Hz.
Wpadłem na pomysł, żeby czujniki podłączyć do 4 osobnych magistrali I2C i używać trybu IT, ale mój procesor ma tylko 1 pin (PC9) odpowiedzialny zarówno za I2C3_SDA, jak i MMC1_D1, czyli w moim przypadku nie da rady go użyć. Musiałbym wykorzystać wersję przynajmniej 176-pinową, a tych nie znalazłem dostępnych w Polsce.
Póki co, aby nieco przyśpieszyć akwizycję, zastosowałem pewien (dziwny) trick i z każdej I2C jeden czujnik obsługuję trybem blokującym, a drugi z użyciem przerwania. Poniżej fragment kodu:

uint8_t my_string[4*24+1]; //bez spacji
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM10) //przerwanie pochodzi od timera 10
	{
		HAL_I2C_Mem_Read(&hi2c1, MPU9250_ACC_ADDRESS_A, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_A, 14, 50); //14 pomiarów od razu
		HAL_I2C_Mem_Read_IT(&hi2c1, MPU9250_ACC_ADDRESS_B, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_B, 14); //14 pomiarów od razu
		HAL_I2C_Mem_Read(&hi2c2, MPU9250_ACC_ADDRESS_C, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_C, 14, 50); //14 pomiarów od razu
		HAL_I2C_Mem_Read_IT(&hi2c2, MPU9250_ACC_ADDRESS_D, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_D, 14); //14 pomiarów od razu
		
		timer_tim10++;

		if (timer_tim10 <= 6*4000)
		{
			sprintf(my_string,
					"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
					"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
					"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
					"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
					MPU9250_Data_A[0],MPU9250_Data_A[1],MPU9250_Data_A[2],MPU9250_Data_A[3],MPU9250_Data_A[4],MPU9250_Data_A[5],MPU9250_Data_A[8],MPU9250_Data_A[9],MPU9250_Data_A[10],MPU9250_Data_A[11],MPU9250_Data_A[12],MPU9250_Data_A[13],
					MPU9250_Data_B[0],MPU9250_Data_B[1],MPU9250_Data_B[2],MPU9250_Data_B[3],MPU9250_Data_B[4],MPU9250_Data_B[5],MPU9250_Data_B[8],MPU9250_Data_B[9],MPU9250_Data_B[10],MPU9250_Data_B[11],MPU9250_Data_B[12],MPU9250_Data_B[13],
					MPU9250_Data_C[0],MPU9250_Data_C[1],MPU9250_Data_C[2],MPU9250_Data_C[3],MPU9250_Data_C[4],MPU9250_Data_C[5],MPU9250_Data_C[8],MPU9250_Data_C[9],MPU9250_Data_C[10],MPU9250_Data_C[11],MPU9250_Data_C[12],MPU9250_Data_C[13],
					MPU9250_Data_D[0],MPU9250_Data_D[1],MPU9250_Data_D[2],MPU9250_Data_D[3],MPU9250_Data_D[4],MPU9250_Data_D[5],MPU9250_Data_D[8],MPU9250_Data_D[9],MPU9250_Data_D[10],MPU9250_Data_D[11],MPU9250_Data_D[12],MPU9250_Data_D[13]);
			if(f_lseek(&fil, f_size(&fil)) != HAL_OK) printf("f_lseek ERROR\n");
			if(f_write(&fil, my_string, sizeof(my_string), &numread) != HAL_OK) printf("f_write ERROR\n");
		}else if (timer_tim10 == 6*4000+1)
		{
			close_file();
			unmount_sd();
			printf("done\n");
		}
	}
}

Jak widać (mam nadzieję), czujnik A i B znajdują się na I2C1, C i D na I2C2. B i D odczytuję z użyciem przerwania (IT) po zakończeniu odczytu odpowiednio A i C.
Jak mogę to zrobić szybciej? Domyślam się, że DMA mogłoby pomóc, ale kompletnie nie umiem tego zrobić. Zwykła zamiana _IT na _DMA nie działa. W sieci znalazłem mnóstwo wątków z problemami użycia DMA na F7, ale bez skutecznych (w moim przypadku) rozwiązań. Proszę tu o Waszą pomoc.

A może mogę jakoś przyśpieszyć zapis na kartę pamięci? Czy tutaj można jakoś zaprząc do pacy DMA lub inny szybki mechanizm?
Wydaje mi się też, że funkcja sprintf zajmuje sporo czasu. Usunąłem z niej wszystkie zbędne znaki i przesyłam jedynie po 2 na każdy rejestr oraz znak nowej linii po zapisaniu wszystkich potrzebnych rejestrów (w liczbie 48), czyli w sumie 97 znaków w każdej iteracji. Czy są jakieś szybsze alternatywy?

Trochę się rozpisałem. Temat jest wielowątkowy, generuje różne problemy i zaskakujące niespodzianki. Starałem się zawrzeć tylko najważniejsze informacje.

Testy przeprowadzam na Nucleo F746. Docelowo chciałem użyć 100-pinowego F756VGT6, ale może być inny (dostępny od ręki) z serii F7.
STM32CubeIDE 1.10.1
MCU Package 1.17.0

Edytowano przez radek04
Link do komentarza
Share on other sites

Pamięć flash zapisuje całą "stronę". Pojęcia z kategorii blok, płaszczyzna itp. charakterystyczne dla tego typu pamięci. Zapisywać dane jednym ciągiem w paczkach wielkości strony dla danej karty - poszukać datasheet. Oczywiście format karty przed użyciem nie zaszkodzi. Trochę wyidealizowane, jakby obsługiwać bezpośrednio pamięć flash bez kontrolera i zapisywać surowe dane, ale nie zaszkodzi spróbować - po prostu większe paczki, może mniejsze od tej "strony".

A propos Bluetooth, to SPP 85 KB/s wyciągnie, jak podają producenci modułów, a BLE jak tutaj. Moduł BLE cały baud UARTu pewnie wtedy wypełni, pozostaje po drugiej stronie kolejnym modułem i jakimś FTDI odbierać. Tak poza tematem tylko.

Link do komentarza
Share on other sites

8 godzin temu, matsobdev napisał:

Pamięć flash zapisuje całą "stronę".

A wcale że nie, zapis jest na ogół możliwy do rozmiaru słowa. Flash *kasuje* całymi stronami, a raczej blokami. Tylko wiesz jaki jest rozmiar takiej "strony" czy raczej bloku w karcie SD? Na ogół kilka MB (typowo 4). Z uwagi na to jak działa FTL, nie masz szans, nawet używając danych wielości strony spowodować synchronizacji zapisu z kasowaniem. A nawet jakby - fun fact, było by gorzej, operacja kasowania bloku jest czasochłonna. 

 

9 godzin temu, radek04 napisał:

Jak mogę to zrobić szybciej? Domyślam się, że DMA

No wtedy to możesz dane z obu magistral nawet czytać jednocześnie. (Ale nie pomogę, bo hejtuje HALa, znaczy nie używam ;p)

A tak szybki rzut oka na kod... po co Ci ten seek przed write? Wskaźnik zapisu będzie na końcu pliku po poprzednim zapisie.

Link do komentarza
Share on other sites

We wcześniejszym wątku napisałeś,że urządzenie ma służyć do pomiaru drgań.Drgania występują wszędzie w gazach,płynach i ciałach stałych.W istocie swej drgania to nic innego jak fale mechaniczne.Załóżmy,że badanym obiektem jest ciało stałe a badane drgania to fale poprzeczne(tylko takie możesz pomierzyć tymi czujnikami).W swoim urządzeniu postanowiłeś użyć do obsługi czujników czterech akcelerometrów oraz płytę z procesorem stm32F746GZ. Przyjrzyjmy się możliwościom akcelerometrów. Transmisja odbywa się poprzez I2C lub SPI. Zasięg czyli odstęp czujnik -procesor to co najwyżej kilka metrów(pojemność linii nie może przekroczyć 400pF) .Akcelerometr 9250 jest 9-osiowym urządzeniem a tak naprawdę jest 6-osiowym bo wartości trzech osi gyro są wyliczane przez wewnętrzny procesor czujnika zgodnie ze wzorem

                                                                                                       α= arcsin(A/g)

 

gdzie                                                                                            A=g x sin(α)

A = zmierzone przyspieszenie

g = wektor grawitacji Ziemi

obraz.thumb.png.b93be268d1f506e6bc50996f26e10148.png

Stąd wniosek ,że nie ma potrzeby przesyłania gyro bo można otrzymać te wielkości w arkuszu kalkulacyjnym,który zapewne stworzysz .Czyli zamiast 18 bajtów na czujnik przesyłasz 12 bajtów na czujnik. Zyskujesz 1/3 czasu w stosunku do pierwotnego rozwiązania.Osobnym zagadnieniem jest odczyt z magnetometru. Czy na pewno jest konieczny skoro badasz drgania?Te drgania to nie są jakieś centymetry,metry tylko dziesiętne części milimetra,co najwyżej ok. milimetra ale wtedy konstrukcja nie nadaje się do użytku. Materiał z którego wykonany jest element szybko się zmęczy i konstrukcja ulegnie zniszczeniu. Wątpię w to,że pole magnetyczne zmieni się drastycznie po przesunięciu o co najwyżej (!) milimetr.Co to oznacza? Oznacza to,że najprawdopodobniej nie ma potrzeby pomiaru pola magnetycznego.

Podłączenie do jednej linii dwóch czujników skutkuje tym,że za każdym razem gdy chcesz odczytać dane pochodzące z akcelerometru musisz nawiązać połączenie . Dwa czujniki dwa adresy a to znowu strata czasu na łączenie. Jak widać tracisz dużo czasu na niepotrzebne operacje. Nie lepiej zastosować cztery linie I2C?Przecież masz możliwości. Program do zapisu danych musi być jak najkrótszy bo czasu masz naprawdę niewiele- u mnie 19 linijek w tym jakieś niezbędne obliczenia i odczyt z innych czujników niepowiązanych z akcelerometrem. U mnie zapis na kartę w pierwotnej wersji był co 1ms i kontroler się wyrabiał. Z drugiej strony ludzie nieźle znający się na statystykach powiedzieli,że nie muszą być aż tak gęste pomiary proponując pomiary co 10ms a stanęło na pomiarach co 5ms czyli 200 odczytów/sek.Przy pomiarach drgań nieuchronne jest przesuwanie czujników wzdłuż elementu drgającego bo można ustawić czujnik w takim miejscu gdzie jest węzeł a to oznacza,że w tym miejscu nie ma drgań. Ty w tych pomiarach zapewne będziesz szukał węzłów i strzałek co pozwoli znaleźć częstotliwości z jaką wibruje element i amplitudę drgań oraz częstotliwości rezonansowe,harmoniczne w których to stanach powstaje fala stojąca,która jest bardzo groźna dla badanego obiektu. Osobnym problemem jest zasilanie z czego trzeba sobie zdać sprawę. Ponieważ zapis jest na kartę SD to, to sugeruje,że urządzenie będzie zasilane z baterii.Trzeba uważać by nie przekroczyć dopuszczalnych napięć. Najlepiej całość zasilić z 5V to znaczy płytę STM,akcelerometr i adapter mikrokarty SD. Zwracam uwagę na to,że w karcie katalogowej akcelerometru jest zdanie mówiące o tym,że lutowanie ma być takie by nie powstały naprężenia na płytce bo to może powodować błędy odczytu.I jeszcze jedno- doradzono mi by dobrze przetestować kartę pomiarową. Włączasz urządzenie na 24 godziny a po upływie czasu sprawdzasz co się zapisało na karcie. W moim przypadku było to ok.2GB danych.Jest co przetwarzać na dużej jednostce obliczeniowej. Widzę,że dałeś radę z f_lseek() ale program powinien wyglądać nieco inaczej na co zwrócił uwagę matsobdev.

Edytowano przez szymonw
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

21 minut temu, kaworu napisał:

... po co Ci ten seek przed write? Wskaźnik zapisu będzie na końcu pliku po poprzednim zapisie.

Dzięki, nie wiedziałem. Myślałem, że za każdym razem trzeba to ustawiać.

 

9 minut temu, szymonw napisał:

Zasięg czyli odstęp czujnik -procesor to co najwyżej kilka metrów(pojemność linii nie może przekroczyć 400pF) .Akcelerometr 9250 jest 9-osiowym urządzeniem a tak naprawdę jest 6-osiowym bo wartości trzech osi gyro są wyliczane przez wewnętrzny procesor czujnika zgodnie ze wzorem

Będzie to maksymalnie ok. 30 centymetrów w 4 strony promieniście od uC.
Jesteś pewny, że w MPU9250 nie ma fizycznego żyroskopu???
Wg mnie tymi wzorami można wyliczyć pochylenie względem płaszczyzny ziemi, a nie prędkości kątowe.

 

13 minut temu, szymonw napisał:

 Wątpię w to,że pole magnetyczne zmieni się drastycznie po przesunięciu o co najwyżej (!) milimetr.Co to oznacza? Oznacza to,że najprawdopodobniej nie ma potrzeby pomiaru pola magnetycznego.

Pomiary zbieram tylko z akcelerometru i żyroskopu. Nie korzystam (w tym konkretnym rozwiązaniu) z magnetometrów. Swoją drogą one mają swój adres I2C, więc dochodziłoby kolejne połączenie z urządzeniem docelowym.

 

15 minut temu, szymonw napisał:

Podłączenie do jednej linii dwóch czujników skutkuje tym,że za każdym razem gdy chcesz odczytać dane pochodzące z akcelerometru musisz nawiązać połączenie . Dwa czujniki dwa adresy a to znowu strata czasu na łączenie. Jak widać tracisz dużo czasu na niepotrzebne operacje. Nie lepiej zastosować cztery linie I2C?Przecież masz możliwości.

No właśnie wspominałem, że nie mam dostępu do czterech linii I2C, ponieważ pin od I2C3_SDA wykorzystuję jako MMC1_D1. Żeby mieć kolejny wolny pin do I2C3_SDA musiałbym kupić uC w wersji przynajmniej LQFP176. Tak na szybko szukając, nie udało mi się go znaleźć. A 3 linie raczej nie będą szybsze od 2 linii przy 4 czujnikach, prawda?

Link do komentarza
Share on other sites

7 minut temu, szymonw napisał:

We wcześniejszym wątku napisałeś,że urządzenie ma służyć do pomiaru drgań

Może tutaj rozsądniejsze byłyby czujniki piezoelektryczne sejsmiczne z uwagi na mierzoną wielkość.

 

9 minut temu, szymonw napisał:

Akcelerometr 9250 jest 9-osiowym urządzeniem a tak naprawdę jest 6-osiowym

Akcelerometr i żyroskop mierzą wielkości fizyczne o innym charakterze. Żyroskop mierzy prędkość kątową, obliczanie kąta arkusem nie otrzymamy tego co z żyroskopu. Akcelerometr i żyroskop siebie uzupełniają. Gołym akcelerometrem ciężko by zmierzyć np. kąt nachylenia pojazdu (używając zależności z rysunku)  względem poziomu w ruchu - by latało na wszystkie strony podczas hamowania, przyspieszania.

28 minut temu, kaworu napisał:

A wcale że nie, zapis jest na ogół możliwy do rozmiaru słowa.

Może źle się wyraziłem. Cała strona w sensie, jak coś zapiszemy, to jest już zamknięta. A kasowanie, zgadzam się, cały blok. Ja spotkałem się dla pamięci TH58NVG5S0FTA20 z karty SD 4GB Kingstona z rozmiarem bloku 64 stron x 4328 (4096 + 232) bajtów.

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

4 minuty temu, matsobdev napisał:

Może źle się wyraziłem. Cała strona w sensie, jak coś zapiszemy, to jest już zamknięta.

No nie, na ogół jest tak, że wartości bitów możesz zawsze zmienić z 1 na 0 kiedy sobie i gdzie tylko chcesz. Operacja w przeciwną stronę wymaga wywołania operacji kasowania. Więc jak skasujesz blok/stronę/cokolwiek i zapiszesz jej połowę, to potem możesz spokojnie zapisać i druga połowę w dowolnym czasie - jest w końcu pusta. Co lepsze możesz zapisywać tam gdzie już dane zapisywałeś wcześniej, z ograniczeniem, że żaden bit 0 nie może zmieć stanu na 1 (a to na ogół nie ma sensu, wiec page erase ;p).

 

10 minut temu, matsobdev napisał:

A kasowanie, zgadzam się, cały blok. Ja spotkałem się dla pamięci TH58NVG5S0FTA20 z karty SD 4GB Kingstona z rozmiarem bloku 64 stron x 4328 (4096 + 232) bajtów.

A co do tego... to tak czy inaczej nie ma znaczenia dla karty SD, bo istnieje na niej kontroler, i ten kontroler robi sobie co mu się podoba i nie masz na to wpływu. Zapisywanie wyrównane do wielkości jakiejś ma sens, ale to będzie rozmiar klastra w systemie plików jakiego używasz, który nijak się ma do erase size pamięci pod spodem. No i tu też nie powinno to miec kosmicznego znaczenia, bo karta SD w 4bit trybie to spokojnie powinna móc wyciągać MB/s, dużo więcej niż jest potrzebne.

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

(edytowany)
16 minut temu, matsobdev napisał:

Może tutaj rozsądniejsze byłyby czujniki piezoelektryczne sejsmiczne z uwagi na mierzoną wielkość.

Czy za ich pomocą mogę dokładnie analizować charakterystyki czasowo-częstotliwościowe mierzonych sygnałów? Bo nie chodzi mi jedynie o wykrycie drgań, a o ich konkretne parametry.

Edytowano przez radek04
Link do komentarza
Share on other sites

Karty SD w trybie SPI są koszmarnie wolne. Ale nie wiem czy by Ci tej koszmarności akurat nie starczyło.

Z obliczeń mi wychodzi, że nawet na jednej magistrali I2C masz wystarczająco dużo czasu na odczyt danych ze wszystkich czujników dla 200Hz.

Także to raczej to jak napiszesz kod niż to jak są urządzenia podłaczone.

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

1 minutę temu, matsobdev napisał:

No tak. Zawartości raz fizycznie zaprogramowanej konkretnej strony nie da się zmienić bez uprzedniego skasowania bloku, w którym się ona znajduje.

No to jak mi nie wierzysz, to spróbuj tu: https://electronics.stackexchange.com/questions/122550/flash-memory-does-the-entire-page-need-to-be-erased-before-writing-just-a-few-b

Albo może google? Jak pisałem da się, o ile to jest zmiana z 1 na 0.

Link do komentarza
Share on other sites

3 minuty temu, kaworu napisał:

No to jak mi nie wierzysz, to spróbuj tu

Datasheet wydaje się lepszym źródłem.

22 minuty temu, radek04 napisał:

Stąd mój post tutaj. Liczę na Wasze sprawdzone sposoby, może nowe pomysły...

A nie może obok F7 działać inny mikrokontroler pomocniczy, z którym masz lepsze doświadczenia??

Link do komentarza
Share on other sites

2 godziny temu, kaworu napisał:

A tak szybki rzut oka na kod... po co Ci ten seek przed write? Wskaźnik zapisu będzie na końcu pliku po poprzednim zapisie.

Usunąłem ten f_lseek(), ale wciąż mam 63 sekundy zamiast 60.
Natomiast zauważyłem, że co kilka pomiarów dwa kolejne powtarzają się. Identyczne jest wtedy wszystkie 48 rejestrów. Zwiększyłem sampling czujników z 500 Hz do 1000 Hz, ale to niczego nie zmieniło. Wydaje mi się, że czasami program odczytuje (a przynajmniej zapisuje na kartę) dwa te same pomiary.

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.