STM32 + FreeRTOS

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

Пункт ноль — окружение.

Я сторонник GCC, поэтому среда разработки — Eclipse, компилятор — Sourcery G++ Lite, отладчик — GDB.
Процессор STM32F103ZET, в принципе заработает на любом STM32F103.
Отладочная плата HY Redbull v3, от нее используются только светодиоды. Пойдет любая.

Пункт первый — стандартные библиотеки CMSIS и SPL (Standard Peripherals Library).

Сама FreeRTOS не использует эти библиотеки, но их будут использовать наши задачи. Соответственно под наши задачи и надо настроить.
Наши задачи будут мигать светодиодами. Как бы оно уже ни надоело, но что-то более внятное автоматом зацепит кучу другой информации. Например работа с экраном — сразу хочется и DMA и фреймбуффер, а значит надо залезть и в подключение SRAM. Нафиг. Мигать так мигать. Значит нам потребуется модуль GPIO из нашего SPL.
Поскольку «в STM32, чтобы выстрелить себе в ногу, пистолет надо сначала включить, а потом затактировать» (с), нам нужен модуль RCC.
Также для правильной работы FreeRTOS требуется работа системного таймера SysTick. Он находится в модуле misc библиотеки.

Проверяем, чтобы в файле stm32f10x_conf.h (который мы скопировали в наш проект) были раскомментированы

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"


Не забываем прописать путь к заголовкам библиотеки и включить исходники библиотеки в проект (или скопировать все что нам нужно в каталог проекта, что в принципе не рекомендуется, но поначалу все так делают).

Пункт второй — настройка FreeRTOS

Тут тоже достаточно просто — подключаем файл FreeRTOSConfig.h с минимальной настройкой параметров:

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#define configUSE_PREEMPTION		1
#define configUSE_IDLE_HOOK			0
#define configUSE_TICK_HOOK			1
#define configCPU_CLOCK_HZ			( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ			( ( portTickType ) 1000 )
#define configMAX_PRIORITIES		( ( unsigned portBASE_TYPE ) 5 )
#define configMINIMAL_STACK_SIZE	( ( unsigned short ) 120 )
#define configTOTAL_HEAP_SIZE		( ( size_t ) ( 18 * 1024 ) )
#define configMAX_TASK_NAME_LEN		( 16 )
#define configUSE_TRACE_FACILITY	0
#define configUSE_16_BIT_TICKS		0
#define configIDLE_SHOULD_YIELD		1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 		0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

#define configUSE_MUTEXES				0
#define configUSE_COUNTING_SEMAPHORES 	0
#define configUSE_ALTERNATIVE_API 		0
#define configCHECK_FOR_STACK_OVERFLOW	0
#define configUSE_RECURSIVE_MUTEXES		0
#define configQUEUE_REGISTRY_SIZE		0
#define configGENERATE_RUN_TIME_STATS	0

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet		0
#define INCLUDE_uxTaskPriorityGet		0
#define INCLUDE_vTaskDelete				0
#define INCLUDE_vTaskCleanUpResources	0
#define INCLUDE_vTaskSuspend			0
#define INCLUDE_vTaskDelayUntil			0
#define INCLUDE_vTaskDelay				1
#define INCLUDE_uxTaskGetStackHighWaterMark 0

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 		255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY	15

/*-----------------------------------------------------------
 * UART configuration.
 *-----------------------------------------------------------*/
#define configCOM0_RX_BUFFER_LENGTH		128
#define configCOM0_TX_BUFFER_LENGTH		128
#define configCOM1_RX_BUFFER_LENGTH		128
#define configCOM1_TX_BUFFER_LENGTH		128

#endif /* FREERTOS_CONFIG_H */


Главное настроить следующие параметры:
configCPU_CLOCK_HZ — частота процессора
configTICK_RATE_HZ — частота тика ОС

INCLUDE_vTaskDelay — разрешить использование функции vTaskDelay
По этому поводу первые грабли: ключи начинающиеся на INCLUDE сделаны для того, чтобы исключить неиспользуемые функции из билда, поэтому без них использовать соответствующие функции не получится — будет ошибка.

Остальное — как придется. Особо не важно.

В папке с FreeRTOS находим нужный нам порт (процессорозависимая часть) и забираем оттуда файлики (или подключаем нужную папку). Для нашего процессора порты находятся в папке:
\Source\portable\GCC\ARM_CM3\
Там два файла, забираем оба.

Также, из папочки \Source\portable\MemMang\ надо утащить один из файлов. Это менеджеры памяти, подробности — на сайте FreeRTOS. Утаскиваем heap_2.c

Пункт три — настройки основного проекта

Для правильной работы FreeRTOS нужны обработчики трех прерываний:

SVC_Handler
PendSV_Handler
SysTick_Handler

В исходниках FreeRTOS они описаны соответственно (файл port.c):
void xPortPendSVHandler( void ) __attribute__ (( naked ));
void xPortSysTickHandler( void );
void vPortSVCHandler( void ) __attribute__ (( naked ));

Чтобы линкер увидел эти описания и правильно собрал таблицу прерываний, надо слегка изменить файл стартапа. Делаем просто — везде, где нашли SVC_Handler меняем его на vPortSVCHandler и так далее.
Второй вариант, менее деструктивный, подсказал Bass: добавляем в файл FreeRTOSConfig.h следующие строки:

#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler


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

В файле main.c подключаем все до кучи:

// подключаем библиотеку CMSIS
#include "stm32f10x.h"

// Подключаем FreeRTOS
#include "FreeRTOS.h"
// из всех возможностей используем пока только переключение задач
#include "task.h"


В принципе все. Файл stm32f10x_it.h я не подключаю по вышеописанным причинам.

Пункт четыре — запуск

Вспоминая пистолет и выстрелы в ногу, надо инициализировать периферию (это все делаю в функции main(), но ничего не мешает вывести инициализацию в отдельную функцию. На усмотрение разработчика):

GPIO_InitTypeDef GPIO_InitStructure;

// запускаем тактирование GPIO порта F
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);

// Устанавливаем пины PF6, PF7, PF8, PF9 как выходные
// использовать будем PF6 и PF7, но уж проинициализируем все четыре LED
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8
		| GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOF, &GPIO_InitStructure);


Дальше запускаем две задачи:
xTaskCreate( vTaskLED1, ( signed char * ) "LED1", configMINIMAL_STACK_SIZE, NULL, 2,
			( xTaskHandle * ) NULL);
	xTaskCreate( vTaskLED2, ( signed char * ) "LED2", configMINIMAL_STACK_SIZE, NULL, 2,
			( xTaskHandle * ) NULL);

и после этого пинаем шедуллер, чтобы он крутил эти задачи:

	vTaskStartScheduler();

Да, надо жеж написать собственно код задач, чтобы было что крутить. Выше функции main(), чтобы не ругался компилятор, описываем две функции:
void vTaskLED1(void *pvParameters) {

	for (;;) {
		GPIO_SetBits(GPIOF, GPIO_Pin_6);
		vTaskDelay(500);
		GPIO_ResetBits(GPIOF, GPIO_Pin_6);
		vTaskDelay(500);
	}

}

void vTaskLED2(void *pvParameters) {

	for (;;) {
		GPIO_SetBits(GPIOF, GPIO_Pin_7);
		vTaskDelay(321);
		GPIO_ResetBits(GPIOF, GPIO_Pin_7);
		vTaskDelay(321);
	}

}

Тут, по-моему, классический пример самодокументированного кода :)
В первой функции мигаем светодиодом на PF6 с периодом 1000мс, во второй — с периодом 642мс. Это чтобы светодиоды мигали вразнобой и создавали полное ощущение асинхронности. Значение задержки задается в тиках системного таймера. У нас тик совершенно случайно равен 1 мс.

Компилим, заливаем, опаньки — все мигает.

Пункт пять — выводы

Объем скомпилированного кода получился чуть больше 5 килобайт:
arm-none-eabi-size  --format=berkeley test02.elf
   text	   data	    bss	    dec	    hex	filename
   5360	     20	  19188	  24568	   5ff8	test02.elf

Огромный объем bss – это heap, который отожрал FreeRTOS под свои нужды (стек задач, переключение контекста). Естественно, настраивается.

Что мы получили за эти деньги:
  • Вытесняющую ОС (если задача явно не передает выполнение операционной системе, ее грубо прерывают и диспетчер крутит задачи дальше). Можно отключить такое поведение.
  • Готовые потокобезопасные очереди, таймеры и семафоры (надо только подключить нужные .h)
  • Набор отладочных макросов. Например, можно узнать, какое максимальное потребление стека было у определенной задачи. Для того, чтобы урезать ей выделяемый стек, например.

Пункт шесть — «а теперь — слайды» (с).

Приложу дерево проекта как оно видно в Eclipse, для самопроверки. Папка Debug – туда, собственно, компилируется проект. Файл .elf и прочие ошметки я из архива удалил — они под 10 метров. Оставил .hex и листинги.
Обратите внимание, фиолетовые includes я добавлял ручками, иначе компилятор их просто не находит



PS. перезалил архив — теперь используется FreeRTOS 7.1.0

  • +5
  • 30 января 2012, 12:54
  • steel_ne
  • 1
Файлы в топике: test02.zip

Комментарии (92)

RSS свернуть / развернуть
С чего вы взяли что эти функции и структуры — это CMSIS? Это вообще то в первую очередь SPL (Standart Periphery Library). Некоторые склонны отождествлять эти вещи, но это не совсем верно.

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOF, &GPIO_InitStructure);
0
Да, действительно, был неправ. Поскольку они шли пакетом, то посчитал SPL частью CMSIS
0
В момент переключения теряются локальные переменные, поскольку они находятся в стеке. Выхода, собственно, два — описывать нужные переменные как static и заключать критические секции в специальные макросы, запрещающие переключение задач. Ну или не использовать вытеснение.

Это как это? Каждая задача имеет свой собственный стек, содержимое которого (локальные переменные, адреса возврата и т. п.) сохраняется между переключениями контекста. Есть еще coroutines, вот они не сохраняют локальных переменных, ибо используют один стек.
0
Блин. Да, это из coroutines, не в тот список плюсов-минусов залез, когда оформлял. Надо на свежую голову перечитывать перед публикацией )
0
configTICK_RATE_HZ не рекомендуется болеее 200 (кажется), в любом случае переключать контекст раз в миллисекунду — слишком часто. Если надо что-то делать с такой периодичностью, лучше использовать аппаратный таймер. configMAX_PRIORITIES в простой программе хватит и 2 (idle task и все остальные). На каждый приоритет ядро тратит память.

configMINIMAL_STACK_SIZE для STM32 должен быть минимум 128. При создании задачи к этому значению надо прибавлять реально требуемый для данной задачи размер стека (кроме idle task). Если у всех задач стек будет по 120 байт, переполнение стека произойдет весьма скоро (например, каждое прерывание расходует минимум 32 байта на сохранение контекста, а прерывания могут быть вложенными). Рекомендуется включать проверку целостности стека, хотя она и не 100% надежна.
0
Совершенно не спорю. Цель данной статьи — быстрый запуск. Тюнинг уже производится под конкретную задачу, серебряной пули не существует.
0
опять же, профайлинг и эксперименты со своими данными никто не отменял. Померять и увидеть глазами всегда нагляднее, чем просто следовать рекомендациям. Без срыва стека никогда не разберешься с распределением памяти
0
Это что-за эстонская ОС такая получается с макс.частотой тиков в 200Гц? Если где-то описано такое ограничение, то может ссылку предоставите?

#define configTICK_RATE_HZ				( ( portTickType ) 1000 )

Прям из демо (все не смотрел, но не в одном точно).
На сколько я понимаю, переключение контекста происходит каждый раз при смене выполняемой задачи, а за один тик они могут смениться не один раз.
configMINIMAL_STACK_SIZE для STM32 должен быть минимум 128.
Опять же хотелось бы узнать на чем основано данное высказывание?
0
Прям из демо (все не смотрел, но не в одном точно).

Вот из документации:

The tick interrupt is used to measure time. Therefore a higher tick frequency means time can be measured to a higher resolution. However, a high tick frequency also means that the kernel will use more CPU time so be less efficient. The RTOS demo applications all use a tick rate of 1000Hz. This is used to test the kernel and is higher than would normally be required.

More than one task can share the same priority. The kernel will share processor time between tasks of the same priority by switching between the tasks during each RTOS tick. A high tick rate frequency will therefore also have the effect of reducing the 'time slice' given to each task.

Почему именно 200 — не помню, но где-то наверное видел. Возможно, что это была рекомендация для менее производительных процессоров. В любом случае, если нужна периодичность 1мс или чаще, стоит вспомнить про таймеры и их прерывания. Задачи ОС служат не для того, чтобы выполнять действие раз в n миллисекунд, им много что может помешать — другие задачи с тем же или более высоким приоритетом и любые прерывания, кроме системных (используемых freertos).

configMINIMAL_STACK_SIZE для STM32 должен быть минимум 128.
Опять же хотелось бы узнать на чем основано данное высказывание?

По той же самой ссылке написано, что

Generally this should not be reduced from the value set in the FreeRTOSConfig.h file provided with the demo application for the port you are using.

А в демо configMINIMAL_STACK_SIZE равен 128. (Еще соображение — регистровый файл cortex-m занимает 16*4=64 байта, при каждом переключении контекста примерно столько стека расходуется, а еще кадр самой task функции и т. п.)
0
В демо для дискавери с STM32F100 configMINIMAL_STACK_SIZE равен 70 (мигание светодиодом) ;)
0
Like the stack size parameter to the xTaskCreate() function, the stack size is specified in words, not bytes. If each item placed on the stack is 32-bits, then a stack size of 100 means 400 bytes (each 32-bit stack item consuming 4 bytes).
0
По поводу стека — в ОС есть процедура мониторинга максимальной глубины стека (watermark). В приведенном примере (мигание светодиодом) значение было 96. Поэтому 128 — вполне нормальный минимум.
0
Если у всех задач стек будет по 120 байт, переполнение стека произойдет весьма скоро (например, каждое прерывание расходует минимум 32 байта на сохранение контекста, а прерывания могут быть вложенными).
И чем опасны вложенные прерывания?
Разве в cortex-m3 нет переключения стека при входе в прерывание? Или в порте не реализованно?
0
на сколько я знаю в ядре нет, а порт и не обязан реализовывать (всё равно может не успеть).
0
>>на сколько я знаю в ядре нет
Вспомнил, где читал: в описание порта scmRTOS для Cortex-m3/GCC.
Порт Cortex-M3/GCC использует отдельный стек для прерываний, то есть
при входе в обработчик прерывания происходит переключение на отдельный стек.
Такой подход даёт экономию стеков процессов, т. к. в этом случае не нужно в стеках
процессов резервировать пространство для работы обработчиков прерываний. В
качестве области памяти, выделенной под стек прерываний, используется память,
которая была стеком до старта ОС. Реализация этой возможности выполняется
аппаратно ядром Cortex-M3.
Схалтурили в FreeRTOS. B тоже самое с Cortex-M0 — удивился когда запускал порт для FreeRTOS на LPCXpresso с lpc1114 — вроде читал что есть такая фишка в ядре, а при входе в прерывание не увидел переключение SP (а может его нельзя увидеть? не тот регистр смотрел? или swd не позволяет). Впечатление тогда создалось: недоделка.

>>а порт и не обязан реализовывать (всё равно может не успеть).
Что не успеть?
0
Пересмотрю на досуге описание ядра. реально не помню в нем описания «аппаратного переключения стеков». у стм8 вроде как дотдельные банки регистров в прерываниях, а вот кортех-м3…
0
>>реально не помню в нем описания «аппаратного переключения стеков»
за что купил, за и продаю

>>у стм8 вроде как дотдельные банки регистров в прерываниях
впечатляет, у Атмел в xmege такого нет, отсталые
0
При создании задач глубина стека указывается в машинных словах. Если указываешь глубину стека 128, то в stm32 будет фактически отдано под задачу 512 байт. Даже для stm32 это расточительно. Так что не стоит принимать числа из примеров за аксиому. Для простого blinker'а на stm32f205 мне достаточно стека 38 слов (152 байта). Нужно делать профайлинг для конкретной задачи.
void vBlinker (void *pvParameters)
{
   (void) pvParameters;
   __GPIOB_CLK_ENABLE();
   GPIO_InitTypeDef GPIO_InitStruct;

   GPIO_InitStruct.Pin = GPIO_PIN_5;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

   while(1)
   {

      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
      vTaskDelay(980);

      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
      vTaskDelay(20);
   }
}
0
Да, еще одна придирка. Следующий код
0


GPIO_SetBits(GPIOF, GPIO_Pin_7);
vTaskDelay(321);
GPIO_ResetBits(GPIOF, GPIO_Pin_7);
vTaskDelay(321);

не обеспечивает мигание светодиодом с периодом 321*2 мс, ибо задача все же не одна и процессорное время не принадлежит ей на 100%. Если нужна определенная периодичность, лучше использовать vTaskDelayUntil().


portTickType lastExecutionTime = xTaskGetTickCount();

while(1) {
    vTaskDelayUntil(&lastExecutionTime, ((portTickType)321 / portTICK_RATE_MS));
    // выполнить действие
}
0
Суммарный период получился 0.642138791 с, погрешность очевидно меньше, чем один тик.
Но здесь «тепличные» условия — задачи 99% своего времени находятся в неактивном состоянии, ожидая завершения задержки
0
Вот именно, и самое главное — нет прерываний.
0
И использование vTaskDelayUntil интересно тогда, когда надо отслеживать задержку не с момента вызова функции vTaskDelay, а с какого-то определенного момента, например начала события.
0
Под Maple можно использовать
akb77.com/g/mcu/maple-stm32-library-for-freertos/
0
  • avatar
  • x893
  • 30 января 2012, 18:41
А можно поподробней расписать как «ручками» добавить фиолетовые фалы — использую CoIDE
Спасибо
0
Как в CoIDE добавляется, не в курсе.
0
Там GCC емнип. Так что под GCC переписать и все. А вообще у CoCOX своя RTOS прикольная есть.
0
Чтобы линкер увидел эти описания и правильно собрал таблицу прерываний, надо слегка изменить файл стартапа. Делаем просто — везде, где нашли SVC_Handler меняем его на vPortSVCHandler и так далее.
Это для чего такой изврат-то? Может просто оставить дефайны в FreeRTOSConfig.h?

#define vPortSVCHandler 				SVC_Handler
#define xPortPendSVHandler 				PendSV_Handler
#define vPortSVCHandler 				SVC_Handler
#define xPortSysTickHandler 				SysTick_Handler

P.S.: Было бу не лишним упомянуть про версию описываемой в статье.
0
  • avatar
  • Bass
  • 31 января 2012, 05:42
У меня версия была 7.0.2, там таких дефайнов не было. Качаю 7.1.0, гляну
0
Накопал такой дейфайн в одном файле. Спасибо, сейчас добавлю в статью.
0
Спасибо за подробное описание, осенью пробовал запустить на плате STM3210C-EVAL, да вот как раз на стартапе споткнулся. Теперь будет от чего оттолкнуться.
0
Предложение:
Добавить п.7:
Приаттачить исходники с файлами проекта в архиве.
Чтобы включил и поехал.
0
эээ. Ну как бы приаттачены.
Файлы в топике: test02.zip
0
Ага, мелким шрифтом :)
Не заметил сперва.
0
А какие у FreeRTOS на cortex-m3 скоростные характеристики. Интересует время переключения между задачами:
то есть, например, одна задача ушла в sleep, управление получает другая. Чему равен этот интервал?

И ешё вопрос сколько времени длится время с полностью запрещёнными прерываниями (если есть иакой запрет)?
0
Запустил такие два таска:

void vTaskLED1(void *pvParameters) {
	uint32_t i;

	for (;;) {
		GPIO_SetBits(GPIOF, GPIO_Pin_6);
		for (i=0; i<1000; i++);
		GPIO_ResetBits(GPIOF, GPIO_Pin_6);
		taskYIELD();
	}

}

void vTaskLED2(void *pvParameters) {
	uint32_t i;

	for (;;) {
		GPIO_SetBits(GPIOF, GPIO_Pin_7);
		for (i=0; i<1000; i++);
		GPIO_ResetBits(GPIOF, GPIO_Pin_7);
		taskYIELD();
	}

}


taskYield() — форсированное переключение контекста.

По данным логического анализатора (24МГц) время между фронтами получилось 3.2917 мксек
0
Спасибо.
>>По данным логического анализатора (24МГц) время между фронтами получилось 3.2917 мксек
Внушает…

>>taskYield() — форсированное переключение контекста.
А что значит форсированное? бывают более долгие?
Интересно было бы оценить время переключения при большем количестве задач — две имхо не характерно.
И какой режим работы? Вытесняющий?
0
Форсированный — это значит не дожидаясь окончания тика. Просто в этом случае включается следующая ожидающая задача.
Поскольку таск добровольно отдает тик, то тут не важно, вытесняющая или нет. Просто при вытеснении уже просто так не получить сигнал, который можно померять, надо будет код корежить.

А при большем количестве что изменится? Ну на десяток тактов будет больше поиск в таблице тасков.
0
taskYield() это не показатель в РТОС.
Это все равно, что сравнивать кооперативку и РТОС.
0
taskYield() это не показатель в РТОС.
Если нет запрета прерываний — то да.
Если есть, то на чём нибудь типа АВР — это очень даже показатель.
Это все равно, что сравнивать кооперативку и РТОС.
Про кооперативные почти ничего не знаю, так что сами понимаете…
0
Это не показаатель.
0
Нет переключения контекста. Не удивительно, что все быстро происходит.
Так, что он ничего не показывает.
0
Недопонял, задачи разные, как без контекста?
0
В чем разница при переключении тасков — добровольно отдать или отнять по таймеру? Время на переключение контекста то же самое. Ну плюс десяток тактов — обработка прерывания.
0
Да это не одно и тоже. Сколько уже говорить.
1) taskYield() — это наследие гибридного шедулера. Т.е. не чистокровный РТОС.
2) taskYield() — не гарантирует переключение на другую задачу. Он лиш передает управление шедуллеру и переводит задачу в состояние Redy.
0
Вот жеж упорный.
Окончание тика и вызов шедулера по прерыванию тоже не гарантирует переключение на другую задачу. Ичо?
Да, если ОС с кооперативной мультизадачностью, то без отдачи тика никакой мультизадачности и не будет. Но этот механизм и РТОС — понятия перпендикулярные. Если моя система обеспечивает требуемый отклик, то это РТОС, а внутри хоть неонка.
+1
Если тебе нравится кооперативный метод переключения задач сравнивать с вытесняющим и невидеть в нем разницу, то сравнивай))
0
Форсированный — это значит не дожидаясь окончания тика. Просто в этом случае включается следующая ожидающая задача.
Понял так(правильно ли)- задача вызвала sheduler

Поскольку таск добровольно отдает тик, то тут не важно, вытесняющая или нет.
да наверное
Просто при вытеснении уже просто так не получить сигнал, который можно померять, надо будет код корежить.
придётся.
А при большем количестве что изменится?
Я б сам хотел знать…
Ну на десяток тактов будет больше поиск в таблице тасков.
Хорошо если так

Терзают смутные сомнения. Опять сошлюсь на scmRTOS:
Fast
Minimal process switching latency:
2.7 us on Cortex-M3 @ 72 MHz
F увас на 24 МГц — 3.29. Интересно почему?
0
Вероятно потому что Minimal означает не «минимальное из всех ОС», а «Минимальное для данной ОС».
FreeRTOS может выполнять переключение быстрее за счёт оперирования упорядоченным списком задач (единым или по уровням). меньшим количеством дополнительных проверок. меньшим количеством объектов (синхронизачии, таймеров и пр.). Короче это уже сравнение символов кода :)
0
Возможно.
Надо смотреть: может доберусь на недельке собрать FreeRTOS для АВР с несколькими задачами, тогда может разберусь где там что и сколько времени занимает.
Пока аргументов и фактов меня нет.
0
частота процессора — 72МГц, 24 — это частота сэмплирования логического анализатора. Указал для того, чтобы была видна погрешность, которую вносит анализатор
0
астота процессора — 72МГц, 24 — это частота сэмплирования логического анализатора.
>>частота процессора — 72МГц,
Ну, как говорится: «так бы сразу и сказал». (А наверное и было сказано, да я не заметил). Я уже кинулся FreeRTOS для АВР рассматривать, в симуляторе запускать. Хорошо времени сейчас не нашлось — неглубоко закопался.
Спасибо, вовремя. Сэкономили мне кучу времени: под cortex FreeRTOTS вполне пойдёт, на под АВР она точно мне нужна.
0
Поправка:
но под АВР она точно мне не нужна.

P.S. Не пойму как сообщение отредактировать? Ну если ошибка какая. Есть такая кнопка?
0
Под АВР я ее хочу в кооперативе погонять. И не с тасками, а с coroutines. Вот это скорее всего и будет самый цимес.
0
Смотря какая АВР.
От тини (тоже с сотнями байт бывают) до xmeg256A3 с 16кБ внутренней или А1 с 16 МБ внешней озу на 32 МГц.
На последних и вытесняющую rtos вполне можно запускать.
0
Ну и выводы)
FreeRTOS выигрывает у scmRTOS:
1) Более широкий функционал.
2) Более шустрый шедуллер (три вида)
3) Меньший размер в больших проектах.
0
Ну и выводы)
Ну у вас ивыводы!!! Как выводили?
1) Более широкий функционал.
Да. Особенно заметное преимущество на «больших» системах. Более того: гораздо большее количество поддерживаемых платформ и количество пользователей.
2) Более шустрый шедуллер (три вида)
Выбор больше. Однозначно.
Более шустрый
scmRtos 2.7 us on Cortex-M3 @ 72 MHz
FreeRtos 3.29. на 72
больше/меньше знаете, я сам частоту не заметил.
Меньший размер в больших проектах.
Откуда дровишки? Из леса?
На авр freertos заявлен ~10кБ. scmrtos — 1-2-3.

Дальше, вопрос. Как понимать это(из описания c-m0);
The processor implements two stacks, the main stack and the process stack,
with independent copies of the stack pointer, see Stack Pointer on page 2-4.
и из с-m3:
The
processor implements two stacks, the main stack and the process stack, with a pointer for each
held in independent registers, see Stack Pointer on page 2-4.
Под рукой нет платы c lpc1114 не могу запустить пример с freertos и посмотреть есть ли переключение. Или его быть не должно?
0
Мда, батенька. Да вам следует прежде матана почитать.
Это разработчики scmRTOS написали. Топай на electronics, там эти операцинки сравнивали разработчики. Там собственно перечислены все пункты в которых scmRTOS проигрывает и подробно расписаны почему.
0
Мда, батенька. Да вам следует прежде матана почитать.
Я вижу, мы несколько потеряли тему разговора: Я не агитирую вас за scmRtos. а привёл цифры потому что других у меня нет. Проверял только на АВР и реальные цифры соответствуют заявленным.
Топай на electronics, там эти операцинки сравнивали разработчики. Там собственно перечислены все пункты в которых scmRTOS проигрывает и подробно расписаны почему.
Ну вы меня послали почти на все 4 стороны — electronics-то — немаленький. Если есть давайте.
Меня как раз и интересуют параметры других Осей для сравнения их между собой в выбора более подходящей.
Дальше, вопрос. Как
Насчёт стека не выскажетесь? Правильно ли я понял, что есть поддержка переключения стеков в кортексах 0 и 3?
Запускал именно FreeRtos на m0 и не увидел переключения(полгода назад).
Да и 2,7 мкс всёж меньше 3,29 мкс у FreeRtos, хотя функционал несомненно у FreeRtos лучше.
0
На электрониксе нужную тему найти 5ть минут. Там раздел посвещеный ОС. Заблудиться сложно.
В кортексе 3 есть аппаратная поддержка переключения контекстов. Конечно она сильно упрощенная. Об этом нужно читать описание на ядро а не на ОС.
0
На электрониксе нужную тему найти 5ть минут. Там раздел посвещеный ОС.
Про раздел знаю. Но там внутри ещё разделы и тем сотни… в общем будем искать… но там поиск такой: иногда проще не найти чем найти...
В кортексе 3 есть аппаратная поддержка переключения контекстов. Конечно она сильно упрощенная.
ну не x86. ну и слава богу.
Об этом нужно читать описание на ядро
В описании ядра нужно смотреть может ли ядро, а в описании ОС — что смогла ОС. Тут легко могу ошибится, так как не знаю как происходит переключение режимов ядра Thread/Handler — в обязательном порядке (тогда от ОС не зависит) или нужно настраивать.
0
И измерял я от выключения светодиода в одном таске до включения в другом. Вполне может быть что под Minimal process switching latency замерялось что-то другое, или при других условиях
0
Всё стало на свои места.
Вполне может быть что под Minimal process switching latency замерялось что-то другое, или при других условиях
Нет, не другое: оно самое и есть.
Один процесс отдал управление, sheduler выбрал следующую задачу, регистры сохранили/востановили, новая задача получила управление.
То есть:

 GPIO_ResetBits(GPIOF, GPIO_Pin_6);//vTaskLED1
 taskYIELD();
 GPIO_SetBits(GPIOF, GPIO_Pin_7);//vTaskLED2
0
Не спорю совершенно. Но зная маркетологическое желание выдать 900 мл за литр уже ничему бы не удивился.
0
Интересно было бы оценить время переключения при большем количестве задач — две имхо не характерно.
Для планировщиков типа O(1) время планирования не зависит от количества задач.
0
Для планировщиков типа O(1) время планирования не зависит от количества задач.
Может я не правильно понял, тип — вытесняющая.
Независит время выгрузки/загрузки регистров (при равном количестве).
А время планирования может зависеть, может не зависеть:
допустим 8-битный процессор, приоритеты фмксированны. Карта готовых к исполнению процессов байт (если 8), слово (16), дв.слово (32).
Номер приритетного процесса определяется сдвигом, пока не встретится установленный бит, число сдвигов подсчитывается и определяет номер запускаемого процесса. На тех же АВР разница будет заметной — раза полтора (есле сделать процессов штук 30, хотя кому это там нужно)б ведь кроме сдвига на 1 бит других команд нет.
Для ARM наверно всё проще, не знаю.
0
Описанный вами алгоритм не является O(1) (то есть константным по времени). В сети полно описаний алгоритма такого планировщика, например вот.
0
Почитаю.
Видно неправильно понял «O(1) ».
0
Связанные списки будет быстрее. готовая задача сразу в голове списка находится. но в таких случаях тяжелее (в ресурсах) будет помещение новой задачи или смена приоритета.
0
а по поводу запрещенных прерываний: в самой FreeRTOS прерывания запрещаются в момент работы с очередями, но там на первый взгляд ненадолго
0
Пока задач мало, наерняка и не заметно (предполагаю).
0
Собрал все под CooCox но никак( Все время у while(1) ((( Может у кого то есть под CooCox?
0
  • avatar
  • VIC
  • 12 мая 2012, 19:57
почему у вас так используется:
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler
Разве тут нет избыточности? разве первая и вторая строки не одинаковы????
в довесок приведу содержание из FreeRTOSV7.1.1\Demo\CORTEX_M4F_STM32F407ZG-SK\FreeRTOSConfig.h
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

разъясните ситуацию??
0
кстати, все требуемые для замены дескрипторы( например, для STM32F4Discovery, IAR) находятся в __vector_table в файле:
STM32F4-Discovery_FW_V1.1.0\Libraries\CMSIS\ST\STM32F4xx\Source\Templates\iar\startup_stm32f4xx.s это так… к сведению. может, кто-то, как я, искал их долго
0
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler</blockquote
разве первая и вторая строки не одинаковы????
>
А разве одинаковы?

vPortSVCHandler=SVC_Handler
и
xPortPendSVHandler=PendSV_Handler
SVC_Handler!=PendSV_Handler
Лишняя строка тут третья (#define vPortSVCHandler SVC_Handler), на неё возможен варнинг (redefinition)
0
о да, тысяча чертей!.. бес попутал, конечно, первая и третья. Описался.
0
Ну лично я понял как «первая и вторая выделенные строки». Тогда все правильно.
0
Пытаюсь запустить на Keil (Discovery).
Линкер ругается на не разрешенную vApplicationTickHook().
У Вас почему то не ругается, её я должен сам определить?
0
Здравствуйте. Решил начать изучение freertos с вашей статьи. Все хорошо, но не знаю что делать с ошибкой:
...
c:/program files (x86)/codesourcery/sourcery_codebench_lite_for_arm_eabi/bin/../lib/gcc/arm-none-eabi/4.6.3/../../../../arm-none-eabi/lib/thumb2\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text+0x12): undefined reference to `_sbrk'
collect2: ld returned 1 exit status
cs-make: *** [LEDs.elf] Error 1

возможно кто-то поможет?
0
_sbrk используется функцией malloc.
undefined reference говорит о том, что _sbrk не найдена, наверное предполагается что её надо реализовать самому или не использовать функции которые вызывают malloc (возможно это printf).
0
Не только malloc. Есть один хороший человек(+100500 ему в карму!) который разжевал newlib:) смотрите вот здесь вот тут, у меня была подобная проблема, решена вот тут
0
artjom прав, возможно, проблема действительно связанна с реализацией malloc().

Дело в том, что FreeRTOS использует динамическое выделение памяти для выделения памяти под стек каждого потока (а также для буферов очередей и т д.). Для выделения памяти, ОС использует функцию void *pvPortMalloc( size_t xWantedSize ).

Есть несколько готовых реализаций данной функции, они лежат в подкаталоге «\FreeRTOS\Source\portable\MemMang\» и называются соответственно heap_1.c, heap_2.c, heap_3.c.

heap_1.c и heap_2.c – это самостоятельная (независимая) реализация pvPortMalloc, а вот heap_3.c реализует pvPortMalloc() через вызов стандартной malloc().

Соответственно, если у вас подключен к проекту heap_3.c, то Вы должны обеспечить реализацию malloc() (а _sbrk(), на которую у вас ругается линкер – это часть реализации malloc()).
0
хм. всем спасибо.
Martovskij , и первый и второй способ работает. все компилится. но в кекс файле нереальная абракадабра:
 E ‘ ‘ ‘ ‘ ‘                 Y ‘     ] ™ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘                                                                                                                                                                                 _шасµ@тВт #xc№@т  Ат  (±@тдАц  Їу Ђ!!pЅ їµ@т Ат K±@тд@тАц  Вт Їу Ђ@т Вт  h)±@т Ат ±˜GЅ ї*ЙІpґШ"± #БT3“BыСpјpG…DFРшњыСХd&?-4DЭ`\`њ`Ь`a\aњaЬab\bњbЬbc\cњcЬc@3Х?-лЬа`\`њ`Ь`3Х-чЬаCшKХ-ъЬ“BЙТш“BыСДз їAк рFpґї $$*”ї $р
FД№Є±x:шKL±Fr±шo:шk#F .цС*±љ !ш“BыСpјpG)FUшK¤с6&крЂ?ЬС:CшK*рШ)FХзЂµЉ° Їx`Oр ыa рьDц@Вт h +3СDц0Вт @т0Вт `Dц0Вт Oр Z`Dц8Вт OфђBZ`Dц8Вт Oр `@т0Вт {a{iOфђBZ`ziDц8Вт `Dц@Вт Oр`{h +РAтаsАц €zhУ{`{hр +Р{h#рс{`{h +rРzhDтяsљBmШDц0Вт ;bDц0Вт h{bа{j;b{j


e_mc2 спасибо, буду пробовать
0
а все, разобрался. надо было в настройках arm-none-eabi-objcopy для бинарника поставить ihex. всем спасибо. система завелась. буду подгонять теперь видеодрайвер для HY-280_262k
0
а как насчет stm32f4-discovery? :)
0
А разве есть разница?
0
есть
0
В чем же, кроме библиотек?
0
в них родимых то и вся разница… в общем вопрос я решил, но повозиться пришлось
0
Как решили вопрос?
У меня пока только при запуске диспетчера все улетает в HardFault((
0
Я не понял. А где у вас ld script для линковки в бинарник?
0
В папке Config лежит.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.