juvf 17 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба MSP430F2418 есть в мэйне основной цыкл while(1). в теле цыкла вызываются всякие процедуры и функции которые по глобальным флагам делают те или иные действия. Есть обработчик прерываний который прерывает этот вайл и выставляет всякие флажки, которые обрабатываются в главном цыкле. обычно цыкл прохонит за несколько мс с учётом времени потраченное в перываниях. но иногда процесс где-то шляется больше секунды. в обработчике прерывания выставляю флаг. в главном цыкле должен по этому флагу запустить процедуру. так вот между выставлением флага в прерывании и проыеркой этого флага в гл. цыкле может пройти больше секунды. из прерывания выход мгновенный. 100%. а вот где потом процесс шляется целую секунду не могу найти. узнать бы в каком месте была прервана программа прерыванием и куда вернулась? Как бы трассировкку процесса устроить? Как это можно решить с помошью IAR EW IDE? или какими еще способами можно выяснить где мы были целую секунду? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shread 0 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба Что-то похожее наблюдал, когда были включены прерывания, а обработчик NMI отсутствовал. Разберитесь с тем что у вас включено из прерываний, а что нет, после чего добавьте обработчики тех прерываний, которые включены. Просто так "шляться" программа в 2хх не может - в этом семействе есть аппаратный модуль сброса на этот случай. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба Исходник обработчика прерывания приведите. Мнится мне, что именно там собака порылась. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба Разберитесь с тем что у вас включено из прерываний, а что нет, после чего добавьте обработчики тех прерываний, которые включены. Просто так "шляться" программа в 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();//разрешение прерывания } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба Угу. Как я и предполагал. Потенциальная бага лежит на видном месте. TBCCR1+=Value32kHz1sCCR; Value32kHz1sCCR это константа? Если да, то выходит что период прерываний у вас постоянный? В таком случае следует использовать таймер не в режиме CountUp, а в режиме Continuous, соответственно используя переполнения от TBCCR0 и поменяв вектор прерываний на TIMERB0_VECTOR. Update. Все многочисленные вычисления следует вынести из прерывания в основной цикл. По поводу второго вопроса. Как минимум переменная happy должна быть глобальной и объявлена с квалификатором volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба Угу. Как я и предполагал. Потенциальная бага лежит на видном месте. 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? Там же оператор "=" вызывает копирующий конструктор, а это может быть тоже не лёгкая функция? Или компилятор сам запретит прерывания при вызове "="? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 10 декабря, 2010 Опубликовано 10 декабря, 2010 · Жалоба Толи гдето в какойто другой обработчик ныряем, толи гдето в майне застреваем. Не могу понять где.Как где? В этом же обработчике, например. У вас там вложенность прерываний допускается. Команда _EINT(); посередь функции имеется. Програvма большая, если что-то менять, то её всю с нуля нада переписывать.Если вся программа написана так, как этот фрагмент, то лучше переписать ее по-новой, более тщательно продумав алгоритмы. Нельзя задерживаться в прерываниях для столь длительной обработки/расчета. Тем более, когда источников прерываний несколько. Максимальное время обработки любого прерывания не должно превышать периода вызова самого "быстрого" прерывания. По поводу второго вопроса: Если happy объявлен глобально так volatile MyClass happy; То при использовании её в потоке маин и в обработчике не нужно беспокоится о колизии при совместном доступе к happy? Там же оператор "=" вызывает копирующий конструктор, а это может быть тоже не лёгкая функция? Или компилятор сам запретит прерывания при вызове "="? Про С++ не могу ничего прокомментировать, не владею им. :laughing: Квалификатор volatile ничего не гарантирует в части "параллельности" и не запрещает никаких прерываний. Он лишь указывает компилятору на то, что доступ к данной переменной не подлежит оптимизации, т.к. переменная может изменяться асинхронно по отношению к данной единице компиляции (функции или модулю). Если же вас интересует атомарность доступа к переменной бОльшей разрядности, чем разрядность архитектуры МК или к группе переменных, то она (атомарность) обеспечивается другими ("ручными") способами. В т.ч. "ручным" запретом вызова того прерывания, в обработчике которого данная переменная (или группа переменных) может модифицироваться. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 17 11 декабря, 2010 Опубликовано 11 декабря, 2010 · Жалоба Нашел багу. В мэйне в одном месте застреваю на долго. :laughing: Всем спасибо! Если вся программа написана так, как этот фрагмент, то лучше переписать ее по-новой, более тщательно продумав алгоритмы.Ну я бы с нуля конечно писал бы по другому. Но что значит "лучше"? Переписать с нуля - это год минимум + год на тестирование. Мне нужно добавить не большой функционал к отлаженной программе, которая работает без сбоев уже годами в сотнях устройств. Лучше потратить 2 года на написание нового кода, чем неделю на нахождении баги, которую я сделал при добавлении нового функционала? Тем более что прога может общятся с кучей устройств, которых физически в данный момент нет. А с ними обмен тоже придется отлаживать. ps И всё же, на будущее, есть в msp430 что-то типа трассировки процесса? Или дерево вызова функций? Слышал что есть. Как бы это поднять? Хотелось бы остановится в брейкпоинте и увидеть что находишся в функции f1(), эта функция была вызвана из f2(), f2 была вызвана прерыванием от uart, прерывание прервало выполнение функции f3(), в момент прерывание выполнения f3 локальные переменные в f3 были такие и такие, регистры такие и такие ну и т.п. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shread 0 14 декабря, 2010 Опубликовано 14 декабря, 2010 · Жалоба Зачастую проще и правильнее переписать с нуля стройно и красиво, нежели пытаться добавить что-то в криво написанный, но как-то работающий код. Простейший пример, это мощные вычисления внутри прерываний - добавление пары команд может привести к полной потери работоспособности кода. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 14 декабря, 2010 Опубликовано 14 декабря, 2010 · Жалоба Переписать с нуля - это год минимум + год на тестирование. ps И всё же, на будущее, есть в msp430 что-то типа трассировки процесса? Или дерево вызова функций? Что же такого можно писать год? Не преувеличивайте, память должна закончиться быстрее, если действительно писать, а не в потолок смотреть ;) Термин "процесс" здесь режет слух. А дерево вызова функций видно в отладчике в окошке "Call stack" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться