Komentator Napisano Czerwiec 13, 2021 Udostępnij Napisano Czerwiec 13, 2021 Do tej pory omówiliśmy dwa interfejsy szeregowe na STM32L4, czyli UART i SPI. Pierwszy wymagał dwóch linii, ale był dość powolny. Drugi pracował szybciej, ale wykorzystywał więcej wyprowadzeń. Teraz zajmiemy się I2C, czyli kolejnym interfejsem komunikacyjnym, dzięki któremu do tych samych linii możemy łatwo podłączyć wiele urządzeń. UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.Przeczytaj całość »Poniżej znajdują się komentarze powiązane z tym wpisem. 1 Link do komentarza Share on other sites More sharing options...
Komentator Czerwiec 13, 2021 Autor tematu Udostępnij Czerwiec 13, 2021 Przypominamy: w komentarzach do kursów rozmawiamy wyłącznie na tematy związane z konkretnym kursem. Mile widziane są również informacje od osób, które korzystały wcześniej z naszych poradników. Wszystko po to, aby kursanci, którzy mają zamiar korzystać z tego kursu nie musieli "przedzierać" się przez dziesiątki postów na inne tematy. Pytania na tematy, które nie są związane z kursem można zadawać na naszym forum o mikrokontrolerach. Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Czerwiec 13, 2021 Udostępnij Czerwiec 13, 2021 Zachęcam do lektury kolejnej części kursu STM32L4 - to już dwunasty odcinek! Tym razem o komunikacji przez I2C na przykładzie małej pamięci EEPROM. W następnym odcinku wykorzystamy tę widzę do komunikacji z precyzyjnym czujnikiem wysokości, dzięki czemu będzie mogli mierzyć wysokość (tak jak robią to np. sportowe zegarki) 😉 Link do komentarza Share on other sites More sharing options...
Popularny post ethanak Czerwiec 14, 2021 Popularny post Udostępnij Czerwiec 14, 2021 Ten odcinek polecam z czystym sumieniem również wszelkiej maści Arduinowcom - może nie muszą czytać o tym jak się gmera po rejestrach STM-a, ale jaka jest zasada transmisji, dlaczego są potrzebne rezystory, słówko o prędkościach - warto wiedzieć. Natomiast w całej części o EEPROM-ie zabrakło jednej ważnej informacji. Ale wyjaśnijmy najpierw, skąd te tajemnicze 5 milisekund. Otóż zapis w pamięci EEPROM działa dwuetapowo. W czasie transmisji dane są zapisywane w jej wewnętrznym buforze roboczym, a dopiero po zakończeniu następuje przepisanie zawartości bufora do właściwej pamięci. Według producenta czas tej operacji nie przekroczy 5 msec. I tu możemy się naciąć na pewną nieprzyjemną cechę zwaną "wielkością bufora". Otóż w omawianym typie pamięci bufor ma wielkość 8 bajtów. I tyle maksymalnie możemy zapisać jednym poleceniem. Maksymalnie - to jednak nie znaczy, że zawsze będziemy mogli zapisywać dane do pamięci w 8-bajtowych sekwencjach. Pamięć ma oczywiście odpowiedni licznik wewnętrzny, i ten jest inkrementowany po przyjęciu każdego bajtu. Ale nie całkiem - inkrementowane są tylko najmłodsze bity w ilości odpowiadającej rozmiarowi strony w pamięci (w tym przypadku, dla 8-bajtowej strony mamy trzy bity). Co z tego wynika - otóż jeśli będziemy wpisywać dane pod adres przekraczający wyrównanie do wielkości strony (czyli w naszym przypadku niepodzielny przez 8), licznik w pewnym momencie po prostu się przekręci i np. następnym adresem po 15 będzie nie 16 a 8! I dlatego przy próbie zapisu dwóch bajtów pod adres 15 w rzeczywistości owe bajty będą zapisane pod adresami 15 i 8 (co oczywiście nie jest naszym celem). To samo stanie się w przypadku próby zapisania więcej niż 8 bajtów nawet pod adres podzielny przez wielkość strony: zapisane zostanie tylko tyle bajtów, na ile pozwala wielkość bufora (przy czym z reguły nie będą to te bajty, na których nam zależy). Dla dociekliwych proponuję więc zadanie: napisanie funkcji zapisującej dane w EEPROM-ie z uwzględnieniem wielkości strony. Przy czym należy pamiętać, że w różnych typach pamięci wielkość strony może być różna! Oczywiście problem nie występuje w czasie odczytu, możemy odczytać tyle danych ile chcemy (i oczywiście na ile nam pozwala architektura naszego mikrokontrolera i używane biblioteki). 3 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
Elvis Czerwiec 14, 2021 Udostępnij Czerwiec 14, 2021 @ethanak może najpierw małe wyjaśnienie - celem tej części kursu było głównie pokazanie sposobu działania interfejsu I2C oraz jego obsługi z poziomu biblioteki HAL dla STM32. Sama pamięć EEPROM jest tylko prostym i popularnym przykładem. Masz oczywiście w pełni rację odnośnie bufora zapisu, postanowiliśmy jednak świadomie nie opisywać tego w tej części kurs. Ograniczyliśmy się tylko do uwagi: "Na dodatek, przesyłając więcej niż jeden bajt, należy brać pod uwagę wielkość licznika oraz adresowanie stron. Szczegóły na ten temat znaleźć można oczywiście w dokumentacji tego układu". Po prostu nie chcieliśmy już dodawać tutaj informacji, które nie są związane ściśle z głównym bohaterem kursu, czyli STM32. Temat, który przytoczyłeś sprawdzi się jednak świetnie w kwestii zadania domowego lub ewentualnej kontynuacji tego kursu 😉 1 Link do komentarza Share on other sites More sharing options...
ethanak Czerwiec 15, 2021 Udostępnij Czerwiec 15, 2021 @Elvis a więc niech mój post pozostanie inspiracją dla młodych padawanów ST 🙂 @Treker robiłeś coś przy edytorze? Bo coraz ładniej wygląda z coraz mniej można z niego korzystać (np. na moim FX-sie nie mogę wywalić nowej linii między nickiem Elvisa a moim tekstem, XUbuntu 20.04) 1 Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Czerwiec 16, 2021 Udostępnij Czerwiec 16, 2021 @ethanak od wielu miesięcy nic w tym zakresie nie było zmieniane. Edytowałem Twój post i linijkę normalnie usunąłem za pomocą klawisza delete (Chrome) 🙂 Link do komentarza Share on other sites More sharing options...
ethanak Czerwiec 16, 2021 Udostępnij Czerwiec 16, 2021 33 minuty temu, Treker napisał: linijkę normalnie usunąłem za pomocą klawisza delete (Chrome) Czyli najnowszy Firefox ma jakieś własne zdanie - zauważyłem to już wcześniej, edytor wariuje nawet jak wstawię emotkę i potrafi nie reagować np. na klawisze kursora. Czyli trzeba się przyzwyczaić. Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Czerwiec 20, 2021 Udostępnij Czerwiec 20, 2021 Kolejna część kursu jest już dostępna - tym razem mowa o czujniku ciśnienia atmosferycznego (również I2C). Staraliśmy się pokazać coś więcej oprócz standardowego pobrania danych z sensora 😉 Zachęcam do lektury: Kurs STM32L4 – #13 – czujnik ciśnienia, pomiar wysokości (I2C) Link do komentarza Share on other sites More sharing options...
Zealota Lipiec 23, 2021 Udostępnij Lipiec 23, 2021 Mam jedną uwagę praktyczną do tej części kursu, a można by to wykorzystać jeszcze w innych miejscach. Chodzi mi o możliwość podglądu zapisu przebiegów z analizatora. Prezentacja w formie pliku graficznego ma swoje ograniczenia, a ładując zapisany plik do własnego programu analizującego można lepiej analizować dane, szczególnie dla takich przypadków, gdy na pliku graficznym ciężko o szczegóły. Wiem że to dodatkowa praca i pewnie jedna osoba na dziesięć z skorzysta, ale może warto to rozważyć 1 Link do komentarza Share on other sites More sharing options...
Emtorek Wrzesień 15, 2021 Udostępnij Wrzesień 15, 2021 Mam pytanie co do funkcji "eeprom_read" i "eeprom_write". Co to znaczy przekazywać do funkcji zmienną typu void? I dlaczego typ void, a nie uint8_t? Link do komentarza Share on other sites More sharing options...
Gieneq Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 (edytowany) @Emtorek witam na forum 🙂 9 godzin temu, Emtorek napisał: I dlaczego typ void void możesz napisać gdy nie podajesz w zmiennej żadnych argumentów. Ale tobie chyba chodzi o coś innego. Wydaje mi się, że pytasz o wskaźnik na zmienną void *. Oznacza to wskaźnik na zmienną – jej adres, który nie ma informacji o tym jaki typ danych jest w tej pamięci więc nie ma informacji ile bajtów zajmują zmienne. HAL_StatusTypeDef eeprom_read(uint32_t addr, void* data, uint32_t size) { eeprom_wait(); return HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDR, addr, 1, data, size, HAL_MAX_DELAY); } Widać to w kodzie, data to bufor (tablica) zmiennych typu void *, czyli wskazujemy początek obszar o rozmiarze size ale nieznanym typie danych. Dzięki temu możemy w kodzie odwołać się do dowolnego typu danych, np. 4 bajtowego countera: eeprom_read(0x10, &counter, sizeof(counter)) I poinformować funkcję ile ma zarezerwować miejsca używajac operatora sizeof, który zwraca liczbę bajtów zajmowaną przez zmienną/typ danych ewentualnie długość tablicy jak jest bezpośrednio podana. Dla uściślenia pierwsza zmienna addr oznacza adres w przestrzeni eepromu, adres daty wskazuje na miejsce w pamięci operacyjnej STM. Wątpliwość jak rozumiem budzi to, że w funkcji HAL jest uint8_t, to pytanie już do @Elvis Edytowano Wrzesień 16, 2021 przez Gieneq 1 Link do komentarza Share on other sites More sharing options...
ethanak Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 37 minut temu, Gieneq napisał: Wątpliwość jak rozumiem budzi to, że w funkcji HAL jest uint8_t Po prostu w C (ale nie C++) typ void * oznacza "wskaźnik na cokolwiek" i można go użyć w miejsce dowolnego wskaźnika. Przykładowo jeśli mamy funkcje: int cośtam(uint8_t *data, size_t count); char *cośinnego(int size); możemy je wywołać np. tak: void *data; int wynik; data = cośinnego(10); wynik = cośtam(data, 10); W C++ już ten numer nie przejdzie 🙂 A uint8_t jest pewnie dlatego, że wygodnie się go używa (np. w iteracjach). Link do komentarza Share on other sites More sharing options...
Gieneq Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 @ethanak tak zgadza się. Tylko tu podejrzane jest przejście z czegoś szczegółowego do ogólnego ale od zewnątrz. Zazwyczaj nabudowuje się w przeciwnym kierunku. Np w Javie funkcje ogólnego przeznaczenia miały u mnie argument List (interfejs, tj. abstrakcyjny), a dopiero w konkretach zastępowałem np. ArrayList który już miał swój obiekt. Odesłałem do wyższej instancji, bo nie jestem ekspertem, ale jednak zaryzykuję i ocenię, że w tej funkcji HAL powinien być void *. Tak przynajmniej kojarzę z prac przy OpenGl, że jak coś się wysyłało do pamięci (tam do pamięci karty graficznej) to do adresowania danych jako zlepek bytów używało się void *. Ale chyba to nie ma większego znaczenia, bo jak jesteśmy w C to void * można iterować tak jak uint8_t co 1B więc to jest chyba tylko dylemat dot. estetyki kodu. Link do komentarza Share on other sites More sharing options...
ethanak Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 42 minuty temu, Gieneq napisał: void * można iterować tak jak uint8_t co 1B Prawie... a prawie robi wielką różnicę. Nie można np. zrobić dereferencji, a to może utrudnić życie. Przykładowo (taka teoretyczna funkcja): wypisz(void *d, int count) { while (count-->0) wypisz_znak(*d++); } raczej słabo się skompiluje... 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ę »