реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> Управление контекстом БЕЗ RTOS
1113
сообщение Nov 21 2014, 09:34
Сообщение #16


Знающий
****

Группа: Свой
Сообщений: 604
Регистрация: 24-02-06
Из: Москва
Пользователь №: 14 658



Цитата(ViKo @ Nov 21 2014, 12:08) *
http://www.coocox.org/CoOS.htm
974 байта.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 21 2014, 09:36
Сообщение #17


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(yanvasiij @ Nov 21 2014, 12:41) *
Этой штукой вообще безопасно пользоваться?
Конечно нет!:)
Как и любой режущий инструмент очень опасен для жизни, но всё же им пользуются...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 21 2014, 10:08
Сообщение #18


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(yanvasiij @ Nov 21 2014, 10:04) *
Может я чего неправильно сказал, но надеюсь смысл понятен. Вопрос: как сделать такое сохранение и загрузку контекста? Где про это можно почитать, посмотреть пример и т.п.
Спасибо!


Это всегда называлось кооперативной многозадачностью.

Переключение будет выглядеть вот так:
Код
/*
* Performs a context switch between two threads.
*/
                PUBLIC _port_switch
_port_switch:
                push    {r4, r5, r6, r7, lr}
                mov     r4, r8
                mov     r5, r9
                mov     r6, r10
                mov     r7, r11
                push    {r4, r5, r6, r7}
                mov     r3, sp
                str     r3, [r1, #CONTEXT_OFFSET]
                ldr     r3, [r0, #CONTEXT_OFFSET]
                mov     sp, r3
                pop     {r4, r5, r6, r7}
                mov     r8, r4
                mov     r9, r5
                mov     r10, r6
                mov     r11, r7
                pop     {r4, r5, r6, r7, pc}


А смотреть надо стандарт ARM EABI по поводу того какие регистры сохранять, а какие не надо сохранять.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Nov 21 2014, 12:21
Сообщение #19


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(scifi @ Nov 21 2014, 15:25) *
Всё придумано до нас: protothreads.

Кстати, о protothreads.
С использованием возможностей С++ становится ещё удобнее.
http://blog.brush.co.nz/2008/07/protothreads/


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Nov 21 2014, 12:46
Сообщение #20


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



А если немного подумать, может и не нужна никакая многозадачность и вполне достаточно event-driven state machine
В случае с двумя светодиодами - однозначно

Я к qp давно приглядываюсь, а он за это время становится все лучше и лучше


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 21 2014, 13:06
Сообщение #21


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(MrYuran @ Nov 21 2014, 14:46) *
А если немного подумать, может и не нужна никакая многозадачность и вполне достаточно event-driven state machine
В случае с двумя светодиодами - однозначно

Я к qp давно приглядываюсь, а он за это время становится все лучше и лучше


Для state machine лучше IAR visualSTATE трудно что либо найти.

Неутомимая Xenia у нас тут с этим помогает.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Nov 21 2014, 13:23
Сообщение #22


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(AlexandrY @ Nov 21 2014, 17:06) *
Неутомимая Xenia у нас тут с этим помогает.

Я из противоположной конфессии. К сожалению. Или к счастью.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
scifi
сообщение Nov 21 2014, 15:46
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(MrYuran @ Nov 21 2014, 15:46) *
А если немного подумать, может и не нужна никакая многозадачность и вполне достаточно event-driven state machine
В случае с двумя светодиодами - однозначно

Как сказать. Если программа описывает процесс, линейно текущий во времени, с ветвлениями и переходами, то она естественным образом ложится на сишный код, и мне такое представление кажется интуитивно более понятным. И protothreads тут весьма кстати. Те же две лампочки вписываются в эту схему.
Да, всё можно свести к конечному автомату, но не всегда стоит это делать, так как читаемость кода может страдать.
Go to the top of the page
 
+Quote Post
WitFed
сообщение Nov 27 2014, 14:04
Сообщение #24


Местный
***

Группа: Свой
Сообщений: 271
Регистрация: 6-12-11
Из: Taganrog
Пользователь №: 68 701



Я лично после долгого знакомства с ОС2000 без отладчика и попытками обуздать там 100 нитей очень негативно отношусь ко всякой шизофрении, когда непонятно, "кто шил костюм", а память портится, причём нестабильно.
Хотя периодически сильно хочется почитать научный обзор страниц так на 100, что же там придумано на текущий момент в этой области. Но по-русски и без наездов.
Лучше всего ИМХО 1-нитевые "шедулеры", которые по очереди исполняют функции, которые были добавлены в список до того, и каждая функция добавляет новые адреса исполнения в список, плюс её возвращаемое значение -- адрес функции, которая должна выполниться после этой, ну или 0, если эта "нитка" завершена.
Задача бъётся на кучу функций, которые имеют глобальные данные (возможно, в отдельных namespace, или там там сидят указатели на них в куче), и никакого сохранения контекста и переключения десятков регистров не нужно, стек у всех один ! Бродить в переключателе контекста на asm-е не надо, чтобы понять, куда меня перешедуливают, само переключение -- выход из одной функции и вызов другой, данные глобальны.
Шедулер тупо вызывает по кругу свой массив адресов функций, они "как бы крутятся", возвращая вместо себя "наследника" в тот же адрес массива на то же место, и что-то кусочно исполняют.
Также можно завести отдельный массив "ожидателей" -- системного таймера или не 0 по какому-то адресу, который будет и "семафором", "мьютексом", и чем угодно -- не нужны никакие критические секции, никто у тебя за спиной бяку никогда не сделает в непонятной нити с высоким приоритетом, лишь бы был отладчик хоть какой-то в IDE.
Прерывания тоже можно использовать, но только в виде исключения -- если уж точно кто-то чего-то требует за 100 тактов, а не за 1000 (в порядке очереди). Ибо от прерываний основные проблемы нестабильности в ртосах всяких, когда и надо что-то бы сделать "где-то", а "там" в этот же момент тоже вдруг кто-то ковыряется "под стрелой"...
Такие коды получаются абсолютно переносимыми (ну, кроме таймера), без-ассемблерными. И все контексты сидят "в домиках" возле каждой функции, их использующей, локальные автоматические переменные действуют недолго и не требуют сохранения между вызовами. Понятно, что ожидания и большие объёмы обработки там недопустимы, надо бить процессы на непрерывные куски.
Случилось нечто -- запускается "процесс" его обработки, т.е. подшедуливается функция, где она расписана.
Единственное плохо -- все варианты событий должны быть известны заранее, хотя во встроенных небольших системах так обычно и есть. Можно и параметры передавать в шедулер, с которыми планируется вызов функции, но это уже непрозрачней гораздо.
Код ТС получается типа такого:
Код
typedef (func*)(void);
func led1On() {/*make*/ addDelayed(led1Off, 1000); return NULL; }
func led1Off() {/*make*/ addDelayed(led1On, 1000); return NULL; }
func led2On() {/*make*/ addDelayed(led2Off, 1000); return NULL; }
func led2Off() {/*make*/ addDelayed(led2On, 1000); return NULL; }

int main() {
  addDelayed(led1On, 1000);
  addDelayed(led1Off, 1000);
  main_loop();
}

Вдруг на самом деле что такое уже есть в мировой практике -- подскажите.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Nov 27 2014, 15:01
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



ага супер луп на конечных автоматах называется... это то что было до операционок.
Вы придумали шаг назадsm.gif...

Go to the top of the page
 
+Quote Post
jcxz
сообщение Nov 28 2014, 04:02
Сообщение #26


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(WitFed @ Nov 27 2014, 20:04) *
Также можно завести отдельный массив "ожидателей" -- системного таймера или не 0 по какому-то адресу, который будет и "семафором", "мьютексом", и чем угодно -- не нужны никакие критические секции, никто у тебя за спиной бяку никогда не сделает в непонятной нити с высоким приоритетом, лишь бы был отладчик хоть какой-то в IDE.

Непонятно - почему не нужны критические секции? Как без них если нужна атомарность доступа к объекту?

Случай (работа под ОС): семафор проверяется внутри критической секции. При его занятости, ОС переводит таск в сост. "ожидает данный семафор" и переключает контекст.
А как Вы своим велосипедом такой случай разрулите? sm.gif
А если внутри двух критических секций?
А как реализуете функцию типа WaitForMultipleObjects?

Все плюсы и минусы построения диспетчера с переключением контекста (ОС) и без (все вариации суперцикла) думаю давно известны.
Суперцикл хорош, только если не нужен блокирующий доступ к ресурсам (защищённым семафорами и мьютексами).
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 07:04
Сообщение #27


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(WitFed @ Nov 27 2014, 16:04) *
Лучше всего ИМХО 1-нитевые "шедулеры", которые по очереди исполняют функции, которые были добавлены в список до того, и каждая функция добавляет новые адреса исполнения в список, плюс её возвращаемое значение ...


Извините, но ваш пост воспринимается как малопонятный набор слов.
А приведенный код попахивает рекурсией. А рекурсия это самое вредное что можно придумать во встраиваемой системе. Убьете стек и не заметите.

Может вы хотели сказать о машинах состояний управляемых шаблонами (цепочками состояний)?
На более высоком уровне это называется интерперетаторы.

Приведу пример простейшей машины состояний по шаблону отрабатывающей управление массивом соленоидов.

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

Этот автомат применяется мною и с RTOS и без.
Сервисы RTOS здесь мало применимы, потому что им тут нечего делать и поскольку момент коммутации соленоидов строго привязан к окончанию выборки АЦП, так чтобы они не засоряли сигнал АЦП.

CODE
// Управляющая структура машины состояний управляемой шаблоном
typedef struct
{
INT32U init_state;
INT32U counter;
INT32U *pattern_start_ptr; // Указатель на массив констант int являющийся цепочкой состояний (шаблоном)
// Если значение в массиве = 0xFFFF, то процесс обработки завершается
// Если значение в массиве = 0x0000, то вернуть указатель на начало цепочки
INT32U *pttn_ptr; // Текущая позиция в цепочке состояний

} T_solnd_ptrn;

// Шаблоны работы соленоидов
// ----------------------------------------------------------------------
// Шаблон состоит из массива пар слов.
// Первое слово - значение напряжения (в процентах от максимального) на текущем интервале времени
// Второе - длительность интервала времени в мс
// интервал равный 0 - означает возврат в начало шаблона
// интервал равный 65535 - означает застывание состояния

const INT32U SOLENOID1_ON[10] = { 100, 300, 25, 300, 100, 300, 25, 300, 25, 0xFFFF };
const INT32U SOLENOID2_ON[10] = { 25, 300, 100, 300, 25, 300, 100, 300, 25, 0xFFFF };
const INT32U SOLENOID_OFF[4] = { 0, 2000, 0, 0xFFFF };
// ----------------------------------------------------------------------

// Массив управляющих структур соленоидов .
T_solnd_ptrn solnd_cbl[2];


/*-------------------------------------------------------------------------------------------------------------
Инициализация машины состояний заданным шаблоном
*pttn - указатель на начало шаблона
n - индекс соленоида (0..1)
-------------------------------------------------------------------------------------------------------------*/
void Set_Solenoid_pattern(const INT32U *pttn, INT32U n)
{
if ( pttn != 0 )
{
solnd_cbl[n].pattern_start_ptr = (INT32U *)pttn;
solnd_cbl[n].pttn_ptr = (INT32U *)pttn;
Set_solenoids_voltage(*solnd_cbl[n].pttn_ptr, n);
solnd_cbl[n].pttn_ptr++;
solnd_cbl[n].counter = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
}
}

/*------------------------------------------------------------------------------
Вызывается из процедуры прерывания АЦП с периодичностью ADC_PERIOD
------------------------------------------------------------------------------*/
void Solenoid_automat(void)
{
static INT32U solnd_presc = 0;
INT32U duration;
INT32U voltage;
INT32U n;

solnd_presc++;

if ( solnd_presc >= (1000 / ADC_PERIOD) ) // Обработка ведется с периодом повторения - 1 мс
{
solnd_presc = 0;
for (n=0; n<2; n++)
{
// Управление состоянием сигнала соленоида
if ( solnd_cbl[n].counter )
{
solnd_cbl[n].counter--;
if ( solnd_cbl[n].counter == 0 ) // Меняем состояние сигнала при обнулении счетчика
{
if ( solnd_cbl[n].pattern_start_ptr != 0 )
{
voltage = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
duration = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
if ( duration != 0xFFFF )
{
if ( duration == 0 )
{
solnd_cbl[n].pttn_ptr = solnd_cbl[n].pattern_start_ptr;
voltage = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
solnd_cbl[n].counter = *solnd_cbl[n].pttn_ptr;
solnd_cbl[n].pttn_ptr++;
Set_solenoids_voltage(voltage, n);
}
else
{
solnd_cbl[n].counter = duration;
Set_solenoids_voltage(voltage, n);
}
}
else
{
// Обнуляем счетчик и таким образом выключаем обработку шаблона
Set_solenoids_voltage(voltage,n);
solnd_cbl[n].counter = 0;
}
}
else
{
Set_solenoids_voltage(0,n);
}
}
}
}

} // if ((prediv & 3)==0)
}


Сообщение отредактировал IgorKossak - Nov 28 2014, 15:58
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Nov 28 2014, 07:49
Сообщение #28


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата
Непонятно - почему не нужны критические секции? Как без них если нужна атомарность доступа к объекту?

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

такие суперлупы неплохое и надежное решение, но все же это предыдущий шаг перед операционкой.






Цитата
Извините, но ваш пост воспринимается как малопонятный набор слов.

труднопонятный sm.gif

Цитата
А приведенный код попахивает рекурсией.

есть такое... может с именами функций что напутано...

WitFed приоткройте завесу, обрисуйте чуть подробнее задумку мастера?
Go to the top of the page
 
+Quote Post
psL
сообщение Nov 28 2014, 08:12
Сообщение #29


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 5-08-05
Пользователь №: 7 390



Цитата(AlexandrY @ Nov 28 2014, 10:04) *
Этот автомат применяется мною и с RTOS и без...

сложный пример. Можно проще:
CODE
enum fsm_state { IDLE, PROCESS, ERROR };

struct fsm {
enum fsm_state state;
// data...
};

static struct fsm myfsm = {
.state = IDLE,
// data startup init...
};

void fsm_init(struct fsm* fsm){
fsm->state = IDLE;
// data (re)init...
}

void fsm_proc(struct fsm* fsm){
switch(fsm->state){
case IDLE:
// do startup init ...
fsm->state = PROCESS;
break;
case PROCESS:
// do process ...
fsm->state = IDLE;
// or fsm->state = ERROR;
break;
default:
fsm->state = ERROR;
case ERROR:
// error handler
break;
}
}

Вообще без ОСи никакого контекста не будет, потому что в этом случае процесс(задача)разветвленная, но одна. В противном случае что такое контекст? Состояние регистров и стека при выполнении подпрограммы или прерывания?

Сообщение отредактировал IgorKossak - Nov 28 2014, 15:59
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Nov 28 2014, 08:17
Сообщение #30


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(psL @ Nov 28 2014, 10:12) *
сложный пример. Можно проще:


Забавно состояние ERROR по отношению к процессу управления светодиодом.
Что бы это могло значить? biggrin.gif
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 16:12
Рейтинг@Mail.ru


Страница сгенерированна за 0.01526 секунд с 7
ELECTRONIX ©2004-2016