Перейти к содержанию
    

Прерывание в прерывании

Как правильно сделать?

Как бы вы не старались, по методике SST правильно не будет никак, поскольку ядро ARM (в частности контроллер прерываний) разрабатывался изначально под классические принципы работы RTOS.

Очевидно, что для этого были веские основания.

Если вам принципиально нужно "по методике SST", то придется городить адские костыли с полной потерей всех прелестей вложенного приоритетного контроллера прерываний.

Отлаживать такой говнокод - еще тот мартышкин труд.

Мало того, что полностью теряется полезнейшая функция sleep/delay, так еще и "задачи" теряют свой привычный очень многим смысл.

Невозможно будет применить чужой код без его тотальной переделки. Зачастую будет написать его заново.

Мифическая экономия ОЗУ и флэши (я бы сказал копеешная экономия) превратиться в неоправданные траты памяти там, где в этом не было нужды под обычной RTOS.

Особенно сочувствую тем, кому придется работать с вашим кодом ...

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

 

 

Впрочем, если вы по-прежнему упорно настроены на SST (задачи работают в фоне прерываний), то придется поломать голову и сделать свое решение самостоятельно,

тогда только в этом случае вы поймете тупиковость этой затеи, как минимум на ARM процах.

 

Для убедительности моих слов разместите тут код простейшей задачи моргания светодиода с различной скважностью в бесконечном цикле "по методике SST".

Время включенного и выключенного состояния - параметры изменяемые и кратны 1мс. Разумеется, процессорное время должно тратиться лишь на включение и выключение светодиода, но не на задержки.

Вот так эта задачка выглядит на привычной OS (все времена в мс):

while(true)
{
  led.on();
  sleep(onTime);
  led.off();
  sleep(offTime);
}

Как это будет выглядеть под мифической SST?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Меня устраивает карусель кооперативная на таймерах, не столь удобно писать код, но мне его поведение выглядит более понятным. Это скорее "железный" стиль, а не программисткий. Да и задач у меня нет промежуточных почти, либо простые, где достаточно прерываний и таймеров с флагами, либо на Линукс всякие видеокамеры. Мутить что то достаточно сложное на малых ресурсах не доводилось. Круто конечно сервер на коппечном проце замутить, только интерес это академический, никому это не надо. Железо стоит копейки, тот же расперри за 10 баксов имеет полноценный линукс, зачем жать доллар в российской реальности, где тиражи малы, конкурентоспособность определяется родственными связями начальникам и величиной откатов заказчику, в время разработки важнее этого несчастного доллара

 

void LedTaskOn (void *pparam)

{

SetTimer (LedTaskOff, onTime);

led.on();

}

void LedTaskOff (void *pparam)

{

SetTimer (LedTaskOn, offTime);

led.off();

}

Можно и одной функцией

Стек не жрет, дискретность микросекнды, никаких проблем с разделением ресурсов - все работают из прерываний. Недостаток - функция такого потока реализуется как машина состояний, что вобщем то не напрягает

Все эти

led.on();

sleep(onTime);

led.off();

sleep(offTime);

хороши как заманилово студентам как все красиво и прекрасно. В реальной задаче все увы не совсем так, обрастает критическими секциями, мьютексам итп. Где-то удобно, а где-то - не нужно. Мне - не нужно пока что точно

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как бы вы не старались, по методике SST правильно не будет никак, поскольку ядро ARM (в частности контроллер прерываний) разрабатывался изначально под классические принципы работы RTOS.
Да,похоже всё так.

 

Для убедительности моих слов разместите тут код простейшей задачи моргания светодиода с различной скважностью в бесконечном цикле "по методике SST".

Время включенного и выключенного состояния - параметры изменяемые и кратны 1мс. Разумеется, процессорное время должно тратиться лишь на включение и выключение светодиода, но не на задержки.

Вот так эта задачка выглядит на привычной OS (все времена в мс):

...

Как это будет выглядеть под мифической SST?

Не знаю, я же ещё толком и не работал с SST. Первое, что приходит в голову так:

void task_ledBlinker_on()
{
  led.on();
  setTask(task_ledBlinker_off, onTime, 0);
}

void  task_ledBlinker_on()
{
  led.off();
  setTask(task_ledBlinker_on, offTime, 0);
}

или так:

task_ledBlinker()
{
  led.toggle();

  if (led.state())
    setTask(task_ledBlinker, onTime, 0);
  else
    setTask(task_ledBlinker, offTime, 0);
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void LedTaskOn (void *pparam)

{

SetTimer (LedTaskOff, onTime);

led.on();

}

void LedTaskOff (void *pparam)

{

SetTimer (LedTaskOn, offTime);

led.off();

}

Очень печальное зрелище - простейший пример усложнил читаемость и очевидность кода на порядки. Также вырос размер кода во флэш.

Уж боюсь предположить, во что превратить более объемный код после переписывания его под SST.

Короче, прихожу к очевидному выводу: SST - это для потомственных мазахистов.... Я пас :cranky:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первое, что приходит в голову так::) о как, у меня также, только я не знал что это SST называется. Просто каруселька и все

 

"простейший пример усложнил читаемость и очевидность кода на порядки. Также вырос размер кода во флэш.", а насколько вырос ваш пример в ОЗУ? И можно плиз зажечь диод через 13.65845 мс ровно? И не надо про отладка на порядок сложнее, многопоточные приложения всегда отлаживать сложнее. К тому же ваш пример содержит ошибку, вы шину GPIO не захватили, а по ней сейчас другой поток занят важным делом - писк на зумер выводит. А потом жалуются, почему динамик хрипит на 1 кГц :)

Добавьте плиз SemaphoreGet. SemaphorePost с кодом иниициализации семафора. А то как-то нечестно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну-ну, песочница оживилась :)

ну ну , понторезка оживилась, давненько тут гастролеров с хабра не было

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первое, что приходит в голову так::) о как, у меня также, только я не знал что это SST называется. Просто каруселька и все

Как я понимаю, для SST нужно добавить задачам приоритеты и возможность асинхронного переключения на более приоритетную задачу из менее приоритетной. Без этого на чистом си можно использовать простейшие планировщики, например этот.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первое, что приходит в голову так::) о как, у меня также, только я не знал что это SST называется. Просто каруселька и все

 

"простейший пример усложнил читаемость и очевидность кода на порядки. Также вырос размер кода во флэш.", а насколько вырос ваш пример в ОЗУ?

 

И можно плиз зажечь диод через 13.65845 мс ровно?

Можно, но в данном случае - в этом нет нужды. Это - главное отличие RTOS от самодельных "каруселек" - не делать то, что не нужно делать.

 

 

И не надо про отладка на порядок сложнее, многопоточные приложения всегда отлаживать сложнее.

Нет, все в точности наоборот. Именно поэтому везде, где возможно, ставлю RTOS. Это сильно упрощает код и делает его легко переносимым из одного проекта в другой.

 

К тому же ваш пример содержит ошибку, вы шину GPIO не захватили,

Во-первых, чтобы зажечь светодиод, не нужно как выговорите "захватывать шину GPIO". Читайте матчасть по ARM Cortex. Не позорьтесь ))

Во-вторых, тут не указана реализация методов класса led - on и off. Да и не имеет это отношения к делу.

 

а по ней сейчас другой поток занят важным делом - писк на зумер выводит.
Читайте матчасть.

 

А потом жалуются, почему динамик хрипит на 1 кГц :)

Хрипит он скорее всего по другой причине - меандр сделан средствами RTOS, без использования аппаратных таймеров. Бывшие ардуинщики именно так и делают.

Правильно будет - реализовывать разные задачи разными инструменты, а не городить все одним.

 

Добавьте плиз SemaphoreGet. SemaphorePost с кодом иниициализации семафора. А то как-то нечестно.

Вот:

// создаем семафор
OS::Semaphore semaphore;

// гипотетическая задача:
while(true)
{
  semaphore.waitForever();
  // что-нить делаем
}

// обработчик прерываний или другая задача
{
  semaphore.signal();
}

Для примера, ожидание семафора бесконечное, но есть другие методы у этого класса OS::Semaphore, в частности позволяющие ждать его не более указанного времени.

 

 

 

Ваша очередь ...

 

давненько тут гастролеров с хабра не было

Такая реакция говорит о том, что "про песочницу" я попал в самую точку :biggrin:

Кстати, кто такие "гастролеры" с некого "хабра"?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

@ Читайте матчасть по ARM Cortex.@ Ладно, спорить тут не о чем. В молодости я тоже был такой горячий и восторженный. Удачи

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

@ Читайте матчасть по ARM Cortex.@ Ладно, спорить тут не о чем.

 

ОК, слив опять защитан. Счет 2:0 :)

 

Для тех, кто не в теме: в ARM Cortex есть такой механизм - BitBanging (вроде правильно написал).

Он позволяет упростить работу с обращениями типа чтение-модификация-запись.

В частности, изменение состояния пинов не требует создания критических секций и т. п, как это было необходимо в более архаичных ARM.

 

В молодости я тоже был такой горячий и восторженный.

В молодости я тоже страдал всякой херней наподобие SST ("каруселек") и т. п. подобной дребедени лишь чисто ради "академического" интереса (в ту пору на Microchip процах).

Кстати, на Microchip только так и можно было использовать RTOS - кооперативная с вагоном соотв. костылей. Но это было давно и осталось в далеком прошлом (к счастью)...

Но времена меняются, и, чтобы не отстать от поезда, нужно осваивать новые решения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для тех, кто не в теме: в ARM Cortex есть такой механизм - BitBanging (вроде правильно написал).

Да чего сейчас только нету в этих ARM-ах.

В последнее время у меня светодиоды RGB и управляются строго по DMA. Никаких обращений в порты.

Пишу шаблон работы типа микроскрипта, гружу в автомат, а тот расчитанные RGB коды пишет просто в память, никаких портов.

const uint32_t RGB_ptrn_Green_blink[6] = {VAL_LEV(0), 250, HSV_GREEN+SAT_LEV(100)+VAL_LEV(50), 50, B_JMP, (uint32_t)&RGB_ptrn_Green_blink[0] }; 

Set_RGB_led_ptrn((uint32_t *)RGB_ptrn_Green_blink);

Мигает, плавно меняет цвет, интенсивность, цветность. Все что хочешь.

Само собой автомат сделан в отдельной задаче RTOS.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Смотрел я исходники ОС, но они все по похожему принципу сделаны - переключение между разными стеками.

...

Да, примерно так и есть.

 

А можете примерно так-же объяснить, что мне сделать для пререключения задач по методике SST?

Выполняем мы задачу А. Так же через вызов прерывания PendSV хотим запустить более приоритетную задачу (запустить функцию). Попали в PendSV_Handler, сохранили (R4-R11) на текущем стеке.

"На текущем" - это на каком? На стеке обработчиков прерываний что-ль? Вы имеете представление, что в ядре Cortex-M есть два стека (аппаратных) - MSP/PSP? И зачем так сделано?

 

Всё, контекст задачи A сохранён. Как теперь правильно запустить задачу В? Сделать просто вызов LDR R1, =taskB, BLX R1 нельзя - функция будет выполняться в контексте прерывания. Как правильно сделать? Из прерывания если выйдем ( BX LR) мы попадём обратно в задачу А. Как мне выйти из прерывания и при этом запустить функцию taskB?
Так Вы же читали как это делают переключатели задач РТОС - сделайте точно так же. Сохраните все регистры на стеке прерванной задачи, также в сегмент данных прерванной задачи сохраните её SP, загрузите SP новой задачи в PSP, восстановите со стека новой задачи ту часть регистров, которая программно сохраняется (R4-R11) и всё - можете выходить из прерывания в контекст уже новой задачи (так как на её стеке сейчас остались регистры, аппаратно сохраняемые при входе в ISR). Естественно - перед первым запуском каждой задачи, её стек нужно проинициализировать корректными значениями регистров расположенных именно в том порядке, в котором они сохраняются/восстанавливаются при входе и внутри PendSV.

Если нужно возбуждать переключение задач из ISR аппаратного прерывания, то естественно в ядре Cortex-M для этого нужно программно возбудить PendSV, выйти из аппаратного ISR и уже в ISR PendSV переключить контекст. Именно такой метод и был задуман проектировщиками ядра. Чтобы такой механизм работал, необходимо чтобы приоритет PendSV был ниже приоритета любого аппаратного прерывания.

И вот когда вы всё это проделаете, то получите стандартную РТОС для Cortex-M :) Именно поэтому вам и пишут, что смысла изобретать свой лисапед нет никакого. Разве что в целях собственного ликбеза.

Остаться внутри ISR аппаратного прерывания каким-то образом не выходя из него, а что-то там замутив со стеком - невозможно без нарушения работы всей системы прерываний - пока не выйдете из этого ISR это прерывание больше не вызовется (и менее приоритетные тоже). Так что такой способ, который Вы описали в первом сообщении, на Cortex-M - нереализуем.

 

PS: И прежде, чем что-то подобное делать - настоятельно рекомендую изучить мануал на ядро. Особенно в части касаемой режимов процессора, входов и выходов в ISR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...