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

Как лучше оформить таск?

У меня сейчас вся инициализация периферии в самом таске

void operation_task()
{
    static int mflag = 0;
	uint16_t message_status = 0;

    CFG_CONFIG_SetVal();

    /* PBIT process */
    power_init();
	WAIT1_Waitms(100);  

    /* SET config. value for FPGA */
    err_dat = init_configuration();
    /* detection of mode by discrete : Maintenance or Operational */
    g_crt_state = mode_detection_by_discrete();

    //includes import parameters from flash
    err_dat |= pbit_process();

    DrawTestDisplay();
    WAIT1_Waitms(500);
    ClearDisplay();

    MENU_Setup();

    ResetGlobalVariables();
    LIGHT_ImportDimParam();

	//////////////////LOGGER/////////////////////
    NFLASH_Reset();
    nand_flash_status = NFLASH_Init();

    LOG_ReadPartitionData(&logger_data);
    ImportBadBlocksData();
	
    Call_1553();
    mcp_init();
    incoming_mailboxes_init();

    while(1)
    {
        WDog1_Clear();

        if(mflag == 0)
        {
            operation_maint_process();
            message_status = MM_check_new_message();
            if (message_status > 1)
                err_count_1553++;
        }

        if(msgFlag == 1)
        {
           msgFlag = 0;

           mflag = dispecth_UART_cmd();
			    
        }
    }
}

int main(void)
{
   rtos_stat = FRTOS1_xTaskCreate((TaskFunction_t)operation_task, (signed char*) "oper_task", /*2048*/ 2048, NULL, 2, NULL);
  
   PEX_RTOS_START();
  
   for(;;){}
}
  

может вынести инициализацию из таска?

void operation_task()
{
    while(1)
    {
        WDog1_Clear();

        if(mflag == 0)
        {
            operation_maint_process();
            message_status = MM_check_new_message();
            if (message_status > 1)
                err_count_1553++;
        }

        if(msgFlag == 1)
        {
           msgFlag = 0;

           mflag = dispecth_UART_cmd();
			    
        }
    }
}

int main(void)
{
     static int mflag = 0;
	uint16_t message_status = 0;

    CFG_CONFIG_SetVal();

    power_init();
	WAIT1_Waitms(100);  

    err_dat = init_configuration();
    g_crt_state = mode_detection_by_discrete();

    err_dat |= pbit_process();

    DrawTestDisplay();
    WAIT1_Waitms(500);
    ClearDisplay();

    MENU_Setup();

    ResetGlobalVariables();
    LIGHT_ImportDimParam();

	//////////////////LOGGER/////////////////////
    NFLASH_Reset();
    nand_flash_status = NFLASH_Init();

    LOG_ReadPartitionData(&logger_data);
    ImportBadBlocksData();
	
    Call_1553();
    mcp_init();
    incoming_mailboxes_init();
  
   rtos_stat = FRTOS1_xTaskCreate((TaskFunction_t)operation_task, (signed char*) "oper_task", 2048, NULL, 2, NULL);
  
   PEX_RTOS_START();
  
   for(;;){}
}
  

 

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


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

6 minutes ago, jenya7 said:

может вынести инициализацию из таска?

Лучше сделать отдельную задачу, которая:

1. Проинициализирует периферию

2. Запустит остальные задачи

3. Самоубьётся

 

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


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

ИМХО, правильно можно так и так:

1. Если в задаче инициализируется только та периферия, которую обслуживает данная задача, тогда можно и в начале задачи это делать. Где-то читал, что в случае, если в инициализации используются системные вызовы, рекомендуется делать так:

void task1(void * param) {
  
  while (1) {
    
    periph_init();
    
    while (1) {
      periph_routine();
    }
      
  }
  
}

Мол компилятор без первого цикла (хоть он и не нужен) может криво оптимизировать и будет бо-бо.

2. Лично я предпочитаю все инициализации делать в одном месте, как в вашем втором случае.

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


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

41 minutes ago, jenya7 said:

может вынести инициализацию из таска?

Да, лучше вынести и разбить на функции по назначению: инициализация дисплея, памяти, интерфейсов и т.п.. Ибо трудно читать такие огромные портянки) Инициализировать в одной задаче, которую затем удалить.

Впрочем, я также инициализирую периферию по "месту требования": т.е. в том файле, где эта периферия нужна. Драйвера периферии не позволяют инициализировать её повторно, поэтому коллизий не возникает.

 

 

23 minutes ago, SMaster said:

Мол компилятор без первого цикла (хоть он и не нужен) может криво оптимизировать и будет бо-бо.

А можно подробнее? Это же обыкновенная функция. Делаю без первого цикла, и всё работает.

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


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

1 hour ago, aaarrr said:

Лучше сделать отдельную задачу, которая:

1. Проинициализирует периферию

2. Запустит остальные задачи

3. Самоубьётся

 

фига се. такого решения я не встречал.

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


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

20 minutes ago, haker_fox said:

А можно подробнее? Это же обыкновенная функция. Делаю без первого цикла, и всё работает.

Да, действительно, для FreeRTOS вряд ли так надо делать. Встречал данную рекомендацию для старенькой jacOS (вот буквально только что нашел ее в доках от этой РТОС). Но там совсем другая история: это кооперативная ОС + IAR вытворял чудеса компиляции, возможно вызванные недоработками самой ОС. Сорри, ляпнул "рекомендацию" не подумав. :)

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


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

3 minutes ago, SMaster said:

для старенькой jacOS

Оооо, так это же начало 2000-х, как помню) Тогда и компиляторы могли "глючить". Тот же IAR.

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


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

У меня периферия, требующая первостепенной инициализации (отладочный UART, например), настраивается перед запуском всех задач.
Т.е. в main() есть некая функция InitDevDrv(), которая настраивает периферию первой необходимости и периферию общего назначения.
Периферия общего назначения это, например, какие-нибудь GPIO для реле, дискретных входов/выходов и т.д.
Их драйверы не обслуживают какую-то конкретную задачу, они лишь предоставляют некий сервисный API любому желающему процессу.

А вот уже конкретная периферия под конкретный программный модуль настраивается в самой задаче перед while(1) или около того.

Вот, к примеру, main()

Скрытый текст

#include "main.h"

#include "pcdbg.h"
#include "gbctl.h"
#include "canctl.h"
#include "sysctl.h"

#include "eds.h"

#include "hw.h"
#include "wdt.h"
#include "dbg.h"
#include "led.h"
#include "pwr.h"
#include "nvm.h"


static void InitDevDrv(void)
{
  wdt_InitExt();
  wdt_UpdAll();
  
  dbg_Init();
  led_Init();
  pwr_Init();
  nvm_Init();
}

static void ActAftSysRst(void)
{
  if(hw_isRstOnPwr())
    SysCtlInf.rstonpwr = 1,
    dbg_PrintWarn("Reset on 'PWR'");
  else if(hw_isRstOnSoft())
    dbg_PrintWarn("Reset on 'SOFT'");
  else if(hw_isRstOnIWDT())
    dbg_PrintCrit("Reset on 'Int. WDT'");
  else if(hw_isRstOnExtWDT())
    dbg_PrintCrit("Reset on 'Ext. WDT'");
  hw_ClrRstInf();
  
  dbg_PrintNorm("System start");
}

static void RunUsrApp(void)
{
  pcdbg_Init();
  gbctl_Init();
  canctl_Init();
  sysctl_Init();
}

int main(void)
{
  InitDevDrv();
  ActAftSysRst();
  
  RunUsrApp();
  eds_RunTskManager();
  
  return 1;
}

P.S. Вот тут движок форума создает пустую строку, которую невозможно удалить и которая режет глаза...

а это, например, функция инициализации модуля взаимодействия по CAN

Скрытый текст

...
void canctl_Init(void)
{
  can_Init();
  
  eds_CreateTsk(EDS_TSKID_CANCTL, CANCtlTsk, 256);
}

 

У Xilinx, например, был небольшой костыль в исходниках FreeRTOS, которую они поставляли с Vivado SDK.
Они в xPortStartSheduler() вставляли вызов пользовательской функции vApplicationSetupHardware(), в которой можно было инициализировать железо.
Но, ИМХО, это не всегда удобно.

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


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

25 minutes ago, haker_fox said:

Оооо, так это же начало 2000-х, как помню) Тогда и компиляторы могли "глючить". Тот же IAR.

Для меня это была вторая половина 2000х :) Пару-тройку лет назад надо было подновить проект тех времен. И тут я удивился: в АТМега16 1 кБ RAM. Рили? Казалось, что больше. И как-то ведь работает. :)

Сорри за офтоп, нахлынули воспоминания. :)

4 minutes ago, Arlleex said:

Они в xPortStartSheduler() вставляли вызов пользовательской функции vApplicationSetupHardware(), в которой можно было инициализировать железо.

Такой костыль несложно и самому добавить. :) В общем-то не страшно и последовательно вызвать vApplicationSetupHardware(), а затем xPortStartSheduler(). :)

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


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

1 hour ago, jenya7 said:

такого решения я не встречал.

Между тем, это правильное решение: так появляется возможность пользоваться средствами ОС при инициализации периферии.

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


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

2 минуты назад, SMaster сказал:

В общем-то не страшно и последовательно вызвать vApplicationSetupHardware(), а затем xPortStartSheduler().

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

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


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

40 minutes ago, aaarrr said:

Между тем, это правильное решение

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

42 minutes ago, Arlleex said:

так это запрещенные прерывания на момент входа в нее.

О как. А заче запрещать прерывания для конфигурации периферии?

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


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

5 минут назад, haker_fox сказал:

О как. А заче запрещать прерывания для конфигурации периферии?

Чтобы какой-нибудь GiveFromISR() не ввел еще не запущенный диспетчер в ступор.
Или, например, в обработчике прерывания вызывается API RTOS выдачи семафора.
А этот семафор еще не выделился в памяти (не был вызван CreateSemaphore()).

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


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

6 часов назад, aaarrr сказал:

3. Самоубьётся

А это то зачем?  :shok:

3 часа назад, Arlleex сказал:

А этот семафор еще не выделился в памяти (не был вызван CreateSemaphore()).

Так вообще то, по уму, сначала делается инит всех переменных драйвера(-ов) в ОЗУ, и только затем - инит периферии, использующей эти переменные.

Если эти переменные (в том числе и средства синхронизации ОС) используются как семафоры разделяемой периферии, то ининтить их можно сразу в состояние "занято". А уже код инициализации периферии, по завершении своей работы, переведёт их в "свободно".

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


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

13 minutes ago, jcxz said:

А это то зачем?  :shok:

За ненадобностью. Можно и не убивать, если придумать ей разумное занятие.

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


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

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...