Skocz do zawartości

Nucleo-H7 - odłączone piny SDMMC


radek04

Pomocna odpowiedź

10 godzin temu, radek04 napisał:

SD na 1 bicie działa dobrze, na 4 bitach potrzebny "dobry dotyk".

Rozumiem, działa bezwarunkowo dobrze cały czas? To może, podłączyć do padów morf 😛 wszystko tak, żeby połączenie było na końcu ścieżki, a nie gdzieś w środku (chociaż same gniazda też będą tak działać). Albo zostawić 1 bit, jeśli działa. 4 razy wolniej, to i tak za szybko. Co do Pololu, w linku, który podałeś, jest schemat - to poszukać pinout do microSD dla SDIO i można dopasować piny gniazda do tych na płytce.

Link do komentarza
Share on other sites

20 godzin temu, radek04 napisał:

SDMMC2_D2 (PB3) domyślnie nazywa się (JTDO/TRACESWO). Czy to może być problem?

Można rozłączyć zworkę SB32, a zostawić SB26. Sprawdź miernikiem, od tego pinu na złączu Arduino, gdzie pewnie podłączasz, czy jest przejście do tej zworki SB32), jeśli ten schemat jest ok. To będzie w gałązka od tego pinu H7 do gniazda zewnętrznego programatora.

Edytowano przez matsobdev
Link do komentarza
Share on other sites

(edytowany)
Dnia 7.12.2022 o 22:04, pmochocki napisał:

Może po kolei zacznijmy modyfikować ten program, układając jednak klocki we właściwe miejsce...

Dodaj sobie zmienną volatile timmer_tick. Ustaw ją na 0 i w przerwaniu licznika podbijaj o jeden.

W głównej pętli programu sprawdzaj czy timmer_tick się zmienił jak tak to zapisz timer_tick to zmiennej lokalnej też volatile i uruchom

@pmochocki, zrobiłem zgodnie z Twoją radą. Sprawdź, proszę, czy jakiegoś błędu w kodzie nie popełniłem:

I2C_HandleTypeDef hi2c1;
I2C_HandleTypeDef hi2c2;
I2C_HandleTypeDef hi2c3;
I2C_HandleTypeDef hi2c4;
volatile uint32_t timer_tick = 0; //zmienna globalna

HAL_TIM_Base_Start_IT(&htim7); //uruchomienie timera generującego przerwanie

int main(void)
{
	volatile uint32_t previous_timer_tick = 0; //zmienna lokalna
	volatile uint32_t current_timer_tick = 0; //zmienna lokalna


	HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, RESET); // 0
	HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, RESET); // 0

  while (1)
  {
	  if (previous_timer_tick != current_timer_tick)
	  {
		  if (current_timer_tick > (previous_timer_tick + 1))
		  {
			  while(1)
			  {
				  HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, RESET);	// 0
				  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, SET);	// 1
			  }
		  }
	  }
	  previous_timer_tick = current_timer_tick;

		if (
			HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_READY
		&& 	HAL_I2C_GetState(&hi2c2) == HAL_I2C_STATE_READY
		&& 	HAL_I2C_GetState(&hi2c3) == HAL_I2C_STATE_READY
		&& 	HAL_I2C_GetState(&hi2c4) == HAL_I2C_STATE_READY
		)
		{
			HAL_I2C_Mem_Read_DMA(&hi2c1, MPU9250_ACC_ADDRESS_A, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_A, 14); //14 pomiarów od razu
			HAL_I2C_Mem_Read_DMA(&hi2c2, MPU9250_ACC_ADDRESS_B, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_B, 14); //14 pomiarów od razu
			HAL_I2C_Mem_Read_DMA(&hi2c3, MPU9250_ACC_ADDRESS_C, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_C, 14); //14 pomiarów od razu
			HAL_I2C_Mem_Read_IT(&hi2c4, MPU9250_ACC_ADDRESS_D, MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_D, 14); //14 pomiarów od razu

			HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, SET); 		// 1
			HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, SET);			// 1
		}
		else
		{
			while(1) // I2C niegotowe
			{
				HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, SET); 	// 1
				HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, RESET);	// 0
			}
		}
  }
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM7)	// przerwanie pochodzi od timera 7
	{
		timer_tick++;
	}
}

Czy dobrze używam tych handlerów od I2C? Czy muszę do nich zrobić jakąś obsługę w dodatkowej funkcji (jak np. przy timerze), czy tak jak mam jest dobrze?
Program zawsze wchodzi w pętlę while(1) // I2C niegotowe.

Co mogę z tym zrobić? Bo zwykły delay nie pomaga.
Dodam, że wykorzystując HAL_I2C_Mem_Read w wersji innej niż blokująca, pierwsze odczyty miałem zawsze zerowe.

 

Edit: Zmieniłem kolejność obsługi diod oraz odczytu I2C i okazuje się, że w pierwszym przebiegu głównej pętli wszystkie I2C są dostępne, ale przestają być po kolejnym wejściu pętli. Sprawdzę tryb blokujący odczytu, powinno pomóc.

Edit 2: Pomogło. Spróbuję zmodyfikować kod, by program oczekiwał na zmianę wartości timer_tick i dopiero sprawdzał, czy I2C są gotowe.

Edit 3: Teraz zauważyłem, że timer_tick używam tylko w przerwaniu timera. Przepisałem Twój kod "na pałę" 🙂

Edytowano przez radek04
Link do komentarza
Share on other sites

(edytowany)

Zmodyfikowałem trochę program:

  while (1)
  {
	  while (previous_timer_tick == current_timer_tick) //jeśli timer nie zmienił jeszcze wartości current_timer_tick
	  {
		  HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, RESET);	// 0
		  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, RESET);	// 0
	  }

	  if (current_timer_tick == previous_timer_tick + 1)
	  {
			while 		//dopóki którykolwiek I2C nie jest gotowy
					(
						HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY
					|| 	HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY
					|| 	HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY
					|| 	HAL_I2C_GetState(&hi2c4) != HAL_I2C_STATE_READY
					)
				{
		  				HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, SET); 		// 1
		  				HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, SET);			// 1
				}
						//kiedy wszystkie I2C gotowe
						previous_timer_tick = current_timer_tick;
						HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, SET); 		// 1
					  	HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, RESET);		// 0

						HAL_I2C_Mem_Read_DMA(&hi2c1, MPU9250_ACC_ADDRESS_A,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_A, 14); //14 pomiarów od razu
						HAL_I2C_Mem_Read_DMA(&hi2c2, MPU9250_ACC_ADDRESS_B,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_B, 14); //14 pomiarów od razu
						HAL_I2C_Mem_Read_DMA(&hi2c3, MPU9250_ACC_ADDRESS_C,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_C, 14); //14 pomiarów od razu
						HAL_I2C_Mem_Read_IT(&hi2c4, MPU9250_ACC_ADDRESS_D,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_D, 14); //14 pomiarów od razu
	  }
	  while (previous_timer_tick < current_timer_tick - 1) //jeśli timer zmienił wartość current_timer_tick więcej niż 1 raz (program nie wyrabia czasowo)
	  {
		  HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, RESET);	// 0
		  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, SET);	// 1
	  }
  }

Przy 500 Hz cały czas mam zapaloną LD1, więc wygląda na to, że sam odczyt z I2C wyrabia się czasowo (jeśli przy I2C4 mam DMA, to niestety po pierwszej próbie odczytu I2C4 przestaje odpowiadać - ten problem na razie zostawiam).

W trybie blokującym odczytu również program wyrabia, ale wyraźnie krótsze jest oczekiwanie między pomiarami. Podczas DMA dioda LD1 świeciła dużo "słabiej", czyli przez większość czasu była zgaszona - pierwsza wewnętrzna pętla while().

Dodanie sprintf() po operacjach odczytu też nie opóźnia zbytnio działania programu:

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]);

Na razie sam zapis na kartę powoduje, że program "nie wyrabia":

f_write(&fil, my_string, sizeof(my_string), &numread);

I to nawet w przypadku, gdy chcę zapisać raptem jedną wartość rejestru:

f_write(&fil, my_string[0], sizeof(my_string[0]), &numread);

Wyłączyłem odczyt i sprintf(), robię zapis dummy data o docelowej wielkości. Przy przerwaniach 50 razy na sekundę (czyli 10x wolniej niż potrzebuję) program wykonuje poprawnie zwykle kilkaset zapisów, po czym pojawia się błąd (zapis nie zdąża się zakończyć przed kolejnym przerwaniem timera). Przy 500 Hz od razu pojawia się błąd (zapalona dioda LD2).

Czyli wychodzi na to, że problem jest z samym zapisem, prawda? Spróbuję trochę przyśpieszyć (większa f zegara, 4 bity...).

Ale pewnie i tak będę potrzebował bufora cyklicznego - nie ukrywam, że nie wiem, jak się za to zabrać. Mogę prosić o pomoc?

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

Czyli ten zapis jest wykonywany wszystkie osie wszystkich czujników na raz, zatem 48 bajtów pierwszy komplet próbek, 48 bajtów drugi komplet próbek itd. Czy takie zakodowanie tutaj wyczerpuje znamiona zapisu ciągłego, czy jakiegoś losowego dziubania karty? Nie wiem jak ze strony karty to wygląda, co ona o tym myśli 😄 A zbieranie rzez całą sekundę 500 zestawów próbek i wtedy write()? Generalnie czy karta dostaje tą porcję i grzecznie czeka na dopełnienia swoich jakichś tam buforów, czy już po otrzymaniu ładuje do macierzy flash, a to trwa i pewnie jeden bajt zapisze tak szybko jak 500. Czy dostanie te dane szybko (1 bit) czy bardzo szybko (4 bity) to nie będzie dla niej mieć znaczenia, jak tych danych będzie tyle samo. Możliwe, że to zachowanie można skonfigurować po stronie H7, instrukcjami jakimi gada z kartą.

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

(edytowany)

@matsobdev, dokładnie o tym samym dziś pomyślałem. Może jutro przetestuję, czy jednorazowy zapis większej liczby danych będzie szybszy. Zwykle karty męczą się takim właśnie "dziubaniem".

Czy zrobienie np. 500x większej tablicy i zapis co 500 odczytów jest dobrym pomysłem, czy raczej potrzebuję czegoś bardziej wyszukanego?

Edytowano przez radek04
Link do komentarza
Share on other sites

Ja bym najpierw to spróbował. A może nawet dwie. Jedna wypełniona i write() i w międzyczasie zapisu na kartę druga wypełnia się przychodzącymi danymi z czujników. Może jest też opcja konfiguracji obsługi bufora kontrolera karty pamięci, że ten czeka z finalizacją zapisu I PS.: Stary telefon, nagrywanie HD, gdzieś 1 MB/s i FAT32 4 - 16 KB przycinki, FAT16 (chyba, bo tylko FAT podaje Windows) 64 KB, git.

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

Pewnie tak się to nazywa, przynajmniej podczas formatowania w 7 jedyna opcja do zmiany poza rodzajem systemu, choć nie wiem, czy tutaj mniejsze, większe lepsze. Może okazać się przeciwnie niż logika wskazuje. A te dwa bufory, tablice, zmienne to będzie działaś, jeśli jeden po zapisaniu da się szybciej opróżnić, niż napływają dane z czujników. W sumie dane zbierasz proporcjonalnie do czasu, zjawisko fizyczne nie czeka. Co 1/500 sekundy jest pomiar ileś tam czasu, żeby pobrać dane, czujnik ich nie gromadzi raczej. Czyli jak jak poniżej sekundy zapiszesz zawartość do karty i go uwalniasz, to jest spoko.

Możesz sprawdzić ile zajmuje czas zapisu pojedynczego kompletu (48 B), i wieloktorności, 10x, 100x, 500x czy jakie tam uznasz. Ile cykli zegarowych, czy ile czasu na podstawie RTC, to będzie podgląd czy karta wyrobi, czy nie, bez pisania tych buforów na początek.

AN5200 wspomina o FIFO w interfejsie SDMMC (32x16 bitów), trybie działa nia, podówjny, pojedynczy, ale konstruktywnych wniosków, że coś jest tak i na pewno nie podam, choć mogę się domyślać.

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

9 godzin temu, matsobdev napisał:

Czyli jak jak poniżej sekundy zapiszesz zawartość do karty i go uwalniasz, to jest spoko.

Ale wtedy musiałbym zapisywać dane w tym samym czasie, co kolejne będą pobierane i konwertowane funkcją sprintf(). O ile sam odczyt robię w trybie nieblokującym, o tyle sprintf() już bedzie blokowane przez zapis, prawda?

Link do komentarza
Share on other sites

Sprintf() może być wykonany jako wstęp, przygotowanie do zapisu. Czyli sprintf() + write() poniżej sekundy. A zatem dwa bufory surowych danych. Ale zrób najpierw benchmarka karty, sprawdź różne taktowania, szerokości magistrali. Sprawdzałeś przejścia miernikiem na zworkach i pinach D2 i debugera? Może to psuje 4-bit. No i nie zaszkodzi przeanalizować, jak dane zapisywane są do karty, czy tam RAM kontrolera buforuje ileś write()ów, AN5200 - może problemu nie ma i nie trzeba dużych zapisów.

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

28 minut temu, matsobdev napisał:

Sprawdzałeś przejścia miernikiem na zworkach i pinach D2 i debugera

Tak. Tego pinu od debugera nie używam. Tego drugiego nie znalazłem w innym złączu. A pin, który jest wyprowadzony na dwa złącza nie ma zworki do ich rozdzielenia. Zresztą one sąsiadują ze sobą na płytce, ścieżka jest bardzo krótka, więc chyba nie powinna ściągać zakłóceń.

Teraz nie ma mnie w domu, więc dokładnie nie pamiętam, o które chodzi. W razie potrzeby później uzupełnię.

 

Link do komentarza
Share on other sites

10 godzin temu, matsobdev napisał:

Możesz sprawdzić ile zajmuje czas zapisu pojedynczego kompletu (48 B), i wieloktorności, 10x, 100x, 500x czy jakie tam uznasz.

To jest bardzo dobry pomysł. 

52 minuty temu, matsobdev napisał:

Ale zrób najpierw benchmarka karty, sprawdź różne taktowania, szerokości magistrali. Sprawdzałeś przejścia miernikiem na zworkach i pinach D2 i debugera? Może to psuje 4-bit.

I to też jest super rada. 

Nie zostało też oszacowane ile średnio zajmuje odczyt jednej paczki z 4 czujników. 

Separation of concerns - odczyt jest już prawie ogarnięty. Wiemy że może być nieblokujacy i że potrzebujemy danych ile czasu zajmuje. Dla zapisu mamy dość mało wiedzy. Czemu nie działa 4bit? Jaka wartość bloku jest optymalna. I dopiero w dlalszej kolejności powinniśmy pomyśleć jak to łączyć w jedną całość. 

  • Lubię! 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.