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

Трассировка процесса

MSP430F2418

есть в мэйне основной цыкл while(1). в теле цыкла вызываются всякие процедуры и функции которые по глобальным флагам делают те или иные действия. Есть обработчик прерываний который прерывает этот вайл и выставляет всякие флажки, которые обрабатываются в главном цыкле. обычно цыкл прохонит за несколько мс с учётом времени потраченное в перываниях. но иногда процесс где-то шляется больше секунды. в обработчике прерывания выставляю флаг. в главном цыкле должен по этому флагу запустить процедуру. так вот между выставлением флага в прерывании и проыеркой этого флага в гл. цыкле может пройти больше секунды. из прерывания выход мгновенный. 100%. а вот где потом процесс шляется целую секунду не могу найти. узнать бы в каком месте была прервана программа прерыванием и куда вернулась? Как бы трассировкку процесса устроить? Как это можно решить с помошью IAR EW IDE? или какими еще способами можно выяснить где мы были целую секунду?

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


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

Что-то похожее наблюдал, когда были включены прерывания, а обработчик NMI отсутствовал. Разберитесь с тем что у вас включено из прерываний, а что нет, после чего добавьте обработчики тех прерываний, которые включены. Просто так "шляться" программа в 2хх не может - в этом семействе есть аппаратный модуль сброса на этот случай.

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


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

Исходник обработчика прерывания приведите. Мнится мне, что именно там собака порылась.

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


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

Разберитесь с тем что у вас включено из прерываний, а что нет, после чего добавьте обработчики тех прерываний, которые включены. Просто так "шляться" программа в 2хх не может - в этом семействе есть аппаратный модуль сброса на этот случай.

да вроде всё что нужно включено, всё что не нужно выключено. Может какой нибудь прерывание не нужное раз в 3 дня включается и процесс постоянно ныряет в него около минуты. потом опять всё нормально. Но я ме могу понять где процесс находится? в каком прерывании или где застревает в мэйне?

 

И всё же, есть у кого-нибудь опыт трассировки процесса? Может кто-нибудь подсказать в какую сторону глянуть?

 

Исходник обработчика прерывания приведите. Мнится мне, что именно там собака порылась.
Ну тут адский код. Черт ногу сломит. Но мож на вскидку кто увидет потенциальную багу.

#pragma vector=TIMERB1_VECTOR
__interrupt void TimerB_Int1(void) {

  switch(__even_in_range(TBIV, 14)) {
    case 2: break; //Прерывание по модулю сравнения 1 (Высший приоритет)
    case 4:  TBCCTL2=0; InvalidIntCNT++; return;        
    case 6:  TBCCTL3=0; InvalidIntCNT++; return;
    case 8:  TBCCTL4=0; InvalidIntCNT++; return;
    case 10: TBCCTL5=0; InvalidIntCNT++; return;
    case 12: TBCCTL6=0; InvalidIntCNT++; return;
    case 14: Tic2sCounter++; return; //Прерывание по переполнению таймера B. Период 32768/65536=0.5 Гц (2 с)
    default: return;
  }
  

  TBCCR1+=Value32kHz1sCCR;
  //Цифровая коррекция хода часов
  //Изменение на 3 такта каждые 79 сек дает 0,1 сек/сут
  if(++DTC79Cnt>=79) {
    DTC79Cnt=0;
    TBCCR1-=(EEPROM.RTC_Correct*3)-60;  //60 - отставание на 2 сек/сут 
  }
  //Если нужно, считаем длительность заряда АКБ
  if(ChargeCnt) if(gFlags.ExtPower) {
    if(++ChargeSticks>4) ChargeSticks=0;
    if(!--ChargeCnt) EndCharge();
  }

  if(P3State != P3_Off) {
    //Если нужно, считаем секундный тайм-аут
    if(Sec_TimeOut) --Sec_TimeOut;
    //Если нужно, проверим время автовыключения
    if(gFlags.ExtPower) {AutoOffCnt=EEPROM.AutoOff; BLAutoOffCnt=EEPROM.BLAutoOff;}
    else{
      if(AutoOffCnt)   if(!--AutoOffCnt)   gFlags.AutoOff=1;
      if(BLAutoOffCnt) if(!--BLAutoOffCnt) InitBackLight();
    }
    //Синхронизируем индикацию с часами
    if((Cnt20ms>1) && (Cnt20ms<18)) Cnt20ms++;
    if((Cnt1S>1)   && (Cnt1S<48))   Cnt1S++;
  }
  //Если идет ожидание окончания измерения, считать секунды
  if(MeasWait) MeasWait--;
  //Если часы остановлены, выход
  if(gFlags.ClockStop) return;
  _EINT();
  //Прибавление секунды к текущему времени
  //NewSec++;
  if( GsmCheckTimeOut != 0)
      --GsmCheckTimeOut;
  ++CurDT.Sec;
  if((CurDT.Sec >= 1) && gFlags.TimeBeginConnect)
  {
      gFlags.TimeBeginConnect = 0;
//PORT_UART_PC &= ~Bit_UART_PC_FOF;//порт сбросим для наблюдения в осцилографе
  }
#ifdef RADIO
  if(CurDT.Sec == 58)
  {//включим питание RFD21733
      UARTAdOn();
      Power4On();
  }
#endif
  
//if(CurDT.Sec == 3)///!!!
//    CurDT.Sec = 56;
    
  if(CurDT.Sec>59) {
     
        
    CurDT.Sec=0;
    //Если есть нормальное питание (EP2), проснуться
    if(!PowerIsLi())
    {
        _BIC_SR_IRQ(LPM3_bits);
        InitUART1();
        IdleDelay=1;
    }
    BCSCTL1 &= ~XT2OFF;
    BCSCTL2 |= SELS;
    gFlags.TimeBeginConnect = 1;
    gFlags.isTest = 1;
    BeginSysTimer(); //сброс дебажного счетчика
    gFlags.Synchronization = 1;
    if(--timeCheckBattary == 0)
    {
        gFlags.CheckBattary = 1; // флаг проверки батареи
        timeCheckBattary = 10;
    }
    //PORT_UART_PC |= Bit_UART_PC_FOF;
    if(++CurDT.Min>59) {
      CurDT.Min=0;
      if(++CurDT.Hour>23) {
        CurDT.Hour=0; CurDT.Day++;
        if(CurDT.Day>CalcDayInMonth(&CurDT)) {  //Месяц закончился
          CurDT.Day=1;
          if(++CurDT.Month>12) {
            CurDT.Month=1;
            CurDT.Year++;
          }
        }
      }
    }
  }  
  //Проверка будильника
  if((AlarmAct != AA_Off) &&                      //Будильник включен,
     (AlarmAct != AA_ProcStop) &&                 //Не требуется окончание процесса
     (*(WORD*)&AlarmDT.Sec==*(WORD*)&CurDT.Sec) &&      //..секунды, минуты совпадают,..
     (*(WORD*)&AlarmDT.Hour==*(WORD*)&CurDT.Hour) &&    //..час, день,..
     (*(WORD*)&AlarmDT.Month==*(WORD*)&CurDT.Month))    //..месяц, год
  {
    //Будильник сработал, установить флаг
    regFlags.Alarm=1; MeasStep=MS_Wait;
    //Если есть нормальное питание (EP2), проснуться
    if(!PowerIsLi()) {_BIC_SR_IRQ(LPM3_bits); IdleDelay=1;}
    //При отсутствии нормального питания установить флаг потенциальной ошибки
    else {InitPower(); regFlags.PotencError=1;}
  }
  //Если при отсутствии нормального питания (EP2) разрешено включение, разобраться
  if((IE_PowerIn & Bit_PowerIn) && PowerIsLi()) {InitPower(); _BIC_SR_IRQ(LPM3_bits); regFlags.PotencError=1;}
  //Программный WDT
  if((P3State != P3_Off) && !--SoftWDT) {regFlags.PotencError=1; regFlags.ResultWrite=0; WarmReset();}
  asm("nop");
  msTime[0] = EndSysTimer(); фиксация дебажного счетчика
}

 

А вот еще возник вопрос, может здесь грабля лежит. Как работает "многопоточность" в мсп430 + иар?

например есть код и есть обработчик прерывания

///main.cpp
bool happy;
int main()
{
happy = false;
while(1)
{
    if(happy)
    {
         divHappySmb();
         happy = false;
    }
}
}

//обработчик прерывания
#pragma vector=TIMERB1_VECTOR
__interrupt void TimerB_Int1() 
{
    happy = checkMyMoney();
}

 

так вот, крутимся постоянно в main. по прерываниям порадаем в TimerB_Int1(). Можно сказать что тут 2 потока - главный и обработчик прерывания. Но ни какой системы синхранизации. Допустим мэйне мы читаем или пишим happy, в это время происходит прерывание. прцессор передает управление обработчику, сохраняется "портрет" состояния мэин и выполняется обработчик TimerB_Int1(). Потом востанавливается картина и передается управление мэйну. Так вот получается как-бы одновременное обращение из двух "потоков" к переменной happy. Не косяк ли это? может ли оператор "=" быть прерван по среди выполнения?

Понятно, что оператор "=" для bool скорее всего одна инструкция и её прервать на середине невозможно, но если happy это int, или какойнибудь тяжелый class MyHappyClass? Нужно ли защищять переменные в мэйне, которые используются в прерывании, типа

 

int main()
{
happy = false;
while(1)
{
    dInt();//запрет прерывания
    if(happy)
    {
         eInt();//разрешение прерывания
         divHappySmb();
         dInt();//запрет прерывания
         happy = false;
    }
    eInt();//разрешение прерывания
     
}
}

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


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

Угу. Как я и предполагал. Потенциальная бага лежит на видном месте.

TBCCR1+=Value32kHz1sCCR;

Value32kHz1sCCR это константа? Если да, то выходит что период прерываний у вас постоянный?

В таком случае следует использовать таймер не в режиме CountUp, а в режиме Continuous, соответственно используя переполнения от TBCCR0 и поменяв вектор прерываний на TIMERB0_VECTOR.

 

Update. Все многочисленные вычисления следует вынести из прерывания в основной цикл.

По поводу второго вопроса. Как минимум переменная happy должна быть глобальной и объявлена с квалификатором volatile.

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


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

Угу. Как я и предполагал. Потенциальная бага лежит на видном месте.

TBCCR1+=Value32kHz1sCCR;

Value32kHz1sCCR это константа? Если да, то выходит что период прерываний у вас постоянный?

В таком случае следует использовать таймер не в режиме CountUp, а в режиме Continuous, соответственно используя переполнения от TBCCR0 и поменяв вектор прерываний на TIMERB0_VECTOR.

а в чем тут бага? есть дефаин

#define Value32kHz1sCCR 32768 //Константа для 1 с: кварц 32768 Гц / таймер 1 Гц = 32768. прерывание происходит при счетчике 0х0000 и 0х8000.

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

 

А по поводу TIMERB0_VECTOR - это прерывание используется и там есть обработчик, не менее адский чем В1. Програvма большая, если что-то менять, то её всю с нуля нада переписывать. Хотелось бы с этой разобраться. Где шляемся? Как можно трассировку процесса организовать? Что за плагин Profiling? Он мне не поможет.

 

 

 

По поводу второго вопроса: Если happy объявлен глобально так

 

volatile MyClass happy;

 

То при использовании её в потоке маин и в обработчике не нужно беспокоится о колизии при совместном доступе к happy? Там же оператор "=" вызывает копирующий конструктор, а это может быть тоже не лёгкая функция? Или компилятор сам запретит прерывания при вызове "="?

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


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

Толи гдето в какойто другой обработчик ныряем, толи гдето в майне застреваем. Не могу понять где.
Как где? В этом же обработчике, например. У вас там вложенность прерываний допускается. Команда _EINT(); посередь функции имеется.

Програvма большая, если что-то менять, то её всю с нуля нада переписывать.
Если вся программа написана так, как этот фрагмент, то лучше переписать ее по-новой, более тщательно продумав алгоритмы. Нельзя задерживаться в прерываниях для столь длительной обработки/расчета. Тем более, когда источников прерываний несколько. Максимальное время обработки любого прерывания не должно превышать периода вызова самого "быстрого" прерывания.

По поводу второго вопроса: Если happy объявлен глобально так

 

volatile MyClass happy;

 

То при использовании её в потоке маин и в обработчике не нужно беспокоится о колизии при совместном доступе к happy? Там же оператор "=" вызывает копирующий конструктор, а это может быть тоже не лёгкая функция? Или компилятор сам запретит прерывания при вызове "="?

Про С++ не могу ничего прокомментировать, не владею им. :laughing: Квалификатор volatile ничего не гарантирует в части "параллельности" и не запрещает никаких прерываний. Он лишь указывает компилятору на то, что доступ к данной переменной не подлежит оптимизации, т.к. переменная может изменяться асинхронно по отношению к данной единице компиляции (функции или модулю). Если же вас интересует атомарность доступа к переменной бОльшей разрядности, чем разрядность архитектуры МК или к группе переменных, то она (атомарность) обеспечивается другими ("ручными") способами. В т.ч. "ручным" запретом вызова того прерывания, в обработчике которого данная переменная (или группа переменных) может модифицироваться.

 

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


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

Нашел багу. В мэйне в одном месте застреваю на долго. :laughing: Всем спасибо!

 

Если вся программа написана так, как этот фрагмент, то лучше переписать ее по-новой, более тщательно продумав алгоритмы.
Ну я бы с нуля конечно писал бы по другому. Но что значит "лучше"? Переписать с нуля - это год минимум + год на тестирование. Мне нужно добавить не большой функционал к отлаженной программе, которая работает без сбоев уже годами в сотнях устройств. Лучше потратить 2 года на написание нового кода, чем неделю на нахождении баги, которую я сделал при добавлении нового функционала? Тем более что прога может общятся с кучей устройств, которых физически в данный момент нет. А с ними обмен тоже придется отлаживать.

 

ps И всё же, на будущее, есть в msp430 что-то типа трассировки процесса? Или дерево вызова функций? Слышал что есть. Как бы это поднять? Хотелось бы остановится в брейкпоинте и увидеть что находишся в функции f1(), эта функция была вызвана из f2(), f2 была вызвана прерыванием от uart, прерывание прервало выполнение функции f3(), в момент прерывание выполнения f3 локальные переменные в f3 были такие и такие, регистры такие и такие ну и т.п.

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


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

Зачастую проще и правильнее переписать с нуля стройно и красиво, нежели пытаться добавить что-то в криво написанный, но как-то работающий код. Простейший пример, это мощные вычисления внутри прерываний - добавление пары команд может привести к полной потери работоспособности кода.

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


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

Переписать с нуля - это год минимум + год на тестирование.

 

ps И всё же, на будущее, есть в msp430 что-то типа трассировки процесса? Или дерево вызова функций?

Что же такого можно писать год? Не преувеличивайте, память должна закончиться быстрее, если действительно писать, а не в потолок смотреть ;)

 

Термин "процесс" здесь режет слух.

А дерево вызова функций видно в отладчике в окошке "Call stack"

 

 

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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