Jump to content

    
Sign in to follow this  
AHTOXA

Универсальный порт для Cortex-Mx (GCC) залит в репозиторий.

Recommended Posts

Всем привет.

 

Добрался до 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.

 

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

Share this post


Link to post
Share on other sites
Замечания и предложения приветствуются:)

Ну раз так, то настало время спросить.

startup.c: Почему бы не разогнать ядро, выполнив init_HW() до инициализации .bss и .data?

Зачем нужен __attribute__((__interrupt__)) для void Reset_Handler(void)? В стандартных шаблонах от производителей этого нет.

sysinit.cpp: Не кошернее ли enable IOPx peripheral делать не в общем для всех случаев файле, а на уровне конкретного проекта?

Share this post


Link to post
Share on other sites
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. Привычка к нормализации:)

Share this post


Link to post
Share on other sites

Обнаружил баг. Оказывается, Cortex-M0 не позволяет побайтовый доступ к регистрам System Control Block (SCB).

Поэтому некорректно устанавливались приоритеты обработчиков прерываний PendSV и SysTick.

Исправил в rev. 586.

Share this post


Link to post
Share on other sites

В более ранних версиях приоритеты обработчиков прерываний PendSV и SysTick устанавливались как

    SCB->SHPR3 = 0
            | (3 << 22)     // PendSV priority = 3, lowest
            | (2 << 30)     // SysTick priority = 2, little higher
           ;

Сейчас они устанавливаются одинаковыми, хоть и наинизшими. Есть какая-то причина?

 

Share this post


Link to post
Share on other sites

Нет, какой-то особой причины нет. Просто я сделал так, как было в порте для M3/M4. Там всю дорогу были одинаковые (наинизшие) приоритеты для PendSV и SysTick. Я подумал, что у M0 приоритетов и так мало, и жалко тратить аж два уровня из них на ось.

К тому же, инициализация SysTick сделана опциональной, так что пользователь всегда может написать свой вариант функции __init_system_timer(), в которой задаст нужный ему приоритет.

А зачем может быть нужно, чтобы SysTick мог прерывать PendSV?

Share this post


Link to post
Share on other sites

Я имел в виду другое. Возможно в более ранней версии для порта Cortex M0 была причина сделать так, чтобы PendSV могла быть вытеснена любым другим прерыванием, в том числе и SysTick.

Об этом неплохо бы у Сергея Борща спросить ;)

ПС: В порте для Cortex M3 приоритеты одинаковые.

Edited by IgorKossak

Share this post


Link to post
Share on other sites

Да простая там идея - чтобы перепланировка выполнялась после всех прерываний, которые могут эту перепланировку потребовать. Чтобы не перепланировать дважды. Само прерывание перепланировки выполняется с запрещенными прерываниями и прервать его никто не может.

Share this post


Link to post
Share on other sites

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

А если мы поднимем приоритет SysTick-а, то всё сработает как надо - сначала SysTick, и уже потом PendSV. Так?

Share this post


Link to post
Share on other sites
Тогда надо приподнять. Сделаю на днях.

Величины приоритетов сейчас задаются жёстко в файле OS_Target_cpp.cpp на уровне порта.

Величина "приподнимания" в случае с Cortex M3/4 будет зависеть от параметра функции NVIC_SetPriorityGrouping(n), в функции void init_HW(void) в файле sysinit.cpp на уровне приложения. На мой взгляд такое распределение не очень удобно. Может лучше эти магические числа вынести куда-нибудь в scmRTOS_TARGET_CFG.h?

Share this post


Link to post
Share on other sites

Нас не волнует группировка приоритетов, нам же не надо, чтобы 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, то оставляем старое поведение.

Share this post


Link to post
Share on other sites

То есть в порт добавляется еще куча объявлений уровня проекта. Зачем вообще пихать это все в ОСь? Достаточно попросить пользователя настроить эти два прерывания и системный таймер где, когда и как ему будет удобно.

 

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

Share this post


Link to post
Share on other sites

Какая куча? Добавляется всего одно объявление, причём как раз на уровне проекта. А в порте - fallback для старых проектов, в которых нет этого объявления. Как здесь можно сделать иначе?

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

Возможность выбрать другой таймер - есть. Возможность заменить функцию инициализации таймера на свою - тоже есть.

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

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this