Skocz do zawartości

Kurs STM32 - #3 - Płytka Nucleo, konfiguracja środowiska


Komentator

Pomocna odpowiedź

Witam serdecznie, potrzebuję pomocy w rozwiązaniu problemu z Debugerem.

Otóż przy pierwszej próbie jego włączenia (tak jak w kursie) nie wystąpiły żadne problemy, natomiast gdy dodałem zmienną "int" na początku main() i inkrementowałem ją w for() wyświetlał się następujący komunikat błędu:

Jestem nowicjuszem jeśli chodzi o Eclipse, mój system operacyjny to WinXP a płytka zawiera STM32F401. Za sugestię i okazaną pomoc będe bardzo wdzięczny.

EDIT:

jeszcze raz uruchomiłem RUN(już bez Debuggera) i w konsoli pojawiły się błędy:

Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '.

Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD

adapter speed: 2000 kHz

adapter_nsrst_delay: 100

srst_only separate srst_nogate srst_open_drain connect_deassert_srst

srst_only separate srst_nogate srst_open_drain connect_deassert_srst

Info : Unable to match requested speed 2000 kHz, using 1800 kHz

Info : Unable to match requested speed 2000 kHz, using 1800 kHz

Info : clock speed 1800 kHz

Error: read version failed //<-- w tym miejscu coś nie tak

in procedure 'program'

in procedure 'init' called at file "embedded:startup.tcl", line 473

in procedure 'ocd_bouncer'

** OpenOCD init failed **

shutdown command invoked

Gdzie szukać przyczyny ?

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

Sebastian_code, programy na mikrokontroler nie mogą się zakończyć - dojść do return w funkcji "main". W programie musi istnieć pętla nieskończona.

Witam, zatem czy to jest główna przyczyna całego zamieszania? Oczywiście sam to sprawdzę ale dzięki za wskazówkę. Niby oczywista rzecz a jednak 🙂

Swoją drogą, dlaczego funkcja main() jest typu "int" a nie "void" skoro nic nie zwraca ?

========================

Witam ponownie, sprawdziłem, poprawiłem i teraz wszystko działa bez problemu. Dzięki za pomoc. Mam jeszcze jedno pytanie. Kod napisałem jak na zdjęciu:

Wiem wiem, niepotrzebnie przekombinowane z zerowaniem zmiennej, ale chodzi mi o coś innego. Przy ostatniej klamrze czasem pojawia się podkreślenie a błąd :"Control reaches ond of program." Z tym że wiadomo że sterowanie nigdy nie osiągnie końca kodu.

Czy należy się tym przejmować?

Link do komentarza
Share on other sites

Pełne wyjaśnienie dlaczego int main() nasz tutaj:

http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c

Ogólnie służy to do zwracania w jaki sposób program zakończył pracę.

No tak tak. Wiem co to oznacza ale zastanawia mnie inna rzecz. Skoro funkcja nic nie zwraca to jej typ powinien byc "void". A funkcja z kursu ma typ "int" a więc powinna zwracać wartość typu int a jednak z powodu tego że jest to program na mikroprocesor nie zwraca niczego bo musi bć ciągła. I kompilator nie zgłasza błędu. Czy w tym przypadku funkcja main() nie powinna być typu void ?

Link do komentarza
Share on other sites

Main w C MUSI być int zgodnie ze standardem.

Praktycznie każdy nowoczesny kompilator dodaje

return 0;

na koniec main jeśli nie znajdzie nic innego. Jednakże dobrą praktyką jest umieszczenie go tam samemu:

int main
   //Kod
   while(1) {
       //Więcej kodu
   }
   return 0; //Nigdy się nie wykona
}
Link do komentarza
Share on other sites

Wiem wiem, niepotrzebnie przekombinowane z zerowaniem zmiennej

Racja, przyznam, że zrobiłeś to tak zawile, że nie mogę nawet się domyślić jaki był tego cel. Możesz z ciekawości opisać, co Tobą kierowało 😉?

Link do komentarza
Share on other sites

Funkcja main() na mikrokontrolerach to dość ciekawy temat. Zacznijmy od nieco większych systemów, powiedzmy Linuxa, czy Windows. Sygnatura powinna być następującej postaci:

int main(int argc, char* argv)

Parametr argc wskazuje liczbę argumentów wywołania programu, natomiast argv to wskaźniki do parametrów. Tradycyjnie pierwszym jest nazwa programu, kolejne są opcjonalne - pojawiają się jeśli program został wywołany z parametrami.

Program jest wczytywany (np. z dysku) przez system operacyjny, system przygotowuje pamięć oraz proces dla programu, po czym wykonuje skok do funkcji main(). Więc kod funkcji main to pierwsza instrukcja nowo wczytanego programu.

Gdy program się kończy, zwraca on informację do systemu - tradycyjnie 0 oznacza, że program wykonał się prawidłowo, inne wartości oznaczają wystąpienie błędu.

Przed uruchomieniem naszego programu działał już system operacyjny, podobnie po jego zakończeniu system nadal kontroluje pracę komputera.

W przypadku mikrokontrolerów sytuacja jest nieco inna - nie mamy systemu operacyjnego, więc co jest uruchamiane przed naszym programem i co miałoby działać po nim?

Odpowiedź kryje się w pliku startup_stm32f10x_md.S. Zawiera on kod w asemblerze i wspominałem o nim podczas kursu. W rzeczywistości main() wcale nie jest pierwszym kodem, który jest wykonywany po uruchomieniu mikrokontrolera. Nie licząc bootloadera, wykonywanie rozpoczyna się od adresu, który jest zapisany w komórce 0x04.

g_pfnVectors:
.word	_estack
.word	Reset_Handler

Jak widać jest tam adres kodu o etykiecie Reset_Handler. Czyli po uruchomieniu lub resecie, zacznie się wykonywać program:

Reset_Handler:

/* Copy the data segment initializers from flash to SRAM */
 movs	r1, #0
 b	LoopCopyDataInit

Pod koniec tego kodu znajdziemy skok do funkcji main:

/* Call static constructors */
   bl __libc_init_array
/* Call the application's entry point.*/
bl	main
bx	lr

Instrukcja "bl main" to właśnie skok do main(). Nie przekazujemy parametrów, więc nawet gdyby ktoś zadeklarował argc i argv, nie powinien ich używać - znajdą się tam losowe wartości.

Skok bl to tzw. skok ze śladem, więc program może "wrócić" do kolejnej instrukcji. Nie powinno mieć to miejsca, ale jeśli jednak zakończymy naszą funkcję main, to program przejdzie do kolejnej instrukcji, czyli:

bx lr

Co ta instrukcja zrobi? Też wykona skok. Niestety jest niepoprawna - chyba trzeba to będzie zgłosić od OpenSTM32 - mają tutaj najzwyklejszy błąd. Powinna to być pętla nieskończona, a zamiast niej wyszedł skok pod nieco losowy adres.

Prawda jest więc taka - nic nie odczytuje wartości zwracanej z main. Więc czy będzie to int, czy void nie ma różnicy. Nie ma też różnicy jaką wartość byśmy zwrócili.

Natomiast kod powinien być zmieniony na:

b .

Wtedy zamiast nieco losowego zachowania, mielibyśmy nieskończoną pętlę, zaraz "za" funkcją main.

Ale ponieważ main nie powinna się kończyć, wiec nikt na taki błąd uwagi nie zwrócił.

Link do komentarza
Share on other sites

Witam, mam pewien problem, a właściwie pytanie, ale zacznę od początku. Jakiś czas temu gdy zaczynałem z STM(właściwie nadal zaczynam), zainstalowałem sobie eclipse, zgodnie z poradnikiem frediegochoppina, może ktoś zna, ale potem znalazłem te gotowe oprogramowanie, które pokazujecie w tym kursie, więc przeszedłem na nie.

W obu wersjach pojawiał się ten sam problem, gdy próbowałem kompilować kod

Co prawda znalazłem w internecie rozwiązanie- w opcjach projektu w zakładce c/c++ build, musiałem zmienić opcje buldier type z external buldier na internal buldier i wtedy było wszystko ok, myślałem że to coś normalnego, ale widzę, że w kursie nie ma o tym mowy, więc pewnie zrobiłem coś źle, podpowie ktoś co?

Link do komentarza
Share on other sites

Prawdopodobnie zainstalowałeś wcześniej kompilator gcc dla arm-ów. I ta wersja jak widać nie bardzo działa. Jeśli instalujesz OpenSTM32 - środowisko instaluje się z kompilatorem, dlatego po zmianie external (zainstalowany wcześniej), na internal (dostarczony z OpenSTM) zaczęło działać. Tak mi się wydaje, bo w sumie ciężko powiedzieć... Spróbuj odinstalować gcc, które zinstalowałeś wcześniej - powinno pomóc.

Link do komentarza
Share on other sites

Wiem wiem, niepotrzebnie przekombinowane z zerowaniem zmiennej

Racja, przyznam, że zrobiłeś to tak zawile, że nie mogę nawet się domyślić jaki był tego cel. Możesz z ciekawości opisać, co Tobą kierowało 😉?

Lenistwo 😉 Skoro miałem już pętle for() to zapisałem w niej warunek na zerowanie zmiennej która była iteratorem tejże pętli. To samo można uzyskać w zasadzie dla fora bez wypełnionych pól ale mogłem dzięki temu obserwować inkrementowaną i zerowaną zmienną(debuger).

Co do omawianego wątku z funkcją main() i zwracaniem wartości to doskonale rozumiem o co chodzi bo na studiach mam programowanie w C++ aczkolwiek dalej nie rozumiem dlaczego funkcja main() posiada typ zwracany int a nie void skoro i tak nie zwraca zadnej wartości.

Skoro nie zwraca to niech będzie void 🙂

Link do komentarza
Share on other sites

int jest zwracany dla zachowania zgodności ze standardem. Taką sygnaturę generuje domyślnie środowisko OpenSTM32 i taka dla naszych potrzeb jest całkiem dobra.

Natomiast co do main() to nie jest zwykła funkcja. Jest traktowana w specjalny sposób - po pierwsze jest wymagana jako start programu, po drugie return 0 jest przez C++ automatycznie dodawane. Więc nie ma co nad tym int-em dyskutować.

Tylko trzeba pamiętać, żeby na mikrokontrolerach z niej nie wychodzić - to nie jest zwykła funkcja.

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.