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

Начало работы с scmRTOS

Как узнать точное использование стека процессами? А то я все делаю вслепую: выставил 100 - работает. Добавил ф-цию - зависает... Использую AVR (Mega324P). JTAG исключен из-за отсутствия свободных выводов. В симуляторе тоже проблематично (как получить ответ от перефирии I2C, SPI, ?..). Было бы совсем неплохо, если бы средствами ОС была возможность в отладочном режиме посмотреть размер неиспользуемого стека каждой задачи через терминал. Такую возможность я увидел в ОС нашего соотечественника uOS. Там для этой цели используется ф-ция task_stack_avail().

 

И второе. По поводу ф-ции Blink в режиме редактирования времени. Я это реализовал с использованием очереди сообщений, как в примере 3- Channel. Создал от базового класса TMsg объект Blink с методом InvertRect(...); Вопрос, собственно, заключается в следующем : Как обеспечить периодический MsgQueue.push(&Blink) ? Конечно, можно для этой цели использовать отдельный таймер, но хотелось бы обойтись системным таймером. Но не хочу использовать SystemTimerUserHook() по понятным причинам. Может воспользоваться OS::GetTickCount(); которая, на сколько я понял, возвращает общее количество тиков с момента запуска ОС ? Тогда при входе в п. меню "Редактирование" сохранить T = OS::GetTickCount(), а в низкоприоритетном процессе LCDProc отсчитывать от значения T 500 тиков (500*2=1сек) и тогда класть сообщение Blink в очередь. Также нужно учитывать переполнение счетчика. Что скажете?

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


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

Как узнать точное использование стека процессами?

Сергей Борщ советовал добавить в конструктор процесса memset, которая заполнит стековую память указанным значением. Стек для эксперимента надо взять с запасом. После этого делается прогон программы и анализируется глубина потребления стека.

 

Вопрос, собственно, заключается в следующем : Как обеспечить периодический MsgQueue.push(&Blink) ? Конечно, можно для этой цели использовать отдельный таймер, но хотелось бы обойтись системным таймером. Но не хочу использовать SystemTimerUserHook() по понятным причинам. Может воспользоваться OS::GetTickCount(); которая, на сколько я понял, возвращает общее количество тиков с момента запуска ОС ? Тогда при входе в п. меню "Редактирование" сохранить T = OS::GetTickCount(), а в низкоприоритетном процессе LCDProc отсчитывать от значения T 500 тиков (500*2=1сек) и тогда класть сообщение Blink в очередь. Также нужно учитывать переполнение счетчика. Что скажете?

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

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


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

Сергей Борщ советовал добавить в конструктор процесса memset, которая заполнит стековую память указанным значением. Стек для эксперимента надо взять с запасом. После этого делается прогон программы и анализируется глубина потребления стека.
Что такое memset ? Можно поподробней?

А что является инициатором (источником события) этого блинка? Вот оно и должно пихать в очередь сообщение.
Инициатором Blink является вход в п. меню "Настройка", в котором меняется режим работы клавиатуры (вернее процесса ScanKey):

..............................

CurrentMode = &EditTime;

}

если в отдельный процесс не выносить, а запускать из имеющегося, выполняющееся с заданной периодичностью).
Т.е. есть необходимо, чтобы был отдельный процесс, который запускается с заданной периодичностью? Я думал для этой цели использовать низкоприоритетный процесс LCDProc, а заданную периодичность в нем же осуществлять проверкой OS::GetTickCount()? и каждые 500 тиков в этом же процессе делать MsgQueue.push(&Blink). Но почему-то это не сработало:

OS_PROCESS void TProcLCD::Exec()    //TProc5
{
    for(;;)
    {
      CurrentTick = OS::GetTickCount();
      
      if(((CurrentTick-T) > 500)&&(CurrentMode == &EditTime))
      {
        MsgQueue.push(&Blink);
        T = CurrentTick;
      }
      
      TMsg* msg;
      
      MsgQueue.pop(msg);
      msg->run();
    }
}

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


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

Что такое memset ? Можно поподробней?

Функция такая. :)

 

Инициатором Blink является вход в п. меню "Настройка", в котором меняется режим работы клавиатуры (вернее процесса ScanKey):

Ну, вот из этого места и надо метать сообщение в очередь.

 

Я имел в виду нечто иное. Когда запускается Blink, то это самостоятельный процесс (просто запускаемый в качестве job), который сам отмеряет все времена и управляет требуемой периферией. Т.е. метнули сообщение в очередь, на том конце очереди сообщение извлекается и вызывается соответствующая функция, которая весь процесс мигания и осуществляет. Отработала, закончилась. Обработчик очереди готов к обработке следующего сообщения. Т.е. вся низкоуровневая работа по формированию времен возложена на виртуальную функцию объекта Blink. А код входа в меню только лишь мечет команду сделать это (путем помещения указателя на объект: &Blink).

 

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

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


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

После этого делается прогон программы и анализируется глубина потребления стека.
Уж извините за назойливость. А каким образом проанализировать глубину потребления стека? Вернее, как просмотреть содержимое стека?

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


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

Уж извините за назойливость. А каким образом проанализировать глубину потребления стека? Вернее, как просмотреть содержимое стека?

В данном случае руками либо написав функцию, которая будет анализировать область памяти, занятую под стек - адреса-то все известны.

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


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

В данном случае руками либо написав функцию, которая будет анализировать область памяти, занятую под стек - адреса-то все известны.

Что значит "руками" ? Или приведите, пожалуйста, пример функции.

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


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

Что значит "руками" ?

Руками - значит, остановить эмулятором прогон программы и посмотреть до куда стек заполнился.

 

Или приведите, пожалуйста, пример функции.

Предлагаете написать мне для вас функцию? :) Там все это совсем не сложно - адрес объекта известен, размер его полей до стека тоже известен, отсюда можно вычислить адрес, где начинается стек. Размер стека тоже известен. По сути надо просто от начала стека пройти до первого значения, которое отличается от значения по умолчанию (того, которым заполнен стек сначала). Это и будет размер свободного пространства в стеке. Далее, можно это опять же эмулятором смотреть, а можно вываливать хоть на терминал или куда удобно.

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


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

Обнаружил такую проблему. Если два процесса ждут один и тот же Signal от третьего процесса, то почему-то программа виснет. Если ef.Wait() в одном из процессов убрать, то все работает. Размеры стеков увеличивал. Не помогло.

OS_PROCESS void TMeasure::Exec()    //TProc1
{
    for(;;)
    { 
      monitoring.Wait();
      
      while(Flags & MEASURE)
      {      
        PCInt1.Wait();    // Ждем окончания преобразования АЦП (RDY => 0)
        measure();  
      }
    }
}

OS_PROCESS void TProcFOSP::Exec()    //TProc2
{
    for(;;)
    {
      monitoring.Wait();  // <<<<<<< Если этот убрать, то работает
      Sleep();
    }
}
...........
При входе в п. меню:
  Flags |= MEASURE;
  ENABLE_PCINT1;      // Разрешить прерывание от RDY
  monitoring.Signal();  
}

Второй процесс вообще ничего не делает, только ждет и спит. В чем может быть проблема?

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


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

Обнаружил такую проблему. Если два процесса ждут один и тот же Signal от третьего процесса, то почему-то программа виснет. Если ef.Wait() в одном из процессов убрать, то все работает.

Возможное решение есть тут. Файлы OS_Services.h и OS_Services.cpp.

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


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

Возможное решение есть тут. Файлы OS_Services.h и OS_Services.cpp.

Заменил эти файлы. Проблема осталась. Плюс перестала работать очередь сообщений. А есть ли смысл пробовать /branches/b1/Common_b2 Rev138 ?

 

PS. Прпробовал заменить файлы из /branches/b1/Common_b2 Rev138 . Обнаружил, что в файле scmRTOS_def.h отсутствует #include "scmRTOS_config.h" со всеми вытекающими ошибками. При подключении scmRTOS_config.h компилятор выдает ошибку:

Error[Pe144]: a value of type "byte" cannot be used to initialize an entity of type "OS::TPriority" D:\...\device\scmRTOS\Common\OS_Kernel.h 355 .

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


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

Заменил эти файлы. Проблема осталась. Плюс перестала работать очередь сообщений.

На данный момент ничего сказать не могу. У меня тоже есть проблемы с этим вариантом реализации в текущем проекте, поэтому я пока использую штатный вариант из trunk. Скоро доберусь до этого. Автор варианта правки бага в этой ветке Сергей Борщ, возможно, он сможет прокомментировать.

 

А есть ли смысл пробовать /branches/b1/Common_b2 Rev138 ?

Это тоже Сергей тренировался (Common_b2), но вся эта ветка (b1) - это полигон для отработки других вещей, никак не связанных с фиксом bug_1878045_fix. Т.ч. тут не ищите.

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


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

Попробовал создать отдельный ef2 для TProc2 и

...........
при входе в п. меню:
  Flags |= MEASURE;
  ENABLE_PCINT1;      // Разрешить прерывание от RDY
  monitoring.Signal(); 
  ef2.Signal();

Не помогло. Программа виснет и все тут... :(

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


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

Попробовал создать отдельный ef2 для TProc2 и

...........
при входе в п. меню:
  Flags |= MEASURE;
  ENABLE_PCINT1;      // Разрешить прерывание от RDY
  monitoring.Signal(); 
  ef2.Signal();

Не помогло. Программа виснет и все тут... :(

Т.е. два разных флага для разных процессов? Ну, тогда не в них дело. А чем смотрите? В смысле, какие отладочные средства есть?

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


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

Отладчиком (JTAG) не пользуюсь по причине отсутствия свободных выводов. Наблюдаю визуально по программе: перестает реагировать на кнопки и не выводит результат на экран через очередь сообщений.

Ну, тогда не в них дело.
А в чем же дело? Два процесса ждут Signal, каждый от своего EventFlag. В процессах после Wait() идет Sleep(). Когда из третьего процесса (из п. меню) даю ef1.Signal() и ef2.Signal() для процессов, то все виснет. В смысле остальные процессы не работают. Что я делаю не так ? :05:

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


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

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

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

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

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

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

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

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

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

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