AHTOXA
Mar 31 2015, 19:03
Всем привет.
Добрался до Cortex-M0+ (STM32L0xx). Подумал, что отличий от порта для Cortex-M4(F) немного, и поэтому взял порт Cortex-M0 от Сергея Борща и влил его в M4(F).
А так как порт Cortex-M4(F) уже поддерживал Cortex-M3, то порт получился универсальный.
Назвал порт
CortexMx, чтоб не трогать имеющиеся. Поддерживаются Cortex-M3, Cortex-M4(F), Cortex-M0, Cortex-M0+, Cortex-M1.
Добавил также
пример для STM32L0xx (плата STM32 NUCLEO-L053R8).
Планирую после тестирования перевести на этот порт все примеры для M3/M4.
Замечания и предложения приветствуются
IgorKossak
Apr 3 2015, 08:45
Цитата(AHTOXA @ Mar 31 2015, 22:03)

Замечания и предложения приветствуются

Ну раз так, то настало время спросить.
startup.c: Почему бы не разогнать ядро, выполнив init_HW() до инициализации .bss и .data?
Зачем нужен __attribute__((__interrupt__)) для void Reset_Handler(void)? В стандартных шаблонах от производителей этого нет.
sysinit.cpp: Не кошернее ли enable IOPx peripheral делать не в общем для всех случаев файле, а на уровне конкретного проекта?
Цитата(IgorKossak @ Apr 3 2015, 13:45)

startup.c: Почему бы не разогнать ядро, выполнив init_HW() до инициализации .bss и .data?
Дело в том, что в общем случае в init_HW() могут использоваться какие-нибудь статические/глобальные переменные, и тогда они будут использованы до инициализации. Если в вашем init_HW() гаранированно не нужны такие переменные, то можно и разогнать.
Цитата
Зачем нужен __attribute__((__interrupt__)) для void Reset_Handler(void)? В стандартных шаблонах от производителей этого нет.
Это из каких-то совсем старых версий тянется, там было. Ни на что не влияет, можно смело убирать.
Цитата
sysinit.cpp: Не кошернее ли enable IOPx peripheral делать не в общем для всех случаев файле, а на уровне конкретного проекта?
Так это и есть уровень проекта. Просто в примерах (когда их больше одного, как в STM32F1XX) файлы startup.c и sysinit.cpp совпадали, вот я их и вынес в папку SamplesCommon. Привычка к нормализации
AHTOXA
Apr 11 2015, 09:24
Обнаружил баг. Оказывается, Cortex-M0
не позволяет побайтовый доступ к регистрам System Control Block (SCB).
Поэтому некорректно устанавливались приоритеты обработчиков прерываний PendSV и SysTick.
Исправил в
rev. 586.
IgorKossak
Apr 16 2015, 17:41
В более ранних версиях приоритеты обработчиков прерываний PendSV и SysTick устанавливались как
Код
SCB->SHPR3 = 0
| (3 << 22) // PendSV priority = 3, lowest
| (2 << 30) // SysTick priority = 2, little higher
;
Сейчас они устанавливаются одинаковыми, хоть и наинизшими. Есть какая-то причина?
AHTOXA
Apr 16 2015, 18:01
Нет, какой-то особой причины нет. Просто я сделал так, как было в порте для M3/M4. Там всю дорогу были одинаковые (наинизшие) приоритеты для PendSV и SysTick. Я подумал, что у M0 приоритетов и так мало, и жалко тратить аж два уровня из них на ось.
К тому же, инициализация SysTick сделана опциональной, так что пользователь всегда может написать свой вариант функции __init_system_timer(), в которой задаст нужный ему приоритет.
А зачем может быть нужно, чтобы SysTick мог прерывать PendSV?
IgorKossak
Apr 16 2015, 18:09
Я имел в виду другое. Возможно в более ранней версии для порта Cortex M0 была причина сделать так, чтобы PendSV могла быть вытеснена любым другим прерыванием, в том числе и SysTick.
Об этом неплохо бы у Сергея Борща спросить

ПС: В порте для Cortex M3 приоритеты одинаковые.
Сергей Борщ
Apr 16 2015, 18:43
Да простая там идея - чтобы перепланировка выполнялась после всех прерываний, которые могут эту перепланировку потребовать. Чтобы не перепланировать дважды. Само прерывание перепланировки выполняется с запрещенными прерываниями и прервать его никто не может.
AHTOXA
Apr 16 2015, 18:58
Ага, то есть, если за время обработки какого-нибудь более приоритетного прерывания взведутся флаги SysTick и PendSV, то, при одинаковых приоритетах, сначала сработает PendSV, и уже потом SysTick, который в свою очередь может взвести флаг PendSV.
А если мы поднимем приоритет SysTick-а, то всё сработает как надо - сначала SysTick, и уже потом PendSV. Так?
Сергей Борщ
Apr 17 2015, 05:19
Цитата(AHTOXA @ Apr 16 2015, 20:58)

А если мы поднимем приоритет SysTick-а, то всё сработает как надо - сначала SysTick, и уже потом PendSV. Так?
Именно.
AHTOXA
Apr 17 2015, 05:37
Тогда надо приподнять. Сделаю на днях.
IgorKossak
Apr 17 2015, 19:14
Цитата(AHTOXA @ Apr 17 2015, 08:37)

Тогда надо приподнять. Сделаю на днях.
Величины приоритетов сейчас задаются жёстко в файле OS_Target_cpp.cpp на уровне порта.
Величина "приподнимания" в случае с Cortex M3/4 будет зависеть от параметра функции NVIC_SetPriorityGrouping(n), в функции void init_HW(void) в файле sysinit.cpp на уровне приложения. На мой взгляд такое распределение не очень удобно. Может лучше эти магические числа вынести куда-нибудь в scmRTOS_TARGET_CFG.h?
AHTOXA
Apr 18 2015, 05:51
Нас не волнует группировка приоритетов, нам же не надо, чтобы SysTick вытеснял PendSV, нам надо лишь, чтобы при одновременно установленных флагах этих прерываний первым срабатывало прерывание от SysTick. Для этого достаточно приподнять приоритет (или субприоритет) SysTick-а на 1 (== обнулить самую младшую значащую единичку в двоичном представлении приоритета).
А вот с поиском позиции этой самой младшей значащей единички - надо будет подумать. Насколько я помню, число значащих бит приоритета зависит от реализации, а значит, его надо задавать на уровне проекта.
К тому же, не хочется ломать совместимость с существующими проектами. Поэтому придётся добавтить в порт какие-то значения по умолчанию для каждой архитектуры.
---
Думаю сделать как-то так:
В scmRTOS_TARGET_CFG.h:
Код
#define CORE_PRIORITY_BITS 2
и в OS_Target_cpp.cpp:
Код
#if (!defined CORE_PRIORITY_BITS)
# define SYS_TIMER_PRIO (0xFF)
#else
# define SYS_TIMER_PRIO (0xFE << (8-(CORE_PRIORITY_BITS)))
#endif
То есть, если не задано CORE_PRIORITY_BITS, то оставляем старое поведение.
Сергей Борщ
Apr 18 2015, 07:26
То есть в порт добавляется еще куча объявлений уровня проекта. Зачем вообще пихать это все в ОСь? Достаточно попросить пользователя настроить эти два прерывания и системный таймер где, когда и как ему будет удобно.
Я вообще делаю все настройки периферии в стартапе и мне совершенно не нужны эти определения. Более того, меня напрягает необходимость сейчас передавать в потроха ОСи значение тактовой частоты.
AHTOXA
Apr 18 2015, 10:08
Какая куча? Добавляется всего одно объявление, причём как раз на уровне проекта. А в порте - fallback для старых проектов, в которых нет этого объявления. Как здесь можно сделать иначе?
Что касаемо вообще настройки таймера в порте, а не в проекте - так уж исторически сложилось. В ядре есть специальный таймер для оси, поэтому удобно иметь настройку этого таймера на уровне порта. Вот например, сейчас - выяснилось, что полезно иметь приоритет системного таймера чуть повыше, чем приоритет прерывания планировщика. Я исправлю порт, и все проекты, использующие этот порт, автоматически получат это исправление. Разве это не хорошо?
Возможность выбрать другой таймер - есть. Возможность заменить функцию инициализации таймера на свою - тоже есть.
Естественно, такого рода вариативность требует некоторых телодвижений, типа задания значение тактовой частоты. Я думаю, что это небольшая плата за гибкость.
AHTOXA
Apr 20 2015, 05:57
Сделал, залил в репозиторий. rev. 587.
Для того, чтобы получить приоритет прерывания системного таймера чуть выше, чем приоритет прерывания планировщика, необходимо в
scmRTOS_TARGET_CFG.h объявить макрос
Код
#define CORE_PRIORITY_BITS 2
Если этот макрос не объявлен, то считается, что приоритет имеет 8 значащих бит. Так как на всех знакомых мне камнях приоритет имеет менее 8 бит, то в этом случае всё будет работать как раньше, приоритет прерывания системного таймера будет самым низким.
esaulenka
Apr 23 2015, 06:23
Цитата(AHTOXA @ Apr 20 2015, 08:57)

Для того, чтобы получить приоритет прерывания системного таймера чуть выше, чем приоритет прерывания планировщика, необходимо в
scmRTOS_TARGET_CFG.h объявить макрос
Код
#define CORE_PRIORITY_BITS 2
Если этот макрос не объявлен, то считается, что приоритет имеет 8 значащих бит. Так как на всех знакомых мне камнях приоритет имеет менее 8 бит, то в этом случае всё будет работать как раньше, приоритет прерывания системного таймера будет самым низким.
Ещё б документировать его не только на форуме...
И вообще, мне кажется, стоит добавить табличку с комментариями в target_cfg.h:
CORE_PRIORITY_BITS = 4 для STM32F1xx, F2xx, (F3xx ?), F4xx, LPC17xx, LPC18xx
CORE_PRIORITY_BITS = 3 для LPC13xx, LM3S
CORE_PRIORITY_BITS = 2 для STM32L0xx, LPC11xx
Значения для этой таблички может выдать grep __NVIC_PRIO_BITS по базе с заголовками на процессоры. У меня таковой нет, к сожалению...
И да, принудительно привести тип будет аккуратнее:
enum { SYS_TIMER_PRIORITY =
(uint8_t)(0xFEUL << (8-(CORE_PRIORITY_BITS))) };
AHTOXA
Apr 23 2015, 10:00
Цитата(esaulenka @ Apr 23 2015, 11:23)

Ещё б документировать его не только на форуме...
Я ещё в список рассылки отписался.
Надо будет ещё добавить про новый порт новость на сайт. И обновить документацию... Но это уж к следующему релизу, наверное

Цитата(esaulenka @ Apr 23 2015, 11:23)

И вообще, мне кажется, стоит добавить табличку с комментариями в target_cfg.h:
Дело в том, что scmRTOS_TARGET_CFG.h - это файл уровня проекта, то есть, он изначально не рассчитан для применения на разных контроллерах.
Хотя, можно и добавить, не помешает.
Цитата(esaulenka @ Apr 23 2015, 11:23)

И да, принудительно привести тип будет аккуратнее:
enum { SYS_TIMER_PRIORITY = (uint8_t)(0xFEUL << (8-(CORE_PRIORITY_BITS))) };
Да, верное замечание, спасибо. Только я лучше маску добавлю, потому что доступ к словам оптимальнее:
enum { SYS_TIMER_PRIORITY = ((0xFEUL << (8-(CORE_PRIORITY_BITS))) & 0xFF) };
arhiv6
Sep 29 2016, 18:55
Разбирался с переключением контекста, появился вопрос: можно ли в обработчике прерывания PendSV_Handler() вместо
Код
" LDR R1, =os_context_switch_hook \n" // call os_context_switch_hook();
" BLX R1 \n"
использовать
Код
" BL =os_context_switch_hook \n" // call os_context_switch_hook();
вроде же команды равнозначны, но получается на одну инструкцию меньше. Или есть причины делать переход по адресу, а не по метке?
AHTOXA
Sep 29 2016, 21:59
Второй вариант короче, быстрее, но не может прыгать так далеко, как первый. Это относительный переход, и есть ограничение на длину прыжка.
а что мешает в таком случае объявление функции os_context_switch_hook сделать в одной секции с PendSV_Handler?
Надо полагать, и остальные хуки можно попробовать сделать так же?
AHTOXA
Oct 12 2016, 07:13
В общем, довольно долго у меня там был как раз ближний переход. Потом обнаружилось, что при разнице адресов больше допустимого для ближнего перехода GCC никак не ругается, а молча генерирует нерабочий код. Обсудили это с коллегами. Обсуждали вариант сделать макрос, чтобы пользователь мог сам переключать. Но потом посчитали, что на фоне всего обработчика (включая код os_context_switch_hook) дополнительные 2 такта настолько ничтожны, что проще, надёжнее и вернее сделать безусловно дальний переход.
Остальные хуки вызываются из сишного кода, поэтому там выбора нет.
alex6441161
Dec 20 2016, 06:26
Цитата(AHTOXA @ Mar 31 2015, 23:03)

Всем привет.
Добрался до Cortex-M0+ (STM32L0xx). Подумал, что отличий от порта для Cortex-M4(F) немного, и поэтому взял порт Cortex-M0 от Сергея Борща и влил его в M4(F).
А так как порт Cortex-M4(F) уже поддерживал Cortex-M3, то порт получился универсальный.
Назвал порт
CortexMx, чтоб не трогать имеющиеся. Поддерживаются Cortex-M3, Cortex-M4(F), Cortex-M0, Cortex-M0+, Cortex-M1.
Добавил также
пример для STM32L0xx (плата STM32 NUCLEO-L053R8).
Планирую после тестирования перевести на этот порт все примеры для M3/M4.
Замечания и предложения приветствуются

Здравствуйте, извиняюсь что не по совсем по теме но...
не могу найти порт для Cortex-A8. Может у кого есть?
QUOTE (alex6441161 @ Dec 20 2016, 13:26)

Здравствуйте, извиняюсь что не по совсем по теме но...
не могу найти порт для Cortex-A8. Может у кого есть?
Эк вы замахнулись!

Нет, такого порта, увы, нет. В перспективе может появиться под SoC c FPGA, но там A9. А у вас какой процессор конкретно?
darkling07
Apr 12 2017, 09:10
Подскажите, на что обратить внимание при переходе с версии 4.00 на 5 (5.10 аналогично)? Есть проект на lpc1768 и gcc, который пережил еще scmRTOS 3. На версии 4.00 все замечательно работает. С версией 5 после изменения CortexM3 на СоrtexMx все скомпилилось, но не работет. Инициализация проходит точно, но после OS::run() процессы не идут.
AHTOXA
Apr 12 2017, 11:03
Проверьте имена обработчиков прерываний SysTick и PendSv. Там что-то менялось, вроде.
darkling07
Apr 12 2017, 16:22
Да, точно они. Спасибо!
Было PendSVC_ISR и SystemTimer_ISR , стало PendSV_Handler и SysTick_Handler
AHTOXA
Apr 12 2017, 19:58
Это чтобы соответствовать нынешним именам в CMSIS. Для PendSV_Handler я оставил weak-алиас:
Код
#pragma weak PendSVC_ISR = PendSV_Handler
А вот с SysTick так не получилось, потому что там ещё нужна возможность использования другого таймера.
esaulenka
Apr 24 2017, 07:30
Балуюсь свежим gcc с link time optimization.
В двух проектах он как-то хитро оптимизировал os_context_switch_hook() и __init_system_timer() - почему-то решил, что символ не определён.
Причём в одном выкинул одну функцию, в другом - другую.
Помогло приписывание этим функциям атрибута used.
Сейчас попробовал тестовый пример - там выкинуло обе :-)
Код
Invoking: Cross ARM GNU C++ Linker
arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding
-flto -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op
-Waggregate-return -Wfloat-equal -g -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts"
-Wl,-Map,"scmRTOS.map" --specs=nano.specs -o "scmRTOS.elf"
./src/src/_cxx.o ./src/src/_exit.o ./src/src/_sbrk.o ./src/src/_syscalls.o ./src/src/assert.o ./src/_write.o ./src/main.o ./src/os_kernel.o
./src/os_services.o ./src/os_target.o ./src/recursive_mutex.o ./src/startup.o ./src/sysinit.o ./src/usrlib.o
C:\Users\ESAULE~1\AppData\Local\Temp\ccEIkvE6.ltrans0.ltrans.o: In function `PendSV_Handler':
<artificial>:(.text.PendSV_Handler+0x1c): undefined reference to `os_context_switch_hook'
C:\Users\ESAULE~1\AppData\Local\Temp\ccEIkvE6.ltrans0.ltrans.o: In function `Reset_Handler':
<artificial>:(.text.Reset_Handler+0x190): undefined reference to `__init_system_timer'
AHTOXA
Apr 24 2017, 09:53
С LTO у меня не получилось собрать ни разу с тех пор, как я перенёс ассемблерные функции в *.cpp.
Похоже, компилятор не понимает вызовов из инлайн-ассемблера.
Вот всё думаю, что раньше случится - авторы gcc допилят gcc, или я переделаю обратно на *.S файл
esaulenka
Apr 24 2017, 10:38
Тем не менее, боевой проект собрался компилятором 5.4 2016q3 (windows, скачан с arm.com) с галкой LTE и успешно работает.
6-я версия тоже работает, но требует некрасивых танцев вокруг шаблонов.
Да, ещё и на
аналогичные грабли с таблицей векторов наступил.
PS что хорошо, размер бинарника уменьшился килобайт на 5. С учётом того, что свободного места у нас осталось впритык, идея LTO требует всяческого развития.
AHTOXA
Apr 24 2017, 11:37
Да, сейчас попробовал, смог собрать с LTO. Добавил __attribute__((used)) к os_context_switch_hook() и __init_system_timer(). Сложность в том, что os_context_switch_hook() объявлена в os_kernel.h, и для того, чтобы добавить к ней этот атрибут, придётся что-то придумывать для всех компиляторов и поддерживаемых контроллеров.
Надо будет попробовать всё же сделать *.S файл, возможно, это позволит обойтись без залезания в общий код оси.
А таблица векторов у меня давно уже с этим атрибутом.
esaulenka
Apr 24 2017, 12:11
Можно просто в scmRTOS_TARGET.h добавить
Код
extern "C" {
extern stack_item_t* os_context_switch_hook(stack_item_t* sp) __attribute__((used));
extern void __init_system_timer() __attribute__((used));
};
AHTOXA
Apr 24 2017, 12:24
Да, так компилируется, но выдаёт warning про "redundant redeclaration". Неаккуратно как-то.
AHTOXA
Apr 25 2017, 22:02
Для проверки вынес PendSV_Handler() в ассемблерный файл. Всё прекрасно собралось с LTE, без внесения изменений в общие файлы оси. Выигрыш на моём тестовом проекте небольшой, но есть (text/data):
- без LTE (-02)...: 5948/468
- с LTE (-02)......: 5704/464
- без LTE (-0s)...: 5576/468
- c LTE (-0s)......: 5536/464
Ещё чуть потестирую, и, наверное, залью в develop. Потому как от этого никакого вреда, окромя пользы
Цитата(AHTOXA @ Apr 26 2017, 03:02)

Ещё чуть потестирую, и, наверное, залью в develop. Потому как от этого никакого вреда, окромя пользы

Залил в develop. Теперь LTE работает.
---
Проверил на небольшом проекте (text/data):
Без LTE: 25320 13956
...с LTE: 23432 13948
Неплохо.
Поправьте, пожалуйста, название файла описания порта.
На данный момент осталось старое название файла scmRTOS.ru.CortexM3.GCC,
хотя внутри уже название корректное Cortex-M/GCC.
С уважением.
AHTOXA
Jan 19 2018, 14:43
Так этот документ только про M3. Это тогда надо и содержание править, а не только название. Когда появится время - обязательно займусь.
Доработал документ, выложил:
scmRTOS.ru.CortexMx.GCC.pdf.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.