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

FreeRtos и его таски

Есть два таска - главный и логер с одинаковым приоритетом.В логере я записываю во флеш память большой кусок данных 4096 байт по SPI.

do
{
     spi_rw_flash(0x00, &flash_data);
    *buff_in++ = flash_data;    /* read data to buffer */                
     leng--;
}while( leng > 0);

время записи 20 милисекунд. время переключения между тасками 2 милисекунды. по идее за эти 20 милисекунд должно быть 10 переключений между тасками.на деле я вижу что во время записи в логер главный таск застревает.Вопрос почему? И второй вопрос - если пришло время переключения таска - скедюлер даст SPI дозаписать текущий байт или выйдет посередине?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все зависит от того в каком режиме RTOS работает, preemptive RTOS scheduler, or cooperative RTOS scheduler.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Все зависит от того в каком режиме RTOS работает, preemptive RTOS scheduler, or cooperative RTOS scheduler.

 

у меня preemptive RTOS scheduler. может стоит перейти на cooperative?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
у меня preemptive RTOS scheduler. может стоит перейти на cooperative?

Наоборот, поведение похоже на cooperative.

 

Как работает в FreeRTOS

Any number of tasks can share the same priority. If configUSE_TIME_SLICING is not defined, or if configUSE_TIME_SLICING is set to 1, then Ready state tasks of equal priority will share the available processing time using a time sliced round robin scheduling scheme.

 

https://freertos.org/RTOS-task-priority.html

 

Еще https://freertos.org/a00110.html#configUSE_TIME_SLICING

configUSE_TIME_SLICING

By default (if configUSE_TIME_SLICING is not defined, or if configUSE_TIME_SLICING is defined as 1) FreeRTOS uses prioritised preemptive scheduling with time slicing. That means the RTOS scheduler will always run the highest priority task that is in the Ready state, and will switch between tasks of equal priority on every RTOS tick interrupt. If configUSE_TIME_SLICING is set to 0 then the RTOS scheduler will still run the highest priority task that is in the Ready state, but will not switch between tasks of equal priority just because a tick interrupt has occurred.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Есть два таска - главный и логер с одинаковым приоритетом.В логере я записываю во флеш память большой кусок данных 4096 байт по SPI.

do
{
     spi_rw_flash(0x00, &flash_data);
    *buff_in++ = flash_data;    /* read data to buffer */                
     leng--;
}while( leng > 0);

время записи 20 милисекунд. время переключения между тасками 2 милисекунды. по идее за эти 20 милисекунд должно быть 10 переключений между тасками.на деле я вижу что во время записи в логер главный таск застревает.Вопрос почему? И второй вопрос - если пришло время переключения таска - скедюлер даст SPI дозаписать текущий байт или выйдет посередине?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
...с одинаковым приоритетом

Вот и ответ - нет причин переключаться.

 

И второй вопрос - если пришло время переключения таска - скедюлер даст SPI дозаписать текущий байт или выйдет посередине?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Я надеюсь, у вас spi_rw_flash отдаёт управление шедулеру при первом удобном случае (работает только по прерываниям, используя средства межпроцессного взаимодействия.

функция без прерываний

uint8_t spi_rw_flash(uint8_t tx, uint8_t* rx)
{
    uint16_t counter_retry = 0;
    uint8_t err = 0;

      g_uiRecFlag_SFL = 0;

    // send byte
      err |= SFL_SPI_SendChar(tx);

    // wait until event of receive occurred
     while(!g_uiRecFlag_SFL){
         counter_retry++;
         if (counter_retry > SPI_TIMEOUT_RETRY)
             return 1;
     };

     // receive and save data in .
     err |= SFL_SPI_RecvChar(rx);

     g_uiRecFlag_SFL = 0;

     return err;
}

а как нужно отдавать управление шедулеру? по идее он сам знает когда переключиться на другой таск.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
функция без прерываний
uint8_t spi_rw_flash(uint8_t tx, uint8_t* rx)

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

а как нужно отдавать управление шедулеру? по идее он сам знает когда переключиться на другой таск.

Да, если это ос вытесняющая, то таймер переключит вас с одного процесса на другой. Ну, а если вы молотите поллингом в задаче, у которой приоритет наивысший, то задачи с меньшим приоритетом никогда не получат управление. Нужно использовать прерывания, и ждать в задаче событий (используя семафоры, очереди, уведомления). Вот тогда, пока благородная железка занимается своим делом, вы ждёте прерывание, а процессор отдаёт это ожидание задаче, которая хочет что-то поделать, пусть она даже и низкоприоритетная. Когда железка закончит, она вызывает прерывание, а в прерывании вы сигналите задаче: "задача, для тебя есть работа". И если нет других, более приоритетных задач, то она получает управление. Обратите внимание, что в обоих случаях (по поллингу и с исопльзованием средств ос) задача ждёт, но время тратиться по-разному.

 

Почитать об этом вы можете в руководство на любую ос. Я рекомендую на scmRTOS. Там всё доходчиво разъяснено. Также почитайте эту тему более, чем десятилетней давности. Там я задавал такие же вопросы)))

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
функция без прерываний

Переделайте на DMA.

Кинул ссылку на буфер - запустил - забыл.

По окончанию можно прерывание выставить, а если на хале - прописать колбэк.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот эта настройка : configUSE_TIME_SLICING, установлена в 1 ?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Вот эта настройка : configUSE_TIME_SLICING, установлена в 1 ?

 

главное что бы она не была установлена в 0.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
главное что бы она не была установлена в 0.

Неа!

В исходниках ОС вот так проверяется : #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) ....

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Неа!

В исходниках ОС вот так проверяется : #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) ....

А если дальше поискать то можно найти в FreeRTOS\Source\include\FreeRTOS.h такие строчки:

#ifndef configUSE_TIME_SLICING
    #define configUSE_TIME_SLICING 1
#endif

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация