Рубрика «freertos» - 2

image

Я уже рассказывал о том как можно использовать FreeRtos для проектов, написанных на С++ в статье STM32, C++ и FreeRTOS. Разработка с нуля. Часть 1. С тех пор прошло целых 3 года, я серьезно постарел, потерял кучу нейронных связей, поэтому решил встряхнуть стариной для того, чтобы эти связи восстановить и замахнуться на обертку для «любой» популярной ОСРВ. Это конечно шутка, я намеренно взял «всех» в кавычки, но в каждой шутке есть доля правды.
Читать полностью »

image

Отладка многозадачных программ дело не простое, особенно если ты сталкиваешься с этим впервые. После того, как прошла радость от запуска первой задачи или первой демо программы, от бесконечно волнительного наблюдения за светодиодами, каждый из которых моргает в своей собственной задаче, наступает время, когда ты осознаешь, что довольно мало понимаешь (вообще не врубаешься) о том, что на самом деле происходит. Классика жанра: «Я выделил целых 3КБ операционной системе и запустил всего 3 задачи со стеком по 128Б, а на четвертую уже почему-то не хватает памяти» или «А сколько вообще стека я должен выделить задаче? Столько достаточно? А столько?». Многие решают данные задачи путем проб и ошибок, поэтому в этой статье я решила объединить большинство моментов, которые, в настоящее время, значительно упрощают мне жизнь и позволяют более осознанно отлаживать многопоточные программы на базе FreeRTOS.

Данная статья рассчитана, в первую очередь, на тех, кто только недавно начал осваивать FreeRTOS, однако вполне вероятно, что и хорошо знакомые с этой операционной системой читатели найдут для себя здесь что-то интересное. Кроме того, несмотря на то, что статья ориентирована на разработчиков встраиваемого ПО, прикладным программистам она тоже будет интересна, т.к. много слов будет сказано о FreeRTOS как таковой, безотносительно микроконтроллерной романтики.

В данной статье я расскажу о следующих моментах:

  1. Настройка OpenOCD для работы с FreeRTOS.
  2. Не забываем включать хуки.
  3. Статическое или динамическое выделение памяти?
  4. Сказ, о параметре configMINIMAL_STACK_SIZE.
  5. Мониторинг использования ресурсов.

Читать полностью »

Как сделать context switch на STM32 - 1
Добрый день!
Потоки… Переключение контекстов… Базовая сущность ОС. И конечно, при разработке библиотек и приложений мы всегда полагаемся на то, что реализация потоков безошибочна. Поэтому было неожиданно найти грубую ошибку в переключении потоков для STM32 на ОСРВ Embox, когда уже продолжительное время работали и сеть, и файловая система и многие сторонние библиотеки. И мы даже успели похвастаться о своих достижениях на хабре.

Я бы хотел рассказать про то, как мы делали переключение потоков для Cortex-M, и тестировали на STM32. Кроме того, постараюсь рассказать о том как это сделано в других ОС — NuttX и FreeRTOS.
Читать полностью »

Доброго времени суток.
Разбираясь с программированием микроконтроллеров Stm32, решил попробовать установить (операционную систему реального времени) ОСРВ — FreeRTOS и столкнулся с рядом трудностей. В интернете есть множество статей, но внятной инструкции я не нашёл, поэтому всех заинтересовавшихся прошу под кат.
Читать полностью »

image

Керамический пьезоизлучатель (buzzer) — простая деталь, наравне со светодиодом требующая минимального набора ресурсов для управления и настолько же легко подключаемая к микроконтроллеру. Как и светодиоду с возможностью плавной регулировки яркости, от микроконтроллера ему требуется не более одного канала таймера и внешний вывод.

Много в интернете уроков «Подключаем пищалку к ардуино», только вот заканчиваются они проигрыванием «В траве сидел кузнечик» или озвучкой срабатывания RFID датчика. Наверное тем, кто занят этим профессионально и серьезно, не до ведения блогов и записи видеоуроков.

А ведь миниатюрный керамический динамик — шаг в сторону более дружелюбного интерфейса с человеком. Нажатия кнопок, касания сенсорной панели, реакция на различные события… Такая вот обратная связь в виде звукового отклика!

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

В предыдущей публикации мы подключали дешевый китайский LCD экран к плате STM32L4 Discovery. Теперь мы попробуем реализовать на этой комбинации что-то выходящее за рамки традиционного моргания светодиодом, а именно анализатор звукового спектра, который использует имеющийся на плате микрофон. Заодно я расскажу, как пользоваться операционной системой FreeRTOS, и зачем она нужна, а также почему в нотной октаве 12 нот, и чем 53 ноты лучше, чем 12.

Измерим гармонию — анализатор звукового спектра на STM32L4 Discovery - 1

Читать полностью »

Ведение

Попав в отпуске в город на Неве и посетив множество красивых мест, я все таки, вечерами за чашкой пива, разбирался с UARTом. Тем более, что я купил не плохие наушники Fisher FA011, к которым пришлось прикупить USB SOUND BLASTER X-FI HD и хотел послушать музыку.
Предыдущие статьи вначале переехали на Geektime потом я обратно их перегнал, даже и не знаю, куда теперь их деть :)
Но так на всякий случай они тут:
STM32, C++ и FreeRTOS. Разработка с нуля. Часть 1
STM32, C++ и FreeRTOS. Разработка с нуля. Часть 2 и
STM32, C++ и FreeRTOS. Разработка с нуля. Часть 3 (LCD и Экраны)

UART

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

Special function types can be used for static member functions. For example, in the
following example, the function handler is declared as an interrupt function:

class Device
{
 static __irq void handler();
};

Но вот незадача, для Cortex M такой способ не подходит и

On ARM Cortex-M, an interrupt service routine enters and returns in the same way as a
normal function, which means no special keywords are required. Thus, the keywords
__irq, __fiq, and __nested are not available when you compile for ARM Cortex-M.

These exception function names are defined in cstartup_M.c and cstartup_M.s.
They are referred to by the library exception vector code:
NMI_Handler
HardFault_Handler
MemManage_Handler
BusFault_Handler

The vector table is implemented as an array. It should always have the name
__vector_table,

Или по простому, ваш обработчик прерывания должен иметь такое же имя, какое он имеет в таблице векторов определенной в startup файле. Это делается с помощью специального ключевого слова — слабой ссылки __weak (в ассемблере PUBWEAK), которая означает, что данное определение будет использоваться до тех пора, пока не найдется хотя бы одно совпадающее по написанию без ключевого слова __week. Ну т.е., если вы определите функцию с точно таким же именем без этой директивы, то компилятро будет использовать это определение, а если не определите, то которое помечено __weak.
Понятное дело, что я не могу в файл startup_stm32l1xx_md.s или startup_stm32l1xx_md.с вставить С++ имя статического метода типа cUart::USART2_IRQHandler(), ассемблер его просто не поймет.
А просто «USART2_IRQHandler» не совпадает с определением «cUart::USART2_IRQHandler()».
Можно использовать extern «C» { void USART2_IRQHandler(void) {...}}, но это означает, что я тут буду делать встаки из Си, что мне совсем не надо, и вообще доступа из такой функции к атрибутам моего класса, например буферу — не будет, и надо будет городить кучу некрасивого кода :).
Поэтому, я решил пойти другим путем и создать файл startup_stm32l1xx_md.cpp. Поиск в интернете обнаружил, что точно такая же проблема была у некоторых людей
В общем идея заключается в следующем: Определяем startup_stm32l1xx_md.cpp в классы со статическими методами (которые и будут являться обработчиками прерываний), создаем таблицу __vector_table, где на каждом из векторов прерываний стоит указатель на на эти статические методы. Дальше делаем __weak определение каждого метода
И теперь когда в коде компилятор видет реализацию void cUart1::handler(), он не задумываясь берет её. Конечно же при этом ваши классы и методы должны называться точь в точь так, как они определены в startup_stm32l1xx_md.cpp.
Нужно еще не забыть про функции FreeRtos: vPortSVCHandler, xPortPendSVHandler, xPortSysTickHandler и поставить их на нужное прерывание и вуаля — все работает:

startup_stm32l1xx_md.cpp

#pragma language = extended
#pragma segment = "CSTACK"
extern "C" void __iar_program_start( void );
extern "C" void vPortSVCHandler(void);
extern "C" void xPortPendSVHandler(void);
extern "C" void xPortSysTickHandler(void);
class cNMI
{
public:
    static void handler(void);
};
class cHardFault
{
public:
    static void handler(void);
};
class cMemManage
{
public:
    static void handler(void);
};
class cBusFault
{
public:
    static void handler(void);
};
class cUsageFault
{
public:
    static void handler(void);
};
class cDebugMon
{
public:
    static void handler(void);
};
class cWindowWatchdog
{
public:
    static void handler(void);    
};
class cPvd
{
public:
    static void handler(void);    
};
class cTamperTimeStamp
{
public:
    static void handler(void);    
};
class cRtcWakeup
{
public:
    static void handler(void);    
};
class cFlash
{
public:
    static void handler(void);    
};
class cRcc
{
public:
    static void handler(void);    
};
class cExti
{
public:
    static void line0Handler(void);
    static void line1Handler(void);
    static void line2Handler(void);
    static void line3Handler(void);
    static void line4Handler(void);
    static void line9Handler(void);
    static void line15_10Handler(void);
};
class cDma
{
public:
    static void channellHandler(void);    
    static void channel2Handler(void);    
    static void channel3Handler(void);    
    static void channel4Handler(void);    
    static void channel5Handler(void);    
    static void channel6Handler(void);    
    static void channel7Handler(void);    
};
class cAdc
{
public:
    static void handler(void);    
};
class cDac
{
public:
    static void handler(void);    
};
class cUsb
{
public:
    static void highPriorityHandler(void);    
    static void lowPriorityHandler(void);
    static void fsWakeupHandler(void);
};
class cComp
{
public:
    static void handler(void);    
};
class cLcdDriver
{
public:
    static void handler(void);    
};
class cTim9
{
public:
    static void handler(void);    
};
class cTim2
{
public:
    static void handler(void);    
};
class cTim3
{
public:
    static void handler(void);    
};
class cTim4
{
public:
    static void handler(void);    
};
class cTim10
{
public:
    static void handler(void);    
};
class cTim6
{
public:
    static void handler(void);    
};
class cTim7
{
public:
    static void handler(void);    
};
class cTim11
{
public:
    static void handler(void);    
};
class cI2C1
{
public:
    static void eventHandler(void);
    static void errorHandler(void);
};
class cI2C2
{
public:
    static void eventHandler(void);
    static void errorHandler(void);
};
class cSpi1
{
public:
    static void handler(void);    
};
class cSpi2
{
public:
    static void handler(void);    
};
class cUart1
{
public:
    static void handler(void);    
};
class cUart2
{
public:
    static void handler(void);    
};
class cUart3
{
public:
    static void handler(void);    
};
class cRtcAlarm
{
public:
    static void handler(void);    
};
typedef void( *intfunc )( void );
typedef union { intfunc __fun; void * __ptr; } intvec_elem;
// The vector table is normally located at address 0.
// When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
// If you need to define interrupt service routines,
// make a copy of this file and include it in your project.
// The name "__vector_table" has special meaning for C-SPY:
// it is where the SP start value is found, and the NVIC vector
// table register (VTOR) is initialized to this address if != 0.
#pragma location = ".intvec"
extern "C" const intvec_elem __vector_table[] =
{
  { .__ptr = __sfe( "CSTACK" ) },
  __iar_program_start,

  cNMI::handler,
  cHardFault::handler,
  cMemManage::handler,
  cBusFault::handler,
  cUsageFault::handler,
  0,
  0,
  0,
  0,
  vPortSVCHandler,             //функции freeRTOS не трогать!
  cDebugMon::handler,
  0,
  xPortPendSVHandler,          //функции freeRTOS не трогать!
  xPortSysTickHandler,         //функции freeRTOS не трогать!
  //External Interrupts
  cWindowWatchdog::handler,    //Window Watchdog
  cPvd::handler,               //PVD through EXTI Line detect
  cTamperTimeStamp::handler,   //Tamper and Time Stamp
  cRtcWakeup::handler,         //RTC Wakeup
  cFlash::handler,             //FLASH
  cRcc::handler,               //RCC
  cExti::line0Handler,         //EXTI Line 0
  cExti::line1Handler,         //EXTI Line 1
  cExti::line2Handler,         //EXTI Line 2
  cExti::line3Handler,         //EXTI Line 3
  cExti::line4Handler,         //EXTI Line 4
  cDma::channellHandler,       //DMA1 Channel 1
  cDma::channel2Handler,       //DMA1 Channel 2
  cDma::channel3Handler,       //DMA1 Channel 3
  cDma::channel4Handler,       //DMA1 Channel 4
  cDma::channel5Handler,       //DMA1 Channel 5
  cDma::channel6Handler,       //DMA1 Channel 6
  cDma::channel7Handler,       //DMA1 Channel 7
  cAdc::handler,               //ADC1
  cUsb::highPriorityHandler,   //USB High Priority
  cUsb::lowPriorityHandler,    //USB Low  Priority
  cDac::handler,               //DAC
  cComp::handler,              //COMP through EXTI Line
  cExti::line9Handler,         //EXTI Line 9..5
  cLcdDriver::handler,         //LCD
  cTim9::handler,               //TIM9
  cTim10::handler,             //TIM10
  cTim11::handler,             //TIM11
  cTim2::handler,             //TIM2
  cTim3::handler,              //TIM3
  cTim4::handler,              //TIM4
  cI2C1::eventHandler,         //I2C1 Event
  cI2C1::errorHandler,         //I2C1 Error
  cI2C2::eventHandler,         //I2C2 Event
  cI2C2::errorHandler,         //I2C2 Error
  cSpi1::handler,              //SPI1
  cSpi2::handler,              //SPI2
  cUart1::handler,             //USART1
  cUart2::handler,             //USART2
  cUart3::handler,             //USART3
  cExti::line15_10Handler,     //EXTI Line 15..10
  cRtcAlarm::handler,          //RTC Alarm through EXTI Line
  cUsb::fsWakeupHandler,       //USB FS Wakeup from suspend
  cTim6::handler,              //TIM6
  cTim7::handler                //TIM7
};
__weak void cNMI::handler()          { while (1) {} }
__weak void cHardFault::handler()    { while (1) {} }
__weak void cMemManage::handler()    { while (1) {} }
__weak void cBusFault::handler()     { while (1) {} }
__weak void cUsageFault::handler()   { while (1) {} }
__weak void cDebugMon::handler()     { while (1) {} }
__weak void cWindowWatchdog::handler()  { while (1) {} }
__weak void cPvd::handler()             { while (1) {} }
__weak void cTamperTimeStamp::handler() { while (1) {} }
__weak void cRtcWakeup::handler()       { while (1) {} }
__weak void cFlash::handler()           { while (1) {} }
__weak void cRcc::handler()             { while (1) {} }
__weak void cExti::line0Handler()       { while (1) {} }
__weak void cExti::line1Handler()       { while (1) {} }
__weak void cExti::line2Handler()       { while (1) {} }
__weak void cExti::line3Handler()       { while (1) {} }
__weak void cExti::line4Handler()       { while (1) {} }
__weak void cExti::line9Handler()       { while (1) {} }
__weak void cExti::line15_10Handler()   { while (1) {} }
__weak void cDma::channellHandler()     { while (1) {} }
__weak void cDma::channel2Handler()     { while (1) {} }
__weak void cDma::channel3Handler()     { while (1) {} }
__weak void cDma::channel4Handler()     { while (1) {} }
__weak void cDma::channel5Handler()     { while (1) {} }
__weak void cDma::channel6Handler()     { while (1) {} }
__weak void cDma::channel7Handler()     { while (1) {} }
__weak void cAdc::handler()             { while (1) {} }
__weak void cUsb::fsWakeupHandler()     { while (1) {} }
__weak void cUsb::highPriorityHandler() { while (1) {} }
__weak void cUsb::lowPriorityHandler()  { while (1) {} }
__weak void cDac::handler()             { while (1) {} }
__weak void cComp::handler()            { while (1) {} }
__weak void cLcdDriver::handler()       { while (1) {} }
__weak void cTim2::handler()            { while (1) {} }
__weak void cTim3::handler()            { while (1) {} }
__weak void cTim4::handler()            { while (1) {} }
__weak void cTim6::handler()            { while (1) {} }
__weak void cTim7::handler()            { while (1) {} }
__weak void cTim9::handler()            { while (1) {} }
__weak void cTim10::handler()           { while (1) {} }
__weak void cTim11::handler()           { while (1) {} }
__weak void cI2C1::errorHandler()       { while (1) {} }
__weak void cI2C1::eventHandler()       { while (1) {} }
__weak void cI2C2::errorHandler()       { while (1) {} }
__weak void cI2C2::eventHandler()       { while (1) {} }
__weak void cSpi1::handler()            { while (1) {} }
__weak void cSpi2::handler()            { while (1) {} }
__weak void cUart1::handler()           { while (1) {} }
__weak void cUart2::handler()           { while (1) {} }
__weak void cUart3::handler()           { while (1) {} }
__weak void cRtcAlarm::handler()        { while (1) {} }
extern "C" void __cmain( void );
extern "C" __weak void __iar_init_core( void );
extern "C" __weak void __iar_init_vfp( void );

#pragma required=__vector_table
void __iar_program_start( void )
{
  __iar_init_core();
  __iar_init_vfp();
  __cmain();
}

image

Читать полностью »

На всякий случай, а то вдруг санкции применят (смаил). Описываемый случай не имеет никакого отношения к реальности и является целиком и полностью выдумкой автора

Раньше было про потоки, семафоры, очереди и HAL

Как-то раз попросили меня посмотреть на одно очень дорогостоящее устройство. Проблема была одна: среди использующих это устройство возникло стойкое убеждение, что 99,99% его цены происходит от того факта, что производитель этого устройства монополист в своей сфере и деваться пользователям этого устройства некуда.

STM32 и FreeRTOS. 5. Приносим пользу и добро! - 1

Вооружившись осциллографом, я полез внутрь.
Читать полностью »

HAL 9000: I'm completely operational, and all my circuits are functioning perfectly.

или это должно быть первой статьей, но я почему-то всегда пишу подобное ближе к концу

Раньше было про потоки, про семафоры и очереди

STM32 и FreeRTOS. 4. Шаг в сторону HAL - 1 Одним из основных препятствий для перехода на STM32 является обилие текстов, инструкций и мануалов, описывающих работу с контроллером. Виновником этого обилия стала сама STMicroelectronics, которая поначалу планомерно запутывала своих пользователей, а затем предлагала неверные варианты выхода.

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

Но не так давно ST поняла, в какую яму она угодила и начала усиленно из нее выбираться, привлекая новые силы. И именно благодаря этому сейчас время старта сократилось до несуразно маленьких величин. Как это выглядит на практике? Добро пожаловать под кат

Читать полностью »

Раньше: про потоки и про семафоры

«Вас много, а я одна!» — классическая фраза продавщицы, которую затерроризировали покупатели с вопросами «А есть ...?». Вот и в микроконтроллерах случаются полностью аналогичные ситуации, когда несколько потоков требуют внимания от какой-либо медленной штуки, которая просто физически не способна обслужить всех разом.

Возьмем наиболее яркий и богатый проблемами пример, на котором «валятся» большинство неопытных программистов. Есть мощный и достаточно быстрый микроконтроллер. К нему подключен с одной стороны адаптер com-порта, через который пользователь подает команды и получает результаты, а с другой — шаговый двигатель, который согласно этим командам поворачивается на какой-то угол. И конечно же, прикольная кнопочка, которая тоже что-то этакое значит для пользователя. Где можно наловить проблем?
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js