Wpis z mikrobloga

Mirki mam dziwny problem. Kod po otrzymaniu danych przez UART ma je odesłać. Przygotowałem dwie wersje kodu:
- wersja 1 - w main wołam serverrun(), który posiada swoją nieskończoną pętlę.
- wersja 2 - w main w pętli wołam funkcję server
task(), która sprawdza warunek, jeżeli spełniony to odsyła dane. Jedyna różnica co do funkcji server_run() to taka, że tutaj nie ma pętli nieskończonej.

Zresztą zobaczcie sami, kod jest bardzo prosty.

Wersja 1 -> klik
Wersja 2 -> klik

Wersja 2 działa - dane są odsyłane, wersja 1 nie działa, dane nie są wysyłane. O co może chodzić?
MCU STM32F103, g++ 8.2.

#programowanie #embedded #mikrokontrolery
  • 33
Wygląda chyba na jakiś race condition i jak o tym myślę to faktycznie może tak przecież być.

Zmiana kodus serverrun na:

void server_run()
{
while(true)
{
cm_disable_interrupts();
size_t s = read_rb.capacity();
cm_enable_interrupts();
if (s >= 64)
{
while (read_rb.capacity() != 0)
{
write_rb.write(read_rb.read());
}
sendData();
}
}
}

naprawia działanie wersji pierwszej, Muszę to przeanalizowac, gdyż to rozwiązanie zostało napisane dość 'na szybko' aby coś sprawdzić.
@bielu000: kod wygląda w porządku. Trzeba jednak wrócić do debugera i wszystko posprawdzać. Ustawić breakpoint na usart1isr(), sprawdzić wykonując krokowo czy wchodzi do readData() jak wyślesz jeden bajt. Jeśli tak, to wejść i śledzić dalej, wejść do readrb.write(), sprawdzić wartość zmiennej capacity, sprawdzić czy jest inkrementowana, jaka jest końcowa wartość. Następnie ustawić breakpoint na linii if (readrb.capacity() >= 64). Jak załapie, to wejść do metody capacity(), sprawdzić
@zarowka12: Tak sprawdzę to jeszcze raz, tylko używając bezpośrednio GDB, bo akutalnie korzystam z VSCdeo i pluginu Cortex-M Debug. Nie miałem z nim póki co problemu, aczkolwiek w tym NIEdziałającym przypadku - sytuacja się trochę zmieniła, bo mimo, że stawiam breakpoint na wywołaniu capacity(), w momencie wysłania danych z PC, owszem breakpoint jest łapany przez debugger, ale przerzuca mnie do usart1_isr(), gdzie w ogóle breakpointa nie mam. Dodatkowo wyłączenie przerwań -
@bielu000: dobrze byłoby ogarnąć debugowanie, nawet za cenę zmiany IDE. Może też być tak, że kompilujesz z mocną optymizacją, np. -O3 i debuger się gubi, zmień na -O0.
Co do przerwań, to możesz inkrementować zmienną w usart1_isr i w ten sposób sprawdzić ile razy było przerwanie wywołane. Zmienna musi być volatile.
@zarowka12: Interesujące, w read_rb, mam capacity = 64 bajty, czyli otrzymane dane faktycznie wleciały do bufora. W związku z tym powineinem wejść w blok ifa, ale nie wchodzę. Próbowałem innych warunków typu >=, lub 54 zamiast 64 i nic. Inwestyguję dalej.
@bielu000: Co ciekawe w takiej formie funkcja działa:

void server_run()
{
while(true)
{
if (read_rb.capacity() == 64)
{
// while (read_rb.capacity() != 0)
// {
// write_rb.write(read_rb.read());
// }
sendData();
}
}
}

Dane są wpisane do bufora gdzieś u góry w inicie. Raz na stałe.
@zarowka12: Zgadza się, kiedy chcę odesłać dane z powrotem, nic już do tego bufora nie jest ładowane, więc też mi to nie pasuje. Kompiluję z -O0 więc raczej żądnych agresywnych optymalizacji nie ma.
ale ten drugi breakpoint (x = 100), nie jest łapany


@bielu000: a co z pracą krokową (Step Over)? Jak się zatrzyma na linii 80, to klikając Step Over, czy jak to się nazywa w Code, nie wchodzi do linii 82?
@zarowka12: Niestety nie. W ogóle jakby nie chciał wskoczyć do tego bloku. Jutro jeszcze to sparwdzę bezpośrednio w gdb i rzuce okiem na assembly, choć wątpię, że będzie tam coś ciekawego. Jak dla mnie bardzo dziwna sprawa. Jak wspomniałem wcześniej - jeżeli dane wpiszę na stałe do bufora, np. w wywołaniu serverinit(), to po otrzymaniu 64 bajtów, dane odsyłane są bez problemu (oczywiście te zahardcodowane), bo w tym przypadku nie