radek04 Napisano Styczeń 6, 2023 Udostępnij Napisano Styczeń 6, 2023 Cześć, powoli muszę kończyć projekt, z którym walczę od kilku miesięcy. Dotyczy on akwizycji danych z czujników inercyjnych (i mikrofonów) oraz ich zapis na kartę SD. Dla zainteresowanych przedstawiam tematy bezpośrednio związane z projektem: STM32 UART wysyłanie danych typu uint16_t, STM32F7 Zbyt mała szybkość zapisu danych z czujników I2C na kartę SD, Nucleo-H7 - odłączone piny SDMMC i dwa związane pośrednio: Gdzie opłaca się zamawiać PCB?, Oscyloskop - pomoc w wyborze. Zmontowałem układ na PCB, co rozwiązało kilka problemów związanych z wyprowadzeniami pinów uC na płytce Nucleo. Zapis na kartę działa już sprawnie, ale wciąż w trybie blokującym. Przez to nawet z użyciem dwóch buforów i naprzemiennego odczytu/zapisu wciąż tracę niektóre pomiary, których nie mogę realizować podczas zapisywania danych na SD. Czy ktoś z Was robił coś podobnego? Szukam rozwiązań w sieci, ale nie mogę niczego konkretnego się doszukać. W CubeIDE jest informacja, by wygenerować kod bazujący na sd_diskio_dma_template.*files. Gdzie znajdę takie takowe szablony? Link do komentarza Share on other sites More sharing options...
matsobdev Styczeń 7, 2023 Udostępnij Styczeń 7, 2023 Tu coś jest, a pewnie bardziej to niż wskazany w odpowiedzi plik z RTOS w nazwie :P. Nie wiedziałem, to się wypowiedziałem. Jest jeszcze drugi w wersji v2. Przepraszam, że tak powiedziałem 😄 1 Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 7, 2023 Autor tematu Udostępnij Styczeń 7, 2023 (edytowany) 9 godzin temu, matsobdev napisał: pewnie bardziej to Tak, widziałem to. Ale właśnie nie mogłem się doszukać, czym te wersje się różnią. No i na razie nie udało mi się żadnej uruchomić. Mam dziesiątki błędów przy kompilacji, więc to nie jest trywialna zamiana plików... Edit: Pozbyłem się błędów. Testuję. Edytowano Styczeń 7, 2023 przez radek04 Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 7, 2023 Autor tematu Udostępnij Styczeń 7, 2023 Rozumiem, że nawet jeżeli zapis na kartę z bufora dokonuje się z wykorzystaniem DMA, to w tym samym czasie nie mogę odczytywać tego bufora i do niego zapisywać? Potrzebuję tutaj 2 buforów pracujących naprzemiennie, tak? Na razie testuję 1 bufor i w czasie zapisu na kartę tracę zawsze 6 odczytów pomiędzy kolejnymi "okrążeniami". Czyli zapisuje mi pierwsze 200 odczytów (rozmiar bufora), następnie jest 6 przerwań timera (12 ms, f=500 Hz), w czasie których zapis do bufora się nie realizuje, kolejna zapisana próbka ma numer 207 i tak w kółko. Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. 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
pmochocki Styczeń 7, 2023 Udostępnij Styczeń 7, 2023 17 minut temu, radek04 napisał: Rozumiem, że nawet jeżeli zapis na kartę z bufora dokonuje się z wykorzystaniem DMA, to w tym samym czasie nie mogę odczytywać tego bufora i do niego zapisywać? Potrzebuję tutaj 2 buforów pracujących naprzemiennie, tak? Tak lub zastosować bufor okreżny. 1 godzinę temu, radek04 napisał: Pozbyłem się błędów. Testuję. Edytowano 59 minut temu przez Wiem, że teraz jest presją czasowa, ale jak już skończysz podsumuj proszę wszystkie te wyzwania, bo są bardzo ciekawe. Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 7, 2023 Autor tematu Udostępnij Styczeń 7, 2023 (edytowany) 46 minut temu, pmochocki napisał: Tak lub zastosować bufor okreżny. No właśnie przy FatFs nie ma w Cube takich ustawień DMA, jak np. przy interfejsach I2C, gdzie w łatwy sposób mogę zrobić bufor okrężny. Natomiast przy samodzielnym podziale na 2 bufory wciąż występuje ten sam problem. Zawsze gubię po 6 odczytów. Tak, jakby DMA nie działało... Wrzucę fragment kodu, może zauważycie jakiś błąd. while (1) { while (previous_timer_tick == current_timer_tick) //jeśli timer nie zmienił jeszcze wartości current_timer_tick { HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, RESET); // 0 HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, RESET); // 0 HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, RESET); // 0 HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, RESET); // 0 } if (previous_timer_tick < current_timer_tick - 1) //jeśli timer zmienił wartość current_timer_tick więcej niż 1 raz (program nie wyrabia czasowo) program się nie zatrzymuje { //printf("Uklad nie wyrabia czasowo (karta)\n"); HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, RESET); // 0 HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, SET); // 1 HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, RESET); // 0 HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, RESET); // 0 current_timer_tick = previous_timer_tick; //naprawa sytuacji, by dalej działało } 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 ) { //printf("I2C nie jest gotowe\n"); HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, RESET); // 0 HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, RESET); // 0 HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, SET); // 1 HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, RESET); // 0 } //printf("Wszystkie I2C sa gotowe, normalna praca\n"); previous_timer_tick = current_timer_tick; HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, RESET); // 0 HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, RESET); // 0 HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, RESET); // 0 HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, SET); // 1 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 if (ktory_bufor == 0) /* wybór buforów */ { sprintf(&my_string_0[(ASCII_char_No + 7)*(round_No-1)], /* zapis z czujników do bufora nr 0 */ "%6d " "%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", real_timer_tick, 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 (round_No == rounds)//jeśli skończą się pomiary w danym etapie (np. przez 5 sekund 500*5) { ktory_bufor = 1; //zmiana bufora round_No = 0; lap++; //kolejne okrążenie HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, SET); //włączenie diody if(f_write(&fil, my_string_0, sizeof(my_string_0), &numread) != HAL_OK) printf("f_write ERROR\n"); /* zapis na kartę z bufora nr 0 */ HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, RESET); //wyłączenie diody - koniec zapisu na kartę }else if (ktory_bufor == 1) /* wybór buforów */ { sprintf(&my_string_1[(ASCII_char_No + 7)*(round_No-1)], /* zapis z czujników do bufora nr 1 */ "%6d " "%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", real_timer_tick, 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 (round_No == rounds)//jeśli skończą się pomiary w danym etapie (np. przez minutę 500*60) { ktory_bufor = 0; //zmiana bufora round_No = 0; lap++; //kolejne okrążenie HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, SET); //włączenie diody if(f_write(&fil, my_string_1, sizeof(my_string_1), &numread) != HAL_OK) printf("f_write ERROR\n"); /*zapis na kartę z bufora nr 1 */ HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, RESET); //wyłączenie diody - koniec zapisu na kartę } if (lap == laps) //koniec wszystkich operacji { HAL_TIM_Base_Stop_IT(&htim7); //uruchomienie timera generującego przerwanie HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, RESET); //wyłączenie diody printf("Zatrzymuje przerwania TIM7\n"); if (f_close(&fil) == HAL_OK) printf("f_close OK\n"); else printf("f_close ERROR\n"); unmount_sd(); printf("previous = %d, current = %d, real = %d, round_No = %d, lap = %d\n", previous_timer_tick, current_timer_tick, real_timer_tick, round_No, lap); printf("done\n"); return 0; } } } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) /* przerwanie timera */ { if (htim->Instance == TIM7) // przerwanie pochodzi od timera 7 { current_timer_tick++; round_No++; real_timer_tick++; //wartość ta nigdy nie jest zerowana } } Edit: Zrobiłem też 2 komplety tablic do zapisu z czujników. Zamiast MPU9250_Data_A[] mam MPU9250_Data_A_0[] oraz MPU9250_Data_A_1[] (i tak dla każdego czujnika), ale efekt bez zmian. Edytowano Styczeń 7, 2023 przez radek04 Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 7, 2023 Autor tematu Udostępnij Styczeń 7, 2023 Na mojej najszybszej karcie tracę ok. 1 pomiar na 50 poprawnie wykonanych i to niezależnie od wielkości bufora jednorazowo zapisywanego na kartę. Link do komentarza Share on other sites More sharing options...
pmochocki Styczeń 8, 2023 Udostępnij Styczeń 8, 2023 To może teraz jakbyś odpuścił sobie ten sprintf i zamiast stingow zapisywał "raw data". To może byś się wyrobił. Taki pomysł, bo wiem, że jest presja czasu. Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 8, 2023 Autor tematu Udostępnij Styczeń 8, 2023 Pomysł jest niezły, aje jak wykorzystać takie dane? Link do komentarza Share on other sites More sharing options...
matsobdev Styczeń 8, 2023 Udostępnij Styczeń 8, 2023 (edytowany) Powiedzmy, że zapisujesz sobie binarnie do pliku 0x05, to w kodzie ASCII, czy UTF-8 to będzie coś (literka) lub nic (krzaczek), bo to będzie znak "zakazany" (jakiś kontrolny itp.). Otwórz w hexedytorze, to będzie miało większy sens. Ten "sprintf" na tych danych z hexedytora zrobisz na konkuterze. Edytowano Styczeń 8, 2023 przez matsobdev 2 Link do komentarza Share on other sites More sharing options...
pmochocki Styczeń 8, 2023 Udostępnij Styczeń 8, 2023 (edytowany) 1 godzinę temu, radek04 napisał: Pomysł jest niezły, aje jak wykorzystać takie dane? No piszesz skrypt w Pythonie i już... Możesz tego zrobić wykresy, podsumowanie statystyczne, średnia, mediana, itd... Edytowano Styczeń 8, 2023 przez pmochocki 2 Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 8, 2023 Autor tematu Udostępnij Styczeń 8, 2023 OK, fajny pomysł. W jakiej formie to jest wtedy faktycznie zapisywane? Zera i jedynki? Najłatwiej by mi było to obrabiać w MATLAB-ie, bo i tak tam będę później przetwarzał te dane. Link do komentarza Share on other sites More sharing options...
radek04 Styczeń 8, 2023 Autor tematu Udostępnij Styczeń 8, 2023 Zasadniczo jest lepiej, bo zapisuje mniej danych, ale i tak występują opóźnienia. W zasadzie jeśli i tak mam przerwy w odczytach, to większej różnicy nie robi mi wielkość tej przerwy, a postać po konwersji funkcją sprintf() jest dla mnie wygodniejsza. Wciąż zależy mi na zapisie ciągłym, to niestety nie jest rozwiązanie. Ale oczywiście dziękuję za propozycję, bo jest bardzo sensowna. 1 Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Bądź aktywny - zaloguj się lub utwórz konto!
Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony
Utwórz konto w ~20 sekund!
Zarejestruj nowe konto, to proste!
Zarejestruj się »Zaloguj się
Posiadasz własne konto? Użyj go!
Zaloguj się »