Timer overflow event -> zamrzne delovanje MCU-ja

Vse kar je v povezavi z ARM-Cotrex-M procesorji. Sem spada tako HW kot SW.

Moderator: tilz0R

Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a NacMan » 14 Avg 2024, 17:24

Dev board: STM Nucleo F103RB

Za potrebo delay check funkcije in ms takta, uporabljam CNT register timerja TIM1.

Vse deluje kot pričakovano, vendar ko counter/timer doseže max 16-bit vrednost CNT registra (oz nastavljeno vrednost htim1.Init.Period) se izvajanje programa ustavi oz zamrzne.

Vrednost CNT registra spremljam preko print funkcije (lwprintf ->Tilz0r).
Z uporabo delay check funkcije pa zraven še toggle-am LED.

V trenutnku overflow/auto reload eventa se oboje ustavi.

TIM1 init koda:
Koda: Izberi vse
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 63999;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 


Branje CNT vrednosti:

Koda: Izberi vse
uint16_t tim1_cnt_reg()
{
  uint16_t current_millis = TIM1->CNT;
  return current_millis;
}


Po določenem času neodzivnosti se vrednosti števca ponovno začenjo printati, vendar so takrat vrednosti okoli 30000(v primeru da šteje do max 16-bit vrednosti).
Na prvi pogled števec še vedno šteje v ozadju, ostalo pa "zamrzne" za določen čas po overflow dogodku.
NacMan
 
Prispevkov: 79
Pridružen: 23 Jan 2015, 09:53
Zahvalil se je: 36 krat
Prejel zahvalo: 24 krat
Uporabnika povabil: Kroko
Število neizkoriščenih povabil: 5

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a tilz0R » 14 Avg 2024, 18:50

Ali kje castaš uint32_t variable z 16-bitih? Verjetno...

mogoče te je "potopil" wider width tipa pri primerjanju vrednosti.

Pojdi v debug, pokaži kodo okoli, kjer se to zgodi.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 2344
Pridružen: 17 Jan 2015, 23:12
Kraj: Črnomelj
Zahvalil se je: 260 krat
Prejel zahvalo: 745 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a NacMan » 16 Avg 2024, 12:20

"Težavo" povzroča lwbtn_process_ex() funkcija. Vendar le v primeru ko za ms takt uporabim svojo funkcijo tim1_cnt_reg() oz vrednost CNT registra(16-bit).
lwbtn_process_ex() prejme/pričakuje argument mstime ki potrebuje biti 32-bit. Tako da v primeru ko uporabim HAL_GetTick() kot source ms takta, problem izgine.

lwbtn_process_ex() funkcija zaškripa ko vrednost ms takta ni večja od 16_bit vrednosti...

Wiki lwbtn knjižnice:
https://docs.majerle.eu/projects/lwbtn/en/latest/
Zadnjič spremenil NacMan, dne 16 Avg 2024, 12:31, skupaj popravljeno 1 krat.
NacMan
 
Prispevkov: 79
Pridružen: 23 Jan 2015, 09:53
Zahvalil se je: 36 krat
Prejel zahvalo: 24 krat
Uporabnika povabil: Kroko
Število neizkoriščenih povabil: 5

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a tilz0R » 16 Avg 2024, 12:29

Smiselno. Timer imaš 16 bitni, ki gre na 0 pri 65535, logika pa dela na 32-bitih.

HAL_GetTick poveča tick na vsak interrupt sistema, tako da vrne vrednost lokalne spremenljivke, ne vrednost timer registra.

Ti potrebuješ 32-bitni timer, ali pa uporabi HAL_GetTick. Ali pa uporabi 16bitni tiker ampak naredi interrupt vsako ms in povečas vrednost v IRQju.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 2344
Pridružen: 17 Jan 2015, 23:12
Kraj: Črnomelj
Zahvalil se je: 260 krat
Prejel zahvalo: 745 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a NacMan » 18 Avg 2024, 18:46

Hvala za vzet čas in ponujene rešitve.
Seveda imam dodatna vprašanja :)

1. Saj tole je lokalna spremenljivka (katera kopira naraščujočo vrednost CNT reg na ms takt) katero vrača funkcija:
Koda: Izberi vse
uint16_t tim1_cnt_reg()
{
  uint16_t current_millis = TIM1->CNT;
  return current_millis;
}


Verjamem da je IRQ pristop bolj higieničen, ampak me zanimajo glavni "downfalls" CNT pristopa.

2. Po vsej logiki bi morala funkcija lwbtn_process_ex() normalno sprejeti tudi 16-bit vrednost...
Lahko razložiš kje misliš da se zatakne?
NacMan
 
Prispevkov: 79
Pridružen: 23 Jan 2015, 09:53
Zahvalil se je: 36 krat
Prejel zahvalo: 24 krat
Uporabnika povabil: Kroko
Število neizkoriščenih povabil: 5

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a tilz0R » 18 Avg 2024, 20:25

Gremo po vrsti.

1. Tvoja funkcija vrne uint16_t, kar pomeni unsigned integer, velikosti 16-bitov. To so HEX vrednosti od 0x0000 do 0xFFFF. Ko vrednost doseže 0xFFFF, bo naslednja povečava te vrednosti naredil "overflow" in bo šla vrednost na 0x0000.
V tvojem primeru tvoja funkcija vrne vrednost registra na mikrokontrolerju. Ta register ima 16 fizičnih D celic, in je 16-biten. Torej, ko pride vrednost do 0xFFFF, bo naslednja vrednost 0x0000.

Downfall CNT pristopa je, da ti CNT ne da vrednosti večje kot 0xFFFF, ki pa jo rabiš, ko delaš z 32-bitnimi spremenljivkami, ki gredo do 0xFFFFFFFF.

2. Pri LwBTN knjižnici je veliko odvisno od časovne enote. V njej so matematična operacije ala trenutni_čas - prejšnji_čas >= maks_razlika_časa, kar pomeni, da primerjamo trenutni čas (ki ga daš kot parameter) z prejšnjim časom, ki si ga knjižnica shrani (to je vrednost, ki si jo dal kot parameter knjižnici ob prejšnjem klicu funkcije).

Unsigned spremenljivke imajo to lepo lastnost, da če ti primerjaš "trenutni - prejšnji", bo rezultat razlika med njima, in to tudi velja, ko so vrednosti tik pri overflow-u. Primer:

Trenutni - Prejšnji = razlika:
- 0xFFFE - 0xFFFD = 1 (razlika med njima je 1, normalna matematika, obe vrednosti sta veliki)
- 0xFFFF - 0xFFFE = 1 (razlika med njima je 1, prvi števec je na najvišji cifri, drugi je eno manj kot najvišja možna cifra)
- 0x0000 - 0xFFFF = 1 (razlika med njima je še vedno 1). V tem primeru je "trenutni" čas že naredil overflow, drugi pa še ne, ampak razlika je še vedno 1.

Analogija s tem bi bila modulus oz. "ostanek pri deljenju".

Kar se zgodi pri tebi, ko imaš 16-bitni števec, je pa to, da ti že res lahko podaš 16-bitno vrednost funkciji, ampak ker funkcija operira z 32-bitnimi številkami, ona pričakuje, da boš podal več kot samo 16-bitov. V tem primeru se dela matematika na 32-bitnem nivoju. Spodnji primer bo sedaj na 32-bitni logiki, kjer je "trenutni" in "prejšnji" čas od tvojega 16-bitnega vnosa.

Trenutni - prejšnji = razlika. Logika je na 32-bitih, ampak vrednosti, ki jih funkcija sprejme, so pa na 16-bitih:

- 0x0000FFFE - 0x0000FFFD = 1 (razlika med njima je 1 - so far so good)
- 0x0000FFFF - 0x0000FFFE = 1 (razlika med njima je še vedno 1 - so far še vedno good)
- 0x00000000 - 0x0000FFFF = koliko ??? Problem tukaj je, da je tvoj parameter 16-bitni, in ko TIM1 doseže 0xFFFF, bo naslednja 0x0000, in to daš funkciji kot parameter. Sedaj pa smo na 32-bitni vrednosti, torej bo overflow po 0xFFFFFFFF, a v našem primeru se je zgodil že po 0x0000FFFF.

Vrednost "trenutni - prejšnji" čas je tukaj enormen, in funkcija misli, da je med dvemi klici minili OGROMNO milisekund, in naredil kar nekaj stvari. In potem se ti logika sesuje.

Spodaj analogija analogne ure, oz. "ostanek pri deljenju".
Posnetek zaslona 2024-08-18 212302.png


Delam repl-it primer.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 2344
Pridružen: 17 Jan 2015, 23:12
Kraj: Črnomelj
Zahvalil se je: 260 krat
Prejel zahvalo: 745 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a tilz0R » 18 Avg 2024, 20:35

Spodnja koda:

Koda: Izberi vse
#include <stdint.h>
#include <stdio.h>

/**
 * Funkcija sprejme in deluje z 32-bitnimi unsigned spremenljivkami.
 * Izpiše razliko med value_current in value_previous.
 */
static void print_difference(uint32_t value_current, uint8_t reset) {
  static uint32_t value_previous = 0;
  if (reset) {
    value_previous = value_current;
  } else {
    printf("Razlika med %08X in %08X je %08X\n", (unsigned)value_current,
           (unsigned)value_previous,
           (unsigned)(value_current - value_previous));
    /* Shrani trenutno vrednost kot prejšnjo za naslednji klic */
    value_previous = value_current;
  }
}

int main(void) {

  /* For zanka, ki bo zunaj delala z 32-bitnimi spremenljivkami */
  printf("32-bit calculations\r\n");
  print_difference(0xFFFFFFFA, 1);
  for (uint32_t value = 0xFFFFFFFB, st_iteracij = 0; st_iteracij < 10;
       ++value, ++st_iteracij) {
    print_difference(value, 0);
  }

  /* For zanka, ki bo zunaj delala z 16-bitnimi spremenljivkami */
  printf("16-bit calculations\r\n");
  print_difference(0xFFFA, 1);
  for (uint16_t value = 0xFFFB, st_iteracij = 0; st_iteracij < 10;
       ++value, ++st_iteracij) {
    print_difference(value, 0);
  }

  return 0;
}


Izpiše tole. Poskrolaj celoten log, boš videl problem

Koda: Izberi vse
32-bit calculations
Razlika med FFFFFFFB in FFFFFFFA je 00000001
Razlika med FFFFFFFC in FFFFFFFB je 00000001
Razlika med FFFFFFFD in FFFFFFFC je 00000001
Razlika med FFFFFFFE in FFFFFFFD je 00000001
Razlika med FFFFFFFF in FFFFFFFE je 00000001
Razlika med 00000000 in FFFFFFFF je 00000001
Razlika med 00000001 in 00000000 je 00000001
Razlika med 00000002 in 00000001 je 00000001
Razlika med 00000003 in 00000002 je 00000001
Razlika med 00000004 in 00000003 je 00000001
16-bit calculations
Razlika med 0000FFFB in 0000FFFA je 00000001
Razlika med 0000FFFC in 0000FFFB je 00000001
Razlika med 0000FFFD in 0000FFFC je 00000001
Razlika med 0000FFFE in 0000FFFD je 00000001
Razlika med 0000FFFF in 0000FFFE je 00000001
Razlika med 00000000 in 0000FFFF je FFFF0001         <<< ------------ tukaj je problem
Razlika med 00000001 in 00000000 je 00000001
Razlika med 00000002 in 00000001 je 00000001
Razlika med 00000003 in 00000002 je 00000001
Razlika med 00000004 in 00000003 je 00000001


https://replit.com/@MaJerle/unsigned1632difference
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 2344
Pridružen: 17 Jan 2015, 23:12
Kraj: Črnomelj
Zahvalil se je: 260 krat
Prejel zahvalo: 745 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a Kroko » 20 Avg 2024, 10:19

Koda: Izberi vse
   if (time >= last)
   {
      if ((time - last) >= delay)
      {
         last = time;
         return true;
      }
   }
   else
   {
      if ((0x0000FFFF - (last - time)) >= delay)
      {
         last = time;
         return true;
      }
   }
   return false;
http://www.planet-cnc.com Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 5983
Pridružen: 14 Jan 2015, 11:12
Kraj: Ljubljana
Zahvalil se je: 764 krat
Prejel zahvalo: 2327 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Timer overflow event -> zamrzne delovanje MCU-ja

OdgovorNapisal/-a NacMan » 21 Avg 2024, 14:34

Hvala za izčrpno in analitično razlago.
16-bit je v bistvu "promoted" v 32-bit in se potem tudi tako obnaša.

Še enkrat hvala za čas in razlage.
NacMan
 
Prispevkov: 79
Pridružen: 23 Jan 2015, 09:53
Zahvalil se je: 36 krat
Prejel zahvalo: 24 krat
Uporabnika povabil: Kroko
Število neizkoriščenih povabil: 5


Vrni se na ARM-Cortex-M

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost