Перейти к содержанию
    

SMaster

Участник
  • Постов

    24
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Информация о SMaster

  • Звание
    Участник
    Участник

Посетители профиля

1 102 просмотра профиля
  1. Для меня это была вторая половина 2000х :) Пару-тройку лет назад надо было подновить проект тех времен. И тут я удивился: в АТМега16 1 кБ RAM. Рили? Казалось, что больше. И как-то ведь работает. :) Сорри за офтоп, нахлынули воспоминания. :) Такой костыль несложно и самому добавить. :) В общем-то не страшно и последовательно вызвать vApplicationSetupHardware(), а затем xPortStartSheduler(). :)
  2. Да, действительно, для FreeRTOS вряд ли так надо делать. Встречал данную рекомендацию для старенькой jacOS (вот буквально только что нашел ее в доках от этой РТОС). Но там совсем другая история: это кооперативная ОС + IAR вытворял чудеса компиляции, возможно вызванные недоработками самой ОС. Сорри, ляпнул "рекомендацию" не подумав. :)
  3. ИМХО, правильно можно так и так: 1. Если в задаче инициализируется только та периферия, которую обслуживает данная задача, тогда можно и в начале задачи это делать. Где-то читал, что в случае, если в инициализации используются системные вызовы, рекомендуется делать так: void task1(void * param) { while (1) { periph_init(); while (1) { periph_routine(); } } } Мол компилятор без первого цикла (хоть он и не нужен) может криво оптимизировать и будет бо-бо. 2. Лично я предпочитаю все инициализации делать в одном месте, как в вашем втором случае.
  4. В кейл инициализация происходит в функции __main (посмотрите ассемблеровский стартап-файлик), откуда в свою очередь вызывается функция main. Попробуйте запихать эту переменную в watch. А еще для более простой отладки я бы для начала выключил оптимизацию.
  5. Протестировал стрим буфер. Компилятор Keil, максимальная оптимизация по скорости, контроллер STM32F103C8T6. Измерил количество тиков на типовые операции и использование стека в байтах. Получились интересные результаты: Create / Send / Receive (тики между переходом управления планировщику и получением байта принимающей задачей) / Stack Стрим буфер = 200 / 572 / 548 / 136 Старая добрая очередь = 290 / 311 / 319 / 176 То есть выигрыш только в стеке? Я надеялся, что и скорость выше будет. :crying: Получается, что есть смысл использовать буферы только если прижимает по стеку, либо ради фишек буферов - Trigger Level для стрим буфера и возможность отправки данных разной длины для буфера сообщений. Код тестовой программы: #include "stm32f10x.h" #include "FreeRTOS.h" #include "stream_buffer.h" #include "task.h" #include "queue.h" StreamBufferHandle_t buf_tmp; QueueHandle_t que_tmp; uint8_t i, j, k; void task_tmp1(void * param) { while (1) { i++; xStreamBufferSend(buf_tmp, &i, sizeof(uint8_t), portMAX_DELAY); vTaskDelay(100); i++; xQueueSend(que_tmp, &i, portMAX_DELAY); vTaskDelay(100); } } void task_tmp2(void * param) { while (1) { xStreamBufferReceive(buf_tmp, &j, sizeof(uint8_t), portMAX_DELAY); __NOP(); } } void task_tmp3(void * param) { while (1) { xQueueReceive(que_tmp, &k, portMAX_DELAY); __NOP(); } } int main() { xTaskCreate(task_tmp1, "tmp1", 128, NULL, 4, NULL); xTaskCreate(task_tmp2, "tmp2", 128, NULL, 3, NULL); xTaskCreate(task_tmp3, "tmp3", 128, NULL, 2, NULL); buf_tmp = xStreamBufferCreate(100 * sizeof(uint8_t), sizeof(uint8_t)); que_tmp = xQueueCreate(100, sizeof(uint8_t)); vTaskStartScheduler(); }
  6. xTaskNotifyStateClear

    А как проверяете была остановлена задача или нет? Не по возвращаемому ли значению функции ulTaskNotifyTake()? Дело в том, что функция xTaskNotifyStateClear() очищает лишь флаг уведомления (значение ucNotifyState в TCB), но не отчищает 32-битное значение переменной уведомления (ulNotifiedValue). При этом xTaskNotifyGive(), которой вы скорее всего пользуетесь для передачи уведомления, выставляет флаг ucNotifyState и инкрементирует ulNotifiedValue, а функция ulTaskNotifyTake() ожидает флага в течение заданного времени, но возвращает не успешность ожидания флака, а значение переменной ulNotifiedValue. Если есть необходимость после сброса уведомления понять блокировалась ли задача (а она скорее всего блокировалась, раз мы непосредственно перед ожиданием уведомления сбросили флаг), то надо применить ulTaskNotifyTake(pdTRUE, 0), которая сбросит не только флаг, но и значение, либо при ожидании воспользоваться функцией xTaskNotifyWait(), например в виде xTaskNotifyWait(0, 0, NULL, portMAX_DELAY), которая вернет флаг pdTRUE = уведомление_произошло, pdFALSE = произошел_таймаут.
  7. Я вот жду релиза версии 9.0, в нем запилили возможность статически выделять память TCB/стек, QCB/очередь.
  8. Я думаю, что с этим у вас все правильно, но все же на всякий случай: все обработчики прерываний, вызывающие API-шные функции операционки, используют специализированные функции с окончанием FromISR()? Все такие функции имеют приоритет 11 и выше (численно)?
  9. М.б. поможет увеличение стека задачи?
  10. 1. Какой контроллер, на какой частоте работает, какой бодрейт у USARTа? Чтобы понимать сколько ресурсов требуется. 2. Какой длины очереди? Если бодрейт не более 115200, то очень странно, что контроллер не успевает отработать очередь. Для увеличения производительности можно попробовать применить т.н. уведомления, которые появились во FreeRTOS сравнительно недавно. http://www.freertos.org/RTOS_Task_Notifica...As_Mailbox.html Код будет приблизительно такой: void USART2_IRQHandler(void) { char byte; volatile u32 status; portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; status = USART2->SR; /* Read one byte from the receive data register */ if (status & USART_FLAG_RXNE) { byte = USART_ReceiveData(USART2); xTaskNotifyFromISR(receive_task_handler, (uint32_t)byte, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); // receive_task_handler - хэндлер задачи, принимающей данные } /* Write one byte to the transmit data register */ if (status & USART_FLAG_TXE) { /* Берем байт из очереди */ if (xQueueReceiveFromISR(qTxGsmQueue, &byte, &xHigherPriorityTaskWoken) == pdTRUE) { /* A character was retrieved from the queue so can be sent to the THR now. */ USART_SendData(USART2, byte); } else { USART_ITConfig(USART2, USART_IT_TXE, DISABLE); } } portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); } void receive_task(void * param) { uint32_t data; while (1) { xTaskNotifyWait(0, 0, &data, portMAX_DELAY); // Время ожидания бесконечность // Do something // ... } } И вообще, интересно взглянуть на вашу задачу, из которой вызывается gsm_get_str(). Как верно заметил den_po время ожидания элемента из очереди = 0. Какой-то не RTOSовский подход - функция будет вызываться вхолостую, вместо того, чтобы выполнение задачи блокировалось до появления данных на входе USART. В моем примере время ожидания бесконечно (при INCLUDE_vTaskSuspend равном 1). Отправку тоже можно упростить (в вычислительном плане), заюзав DMA. Судя по вызову USART_ITConfig, контроллер серии STM32 => DMA на борту имеется.
  11. Насколько я понимаю, xSemaphoreGive() в случае применения его к мутексу вызывает переключение контекста только в случае, если более высоприоритетная задача находится в ожидании этого мутекса. Функция xSemaphoreTake() также не вызывает переключения контекста, если мутекс не занят. Итого, при использовании его в подобной тестовой ситуации с одинаковым приоритетом задач без использования задержек и событий нужно как минимум воткнуть taskYIELD(). Думаю, что в реальной ситуации таких вопросов бы не возникло. Там скорее всего приоритет задач, использующих общий ресурс, разный. Либо есть задержки vTaskDelay(), либо работа с общим ресурсом происходит по событию. Если ответить на вопрос про очередь задач задач, обратившихся за мутексом, то очереди здесь нет, но мутекс "помнит", что его ожидает задача с более высоким приоритетом и в этом случае при отдаче переключает контекст, а там уже планировщик разруливает, что же делать дальше.
  12. Только он стоит дороже STM32F303VC при том, что у f3 покруче ядро и периферия
  13. Вам подойдет серия STM32F3. Рекомендую обратить внимание конкретно на STM32F303VC: 4 АЦП на 5 мегавыборок/с, 39 аналоговых каналов. И самое главное: копеешная отладочная плата STM32F3DISCOVERY.
  14. Кто-нибудь может объяснить нафига в 8.2.1 добавили thread local storage? Как они поясняют, так некоторые библиотечные фунции используют глобальную переменную err для оработки ошибок, но как это заюзать на практике - примеров нет... :( Хочется понять что за штука такая, может полезно будет. Direct task notifications, например, из релиза 8.2.0 я использую уже плотно, мне эта штука понравилась. Экономия памяти и времени.
  15. Есть ли какие подводные камни при переходе на эту версию компилятора с версии 5.11? Какие нужно отключать оптимизации для работы под jacOS?
×
×
  • Создать...