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

Написал порт scmRTOS под ARM

Послушал советы, кое-чего поправил. Сделал targets для AT91SAM7S64(RAM/Flash) и LPC2119(RAM/FLASH). В качестве стека прерываний теперь используется стек main(), процесс Idle как обычный со своим стеком. Исходники самой ОС взял от последней версии 2.04а.

Надеюсь, возможность попробовать порт на LPC увеличит активность отзывов/советов.

Вопрос с симулятором остается открытым. По моим понятиям все же он некорректно отрабатывает LDMFD LR, {R0-LR}^. Попробую выяснить этот вопрос в отдельной ветке.

scmRTOS_ARM.zip

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


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

Странно, но почему-то в моем макете с AT91SAM7S64 при отладке через MT-Link перегрузки CPSR не происходит. Могу попробовать на LPC2119, но не думаю что будет большая разница.

Совсем забыл. Перезагрузка CPSR происходит только когда процессор находится не в USER или SYSTEM режиме. Потому что в этих режимах регистра SPSR вообще нет. Команда как бы некорректная, хотя процессор не падает. И ещё. Прочитать (загрузить в CPSR) можно только SPSR текущего режима. Запись в SPSR - аналогично. Даже если в команде явно будет указан регистр SPSR из другого режима. Непонятно только, зачем ассемблер разрешает так писать.

 

У вас вообще по какому событию происходит переключение?

 

А для чего или кого вообще пишите?

Изменено пользователем GetSmart

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


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

Странно, но почему-то в моем макете с AT91SAM7S64 при отладке через MT-Link перегрузки CPSR не происходит. Могу попробовать на LPC2119, но не думаю что будет большая разница.

 

Совсем забыл. Перезагрузка CPSR происходит только когда процессор находится не в USER или SYSTEM режиме.

Все это понятно. На это я с самого начала нарвался :-) У меня эта команда выполнятеся в IRQ_mode.

Но все же я настаиваю, что восстановление CPSR происходит только в одном варианте команды: когда стоит крыжик (^) И в списке регистров есть R15(PC). При этом восстанавливаются регистры в банке соотв. режима исключений. Если же в команде стоит крыжик и R15 в списке нет, то восстанавливаются регистры user(system) банка и CSPR не восстанавливается.

Или другими словами: если в списке LDM есть R15, то крыжик означает восстановление CSPR, если R15 нет - то крыжик означает восстановление в _user регистры. Детализируя:

LDMxx {R13-R15}^ восстанавливает R13_mode, R14_mode, PC, SPSR_mode->CPSR

LDMxx {R13-R14}^ восстанавливает R13_user, R14_user

Именно так происходит в железе (LPC2119 тоже проверил). Можете проверить. Симулятор же отрабатывает эту команду иначе. Я не вижу ничего незаконного в этой команде поэтому продолжаю считать что в этом случае симулятор явно ошибается.

 

Даже если в команде явно будет указан регистр SPSR из другого режима. Непонятно только, зачем ассемблер разрешает так писать.
Ассемблер не позволяет их указывать. Это в описании ядра они имеют такие обозначения.

У вас вообще по какому событию происходит переключение?
Планировщик взводит бит программного прерывания в контроллере прерываний.

А для чего или кого вообще пишите?
Для себя :-) Готовлю почву для новых проектов. FreeRTOS не понравилась чрезмерными требованиями к ОЗУ и кривизной написания. scmRTOS использовал в одном проекте на MSP430, понравилась. Из кристаллов под рукой есть макетки с SAM7 и LPC, есть еще ADuС, но на нем пока только пример из иара запускал. Ближайшие 2 проекта будут на ADuC и LPC.
Изменено пользователем Сергей Борщ

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


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

Смотрите, что я нарыл:

(цитата из книжки)

Бит S используется для управления (обновления, по-моему) флагами условий. Если этот бит установлен, флаги условий изменяются в соответствии с результатом выполнения команды. Если этот бит сброшен, состояние флагов условий не меняется. Однако, если при установленном бите S в качестве регистра результата указан R15 производится копирование содержимого SPSR текущего режима в регистр CPSR. Эта возможность используется для восстановления РС и переключения в исходный режим в конце обработки исключительных ситуаций. Не пытайтесь выполнить такую команду в режиме User (System забыли!), поскольку в этом режиме отсутствует регистр SPSR и соответственно результат выполнения этой команды невозможно предсказать.

___________________________

Я так понял, что бит S и есть эта галочка (^). В командах она означает обновление арифметических флагов в CPSR после выполнения команды, если результат не в R15. Если же в R15, то обновится весь CPSR значением из SPSR.

__________________________

Проверил в отладчике IAR 4.20

Команда с битом S типа SUBS R15,R0,R0 перегружает R15 и SPSR копирует в CPSR. А команда SUBS R1,R0,R0 обновляет только арифметические флаги в CPSR.

Команда LDRxx Rx,{R0}^ вообще не меняет регистр CPSR. Тем более, что арифметической операции и нет. Команда LDRxx Rx,{...,R15}^ копирует SPSR в регистр CPSR.

Всё это я проделывал находясь в IRQ режиме, а в SPSR был SYSTEM.

В командах STMxx эта галочка (^) вообще ни на что не влияет, даже если указан R15. Хотя, может и нет. Надо это ещё проверить.

___________________________

А нафига вы её решили использовать без регистра R15 ?

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


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

Касательно файла Target_LPC2xxx.h

 

"#define CONTEXT_SWITCH_INT VIC_SW"

- Использовать отдельное прерывание (VIC_SW) не обязательно, если у вас так же прерывать задачу может таймер. Для этого я принудительно вызывал прерывание от таймера такой командой:

VICSoftInt = (1 << VIC_TIMER1)

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

 

Так писать не нужно:

"VICIntEnable |= (1<<CONTEXT_SWITCH_INT);"

Через этот регистр можно только устанавливать биты, но не сбрасывать. Поэтому пишите так:

VICIntEnable = (1<<CONTEXT_SWITCH_INT);

 

А эта конструкция вообще убьёт всю систему:

"#define BlockContextSwitchMacro() do { \

VICIntEnable &= ~(1<<CONTEXT_SWITCH_INT); \

} while (0) // disable context switching interrupt

"

Для сброса бита разрешения конкретного прерывания есть другой регистр. Надо так:

VICIntEnClear = (1<<CONTEXT_SWITCH_INT);

 

Кстати, зачем пишите "do {...} while (0)" ???

 

Для чего timer 0, match 0 используете?

 

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

 

Для справки, все свободные биты из 32 источников прерываний можно использовать для своих нужд через регистр VICSoftInt. Специально для этого сделан VIC_SW, но и остальные действуют аналогично. Я проверял. В одной проге аж 4 независимых софт-прерывания зафигачил. Кстати, у меня прерывание, переключающее задачи (которое я приводил) сделано так, что прерывания запрещены очень короткий момент и даже для 100 КГц прерываний ни одного не потеряется!

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


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

Но все же я настаиваю, что восстановление CPSR происходит только в одном варианте команды: когда стоит крыжик (^) И в списке регистров есть R15(PC). При этом восстанавливаются регистры в банке соотв. режима исключений. Если же в команде стоит крыжик и R15 в списке нет, то восстанавливаются регистры user(system) банка и CSPR не восстанавливается.

Или другими словами: если в списке LDM есть R15, то крыжик означает восстановление CSPR, если R15 нет - то крыжик означает восстановление в _user регистры. Детализируя:

LDMxx {R13-R15}^ восстанавливает R13_mode, R14_mode, PC, SPSR_mode->CPSR

LDMxx {R13-R14}^ восстанавливает R13_user, R14_user

Именно так происходит в железе (LPC2119 тоже проверил). Можете проверить. Симулятор же отрабатывает эту команду иначе. Я не вижу ничего незаконного в этой команде поэтому продолжаю считать что в этом случае симулятор явно ошибается.

Думаю вы правы. Однако у меня симулятор всё как надо сделал. Оказывается в командах LDM и STM когда указан ^ и нет R15 сохраняются и восстанавливаются регистры User/System. Можно даже не переключаться специально в эти режимы. А я и не знал! Команды "LDMFD LR, {R0-LR}^ ; NOP ; ADD LR, LR, #15*4" можно упростить до "LDMFD LR!, {R0-LR}^". У меня в отладчике нормально прошло.

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


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

Думаю вы правы. Однако у меня симулятор всё как надо сделал. Оказывается в командах LDM и STM когда указан ^ и нет R15 сохраняются и восстанавливаются регистры User/System. Можно даже не переключаться специально в эти режимы. А я и не знал!
Ну вот хоть какая-то польза :-)

Команды "LDMFD LR, {R0-LR}^ ; NOP ; ADD LR, LR, #15*4" можно упростить до "LDMFD LR!, {R0-LR}^". У меня в отладчике нормально прошло.
Нет, нельзя. Если идет ^ и в качестве опроного используется банкируемый регистр то нельзя писать в него обратно и в следующем такте обращаться к нему тоже нельзя. Вот цитата из того же ARM DDI 0029E:
R15 not in list and S bit set (User bank transfer)

For both LDM and STM instructions, the User bank registers are transferred rather

than the register bank corresponding to the current mode. This is useful for saving the

user state on process switches. Base write-back should not be used when this

mechanism is employed.

When the instruction is LDM, care must be taken not to read from a banked register

during the following cycle (inserting a dummy instruction such as MOV R0, R0 after

the LDM will ensure safety).

Да, вот из старого сообщения:

А команды сохранения и восстановления контекста как бы парные (точнее префиксы stmDB и ldmIA). У вас они почему-то одни и те же.

На самом деле это одни и те же команды, разработчики зачем-то дали этим командам по два имени " to support stacks or for other purposes." Так что STMDB == STMFD, LDMIA == LDMFD

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


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

Не сочтите за 'наезд' - работа несомненно полезная! Однако не могу не отметить, что основная прадигма отлично реализованная в scmRTOS на типичном ARM смотрится уже не так привлекательно,

как на AVR с полукилобайтом-килобайтом памяти.

FreeRTOS не понравилась чрезмерными требованиями к ОЗУ и кривизной написания.

В частности по этой причине не смог пройти спокойно мимо вышеотцитированого :-(.

"Кривизну", в виду неопределенности формулировки, оставим в покое (хотя можем и побеседовать - тут

есть подходящие ветки ) а по RAM..

Cобрал Ваш демо проект с тремя светодиодиками:

 

Module               CODE      DATA      CONST
------               ----      ----      -----
                    (Rel)  (Rel)  (Abs)  (Rel)
?CMAIN                108
?CSTARTUP              56
?EnI_t                 20
?RESET
  + common             60
?_EXIT                 12
?__dbg_break            2
?__exit                18
?cppinit               70
?exit                  14
?segment_init          84
OS_Kernel             300     40
  + shared             32             8     12
OS_Services            16
OS_Target_cpp         272    108
  + shared                            8
main                  478    940    220
scmRTOS_Asm           132
  + common             28
N/A (command line)           768
N/A (alignment)        10
----------          -----  -----    ---     --
Total:              1 624  1 856    236     12
  + common             60

И под FreeRTOS такой-же:

Module               CODE      DATA      CONST
------               ----      ----      -----
                    (Rel)  (Rel)  (Abs)  (Rel)
?CMAIN                 80
?CSTARTUP             476
?DiI_t                 32
?EnI_t                 16
?RESET
  + common             64
?_EXIT                 12
?__exit                 2
?exit                  14
?segment_init          84
?strncpy               44
croutine
  + shared                                  12
heap                  244     24
leds                   76             8
  + shared                            4
list                  174
ll_init                 4
main                  186             8     16
port                  376      4     40     16
portasm               340
tasks                 902    168             8
N/A (command line)           530
N/A (alignment)        10
----------          -----    ---     --     --
Total:              3 072    726     60     52
  + common             64

 

Собственно разница по декларированному критическому ресурсу (RAM занимаемому ядром) отнюдь не впечатляет:

scmRTOS = 0x148 байт

FreeRTOS = 0x1AC

Итого - 100(dec) байт. Не слишком большая плата за несколько отличающюся базовую функциональность и (личное мнение) за большую способность к доработкам.

Причем, при "необходимости" можно убрать еще по 8 байт на задачу во FreeRTOS :-)

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


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

Смотрите, что я нарыл:

(цитата из книжки)

___________________________

Я так понял, что бит S и есть эта галочка (^). В командах она означает обновление арифметических флагов в CPSR после выполнения команды, если результат не в R15. Если же в R15, то обновится весь CPSR значением из SPSR.

__________________________

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

Проверил в отладчике IAR 4.20

Команда LDRxx Rx,{R0}^ вообще не меняет регистр CPSR. Тем более, что арифметической операции и нет.

В данном контексте (R15 нет) ^ означает доступ к user-банку. Но поскольку R0 небанкируемый, то в этом конкретном варианте наличие ^ не играет роли.

Команда LDRxx Rx,{...,R15}^ копирует SPSR в регистр CPSR.

Всё это я проделывал находясь в IRQ режиме, а в SPSR был SYSTEM.

Вот тут появляется тонкость, которая не позволила мне восстановить весь контекст одной командой: если в списке есть R15, то ^ означает копирование SPSR в CPSR а не восстановление user-банка. Т.е. значения со стека попадут вместо необходимого мне SP_user, LR_user в SP_irq, LR_irq. Это ответ на

А нафига вы её решили использовать без регистра R15 ?

В командах STMxx эта галочка (^) вообще ни на что не влияет, даже если указан R15. Хотя, может и нет. Надо это ещё проверить.
Влияет. В STM если есть галочка будут сохранены регистры user mode.

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


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

FreeRTOS не понравилась чрезмерными требованиями к ОЗУ и кривизной написания.

В частности по этой причине не смог пройти спокойно мимо вышеотцитированого :-(.

"Кривизну", в виду неопределенности формулировки, оставим в покое (хотя можем и побеседовать - тут

есть подходящие ветки )

Объясню очень просто: указатели на любой объект передаются как void* что легко позволяет мне передать вместо указателя на семафор указатель на процесс или очередь. Зачем же в "языке высогага уровня Ц" был придуман контроль типов на этапе компиляции? Далее это же void * передается в другие функции место указателя соответствующего типа, а чтобы компилятор не выдавал предупреждения вместо элементарного создания локальной переменной нужного типа и приведения типа

signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void *pvItemToQueue, portTickType xTicksToWait )
{
xQueuePtr pxQueue = xQueue;

в описании предлагается задавить предупреждения этого типа в опциях компилятора. Причем предупреждения возникают при компиляции кода самой ОС. Что же это как не кривизна?

а по RAM..
46 байт на битовый семафор мне показалось расточительно. Они его реализуют как очередь из одного элемента нулевого размера. Да и на очередь 46 байт ОЗУ накладных "жаба душит".

 

Cобрал Ваш демо проект с тремя светодиодиками:

Собственно разница по декларированному критическому ресурсу (RAM занимаемому ядром) отнюдь не впечатляет:

scmRTOS = 0x148 байт

FreeRTOS = 0x1AC

Итого - 100(dec) байт. Не слишком большая плата за несколько отличающюся базовую функциональность и (личное мнение) за большую способность к доработкам.

Причем, при "необходимости" можно убрать еще по 8 байт на задачу во FreeRTOS :-)

Я не отрицаю большого потенциала в FreeRTOS. Однако в моем примере из базовой функциональности был только один сервис Sleep(). Оно и понятно - надо было отладить переключатель контекста. Более серьезный пример идет в исходнике scmRTOS с сайта автора. Там есть и семафоры и очереди. Если есть желание - можем сравнить.

Еще раз - я не хоче наступить на горло FreeRTOS, просто мне она субъективно не понравилась.

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


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

Касательно файла Target_LPC2xxx.h

 

"#define CONTEXT_SWITCH_INT VIC_SW"

- Использовать отдельное прерывание (VIC_SW) не обязательно, если у вас так же прерывать задачу может таймер. Для этого я принудительно вызывал прерывание от таймера такой командой:

VICSoftInt = (1 << VIC_TIMER1)

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

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

Так писать не нужно:

"VICIntEnable |= (1<<CONTEXT_SWITCH_INT);"

Через этот регистр можно только устанавливать биты, но не сбрасывать. Поэтому пишите так:

VICIntEnable = (1<<CONTEXT_SWITCH_INT);

А эта конструкция вообще убьёт всю систему:

"#define BlockContextSwitchMacro() do { \

VICIntEnable &= ~(1<<CONTEXT_SWITCH_INT); \

} while (0) // disable context switching interrupt

"

Для сброса бита разрешения конкретного прерывания есть другой регистр. Надо так:

VICIntEnClear = (1<<CONTEXT_SWITCH_INT);

Каюсь, здесь я промухал. Посыпаю голову окурками :-)

Кстати, зачем пишите "do {...} while (0)" ???

Это долгая история. Сначала увидел такую конструкцию в исходниках линукса и тоже был озадачен. Задал вопрос на сахаре и ReAl мне наглядно объяснил, что поскольку в макрос может быть добавлена еще одна команда то его лучше сразу заключить в {}, но макрос с {} нельзя использовать в лоб в конструкции if(cond) Macro(); else ....; а если добавить do while(0) то смысл не изменится но ограничений уже не будет.

Для чего timer 0, match 0 используете?
Системное время, ОС по нему считает тайм-ауты.

Для справки, все свободные биты из 32 источников прерываний можно использовать для своих нужд через регистр VICSoftInt. Специально для этого сделан VIC_SW, но и остальные действуют аналогично. Я проверял.
Угу, мне об этом говорили. Я, наивный, подумал что в атмеловском SAM7 так же. И тут же получил граблями в лоб - у атмела неиспользуемые биты не реализованы физически, т.е. "атакой, не атакуй...". С тех пор я слегка пуганый, и когда увидел в описании специально заточенный бит подумал "ВОТ!" и глубже решил не копать.

Кстати, у меня прерывание, переключающее задачи (которое я приводил) сделано так, что прерывания запрещены очень короткий момент и даже для 100 КГц прерываний ни одного не потеряется!
Я еще не измерял сколько у меня получилось время переключения - наверное сегодня выделю минутку. Вообще мы с автором scmRTOS обсуждали идею как сильно сократить время запрета прерываний, но пока это на уровне идеи - должно какое-то время повариться в мозгу.

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


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

Еще раз - я не хоче наступить на горло FreeRTOS, просто мне она субъективно не понравилась.

Это пожалуй главное. Так бывает. Я тоже не в восторге от многого, но идеал при знании потрохов :-)

недостижим, посему начал просто править "под себя" и под свой "вкус". А как "база" максимально устроила.

Объясню очень просто: указатели на любой объект передаются как void*

Ну такуж и на любой. Семафоры ака очередь это отдельная песня и при необходимости иметь оные несомненно буду встраивать 'семафористые' семафоры :-).

Причем предупреждения возникают при компиляции кода самой ОС. Что же это как не кривизна?

Это бардак :-(, такие места правлю, правда "легкой" c "наплевать на warnings" переносимости под разные компиляторы уже гарантировать нельзя.

Более серьезный пример идет в исходнике scmRTOS с сайта автора. Там есть и семафоры и очереди. Если есть желание - можем сравнить.

Нет, особого желания нет. Порядок "платы" ясен и меня совсем не смущают пару сот байт, особенно по отношению к размеру стеков (особенно при отсутствии даже простейших механизмов контроля обьема использования стека присутствующих в FreeRTOS) задач :-(. Кстати о стеках, на штатное (руками и так реализуется без напряга) нововведение FreeRTOS 4.x обратили внимание?

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


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

Объясню очень просто: указатели на любой объект передаются как void*

Ну такуж и на любой. Семафоры ака очередь это отдельная песня и при необходимости иметь оные несомненно буду встраивать 'семафористые' семафоры :-).

typedef void * xQueueHandle;

typedef xQueueHandle xSemaphoreHandle;

typedef void * xTaskHandle;

Собственно других открытых пользователю сервисов там вроде и нет.

 

Более серьезный пример идет в исходнике scmRTOS с сайта автора. Там есть и семафоры и очереди. Если есть желание - можем сравнить.

Нет, особого желания нет. Порядок "платы" ясен и меня совсем не смущают пару сот байт, особенно по отношению к размеру стеков (особенно при отсутствии даже простейших механизмов контроля обьема использования стека присутствующих в FreeRTOS) задач :-(.

Надо будет этот вопрос изучить, спасибо за наводку.

Кстати о стеках, на штатное (руками и так реализуется без напряга) нововведение FreeRTOS 4.x обратили внимание?
Нет, я работал с 3.2.2, как проект сдал больше на FreeRTOS.org не заглядывал. Посмотрю обязательно, спасибо.

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


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

Команды "LDMFD LR, {R0-LR}^ ; NOP ; ADD LR, LR, #15*4" можно упростить до "LDMFD LR!, {R0-LR}^". У меня в отладчике нормально прошло.

Нет, нельзя. Если идет ^ и в качестве опроного используется банкируемый регистр то нельзя писать в него обратно и в следующем такте обращаться к нему тоже нельзя. Вот цитата из того же ARM DDI 0029E:

Если подумать, то обратная запись в этой команде происходит не в тот регистр, который восстанавливается из стека. Поэтому мне кажется, что всё должно нормально прокатить. А в документе просто не слишком подробно этот момент описан. Он в некотором смысле уникальный. Я бы на вашем месте реально попробовал так упростить и проверить прямо на проце. Тем более, что мой отладчик (IAR 4.20) это проглатил и не подавился.

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


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

typedef void * xQueueHandle;

typedef xQueueHandle xSemaphoreHandle;

typedef void * xTaskHandle;

А здесь-то криминал-то в чем? Совершенно разные типы. Я 'дико извиняюсь', но это

typedef а не define - любой компилятор находясь в твердом уме и здравой памяти обломает

подмену безвариантно.

 

 

 

 

 

Нет, я работал с 3.2.2, как проект сдал больше на FreeRTOS.org не заглядывал. Посмотрю обязательно, спасибо.

Кстати :-) обратите внимание, там в переключении контекстов 'nop'-чик недавно добавился...

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


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

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...