Добра практика за вградено програмиране ли е да деактивирате прекъсване в прекъсване? [затворено]

Искам да внедря нещо в процесор ARM Cortex-M3 (с NVIC). Имам ограничени познания за вградените системи, но знам, че ISR рутинната трябва да бъде възможно най-проста.

Сега имам следния проблем: имам програма за прекъсване, която се задейства при получаване на CAN съобщение. В един случай трябва да изчисля някаква отнемаща време задача с CAN съобщението, която задача не може да бъде прекъсната от друго CAN съобщение, но други прекъсвания могат да бъдат обслужвани по време на тази операция. Идеята ми е следната:

  1. Получено CAN съобщение, ISR стартира, извършете някои прости задачи (напр. настройка на флагове)
  2. Деактивирайте CAN прекъсванията в рутинната CAN ISR. Също така запазете CAN съобщението в глобална променлива, така че да може да бъде достигнато в главния цикъл.
  3. В основния цикъл направете трудоемката задача.
  4. След тази задача активирайте отново обработката на CAN прекъсвания.

Това добра (или не съвсем лоша) идея ли е или трябва да направя това по друг начин?


person Zoltán Várnagy    schedule 25.01.2016    source източник
comment
Не знам - какво има в системата за задачи? Нишки и семафори?   -  person Martin James    schedule 25.01.2016
comment
Като цяло оставянето на прекъсвания маскирани за дълги периоди е нещо, което трябва да избягвате, ако може да се използва по-добра схема за контрол на потока.   -  person Martin James    schedule 25.01.2016
comment
Може би използвайте пръстен буфер, достатъчно голям, за да побере 2 или повече съобщения (или чифт буфери, които редувате). Тогава не е нужно да копирате данни и следващото CAN съобщение може да бъде получено, докато обработвате първото.   -  person Weather Vane    schedule 25.01.2016
comment
@WeatherVane Той ще трябва да копира данните от CAN хардуерния буфер в RAM, това е неизбежно. Така че няма смисъл да имате повече буфери от един. CAN хардуерът обикновено има множество вътрешни буфери, така че не е нужно да се притеснявате кой буфер се запълва, кой е готов и т.н. Всичко това се поема в момента, когато CAN ISR се задейства.   -  person Lundin    schedule 25.01.2016
comment
Ако входът от шината е „избухнал“, както често се случва, когато сте ограничени само до 8 байта на трансфер, тогава пул от буфери, т.е. повече от един, не е неразумно.   -  person Martin James    schedule 25.01.2016


Отговори (2)


Като цяло не е добра идея да деактивирате всички (CAN) прекъсвания. Изглежда, че това, от което искате да се предпазите, е същото съобщение да пристигне втори път, преди да приключите с първото.

В такъв случай трябва да се възползвате от това, че самият ISR е непрекъсваем. Можете да създадете прост семафор с променлива bool и тъй като прекъсването, което го задава, е непрекъсваемо, дори не е нужно да се притеснявате за атомарния достъп до тази булева стойност. C-подобен псевдокод за манипулатора на консерви:

typedef struct
{
  bool busy;
  can_msg_t msg;
} special_msg_t;

// must be volatile, to prevent optimizer-related bugs:
volatile static special_msg_t special = { false, {0} };

interrupt void can_isr (void)
{
  // non-interruptable ISR, no other interrupt can fire

  if(id==SPECIAL && !special.busy)
  {
    special.busy = true;
    // right here you can open up for more interrupts if you want
    memcpy(&special.msg, &new_msg, size);
  }
}

result_t do_things_with_special (void) // called from main loop
{
  if(!special.busy) 
    return error; // no new message received, no can do

  // do things with the message

  special.busy = false; // flag that processing is done
  return ok;
}
person Lundin    schedule 25.01.2016
comment
Имайте предвид, че този код предполага, че няма друг буфер освен CAN хардуерния буфер. В противен случай можете малко да ускорите ISR, като размените указатели, вместо да правите хартиено копие на буфера. - person Lundin; 25.01.2016
comment
Няма ли да е по-безопасно да отворите за прекъсвания, след като данните от new_msg бъдат копирани? - person AlphaGoku; 22.02.2018

ISR рутинната трябва да бъде възможно най-проста.

Точно.

Има концепция за ядрото на Linux, наречена долна половина. т.е. поддържане на ISR просто, доколкото е възможно. Останалите операции за обработка на прекъсвания се отлагат за по-късен момент.

Има много начини за внедряване на долната половина като task-let, work-queues и т.н

Препоръчваме да прочетете следните връзки
http://www.makelinux.net/ldd3/chp-10-sect-4
http://www.ibm.com/developerworks/library/l-tasklets/

Прекъсването, деактивирано за по-дълго време, може да доведе до липса на прекъсване (очевидно известна загуба на данни). След като флагът за прекъсване е зададен, създайте отложена работа и излезте от контекста на прекъсването.

person Jeyaram    schedule 25.01.2016
comment
Можете ли наистина да вкарате Linux ядрото в Cortex-m3... и дори да можете, това добра идея ли е? Предполагам, че това е MCU без метал. - person Lundin; 25.01.2016
comment
@Lundin, предположих, че това е вградена система, в която работи Linux. - person Jeyaram; 25.01.2016
comment
Да, забравих да спомена, че това е обикновен микроконтролер без операционна система, моя грешка. - person Zoltán Várnagy; 25.01.2016
comment
Linux ще работи на Cortex-m3 и е само ~300k-1M, когато е минимален с планировчик и управление на паметта. Файловите системи, мрежите и т.н. заемат много място в кода. Въпреки това, ако използвате само такъв минимален набор, може би има налични по-добри решения в зависимост от вашите точни нужди. Вижте: Минимален размер на ядрото на Linux - person artless noise; 25.01.2016