Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Защитени променливи в ембедед програмирането
http://mcu-bg.com/mcu_site/viewtopic.php?f=3&t=3613
Страница 1 от 3

Автор:  Реконструктор [ Пон Яну 22, 2007 10:36 am ]
Заглавие:  Защитени променливи в ембедед програмирането

Възниква следният проблем: основния цикъл на програмата и някакво прекъсване трябва да споделят обща съставна променлива, т.е. такава, която е по-голяма от разредността на ядрото. Например, 32 битова променлива тип long в 8 битов процесор. Задачата за решаване е следната: Основния цикъл започва да работи с тази променлива, например да я копира на друго място, стига до 2-рия байт и в това време се генерира прекъсването, което записва съвсем друга стойност и когато управлението се върне обратно в цикъла, копирането на последните 2 байта създава неприятна боза.
Най-простото нещо, което ползвам (друго не се сетих), е просто да правя полу-семафор и да заключвам променливата, преди да започна да я обработвам. Прекъсването проверява дали е заключена, и ако е, не я пипа. Да, но тук възникват 2 основни момента, за които нямам решение.
1. При неприятно стечение на обстоятелствата, прекъсването може да изпадне в резонанс с основния цикъл и моментът на възникването му да съвпада винаги с момента, в който променливата се обработва и, съответно, е заключена. По този начин променливата никога няма да се опреснява.
2. Ако опресняването е критично, т.е. не можем да пропускаме обработката в прекъсването, то, очевидно заключващия механизъм няма смисъл.
Ще ви бъда благодарен, ако пуснете някакви линкове по въпроса, или споделите нещо, което сте измислили сами. :)

Автор:  evc [ Пон Яну 22, 2007 11:07 am ]
Заглавие:  Re: Защитени променливи в ембедед програмирането

Реконструктор написа:
...Основния цикъл започва да работи с тази променлива, например да я копира на друго място, стига до 2-рия байт и в това време се генерира прекъсването, което записва съвсем друга стойност и когато управлението се върне обратно в цикъла, копирането на последните 2 байта създава неприятна боза...

Отложи (забрани) си прекъсването до края на операцията с тази променлива в основния цикъл. В началото на копирането забраняваш всички прекъсвания, в края на копирането - разрешаваш. Ако по време на обработката възникне irq, веднага след разрешаване на прекъсванията, ще влезеш в обработка. Ако пък е критично прекъсването да се обработи веднага след постъпване на irq, направи си дублираща променлива и в комбинация с флага, който ползваш за "заключване", ще ползваш или едната или другата променлива, в зависимост от състоянието на флага, т.е. нещо като стек.

Автор:  mndsl [ Пон Яну 22, 2007 11:13 am ]
Заглавие: 

Може да направиш обратното. Когато прекъсването опресни променливата да дигне един флаг. В главната програма преди копирането на всеки байт ще проверяваш този флаг и ако установиш, че се е промени по време на копиране връщаш цикъла отначало за да прочете отново всички байтове, като преди това естествено нулираш флага.

Автор:  Реконструктор [ Пон Яну 22, 2007 11:32 am ]
Заглавие:  Re: Защитени променливи в ембедед програмирането

evc написа:
Отложи (забрани) си прекъсването до края на операцията с тази променлива в основния цикъл. В началото на копирането забраняваш всички прекъсвания, в края на копирането - разрешаваш. Ако по време на обработката възникне irq, веднага след разрешаване на прекъсванията, ще влезеш в обработка. Ако пък е критично прекъсването да се обработи веднага след постъпване на irq, направи си дублираща променлива и в комбинация с флага, който ползваш за "заключване", ще ползваш или едната или другата променлива, в зависимост от състоянието на флага, т.е. нещо като стек.


Ами отлагането чисто хардуерно не знам дали е взъможно. В смисъл, в доста от системите, особено тия, дето са само с 1 вектор на прекъсване, май събитието се губи, ако в този момент са ти забранени прекъсванията.
Другото е добро, наистина ще работи, но трябва да има 2 флага - коя променлива е заключена и коя е последно обновена. Ще се усложни обработката, но ще работи (направо ще си трябва библиотека). Мерси! :)

Автор:  Реконструктор [ Пон Яну 22, 2007 11:36 am ]
Заглавие: 

mndsl написа:
Може да направиш обратното. Когато прекъсването опресни променливата да дигне един флаг. В главната програма преди копирането на всеки байт ще проверяваш този флаг и ако установиш, че се е промени по време на копиране връщаш цикъла отначало за да прочете отново всички байтове, като преди това естествено нулираш флага.


Ами това си го мислех, но трябва да си пиша цялата ф-я по прехвърлянето на асм (не съм фен). :)

Автор:  Цецо [ Пон Яну 22, 2007 11:57 am ]
Заглавие: 

Едва ли ще намериш процесор, на който прекъсването да не се "запомня". Това си е стандарт, флага за прекъсване се вдига, даже и прекъсването да е забранено и когато го разрешиш, то се активира "моментало", ако междувременно не си нулирал флага насила.

То това му е и идеята на тоя механизъм, да се "запомнят" прекъсванията и да се обработят, било то и с малко закъснение.

Автор:  Nikola Kirov [ Пон Яну 22, 2007 1:12 pm ]
Заглавие: 

Точно с забраняване на прекъсванията е начина. Не съм имал случай когато забавянето на прекъсването с 4-5 такта да е проблем.

Погледни ако искаш как е в ембедед OS-ите.

там забраняването на прекъсванията е доста често. Много операции се правят точно в такъв режим.

Там механизнма обикновенно е следния

Код:
void vPortEnterCritical( void )
{
   __disable_interrupt();

   /* Now interrupts are disabled ulCriticalNesting can be accessed
   directly.  Increment ulCriticalNesting to keep a count of how many times
   portENTER_CRITICAL() has been called. */
   ulCriticalNesting++;
}

void vPortExitCritical( void )
{
   if( ulCriticalNesting > portNO_CRITICAL_NESTING )
   {
      /* Decrement the nesting count as we are leaving a critical section. */
      ulCriticalNesting--;

      /* If the nesting level has reached zero then interrupts should be
      re-enabled. */
      if( ulCriticalNesting == portNO_CRITICAL_NESTING )
      {
         __enable_interrupt();
      }
   }
}


Това са функциите на freeRtos за забраняване и разрешаване на прекъсванията.

Автор:  bkulev [ Пон Яну 22, 2007 1:14 pm ]
Заглавие: 

Рек има и трети начин - променливата я пипаш само на едно място (ти си реши къде, дали irq или другаде), а в местата където сега я модифицират само даваш заявка(вдигаш флаг).
Ама и това е според зависи... :)

Автор:  Реконструктор [ Пон Яну 22, 2007 1:48 pm ]
Заглавие: 

Nikola Kirov написа:
Там механизнма обикновенно е следния


Да, това си е класически семафор/критична секция. :)
Аз поради няква причина останах с впечатлението, че доста системи не си "помнят" прекъсванията, за това възникна въпроса.

Автор:  plameniv [ Пон Яну 22, 2007 1:53 pm ]
Заглавие:  Hm

Реконструктор написа:
Nikola Kirov написа:
Там механизнма обикновенно е следния


Да, това си е класически семафор/критична секция. :)
Аз поради няква причина останах с впечатлението, че доста системи не си "помнят" прекъсванията, за това възникна въпроса.

Какъв е проблема важния ти цикъл да си работи с 2 променливи негова и друга идваща от прекъсване , просто проверяваш в основния цикъл дали има имат разлика и ако има нужда основния цикъл я променя с новата .
Просто прекъсването винаги ще си пише на 1 място което си е негова променлива а не обща.

Автор:  miro_atc [ Пон Яну 22, 2007 2:22 pm ]
Заглавие: 

Комбинации има много на тая тема... Въпреки че повечето се споменаха ще се пробвам да ги обобщя:

1) Ако бачкаш на С компилатор, повечето имат __monitor опции за функции. Правиш си функциите които четат/пишат защитената променлива с тая опция и оставаш на компилатора да му мисли...

2) Ако нямаш вложени извиквания на критични секции, може просто:

__disable_interrupt();
// бачкаш си защитената променлива
__enable_interrupt();

3) Ако имаш вложени критични секции и битови операции на процесора с достъп до флага за прекъсвания, може по следния начин:

bit old_flag;
old_flag = int_flag;
int_enable_flag = DISABLE;
// бачкаш си защитената променлива
int_enable_flag = old_flag;

4) Друг вариант е да броиш колко пъти си искал да забраниш прекъсванията - както е показал Никола...

5) Когато прекъсването само чете защитената променлива, а отдолу се променя, можеш да направиш две копия на променливата и един флаг който показва кое е валидното копие. В основната програма променяш "невалидното копие" и сменяш флага (с атомична операция). Така никога не забраняваш прекъсванията.

6) Когато само прекъсването пипа променливата, ти трябва едно копие на променливата и един флаг. Просто прекъсването винаги като пипне променливата вдига и флага. Отдолу, за да изчетеше променливата правиш цикъл в който първо сваляш флага, правиш си копие и проверяваш дали междувременно не се е вдигнал флага. Ако се е вдигнал зацикляш, докато успееш да прочетеш без да е имало прекъсване...


7) Ако променливата се променя от много места и не искаш да забраняваш прекъсванията може и по-сложен алгоритъм да се направи. Тук зависи дали имаш атомични операции, примерно на ARM може да нямаш и тогава семафорите стават една красива работа....

Автор:  Ки4о [ Пон Яну 22, 2007 4:01 pm ]
Заглавие: 

Рек това което казваш ти но използваш приоритетни прекъсвания - прекъсването с по-голям приоритет заменя стойността,а това с по-нисък- не я пипа.

Автор:  trm_only_for_work [ Пон Яну 22, 2007 5:24 pm ]
Заглавие: 

Nikola Kirov написа:
Точно с забраняване на прекъсванията е начина. Не съм имал случай когато забавянето на прекъсването с 4-5 такта да е проблем.

Погледни ако искаш как е в ембедед OS-ите.

там забраняването на прекъсванията е доста често. Много операции се правят точно в такъв режим.

Там механизнма обикновенно е следния

Код:
void vPortEnterCritical( void )
{
   __disable_interrupt();

   /* Now interrupts are disabled ulCriticalNesting can be accessed
   directly.  Increment ulCriticalNesting to keep a count of how many times
   portENTER_CRITICAL() has been called. */
   ulCriticalNesting++;
}

void vPortExitCritical( void )
{
   if( ulCriticalNesting > portNO_CRITICAL_NESTING )
   {
      /* Decrement the nesting count as we are leaving a critical section. */
      ulCriticalNesting--;

      /* If the nesting level has reached zero then interrupts should be
      re-enabled. */
      if( ulCriticalNesting == portNO_CRITICAL_NESTING )
      {
         __enable_interrupt();
      }
   }
}


Това са функциите на freeRtos за забраняване и разрешаване на прекъсванията.


Цецо и Никола добре го казаха, отделн оче го пише и в datasheet на PIC,ARM , значи и в док. на AVR трябва да го пише.

Проблема не е дори, когато имаш някокло прекъсваня (а ако имаш и приоритети на прекъсванята хептен).
Пробелма е, когато може едно прекъсване да бъде задействано от две или повече неща/ситуации.

Примерно вързал си 4,8пина с int_on_statechange и става страшно , ако го забавиш.
Ако ползваш един външен int за няколко събития (примерно IC подава int_out към главното mcu< но това е знак само за събитие, но не и кое точно събтие).
И ако възникнат две събития в IC-то ,дали IC-то така ще е у-но , че да "помни" предишното състояние или препокривя ~"STATUS" регистъра (применро).

Може и със флагове , но софтуерно. Въпреки че в твоят случей ще е дървено така:

т.е

critical_point:

bsf MYSTATUS,CP ; critical point execution flag set
do
do
do
do
____int_ ->>>
do
do
do
bsf MYSTATUS,CP ; critical point execution done
return ; to main or whatever is in STACK

...

int:

btfsc MYSTATUS,CP
goto ... Или нещо друго

do_int

--- в твоя случей да опзлваш софтуерни флагове , за да следиш къде ти е програмата хич не е това, което искаш , но пак е вариант, макар и не добър.

Автор:  Nikola Kirov [ Пон Яну 22, 2007 5:55 pm ]
Заглавие: 

маниак,пооправил си си наистина съобщенията но още малко ще трябва. След едно прочитане не разбрах какво искаш да кажеш. Не смятам да го чета пак и да гадая.
Още малко по смислено и си ОК :)

Автор:  Ки4о [ Пон Яну 22, 2007 10:13 pm ]
Заглавие: 

Маниак,идеята на приоритетните прекъсвания е че ти сам задаваш приоритета,демек знаеш къде кво правиш :wink:
При прекъсвания в прекъсването се запазват статуси,работни регистри,програмни броячи,.....но явно още не си стигнал до тези неща или кат си ги чел си ги попрескочил.

Страница 1 от 3 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/