Как стать автором
Обновить

Комментарии 22

Не смог найти примера для Keil/ARMCC.
Плохо искал?
Если вы про Embox, то у нас не под Keil. Собираемся легко из консоли)
На странице проекта есть короткое описание как собирать. Для прошивки stm32 используем openocd.
Embox собирается с помощью gcc.
Можно попробовать собрать llvm, но пока там есть нюансы:)
Для охвата всей аудитории желательно под все три компилятора.
GCC может и не плох, но далеко не идеал.
Тут дело в том, что считать всей аудиторией:)
У нас cortex-m лишь маленькая, пусть и интересная часть, поддерживаемых платформ!
И на текущий момент, только gcc являтся стандартом де-факто, под все (почти) архитектуры.
Приведенные Вами среды и компиляторы, хорошо подходят для разработки под конкретный микроконтроллер! Но у Embox одной из основных идей является привнесение в мир микроконтроллеров удобства программирования, как на большим системах, благо ресурсов хватает. Немного подробнее об этом в статье.
Да я не настаиваю. Дело хозяйское.
Все просто — много где есть sleep(), mutex_lock() и прочие “wait”, и за счет них потоки естественным образом и переключались.

Как мне это знакомо :) Только причина у нас была другая: мы таймер планировщика затёрли, а система до 15-25 минут могла нормально работать, пока не случался момент, когда все потоки решали подождать чего-то. Cypress FX3/ARM926E-JS/ThreadX. Такой вот гибрид кооперативной и вытесняющей многозадачности.


Кстати, косвенно про переключение контекстов в ThreadX можно посмотреть тут: https://habrahabr.ru/post/249991/. Отмечу, что под разные целевые платформы поведение может отличаться. ARM926E-JS в данном случае интересен тем, что существует два способа сохранить контекст в стек.

Да, с перетиранием тоже постоянно сталкивались, добавляли потом защиту стека для потоков, но не всегда помогает :) Ага, спасибо, просмотрел Вашу публикацию.
Кроме того, рассматривается случай, когда доступа к исходникам ThreadX нет и не предвидится.
А если не секрет, то зачем тогда именно ThreadX использовали?

Не секрет — это часть SDK от Cypress для FX3. Писать свой драйвер для USB 3.0 чисто по открытым исходникам Cypress и без документации было нецелесообразно.

Нам не очень подходит вариант FreeRTOS, так как эта ОС, направлена прежде всего на микроконтроллеры, что влечет за собой некую “захардкоженность” context_switch под конкретный чип

… FreeRTOS перед первым запуском задачи инициализирует стек (в том числе разрешает прерывания) этой задачи, что кмк должно происходить в любой ОС
Мы тут не говорим, что во FreeRTOS что-то плохо с переключением потоков. Я уверен, что все прекрасно переключается. Дело в том, что у них context_switch делается прямо ассемблерной вставкой внутри обработчика прерывания PendSV. А хочется отдельную функцию, без всяких прерываний, которую можно вызвать явно.

… FreeRTOS перед первым запуском задачи инициализирует стек
А про инициализацию в статье есть :)
Давайте изначально проинициализируем создаваемый поток так, как если бы мы выходили из прерывания — /* Simulate the stack frame as it would be created by a context switch interrupt. */
И приводится код функции pxPortInitialiseStack.

… про FreeRTOS понятно, а Embox инициализирует стек/регистры перед запуском потока (в статье этого не нашел)?
Да, инициализирует. Сама инициализация для cortex-m вот. А вот здесь она вызывается при создании потока.
Достаточно перейти в защищённый режим, и будим иметь два уникальных стека — для потоков и прерываний.
В этом случае любое прерывание сохраняет контекст в прерванный поток, а новые данные вытесняются уже в стек прерываний. Не важно какая-там получается глубина вложений прерываний, всё восстанавливается до первоначального вида.
Не требуется универсальный обработчик прерываний — это кстати костыль FreeRTOS и чибиос и ещё кучи последователей свидетелей иеговы. Не требуется запрет прерываний.

Необходимо выполнить всего одно условие: обработчик системных вызовов должен иметь нулевой приоритет, и вызываться из двух трёх прерываний максимального уровня (15) — это таймер реального времени, и таймер задачи. Пользовательские прерывания должны иметь приоритет от 1 до 15.
В качестве системного обработчика идеально подходит SVC.
Да собственно https://bitbucket.org/AVI-crak/rtos-cortex-m3-gcc/overview — моё.
Достаточно перейти в защищённый режим, и будим иметь два уникальных стека
Вы похоже про MSP и PSP? Как конкретно это решает проблему описанную в статье? Вот вы вошли в обработчик прерывания, вот у вас есть стек — окей, но пока вы из него не выйдете по стеку, новые прерывания того же типа не случаются. Именно поэтому во FreeRTOS и NuttX модифицируется стек.

Не требуется универсальный обработчик прерываний — это кстати костыль FreeRTOS и чибиос
У них есть вектор прерываний, насколько я знаю. На каждое прерывание дергается свой обработчик
В том весь и прикол, в защищённом режиме поток не может самостоятельно модифицировать свой стек, модификация возможна в теле прерывания.
Для того чтобы иметь 100% уверенности в том что стек прерываний полностью выбран — прерывания таймеров реального времени и таймера задачи — должны иметь 15 уровень — максимальный. Их могут все перебивать вдоль и поперёк, однако когда из них вызовется SVC — всё остальное будет ждать.

Не требуется запрет прерываний, не требуется кукла для всех прерываний сразу, нет потери прерываний.

Замена контекста у всех ос выглядит почти одинаково — переписываем стек и часть регистров. Вопрос в другом — зачем усложнять простое решение?
Не требуется запрет прерываний
Конечно не требуется, обработка вложенных прерываний — обычное дело.
не требуется кукла для всех прерываний сразу
Почему это плохо? Мне кажется — часто удобно.
Замена контекста у всех ос выглядит почти одинаково — переписываем стек и часть регистров. Вопрос в другом — зачем усложнять простое решение?
Статья как раз была об этом. Еще раз повторюсь :)
dsb
ldr r12, =__SysTick_CTRL
ldr r2, [r0, #8] // читаем адрес стека
ldmia r2!, {r4-r11} // читаем сохранённое
vldmia r2!, {s16-s31} // грузим математику
ldr r3, [r0, #20] // читаем новое время Task activity timer
str r3, [r12, #4] // сохранили время #0xE014 SysTick->LOAD
mov r3, #7
str r3, [r12, #8] // перезапуск #0xE018 SysTick->VAL
strh r3, [r12]
msr psp, r2 // переписываем стек
dsb
isb
bx lr

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

Кукла для всех прерываний кроме своего прямого назначения, делает ещё и мелкую пакость — вносит неконтролируемою задержку выполнения прерываний. Ведь кукла вызывается не в момент срабатывания конкретного прерывания, а просто по таймеру. Это не слишком заметно на проектах мигания лампочкой, но если требуется обработка в реальном времени — начинается цирк.
Нет, регистры мы так же быстро грузить умеем, с инструкцией ldmia знакомы, уж поверьте.
Ну а вообще да, жертвуя читабельностью что угодно можно на асме наваять. Хотя может это что-то и крутое, я без цельной картины не пойму отдельно выдранный кусок
Ведь кукла вызывается не в момент срабатывания конкретного прерывания, а просто по таймеру
А вот тут я видимо неправильно Вас понял сначала. Подумал как раз про общий обработчик, который уже остальные дергает. И им весь вектор прерываний заполняется.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.