Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Переинициализация задач
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
pokk
Добрый день, только недавно начал осваивать Freertos и не как не могу правильно сориентироваться с перезагрузкой зависших процессов.
Итак запускаю FreeRTOS в кооперативном режиме.
Создаю несколько задач
1) LCD
2) Термдатчик
3) Светодиоды
4) Usart
Первые три (LCD,T,LED) работают через I2C. Usart сам по себе
Разделение доступа ещё не сделал, но сделаю с использованием мьютекса.
Теперь если рассмотреть две созданные задачи LCD и USART
то выглядит это так:
CODE
Код
void vTaskUsart(void *pvParameters) {
  for (;;) {
    //-----Происходит передача данных по USART--------------
  }
}


void vTaskInitLcd(void *pvParameters) {
    unsigned long int delay=0;
  for (;;) {
      init_I2c();    //инициализация выводов
      init_lcd();     //инициализация выводов
      F_LCD_INIT(); // инициализация LCD(загрузка команд)  
      xTaskCreate( RunLcd, ( const char * ) "lcd", configMINIMAL_STACK_SIZE, NULL,2, &xHandleTask1);
      vTaskDelete(xTaskInitLcd);
  }
}

void ShowLcd(void *pvParameters) {
  for (;;) {
    //WriteLCDdata- это почти макрос функции I2C_Send_data
    //так что можно смело считать WriteLCDdata=I2C_Send_data     
     WriteLCDdata('H');  
     WriteLCDdata('E');
     WriteLCDdata('L');
     WriteLCDdata('L');
     WriteLCDdata('O');
     taskYIELD();
  }
}

void I2C_Send_data(unsigned char data1,unsigned char data2){
    /* initiate start sequence */
    I2C_GenerateSTART(I2C2, ENABLE);
    /* check start bit flag */
    while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_SB)){taskYIELD();};
    /*send write command to chip*/
    I2C_Send7bitAddress(I2C2, I2C2_SLAVE_ADDRESS7, I2C_Direction_Transmitter);
    /*check master is now in Tx mode*/
    //--------------------------------------------------------------------------
    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){taskYIELD();};  //Spead=400KHz delay=1000 clock   Spead=1KHz delay=65000 clock
    /*mode register address*/
    I2C_SendData(I2C2, data1);
    //--------------------------------------------------------------------------
    /*wait for byte send to complete*/
    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){taskYIELD();};  //3600 Speed=100Khz
    /*clear bits*/
    I2C_SendData(I2C2, data2);
    //--------------------------------------------------------------------------
    /*wait for byte send to complete*/
    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){taskYIELD();};
    //--------------------------------------------------------------------------
    /*generate stop*/
    I2C_GenerateSTOP(I2C2, ENABLE);
     while(I2C_GetFlagStatus(I2C2, I2C_FLAG_STOPF)){taskYIELD();};
}


Теперь собственно вопросы:
1) В случае зависания i2c как правильно сделать перезапуск lcd (
Хотел завести счётчик проверок условий(или по времени) в I2C_Send_data и по переполнению его создавать процесс vTaskInitLcd
потом решил что не правильно в функцию I2C_Send_data пихать внешние функции vTaskInitLcd и тд.
)
2) собственно тот же вопрос только при работе всех 4х задач.
3) Как запустить функцию(или задачу) I2C_Send_data с удалением по таймауту.(т.е если процесс запущен больше 10ms значит завис)



zltigo
QUOTE (pokk @ Oct 23 2015, 07:35) *
Добрый день, только недавно начал осваивать Freertos и не как не могу правильно сориентироваться с перезагрузкой зависших процессов.
Итак запускаю FreeRTOS в кооперативном режиме.

Начните с того, что НЕ используйте кооперативный режим. После чего следует подумать, что такое "зависший процесс" и зачем его вообще перезапускать вместо аккуратного написания кода.
Жмите уж тогда сразу reset sad.gif всему контролеру, если не заете причину "зависания", котороя вообще может быть и не я этом процессе. Наличие хоть вытесняющей, хоть нет многозадачности не отменяет использование обработчиков прерывания для, например, того-же I2C. Если уж продолжать говорить про "зависания", то тогда, как вариант, должен быть самый низкоприоритетный процесс до которого в случае "зависания" какого-либо из высоприоритетных процессов очередь запуска не дойдет и там уже если не доходит, то перезапуск всего по WD, либо, когда доходит - посмотреть вообще что в системе твориться.
Непомнящий Евгений
Убивать задачу в общем случае нельзя. К примеру задача в момент убийства может работать с очередью и очередь останется захваченной. Или задача может выделить память в куче - после убийства память не вернется. Могут быть разные проблемы, если во время убийства задача была внутри какой-то системной функции.

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

Код
int i2c_send(void *, unsigned);

int lcd_send() {
  ...
  if (int err = i2c_send(...))
    return err;
  ...
  return 0;
}


void lcd_task(void*) {
start:
  i2c_init(...);
  lcd_init(...);
  for (;;) {
    if (lcd_send(...)==ERR_TIMEOUT) {
       goto start;
    }
  
  }
}
pokk
Благодарю всех за ответ.
Цитата(zltigo)
После чего следует подумать, что такое "зависший процесс" и зачем его вообще перезапускать вместо аккуратного написания кода.

Физический обрыв периферии, либо сбой её (от помехи,или кривого кода). Если обрыв то после 2-3 перезапусков сигнализировать что это периферия отвалилась, и завершать выполнение задачи(хотя об завершении ещё подумаю).
Цитата(Непомнящий Евгений)
При истечении таймаута выдавать ошибку, которую пробрасывать наверх.

В принципе я изначально так и хотел сделать, но меня озадачило то что в надо городить много проверок.
Вот в функция lcd_init(...); в случае разрыва i2c может зависнуть на любой строчке получается её надо каждую проверять. В данном варианте в принципе это сделать можно, но в будущем могут возникнуть похожие проблемы которые так не решить.
Код
    WriteLCDcommand(0x30);
    delay_ms(7);
    WriteLCDcommand(0x30);
    WriteLCDcommand(0x30);
    WriteLCDcommand(0x3C); //8-и битный интерфейс

По этому я хотел сделать глобальный флаг который выставляется при истечении таймаута, но где и как его опрашивать так и не придумал.
Сейчас обдумываю следующее функцию i2c_send запускать как задачу и после выполнения удалять её, с засеканием время жизни задачи если время больше таймаута, то производитель переинициализацию. Но тут опять много проблем(очистка кучи при удалении, перезапуск задачи сначала .. )
Непомнящий Евгений
Цитата(pokk @ Oct 26 2015, 04:53) *
В принципе я изначально так и хотел сделать, но меня озадачило то что в надо городить много проверок.
Вот в функция lcd_init(...); в случае разрыва i2c может зависнуть на любой строчке получается её надо каждую проверять. В данном варианте в принципе это сделать можно, но в будущем могут возникнуть похожие проблемы которые так не решить.


Можно чуток модифицировать код

Код
    
int error  = 0;

void WriteLCDcommand(byte v) {
  if (error) return; // если была ошибка - ничего не делаем
  error = i2c_send_withTimeout(v)
}

int lcd_refresh() {
  error = 0;
  WriteLCDcommand(0x30);
  delay_ms(7);
  WriteLCDcommand(0x30);
  WriteLCDcommand(0x30);
  WriteLCDcommand(0x3C); //8-и битный интерфейс
  return error;
}


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


Еще раз - нельзя в общем случае удалять задачу. Это крайне порочная практика, что на фриртос, что на винде / линуксе. Удалять можно процесс целиком, но на фриртос процессов нет sm.gif

Безопасно удалить можно что-то в таком духе
Код
void task(void*) {
  int a = 0;  
  for(;;) ++a;
}


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

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.