Апрацоўка перапыненняў ў мікракантролерах і FSM прыклад

першапачатковы пытанне

У мяне ёсць агульнае пытанне аб апрацоўцы перапыненняў у мікракантролерах. Я выкарыстоўваю MSP430, але я думаю, што пытанне можа быць распаўсюджаны і на іншыя UCS. Я хацеў бы ведаць, ці з'яўляецца ці не вельмі добрая практыка, каб уключыць/адключыць перапынення часта па кодзе. Я маю на ўвазе, калі ў мяне ёсць частка коды, якая не збіраецца быць адчувальнымі да перапыненняў (ці яшчэ горш, не павінна слухаць перапынення, па якой-небудзь прычыне), што лепш:

  • Адключыць перапынення да і затым зноў уключыць іх пасля крытычнай секцыі.
  • Пастаўце сцяжок ў адпаведным ISR і (замест таго, каб адключыць перапыненне), усталюйце сцяг у хлусня да крытычнай секцыі і скінуць яго праўду, толькі пасля. Для таго, каб прадухіліць код ISR ад выконваецца.
  • Ні адзін з гэтых двух, так прапановы вітаюцца!

Абнаўленне: перапынення і дыяграма станаў

Я падам канкрэтную сітуацыю. Давайце выкажам здагадку, што мы хочам рэалізаваць дзяржаўную схему, якая складаецца з 4-х блокаў:

    <�Літый> Пераходы/Эфект.
  1. ўмовы выхаду.
  2. запіс актыўнасці.
  3. Ці ёсць дзейнасць.

Гэта тое, што прафесар вучыў нас ва універсітэце. Магчыма, не самы лепшы спосаб зрабіць гэта, вынікаючы гэтай схеме:

while(true) {

  /* Transitions/Effects */
  //----------------------------------------------------------------------
  next_state = current_state;

  switch (current_state)
  {
    case STATE_A:
      if(EVENT1) {next_state = STATE_C}
      if(d == THRESHOLD) {next_state = STATE_D; a++}
      break;
    case STATE_B:
     //transitions and effects
      break;
    (...)
  }

  /* Exit activity -> only performed if I leave the state for a new one */
  //----------------------------------------------------------------------
  if (next_state != current_state)
  {
    switch(current_state)
    {
      case STATE_A:
       //Exit activity of STATE_A
        break;
      case STATE_B:
       //Exit activity of STATE_B
        break;
        (...)
    }
  }

  /* Entry activity -> only performed the 1st time I enter a state */
  //----------------------------------------------------------------------
  if (next_state != current_state)
  {
    switch(next_state)
    {
      case STATE_A:
       //Entry activity of STATE_A
        break;
      case STATE_B:
       //Entry activity of STATE_B
        break;
      (...)
    }
  }

  current_state = next_state;

  /* Do activity */
  //----------------------------------------------------------------------
  switch (current_state)
  {
    case STATE_A:
     //Do activity of STATE_A
      break;
    case STATE_B:
     //Do activity of STATE_B
      break;
    (...)
  }
}

Выкажам здагадку таксама, што з, скажам, STATE_A , я хачу, каб быць адчувальным да перапынення надыходзячым з набору кнопак (з сістэмай debouce і г.д. і да т.п.). Калі хто-то націскае на адну з гэтых кнопак, генеруецца перапыненне і сцяг звязаны з уваходным портам капіюецца ў зменную buttonPressed . Калі бразгату усталяваны на 200 мс нейкім чынам (вартавы таймер, таймер, лічыльнік, ...), мы ўпэўненыя, што buttonPressed не можа быць абноўлена з новым значэннем да 200 мс. Гэта тое, што я прашу вас (і я :) вядома)

Ці павінен я ўключыць перапыненне у дзейнасці DO з STATE_A і адключыць перад ад'ездам?

/* Do activity */
//-------------------------------------
switch (current_state)
{
  case STATE_A:
   //Do activity of STATE_A
    Enable_ButtonsInterrupt();//and clear flags before it
   //Do fancy stuff and ...
   //... wait until a button is pressed (e.g. LPM3 of the MSP430)
   //Here I have my buttonPressed flag ready!
    Disable_ButtonsInterrupt();
    break;
  case STATE_B:
   //Do activity of STATE_B
    break;
  (...)
}

У пэўным сэнсе, што я ўпэўнены, што ў наступны раз, калі я execxute блок 1 (пераходныя/эфекты) на наступным ітэрацыі я ўпэўнены, што ўмовы правяраюцца па пераходах не зыходзіць ад наступнага перапынення, які перазапісвальны папярэдняе значэнне <�код > buttonPressed , што мне трэба (хоць гэта немагчыма, што гэта адбываецца з-за 250 мс павінны прайсці).

10
Гэта цяжка зрабіць рэкамендацыю, не ведаючы больш аб вашай сітуацыі. Але часам яго трэба адключыць перапынення ва ўбудавальных сістэмах. Гэта пераважней трымаць перапыненне адключаная на працягу кароткіх перыядаў часу, так што перапынення не прапусцілі. Можа быць, можна адключыць толькі пэўныя перапынення, а не ўсе перапынення. Я не памятаю, калі-небудзь з выкарыстаннем метаду сцяга унутры-ISR, як вы апісалі, так што я сумняваюся, што будзь лепшае рашэнне.
дададзена аўтар Bevan, крыніца

5 адказы

Першая тактыка архітэктара агульная прашыўка, так што гэта нармальна для перапынення адбыцца ў любы час. Маючы адключыць перапынення, так што на першы план код можа выканаць атамарным паслядоўнасць павінна быць зроблена эканомна. Існуе часта архітэктурны шлях вакол яго.

Тым не менш, машына павінна служыць вам, а не наадварот. Агульныя правілы эмпірычнага толькі трымаць дрэнныя праграміст пісаць сапраўды дрэнны код. Гэта значна лепш <�я> разумею </я> дакладна, як працуе машына, а затым архітэктар добры спосаб, каб выкарыстоўваць гэтыя магчымасці для выканання патрабаванай задачы.

Майце на ўвазе, што калі вы сапраўды не зацягнуты на цыклах або вочках памяці (можа, вядома, здарыцца), што ў адваротным выпадку вы хочаце аптымізаваць для яснасці і рамонтапрыдатнасць кода. Напрыклад, калі ў вас ёсць 16 бітнай машыне, якая абнаўляе 32-бітны лічыльнік ў перапыненні кляшча, вам неабходна пераканацца, што, калі на першы план код счытвае лічыльнік, што дзве паловы гэтага з'яўляюцца паслядоўнымі. Адзін са спосабаў, каб адключыць перапынення, прачытаць два словы, а затым уключыце перапынення назад. Калі затрымка перапынення не мае вырашальнага значэння, то гэта цалкам прымальна.

У тым выпадку, калі вы павінны мець нізкі latentcy перапынення, вы можаце, напрыклад, чытаць высокае слова, прачытаць малодшае слова, чытаць старэйшае слова зноў і паўтарыць, калі ён змяніўся. Гэта запавольвае пярэдні план кода трохі, але не дадае затрымак перапынення на ўсіх. Ёсць розныя маленькія хітрасці. Іншы можа быць, каб усталяваць сцяг у перапынення, які паказвае, лічыльнік павінен быць павялічаны, то зрабіць гэта ў галоўным цыкле апрацоўкі падзей на пярэднім плане кода. Гэта выдатна працуе, калі лічыльнік перапыненняў хуткасць досыць павольна, так што цыкл падзей будзе рабіць прырашчэнне перад сцяг усталяваны зноў.

Ці, замест таго, каб сцяг выкарыстоўваць адно слова лічыльнік. Прыярытэтны код захоўвае асобную зменную, якая змяшчае апошні лічыльнік яна абнавіла сістэму. Гэта робіць непадпісаныя адняць з жывога лічыльніка мінус захаванага значэння, каб вызначыць, колькі кляшчоў у той час, ён павінен справіцца. Гэта дазваляе на першым плане код прапусціць да 2 N -1 падзей у той час, дзе N ёсць лік бітаў у роднае слова АЛУ можа апрацоўваць атамарна.

Кожны метад мае свой уласны набор пераваг і недахопаў. Там няма ні аднаго правільнага адказу. Зноў жа, <�я> разумею </я> як машына працуе, то вам не патрэбныя правілы вялікага пальца.

18
дададзена

Калі вам патрэбен крытычны раздзел, вы павінны пераканацца, што аперацыя ахоўваючы ваш крытычны раздзел атамная і не можа быць перапыненая.

Такім чынам, адключэнне перапыненняў, якія часцей за ўсё апрацоўваюцца з дапамогай адной каманды працэсара (і званых з дапамогай кампілятара характарыстычнай функцыі), з'яўляецца адным з самых бяспечных ставак, якія вы можаце зрабіць.

У залежнасці ад сістэмы, могуць быць некаторыя праблемы з тым, як перапыненне можа атрымаць прапусцілі. Некаторыя мікракантролеры усталёўваюць сцягі, незалежна ад стану глабальнага дазволу перапыненняў, а пасля выхаду з крытычнай секцыі перапынення атрымаць выкананы і толькі з затрымкай. Але калі ў вас ёсць перапыненне, якое адбываецца пры высокай хуткасці, вы можаце прапусціць другі раз адбылося перапыненне, калі вы будзеце блакаваць перапынення на працягу занадта доўгага часу.

Калі крытычная секцыя патрабуе толькі адзін перапынення не будзе выкананы, але іншыя павінны быць выкананы, іншы падыход, як уяўляецца жыццяздольным.

Я лічу сябе праграмаваннем падпраграмы абслугоўвання перапыненняў як мага карацей. Такім чынам, яны проста ўсталяваць сцяг, які затым правяраецца пры нармальных стандартных праграм. Але калі вы зробіце гэта, сцеражыцеся умоў гонкі, чакаючы, што сцяг павінен быць усталяваны.

Ёсць шмат варыянтаў, і, вядома, не адзін правільны адказ на гэтае пытанне, гэта тэма, якая патрабуе дбайнай прапрацоўкі і заслугоўвае трохі больш, чым думкі іншых рэчаў.

7
дададзена

Калі вы вызначылі, што частка кода павінна працаваць бесперабойна, то, за выключэннем асаблівых абставін, вы павінны адключыць перапынення для мінімальнай працягласці магчымага для выканання гэтай задачы, і паўторна ўключыць іх пасля.

<�Р> Пастаўце сцяжок ў адпаведным ISR і (замест таго, каб адключыць перапыненне), усталюйце сцяг у хлусня да крытычнай секцыі і скінуць яго праўду, толькі пасля. Для таго, каб прадухіліць код ISR ад выконваецца.

Гэта будзе па-ранейшаму дазваляе перапыненне адбудзецца, кодавы скачок, чэк, а затым вяртанне. Калі ваш код можа справіцца з гэтым шмат перапынкаў, то вы, верагодна, варта проста спраектаваць ISR ўсталяваць сцяг замест выканання праверкі - гэта было б карацей - і апрацоўваць сцяг у вашым звычайным кодзе руціна. Гэта гучыць, як хто-то паклаў занадта шмат коды ў перапыненне, і яны выкарыстоўваюць перапынення для выканання працяглых дзеянняў, якія павінны мець месца ў рэгулярным кодзе.

Калі вы маеце справу з кодам, дзе перапынення доўгія, сцяг, як вы прапануеце можа вырашыць гэтую праблему, але яна ўсё роўна будзе лепш проста адключыць перапынення, калі вы не можаце перароблены код для ліквідацыі празмернага кода перапынення ,

Асноўная праблема з рабіць гэта так, як сцяг, што вы не выконваюць перапыненне наогул - што можа мець наступствы пазней. Большасць microcontrolers будзе адсочваць перапынення сцягі нават падчас перапынення адключаныя ва ўсім свеце, а затым выканаць перапыненне пры паўторным уключэнні перапынення:

    <�Літый> Калі перапынення не адбылося ў крытычнай секцыі, ні адзін не выконваюцца пасля. <�Літый> Калі ўзнікае адно перапыненне падчас крытычнай секцыі, адзін выконваецца пасля. <�Літый> Калі некалькі перапыненняў адбываюцца падчас крытычнай секцыі, толькі адзін выконваецца пасля.

Калі ваша сістэма з'яўляецца складанай і адсочваць перапынення больш поўна, вы будзеце павінны распрацаваць больш складаную сістэму адсочвання перапыненняў і дзейнічаць адпаведным чынам.

Тым не менш, калі вы заўсёды ствараць свае перапынення для выканання мінімальнай працы, неабходнай для дасягнення сваёй функцыі, і адкласці ўсё астатняе на рэгулярную апрацоўку, то перабівае рэдка ўплывае на ваш іншы код адмоўна. Ёсць захоп перапынення або вызваліць дадзеныя, калі гэта неабходна, альбо ўсталявання/скід выхадаў, і г.д., як гэта неабходна, то ёсць асноўны код шляху звярніце ўвагу на сцягі, буфера і зменныя перапынення ўплываюць так працяглая апрацоўка можа быць зроблена ў асноўным цыкле, а не перапынення.

Гэта павінна ліквідаваць усе, але вельмі, вельмі нешматлікіх сітуацый, калі вам можа спатрэбіцца бесперапынны раздзел кода.

5
дададзена
У вашым прыкладзе кода, я б разгледзець магчымасць адключыць канкрэтнае перапыненне кнопкі, калі не патрабуецца, і ўключыць яго ў выпадку неабходнасці. Рабіць гэта часта не з'яўляецца пытаннем яго дызайн. Пакіньце глабальныя перапынення на так што вы можаце дадаць іншыя перапынення да кода пазней, калі гэта неабходна. З іншага боку, проста скінуць сцяг, калі вы ідзяце ў стан А і ў адваротным выпадку яго ігнараваць. Калі кнопка націснутая і сцяг усталяваны, хто клапоціцца? Ігнаруйце яго, пакуль вы не вернецеся ў стан A.
дададзена аўтар Federico Builes, крыніца
Я абнавіў свой пост, каб лепш растлумачыць сітуацыю я працую ў :)
дададзена аўтар zardilior, крыніца
Да! Гэта можа быць рашэннем, таму што ў рэальнай канструкцыі я часта ездзіце ў LPM3 (MSP430) з глабальнымі перапыненнямі і I выхадам з LPM3, аднавіць выкананне, як толькі выяўляецца перапыненне. Такім чынам, рашэнне з'яўляецца той, які вы прадставілі, якія я думаю, паведамляецца ў другой частцы кода: дазволіць перапынення, як толькі я пачынаю выконваць рабіць дзейнасці дзяржавы, якое мае патрэбу ў ёй і адключыць перад пераходам да пераходаў блакавальных. Можа іншы магчымае рашэнне будзе адключыць перапыненне толькі перш чым пакінуць «Do блок дзейнасці» і паўторна ўключыць некаторы час (калі?) Пасля таго, як?
дададзена аўтар zardilior, крыніца

Паставіўшы сцяг ўнутры ISR, як вы апісваеце, верагодна, не будзе працаваць, так як вы ў асноўным ігнаруюць падзея, якая выклікала перапыненне. Адключэнне перапыненняў ва ўсім свеце, як правіла, з'яўляецца лепшым выбарам. Як ужо сказаў, вы не павінны рабіць гэта вельмі часта. Майце на ўвазе, што любое чытанне або запіс, што робіцца з дапамогай адной інструкцыі не павінны быць абаронены, так як каманда альбо выконваецца, альбо няма.

Шмат што залежыць ад таго, якія рэсурсы вы спрабуеце падзяліць. Калі вы харчуецеся дадзеныя з ISR ў асноўнай праграме (ці наадварот), вы маглі б рэалізаваць нешта накшталт буфера FIFO. Толькі атамарнага аперацыя будзе абнавіўшы чытання і запісы паказальнікаў, што зводзіць да мінімуму колькасць часу, якое вы праводзіце з перапыненнямі, адключанымі.

1
дададзена

Існуе тонкае адрозненне вам трэба прыняць да ўвагі. Вы можаце выбраць для «затрымкі» пры апрацоўцы перапынення або «ігнараванне» і перапыненне.

Часта мы кажам, у кодзе, які мы адключыць перапыненне. Што, верагодна, будзе адбывацца з-за апаратныя функцыі, з'яўляецца тое, што калі-то мы дазваляем перапынення гэта спрацуе. Гэта такім чынам затрымлівае перапыненне. Для таго, каб сістэма надзейна працаваць, мы павінны ведаць максімальны час мы можам адкласці апрацоўку гэтых перапыненняў. А затым пераканацца, што ўсе выпадкі, калі перапынення адключаныя будуць завершаны ў больш кароткія тэрміны.

Часам мы хочам ігнараваць перапынення. Лепшы спосаб можа быць, каб заблакаваць перапыненне на апаратным узроўні. Там часта з'яўляецца кантролер перапыненняў ці аналагічны, дзе мы маглі б сказаць, якія ўваходы павінны генераваць перапынення.

0
дададзена