SWD debuginimas revisited

Posted: 2016-02-16 in Darbeliai
Žymos:, ,

Kažkada čia rašiau, kaip išjungti JTAG debuginimą paliekant SWD. Viskas kaip ir gražu ir paprasta, dvi funkcijikes iškviečiam ir pamirštam. Deja, išskyrus tai, kad tos funkcijikės iš STM32 sukurto rinkinuko Standard Peripherals. Visokios tos funkcijikės ganėtinai gremėzdiškos, su visokiais assertais ir pan. Na, assertus galima išjungti, bet vis tiek perteklinio kodo yra žiauriai daug. Na, kažkas panašaus į Arduino.

Aš pats truputuką iš tingėjimo dažniausiai su Standard Peripherals pasidarau visokias inicializacijas, susijunginėju laikrodukus, GPIO, laikmačius ir panašiai. Na, ir JTAG/SWD taip pat. Bet kai reikia vartyti GPIO bitukus ar per USARTą juos siųsti, aš paprastai lendu į SP kodą ir išsitraukiu iš ten reikalingus pažongliravimus registrais. Gaila be reikalo švaistomos atminties.

Bet va, tam JTAG išjungimui su SWD palikimu pagalvojau irgi: operacija atliekama vieną kartą. SP tikrai bus kažko privelta, gal pasižiūrėsiu, ar neverta persidaryti į kokį makrosą.

Pasirodė, kad verta ir dar labai…

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

Šitos SP funkcijos padaro, ką reikia. Pirmoji įjungia AFIO, be kurio elektrodų paskirties keitimas neįmanomas, o antroji kažkur ten AFIO registruose kažką pakeičia pagal poreikį.

RCC įjungimas persirašo gan paprastai, ten kodo nedaug. Tai va pora makrosų:

#define AFIO_ENABLE RCC->APB2ENR |= RCC_APB2RSTR_AFIORST;
#define AFIO_DISABLE RCC->APB2ENR &= ~RCC_APB2RSTR_AFIORST;

Čia konstantos iš CMSIS, be SP. Viskas paprasta ir aišku, APB2ENR registre pakeičiam tik vieną bituką.

Na, o dabar reikia pasižiūrėti, kas gi yra GPIO_PinRemapConfig funkcijoje. O ten yra bile kiek nereikalingo kodo, keistų konstantų ir dar visokios velniavos. Ji padaryta labai labai universali, kad programuotojas galėtų nesukti galvos, kurį iš dviejų AFIO elektrodų perjungimo registrų naudoti (MAPR ar MAPR2), kurią ten funkciją įjungti/išjungti ir panašiai. Na, ir dar viską pasideda į laikinus kintamukus. Pabandykite čia atsekti kelią, blė, kaip išjungiamas JTAG, bet įjungiamas SWD, atsiverskite stm32f10x_gpio.c failiuką:

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
{
  uint32_t tmp = 0x00, tmp1 = 0x00, tmpreg = 0x00, tmpmask = 0x00;

  /* Check the parameters */
  assert_param(IS_GPIO_REMAP(GPIO_Remap));
  assert_param(IS_FUNCTIONAL_STATE(NewState));  
  
  if((GPIO_Remap & 0x80000000) == 0x80000000)
  {
    tmpreg = AFIO->MAPR2;
  }
  else
  {
    tmpreg = AFIO->MAPR;
  }

  tmpmask = (GPIO_Remap & DBGAFR_POSITION_MASK) >> 0x10;
  tmp = GPIO_Remap & LSB_MASK;

  if ((GPIO_Remap & (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK)) == (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK))
  {
    tmpreg &= DBGAFR_SWJCFG_MASK;
    AFIO->MAPR &= DBGAFR_SWJCFG_MASK;
  }
  else if ((GPIO_Remap & DBGAFR_NUMBITS_MASK) == DBGAFR_NUMBITS_MASK)
  {
    tmp1 = ((uint32_t)0x03) << tmpmask;
    tmpreg &= ~tmp1;
    tmpreg |= ~DBGAFR_SWJCFG_MASK;
  }
  else
  {
    tmpreg &= ~(tmp << ((GPIO_Remap >> 0x15)*0x10));
    tmpreg |= ~DBGAFR_SWJCFG_MASK;
  }

  if (NewState != DISABLE)
  {
    tmpreg |= (tmp << ((GPIO_Remap >> 0x15)*0x10));
  }

  if((GPIO_Remap & 0x80000000) == 0x80000000)
  {
    AFIO->MAPR2 = tmpreg;
  }
  else
  {
    AFIO->MAPR = tmpreg;
  }  
}

Na, aš suprantu, kad patogu tokias funkcijas naudoti. Bet pagalvokim iš kitos pusės: tas JTAG off/SWD on yra labai kasdieniškas daiktas. Praktiškai kiekviename projekte reikalingas, ypač su mažučiais devboardukais. Jie, be abejo, veikia ir su įjungtu JTAG, kuris protokolas naudojamas, priklauso nuo gdb serverio. Bet juk norisi atlaisvinti nenaudojamus elektrodus savo reikmėms. Ir vien dėl to naudoti va tokį gargarą, kurio sėkmingam darbui reikia šešių konstantų, kelių kintamųjų ir dar krūvos if/else? Nu negali būti taip sudėtinga, einam rūkyt datašyto.

Dar, tiesa, ta funkcija ir su bugu:

    tmpreg &= DBGAFR_SWJCFG_MASK;
    AFIO->MAPR &= DBGAFR_SWJCFG_MASK;

tmpreg kintamasis yra skirtas išsaugoti einamąją MAPR (arba MAPR2) reikšmę. A tai nafig tada šitoj vietoj keičiamas ir tmpreg, ir pats registras? 🙂 Niekuo negalima pasitikėti…

Grįžtam prie datašyto. O datašyte apie JTAG/SWD va šviečia toks tekstukas:

JTAG disable SWD enable, AFIO MAPR registras, STM32F10x | Darau, blė

Nu va, viskas aišku. Kažkur, AFIO MAPR registre yra trys bitukai, SWJ_CFG[2:0], kuriuos keičiant galima pakeisti ir debuginimo elgesį. Jei pasiliekam tik SWD, tuos bitukus reikia nustatyti į 010 (dvejetainiu kodavimu). Ok, dabar žiūrom, kaip atrodo to registro sudėtis:

AFIO MAPR registras STM32F10x | Darau, blė

Vuolia, bitukai [26:24] yra tie, kurių mums reikia. Teoriškai, žinant, kad standartiškai yra įjungtas SWD, galima būtų iškarto paorinti 010 reikšmę į registrą ir palikti. Bet praktiškai dėl visa ko reikėtų tuos bitukus pirma išvalyti, o paskui įrašyti, kas reikia. Na ir va, pora konstantų, makrosas:

#define SWJ_CLEAR ((uint32_t)0xF8FFFFFF)
#define JTAG_OFF_SWD_ON ((uint32_t)0x02000000)

#define REMAP_SWJ_JTAGDISABLE \
	AFIO->MAPR &= SWJ_CLEAR; \
	AFIO->MAPR |= JTAG_OFF_SWD_ON;

Na, manau, viskas aišku. SWJ_CLEAR konstanta yra su visais vienetukais išskyrus SWJ_CFG bitukus. Na, o konstanta JTAG_OFF_SWD_ON atitinkamai yra vienetukas 25 bite (2²⁵). Pirma komanda SWJ_CFG išvalom, antra — nustatom, ko norim. Viskas paprasta, gargaro nereikia. Trys paprasti priskyrimai vietoj krūvos Standard Peripherals bibliotekoj. Imkitės ir naudokitės, jei reikia. Ir visada kapstykite giliau 🙂

Su Lietuvos gimtadieniu jumi taip pat.

Parašykite komentarą

Įveskite savo duomenis žemiau arba prisijunkite per socialinį tinklą:

WordPress.com Logo

Jūs komentuojate naudodamiesi savo WordPress.com paskyra. Atsijungti /  Pakeisti )

Google photo

Jūs komentuojate naudodamiesi savo Google paskyra. Atsijungti /  Pakeisti )

Twitter picture

Jūs komentuojate naudodamiesi savo Twitter paskyra. Atsijungti /  Pakeisti )

Facebook photo

Jūs komentuojate naudodamiesi savo Facebook paskyra. Atsijungti /  Pakeisti )

Connecting to %s

Brukalų kiekiui sumažinti šis tinklalapis naudoja Akismet. Sužinokite, kaip apdorojami Jūsų komentarų duomenys.