|
Глюки компилятора IAR?, Важно! Код прошивки по непонятным причинам не стартует в МК AVR. |
|
|
|
Jan 10 2008, 19:42
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Всех с прошедшими праздниками!
Присказка. Чуть больше 6 месяцев вплотную работаю с контроллерами ATMEL и компилятором IAR. Каких только финтов не выкидывала эта связка и вот очередная проблема.Программлю я поэтапно, шаг за шагом проверяя функционально законченные блоки кода. В результате, у меня получился основной код девайса и код, который производит самотестирование периферии контроллера. По отдельности все отлично и стабильно работает. Пришло время отлаживать всё в комплексе и тут начался полтергейст, который я пытаюсь изкоренить методом прямого шаманства. В чём причина конккретно не знаю, одни догадки... Суть проблемы. Короче код после прошивки то запускаетя и работает, то вообще не исполняется ни одной команды. Крутил оптимизацию, распределение памяти - не помогло. Со сбросом всё в порядке, схема не причем, контроллер тоже. Остается компилятор и наверное настройки файла *.xcl Контроллер использую Atmega8. Пишу на С. Использую стандартный lnkm8.xcl. high оптимизация проекта по размеру. IDE: IAR 4.20A/W32 [Evaluation] (4.20.1.3). Компилятор: IAR XLIB 3.29L/386 (3.29.0.12) IAR XLINK 4.59Z (4.59.26.0)
Из своего опыта. Кодил я девайс: считыватель чип-карт, который подключается к USB. Отлаживал отдельно часть кода для работы с картой ичасть кода для обмена по USB. Поставил оптимизацию всего проекта по скорости, т.к. 10 байт с карты приходили верный, а остальные контроллер не успевал обрабатывать (кодил опять же на С). Ладно добился правильной работы оптимизацией. Как только я начал отлаживать все в комплексе - обмен с картой и обмен по USB, то начались проблемы! С картой обмен есть, с USB нет. Оптимизацию вырубаю - наоборот с USB работает, а с карты искаженные данные. Долго я шаманил над проектом... И в итоге сделал так: включил оптимизацию проекта по скорости, а перед теми функциями, которые конкретно отвечают за обмен с USB, воткнул директиву компилятора отключающую оптимизацию именно это процедуры. После этого всё работает. Это конечно ни есть хорошо, но выходя я пока так и не нашёл. Одним словом - шаманство!!!
Посоветуйте, в каком направлении мне копать! Кто сталкивался с такими проблемами?
|
|
|
|
|
 |
Ответов
(1 - 91)
|
Jan 10 2008, 20:26
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Забыл спросить. А есть ли у компилятора такая фишка: хочу чтобы в зависимости от значения параметра в коде программы компилятор создавал прошивку с именем файла в зависимости от значения этого параметра. Цитата(prottoss @ Jan 10 2008, 22:59)  Пробовал сократить количество вхождений подпрограмм. Разместил почти все подпрограммы в одной. После этого ситуация немного изменилась в лучшую сторону. Количество отказов стало меньше, но проблема-то осталась. Сначала подозрение было на распределение памяти и стека, но я отбросил эту мысль, т.к. программа вообще не запускается и подпрограммы не возвращают никаких параметров.
|
|
|
|
|
Jan 11 2008, 08:11
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(DiMonstr @ Jan 10 2008, 21:42)  Пришло время отлаживать всё в комплексе и тут начался полтергейст, который я пытаюсь изкоренить методом прямого шаманства. В чём причина конккретно не знаю, одни догадки... Первое, что нужно сделать - посмотреть в листинг и убедиться, что компилятор понял вас правильно. Цитата(DiMonstr @ Jan 10 2008, 21:42)  Короче код после прошивки то запускаетя и работает, то вообще не исполняется ни одной команды. Крутил оптимизацию, распределение памяти - не помогло. Со сбросом всё в порядке, схема не причем, контроллер тоже. Остается компилятор и наверное настройки файла *.xcl Это понятно, что компилятор обвинить проще простого. У меня подобное поведение наблюдалось однажды, когда ошибочно был установлен фуз BRST. А у студента - когда подтяжка ресета вместо питания была подключена к одному из портов. Он порт настраивает на вывод - контроллер ресетится. В общем есть предложение поспорить на ящик пива, что компилятор снова не при чем, а виноваты недостаток знаний и опыта.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 12 2008, 14:03
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Сергей Борщ @ Jan 11 2008, 11:11)  ...В общем есть предложение поспорить на ящик пива, что компилятор снова не при чем, а виноваты недостаток знаний и опыта. Да запросто! Так все дело-то в том, что всё работает отлично, если закомментирована часть кода. С ресетом всё правильно - 100%, с фузами тоже - 100%. А подозрения у меня на компилятор. Да по любому он!!! Сейчас уже такая закономерность: написан код - все отлажено и работает. Начинаю добавлять дополнительные функции и достигается такая граница, при которой камень ведёт себя так, как описано выше. Что скажете? Цитата(arttab @ Jan 11 2008, 05:01)  Тут и само собой все ясно: скорость передачи данных по USB в 10 раз выше, чем с картой. Это не критично. Версия девайса под RS-232работает медленнее, чем USB-шная.
|
|
|
|
|
Jan 12 2008, 14:04
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(DiMonstr @ Jan 12 2008, 15:59)  Да по любому он!!!  Цитата Что скажете? 1.  2. Пока не сможете четко (читай грамотно) донести свою мысль до компилятора и не придется: Цитата ...сделал так: включил оптимизацию проекта по скорости дальше можете и не двигаться. Это первейшее необходимое, хотя возможно и недостаточное условие.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 12 2008, 14:28
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(GDI @ Jan 11 2008, 10:02)  Этой фичей компилятора я ещё не интересовался. Посмотрю... А в целом, как правильно назначить размеры отдельным участкам карты памяти (RSTACK, CSTACK, HEAP)? Из каких соображений изходить при этом? И такой вопрос. У меня примерно 100 константных байт которые разумно разместить во флэш памяти программы, но больше 20 не получается - компилятор ругается. Посмотрел hex-файл, а мои данные размещаются в самом его начале. Что нужно сделать и где, чтобы разместить их в конце? Цитата(zltigo @ Jan 12 2008, 17:04)  Нееет. Без оптимизации никак низя... Протокол с картой организован побитный и каждый бит, карта передает мне каждую 1 мкс (к примеру, сколько точно не помню сейчас), а я каждый бит обрабатываю в прерывании по таймеру - это подсчет бит, проверка на старт бит, проверка четности, и ещё что-то). Так как написано на С, то без оптимизации за 1 мкс эта часть кода контроллером не успевает обрабатывается и начинается потеря бит. Правда первые 2 десятка байт принимаются верно...
Сообщение отредактировал DiMonstr - Jan 12 2008, 14:31
|
|
|
|
|
Jan 12 2008, 14:48
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(DiMonstr @ Jan 12 2008, 18:28)  И такой вопрос. У меня примерно 100 константных байт которые разумно разместить во флэш памяти программы, но больше 20 не получается - компилятор ругается. Посмотрел hex-файл, а мои данные размещаются в самом его начале. Что нужно сделать и где, чтобы разместить их в конце? Давайте по порядку и конструктивно? 1) Как ругается компилятор на расположение констант во флэши, 2) как Вы их располагаете, 3) и зачем Вам нужно, чтобы они были в конце?
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jan 12 2008, 15:00
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(zltigo @ Jan 12 2008, 17:49)  Если говорить про ATMEGa8, то без оптимизации код написанный на СИ очень громоздкий и не помещается в камень. Компилятор при этом выдает кучу ошибок относительно размера стэков. Но код на самом деле не поместиться без оптимизации.
|
|
|
|
|
Jan 12 2008, 15:20
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(zltigo @ Jan 12 2008, 18:10)  Код рабочий
Сообщение отредактировал DiMonstr - Jan 12 2008, 15:20
|
|
|
|
|
Jan 12 2008, 18:21
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Jan 12 2008, 17:49)  Повторяю - код должен быть работоспособным ПРИ ЛЮБОЙ ОПТИМИЗАЦИИ а не только без оптимизации или при оптимизации по размеру. Это не совсем правда, бывает что нужно записать значение в регистр и потом в течении нескольких тактов в другой, без оптимизации это может не работать, хотя автор: Цитата Код рабочий  конечно ЖЖЕТ!!! Автор, если у Вас например прерывание вызывается каждые 1000тактов и требует 1500тактов на обработку, виноват компилятор ???
|
|
|
|
|
Jan 12 2008, 19:56
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(singlskv @ Jan 12 2008, 21:21)  Автор, если у Вас например прерывание вызывается каждые 1000тактов и требует 1500тактов на обработку, виноват компилятор ??? В данном случае ДА! На асме этот же код работает без оптимизации, а программа на СИ как уже всем известно в мнемонике она в 1,5-2 раза больше по размеру. Это можно посмотреть в отладчике хоть в AvrStudio, хоть в штатном ИАРовском. Зачем же Вы спорите товарищи? Я разве не прав??? А у кого-нибудь есть на ходу рабочая плата/макет с МК ATMEGA8? Я тогда здесь исходники выложу, а вы посмотрите.
|
|
|
|
|
Jan 12 2008, 20:11
|

Просто Che
    
Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881

|
Цитата(DiMonstr @ Jan 12 2008, 21:52)  В данном случае ДА! На асме этот же код работает без оптимизации, а программа на СИ как уже всем известно в мнемонике она в 1,5-2 раза больше по размеру. Это можно посмотреть в отладчике хоть в AvrStudio, хоть в штатном ИАРовском. Зачем же Вы спорите товарищи? Я разве не прав??? Насчет обвинения компилятора неправы БЕЗУСЛОВНО, а насчет увеличения кода неправы ЧАСТИЧНО. Если у вас есть некие критические секции программы, они должны быть написаны более тщательно, чем обычно. И уж без заглядывания в листинг при этом не обойтись А насчет увеличения размера кода в 1,5-2 раза это как сказать. Если в два раза, то это просто плохое знание Си. Некоторые конструкции компилятор может оттранслировать так что вам и не снилось написать на ассемблере, а может вас не понять и нагородить ерунды. Использование одинаковых кусков кода тоже в ИАРе реализовано отлично. Если же вам все равно не хватает быстродействия, то никто не мешает вам написать критичные функции на ассемблере. p.s. а мнемонику и отладчики вы вообще не к месту приплели
|
|
|
|
|
Jan 12 2008, 20:12
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(DiMonstr @ Jan 12 2008, 21:56)  А у кого-нибудь есть на ходу рабочая плата/макет с МК ATMEGA8? Я тогда здесь исходники выложу, а вы посмотрите.  Есть. А вы потом не откажетесть от Цитата Цитата ...В общем есть предложение поспорить на ящик пива, что компилятор снова не при чем, а виноваты недостаток знаний и опыта. Да запросто! ?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 12 2008, 20:21
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Сергей Борщ @ Jan 12 2008, 23:12)  Есть. А вы потом не откажетесть от Да запросто! ? Лады. Но выложить смогу только в понедельник, сейчас нет на руках исходников.
|
|
|
|
|
Jan 20 2008, 15:26
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Выкладываю исходники проекта. Попробуйте прошить контроллер и прочитать содержимое EEPROM. Что можно предпринять по оптимизации проекта, с учетом вышеизложенных проблем?
Прикрепленные файлы
pwrc.rar ( 286.74 килобайт )
Кол-во скачиваний: 62
|
|
|
|
|
Jan 20 2008, 17:23
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(SasaVitebsk @ Jan 20 2008, 19:58)  Никак не могу найти причину такого поведения программы. Может я уже зацыклился? По выходному листингу всё вроде нормально. Посмотрите кто-нибудь свежим взглядом на программу? Подскажите где возможна исключительная ситуация.
|
|
|
|
|
Jan 20 2008, 17:34
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(SasaVitebsk @ Jan 20 2008, 19:58)  Самые распространнённые в этом случае ошибки это ошибки связанные с volatile ... Я не нашел в Вашей програме ни одного "volatile". Прочитайте вот это и добавте "volatile" для тех переменных для которых надо. Сорри что текст на англискон. My program doesn't recognize a variable updated within an interrupt routineWhen using the optimizer, in a loop like the following one: Код uint8_t flag; ... ISR(SOME_vect) { flag = 1; } ...
while (flag == 0) { ... } the compiler will typically access flag only once, and optimize further accesses completely away, since its code path analysis shows that nothing inside the loop could change the value of flag anyway. To tell the compiler that this variable could be changed outside the scope of its code path analysis (e. g. from within an interrupt routine), the variable needs to be declared like: Код volatile uint8_t flag;
|
|
|
|
|
Jan 20 2008, 18:39
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(aesok @ Jan 20 2008, 20:34)  Правильно ли я понял, что глобальные переменные используемые в циклах подпрограмм прерываниий необходимо объявлять с ключевым словом volatile? Спасибо. Я к проекту подключил командный файл линкера lnkm8s.xcl. Может стоит изменить размеры стэков, как думаете? Товарищи! Какие ещё будут нарекания по программе?
Сообщение отредактировал DiMonstr - Jan 20 2008, 18:40
|
|
|
|
|
Jan 20 2008, 19:01
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Приведу пример для понимания происходящего допустим есть переменные глобальные Код volatile uint8_t AvarFuelWt, AvarCAN=0, // Счётчик секунд задержки на потерю топлива и CAN CAN_Temp, // Значение температуры двигателя по CAN CAN_POil; // Значение давления масла двигателя по CAN В прерывании есть такой код Код if((timesec--)==0) { timesec=FPWM; Flag.fSecond=1; AvarFuelWt++; AvarCAN++; } В голове следующий код Код if(AvarCAN>2) // Обработка потери CAN CAN_Temp=CAN_POil=0; // Обнулить значение Смысл обработки прост - если сообщений нет более 2 секунд, то обнулить значения (иначе при потере CAN сохраняются последние принятые значения). Вот что получим при компиляции Код 540 if(AvarCAN>2) // Обработка потери CAN \ ??main_16: \ 00000182 8D05 LDD R16, Z+29 \ 00000184 3003 CPI R16, 3 \ 00000186 F018 BRCS ??main_17 541 CAN_Temp=CAN_POil=0; // Обнулить значение \ 00000188 E000 LDI R16, 0 \ 0000018A 8F07 STD Z+31, R16 \ 0000018C 8F06 STD Z+30, R16 Уберём volatile. Код volatile uint8_t AvarFuelWt, AvarCAN=0; // Счётчик секунд задержки на потерю топлива и CAN uint8_t CAN_Temp, // Значение температуры двигателя по CAN CAN_POil; // Значение давления масла двигателя по CAN Получим следующее. Код 545 if(AvarCAN>2) // Обработка потери CAN \ ??main_16: \ 00000182 8D05 LDD R16, Z+29 546 CAN_Temp=CAN_POil=0; // Обнулить значение 547 // Обработка АЦП и выставление положения стрелок Как видите значение AvarCAN было извлечено, а дальше обработка не осуществлялась, так как для компилятора в ней "не было смысла".
|
|
|
|
|
Jan 21 2008, 03:50
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Кто нить ещё смотрел этот проект? Впечатление в целом, если коротко - ужоснах. Конечно, брёвна в чужих глазах все мастера замечать, но в данном случае, автор действительно жжёт. (Автор, не обижайтесь, воспримите это как конструктивную критику). Первое замечание в общем - код жутко неоптимален. ИАР, конечно многомощный комипилятор, но расчитывать на то, что он всё это дело оптимально разгребёт, не стоит. Пример в частности: в функции main есть switch (channel), в котором по каждой метке выполняется почти один и тот же код: case 0x01: { DebuggingData(); if (Value > MinValue & Value < MaxValue) /*<- здесь действительно побитовое И требуется ?*/ { MeanValue_CH1 = MeanValue_CH1 + Value; /* в каждой метке свитча своя только переменная MeanValue_CH* можно было бы объявить массив этих переменных и обращатся в ним по индексу: */ // MeanValue_CH[channel] += Value; if (MeanCount_CHx == StepMeanVoltage) { MeanValueVoltage[channel] = MeanValue_CH1 / StepMeanVoltage; // MeanValueVoltage[channel] = MeanValue_CH[channel] / StepMeanVoltage; MeanValue_CH1 = NULL; /* почему, кстати, целочисленной переменной присваивается значание указателя ? */ } break; } ALARM_PROCCESS = TRUE; break; } Если так поменять, тогда вообще никакого свитча не понадобится, и размер кода заметно уменьшиться. Такие места есть ещё. И ещё много чего интересного и занимательного есть, из-за чего этот код рабочим не является, и, похоже, никогда таковым не был.
|
|
|
|
|
Jan 21 2008, 11:58
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(forever failure @ Jan 21 2008, 06:50)  ...Если так поменять, тогда вообще никакого свитча не понадобится, и размер кода заметно уменьшиться. Такие места есть ещё. Да зачем я буду обежаться, я и разместил здесь проект, чтобы в свой адрес услышать критику. Что и как я сделал не правильно, почему, как надо и т.д. Я же не профессионал, поэтому и прошу совета. За предложение forever failure благодарю! Буду переделывать. Цитата(forever failure @ Jan 21 2008, 06:50)  И ещё много чего интересного и занимательного есть, из-за чего этот код рабочим не является, и, похоже, никогда таковым не был. Ну зачем так жестко критиковать, код более менее рабочий, выполняет основные задачи без сбоев. Но уверенности у меня в нем 100%-ой нет, поэтому и обратился на форум с целью обогащения своих знаний и опыта. Какие ещё есть косяки в коде? Огласите пожалуйста. Цитата(forever failure @ Jan 21 2008, 06:50)  1) if (Value > MinValue & Value < MaxValue) /*<- здесь действительно побитовое И требуется ?*/ 2) MeanValue_CH1 = NULL; /* почему, кстати, целочисленной переменной присваивается значание указателя ? */ 1) Никак нет, в данном случае производится элементарное сравнение - логическое И значит. 2) В данном случае переменная обнуляется.
Сообщение отредактировал DiMonstr - Jan 21 2008, 12:03
|
|
|
|
|
Jan 21 2008, 12:19
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(DiMonstr @ Jan 21 2008, 13:58)  1) Никак нет, в данном случае производится элементарное сравнение - логическое И значит. Тогда и надо писать if (Value > MinValue && Value < MaxValue). Код будет значительно компактнее и быстрее. Цитата(DiMonstr @ Jan 21 2008, 13:58)  2) В данном случае переменная обнуляется. Тогда так и надо писать: MeanValue_CH1 = 0. NULL имеет тип указателя, удивительно что компиялтор пропустил такое присваивание (если только в режиме C++, но в нем как раз рекомендуется использовать 0 в том числе и для указателей вместо NULL).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 21 2008, 12:56
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(Сергей Борщ @ Jan 21 2008, 15:19)  NULL имеет тип указателя, удивительно что компиялтор пропустил такое присваивание (если только в режиме C++, но в нем как раз рекомендуется использовать 0 в том числе и для указателей вместо NULL). Я вот всю жизнь считал что NULL имеет тип unsigned int, такой же как указатель, но это все же не одно и тоже. Так что при присваивании переменная = NULL произойдет обычное преобразование типов, если это нужно, и никаких варнингов не последует.
|
|
|
|
|
Jan 21 2008, 13:04
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Qwertty @ Jan 21 2008, 15:56)  Я вот всю жизнь считал что NULL имеет тип unsigned int, такой же как указатель, но это все же не одно и тоже. typedef void *PVOID; #define NULL ((PVOID)(0)) DiMonstrНашел у вас в коде такие записи: Цитата BufLog[0] = StartByte; BufLog[1] = MSB(tics); BufLog[2] = LSB(tics); BufLog[3] = seconds; BufLog[4] = minutes; BufLog[5] = hours; BufLog[6] = day; BufLog[7] = month; BufLog[8] = MSB(year); BufLog[9] = LSB(year); BufLog[10] = StopByte; Но ведь можно просто объявить структуры, где будут храниться ваши записи, например: Код typedef struct tagRTC_TIME { U16 Ticks; U8 seconds; U8 minutes; U8 hours; U8 day; U8 month; U16 year; } TRTC_TIME, *PRTC_TIME;
TRTC_TIME rtcTime; И далее в отчет просто копировать всю запись целиком одной строкой: memcpy( &BufLog[ 1 ], &rtcTime, sizeof( rtcTime )); При отправке этого BufLog'a, или записи в eeprom - подцеплять "старт" и "стоп" таги.
|
|
|
|
|
Jan 21 2008, 13:21
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(defunct @ Jan 21 2008, 16:04)  typedef void *PVOID; #define NULL ((PVOID)(0)) Да, был неправ. Нашел целых три определения: #define NULL __null #define NULL ((void *)0) #define NULL 0 Второе - С, третье С++, а первое непонятно...
|
|
|
|
|
Jan 21 2008, 19:35
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Сергей Борщ @ Jan 21 2008, 15:19)  Тогда и надо писать if (Value > MinValue && Value < MaxValue). Код будет значительно компактнее и быстрее. Т.е., как я понимаю, результат при сравнении операторами '&' или '&&' будет одинаков, за исключением того, что оператор '&' делает это побитно, а '&&' побайтно. Верно? Цитата(Сергей Борщ @ Jan 21 2008, 15:19)  Тогда так и надо писать: MeanValue_CH1 = 0. NULL имеет тип указателя, удивительно что компиялтор пропустил такое присваивание (если только в режиме C++, но в нем как раз рекомендуется использовать 0 в том числе и для указателей вместо NULL). В файле <stdio.h> NULL объявлена как 0: #ifndef NULL #define NULL (0) #endif И в других хидерах переопределений нет. Поэтому так и написал. А то, что NULL имеет тип указателя я и не знал. Для надежности всё же исправил. Цитата(forever failure @ Jan 21 2008, 15:42)  Логика такая: при выходе измеряемого напряжения (Value) за допустимые значения (MinValue и MaxValue) необходимо отключать питание системы. Т.е. в данном случае, если условие соблюдается, то всё в порядке, иначе блокируем работу системы. В отладчике проверял - работает. На практике проверял - тоже работает.Поэтому так и оставил. Теперь исправил. Цитата(SasaVitebsk @ Jan 21 2008, 15:52)  Либо локализуйте ошибку - либо выкиньте часть текста, до которого всё равно дело не доходит и тогда обращайтесь. Простите, это моё мнение. По поводу оптимизации. В варианте со switch компилятор, тем не менее сам найдёт общие куски и объединит их. Я бы для начала отладил бы прогу в целом, а уж потом занялся оптимизацией проекта (если уж сразу не удалось написать оптимально). А то сейчас начать оптимизацию - это добавить новых ошибок. Заметьте, отлаживать за себя я никого не просил. Я лишь хочу научиться правильно писать программу на практических советах уважаемых посетителей форума. Эти советы я думаю будут полезны и другим новичкам. Если человек с большим опытом, то ему не составит большого труда просмотрев код, даже не вникая в алгоритм, найти участки кода и сделать их более эффективными. От свитча я вовсе избавился, действительно через массив оказалось всё просто, компактно и эффективно. Оптимизация у меня давно выставлена по размеру и я её больше не трогаю с тех пор как компилятор по мере реализации новых фунций начал выдавать такие сообщения: Код Building configuration: pwr_control - Release Updating build tree... main.c Linking Error[e16]: Segment CODE (size: 0x202e align: 0x1) is too long for segment definition. At least 0xa0 more bytes needed. The problem occurred while processing the segment placement command "-Z(CODE)CODE=26-1FFF", where at the moment of placement the available memory ranges were "CODE:72-1fff" Reserved ranges relevant to this placement: CODE:26-3d NEAR_F CODE:3e-65 SWITCH CODE:66-71 INITTAB CODE:72-1fff ?FILL1 Error[e16]: Segment TINY_ID (size: 0 align: 0) is too long for segment definition. At least 0 more bytes needed. The problem occurred while processing the segment placement command "-Z(CODE)TINY_ID,NEAR_ID=26-1FFF", where at the moment of placement the available memory ranges were "-none-" Reserved ranges relevant to this placement: CODE:26-3d NEAR_F CODE:3e-65 SWITCH CODE:66-71 INITTAB CODE:72-1fff ?FILL1 Error[e16]: Segment NEAR_ID (size: 0xe1 align: 0) is too long for segment definition. At least 0xe1 more bytes needed. The problem occurred while processing the segment placement command "-Z(CODE)TINY_ID,NEAR_ID=26-1FFF", where at the moment of placement the available memory ranges were "-none-" Reserved ranges relevant to this placement: CODE:26-3d NEAR_F CODE:3e-65 SWITCH CODE:66-71 INITTAB CODE:72-1fff ?FILL1 Error[e16]: Segment CHECKSUM (size: 0x2 align: 0) is too long for segment definition. At least 0x2 more bytes needed. The problem occurred while processing the segment placement command "-Z(CODE)CHECKSUM#1FFF", where at the moment of placement the available memory ranges were "-none-" Reserved ranges relevant to this placement: CODE:0-17 INTVEC CODE:18-25 NEAR_ID CODE:26-3d NEAR_F CODE:3e-65 SWITCH CODE:66-71 INITTAB CODE:72-1fff ?FILL1 Error[e18]: Range error, Address out of range. Valid range is 0 to 8190 (0x1FFE). File: E:\_CRYPTOSOFT\PWR_CONTROL\SRC\util.c, Line: 240 Source: RCALL ?PROLOGUE4_L09 Where $ = slow_crc16 [0x370] in module "main" (E:\_CRYPTOSOFT\PWR_CONTROL\SRC\Release\Obj\main.r90), offset 0x0 in segment part 159, segment CODE What: ?PROLOGUE4_L09 [0x2000] Allowed range: 0x0 - 0x1FFE Operand: ?PROLOGUE4_L09 [0x2000] in module ?PROLOGUE_L09 (D:\Program Files\IAR Systems\Embedded Workbench 4.0 Evaluation\ avr\LIB\CLIB\cl1s-ec_mul.r90), Offset 0x0 in segment part 12, segment CODE Error[e18]: Range error, Address out of range. Valid range is 0 to 8190 (0x1FFE). File: E:\_CRYPTOSOFT\PWR_CONTROL\SRC\util.c, Line: 257 Source: RJMP ?EPILOGUE_B4_L09 Where $ = slow_crc16 + 0x56 [0x3C6] in module "main" (E:\_CRYPTOSOFT\PWR_CONTROL\SRC\Release\Obj\main.r90), offset 0x56 in segment part 159, segment CODE What: ?EPILOGUE_B4_L09 [0x201A] Allowed range: 0x0 - 0x1FFE Operand: ?EPILOGUE_B4_L09 [0x201a] in module ?EPILOGUE_B_L09 (D:\Program Files\IAR Systems\Embedded Workbench 4.0 Evaluation\ avr\LIB\CLIB\cl1s-ec_mul.r90), Offset 0x0 in segment part 12, segment CODE Error[e18]: Range error, Address out of range. Valid range is 0 to 8190 (0x1FFE). File: E:\_CRYPTOSOFT\PWR_CONTROL\SRC\rdc.c, Line: 29 Source: RCALL ?PROLOGUE2_L09 Where $ = BeginDataWriteToRDC [0x3C8] in module "main" (E:\_CRYPTOSOFT\PWR_CONTROL\SRC\Release\Obj\main.r90), offset 0x0 in segment part 160, segment CODE What: ?PROLOGUE2_L09 [0x2004] Allowed range: 0x0 - 0x1FFE Operand: ?PROLOGUE2_L09 [0x2004] in module ?PROLOGUE_L09 (D:\Program Files\IAR Systems\Embedded Workbench 4.0 Evaluation\ avr\LIB\CLIB\cl1s-ec_mul.r90), Offset 0x0 in segment part 14, segment CODE ....... ну и так далее ....... Total number of errors: 33 Total number of warnings: 0 Ну я и воткнул оптимизацию по размеру на максимум. Всё работает, но вот елси разрешить выполнение следующего кода: Код #if(CheckMCU) sum = slow_crc16(sum,(unsigned char __flash *)0, (unsigned long)&__checksum); // call with two 0 bytes for the correct calculation of crc sum = slow_crc16(sum,(unsigned char __flash *)&zero,2); ... #endif то прошивка лобо вообще не запускается либо запускается через раз. А по отдельности эти части кода фунциклируют по честному. Цитата(defunct @ Jan 21 2008, 16:04)  А я сначала и объявлял переменные через структуру. Только не смог передать содержимое структуры не в массив, не напрямую в eeprom. Я вообще не знал про эту функцию: Код memcpy( &BufLog[ 1 ], &rtcTime, sizeof( rtcTime )); А каким образом можно без неё вообще обойтись и записывать структуру непосредственно в eeprom? Спасибо за дельный совет.
Сообщение отредактировал DiMonstr - Jan 21 2008, 19:00
|
|
|
|
|
Jan 21 2008, 19:43
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(DiMonstr @ Jan 21 2008, 23:27)  Т.е., как я понимаю, результат при сравнении операторами '&' или '&&' будет одинаков, за исключением того, что оператор '&' делает это побитно, а '&&' побайтно. Верно? Нет не верно. выражение внутри скобок if (Value > MinValue && Value < MaxValue) означает что если Value > MinValue И Value < MaxValue, то ... Если вы вместо && поставите &, то это будет означать, что сначала выполнятся два сравнения потом выполнится логическое & над результатами а потом результат будет сравнён с "0". Поскольку значение "true" определена как "не 0", то в общем случае результаты могут не совпадать. По своему опыту скажу, что достаточно часто при такой ошибке написания результат операции не соответствует ожидаемому. Поэтому лучше указывать всё точно и явно. Также, как многие писали, лучше немного перестараться со скобками.
|
|
|
|
|
Jan 22 2008, 00:22
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата А я сначала и объявлял переменные через структуру. Только не смог передать содержимое структуры не в массив, не напрямую в eeprom. Я вообще не знал про эту функцию: ... А каким образом можно без неё вообще обойтись и записывать структуру непосредственно в eeprom? Можно написать свою функцию для записи блоков в eeprom, например такую: Код void store_to_eeprom( int dst_addr, void *pData, int size) { unsigned char *p = (unsigned char *)pData; while( size--) EEPROM_write_byte( dst_addr++, *p++); } и передавать структуры посредством указателей: Код store_to_eeprom( RTC_OFFSET, &rtcTime, sizeof( rtcTime )); В этой функции Вы можете добалять какую-то служебную информацию, например CRC для записываемого блока или таги для поиска как у Вас было. Так можно сократить количество повторяющегося кода. Если пользуетесь компилятором от IAR, то перед структурой можно поставить ключевое слово __eeprom и она будет располагаться в eeprom'е сразу, и пользоваться ее полями можно точно так же как если бы она лежала в RAM. Но не следует этим злоупотреблять, т.к. надо помнить, что ресурс eeprom ограничен. Цитата(SasaVitebsk @ Jan 21 2008, 22:43)  Цитата результат при сравнении операторами '&' или '&&' будет одинаков Нет не верно. выражение внутри скобок if (Value > MinValue && Value < MaxValue) означает что если Value > MinValue И Value < MaxValue, то ... Если вы вместо && поставите &, то это будет означать, что сначала выполнятся два сравнения потом выполнится логическое & над результатами а потом результат будет сравнён с "0". Поскольку значение "true" определена как "не 0", то в общем случае результаты могут не совпадать. Саша, в данном конкретном случае & даст такой же результат как и &&, хотя и более долгим путем  Но в общем случае, конечно надо быть внимательным. Иногда помогает помнить, что в теле if() "==" - это сравнение, а "=" - катастрофа  аналогично для & и | ;>
|
|
|
|
|
Jan 23 2008, 19:45
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(defunct @ Jan 22 2008, 04:22)  Саша, в данном конкретном случае & даст такой же результат как и &&, хотя и более долгим путем  Но в общем случае, конечно надо быть внимательным. Иногда помогает помнить, что в теле if() "==" - это сравнение, а "=" - катастрофа  аналогично для & и | ;> В данном случае я отвечал не на вопрос "будет ли такой же результат", а отвечал на вопрос "как я понимаю". И подтверждаю, что человек неправильно понимает. Компилятор IAR результат логической операции принимает как 0 или 1, но это не гарантируется стандартом о чём я и высказался. Согласно стандарту - 0 и отличное от нуля значение. А это отнюдь не 1. Иными словами если в одном выражении будет к примеру 1 а в другом 2, то согласно стандарту всё будет корректно но логическое & над этими операндами даст 0, а это не верный результат. Конечно это чисто теоретический случай, но понимание работы должно быть полным. Программист не должен полагаться на конкретную реализацию компилятора, а должен ориентироваться на стандарт. Тем более, что эта мелочь действительно приведёт к настоящей ошибке в другом месте. То есть человек должен понимать разницу между побитовой и логической операцией. Сравните например: 79 if(~Flag.Sek)show(1,j); \ 00000046 01A2 MOVW R21:R20, R5:R4 \ 00000048 01B3 MOVW R23:R22, R7:R6 \ 0000004A E001 LDI R16, 1 \ 0000004C .... RCALL show и 79 if(!Flag.Sek)show(1,j); \ 00000046 .... LDI R30, Flag \ 00000048 E0F0 LDI R31, 0 \ 0000004A 8100 LD R16, Z \ 0000004C FD00 SBRC R16, 0 \ 0000004E C004 RJMP ??main_0 \ 00000050 01A2 MOVW R21:R20, R5:R4 \ 00000052 01B3 MOVW R23:R22, R7:R6 \ 00000054 E001 LDI R16, 1 \ 00000056 .... RCALL show
|
|
|
|
|
Jan 23 2008, 22:37
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SasaVitebsk @ Jan 23 2008, 21:45)  Компилятор IAR результат логической операции принимает как 0 или 1, но это не гарантируется стандартом о чём я и высказался. Согласно стандарту - 0 и отличное от нуля значение. А это отнюдь не 1. Ну это не совсем так и компилятор точно следует стандарту: Цитата 6.5.13 Logical AND operator 3 The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int. 4 Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated. Т.е. "ноль" и "не ноль" отностится не к результату, а к операндам. Цитата 6.5.13 Logical AND operator 3 The usual arithmetic conversions are performed on the operands. 4 The result of the binary & operator is the bitwise AND of the operands (that is, each bit in the result is set if and only if each of the corresponding bits in the converted operands is set). Поэтому первое отличие: для A=1 и B=2 A&B=0, A&&B=1. Второе - для && операнды вычисляются слева направо и если правый операнд равен нулю, то уже сразу известно, что и результат будет равен нулю, поэтому второй операнд вычисляться не будет.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 23 2008, 23:37
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Сергей Борщ @ Jan 24 2008, 01:37)  Ну это не совсем так и компилятор точно следует стандарту:Т.е. "ноль" и "не ноль" отностится не к результату, а к операндам. Как я понял - речь шла о том гарантируется ли стандартом то, что результатом любого сравнения вида ">" ">=" и т.п. всегда будет только одно из двух "1" или "0", либо такие сравнения гарантируют только "0" и "!0". Вы привели цитаты только для & и &&, что не раскрывает вопроса ;> Хотя что-то мне подсказывает что цитаты для && достаточно. Я всегда считал, что рез-татом любого сравнения будет гарантировано "1" или "0", всвязи с чем часто пользуюсь такими конструкциями: x = (y & 1 << somebit ) != 0; для "засовывания" интересующего меня бита в бит0.
|
|
|
|
|
Jan 24 2008, 15:17
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(defunct @ Jan 24 2008, 01:37)  Как я понял - речь шла о том гарантируется ли стандартом то, что результатом любого сравнения вида ">" ">=" и т.п. всегда будет только одно из двух "1" или "0", либо такие сравнения гарантируют только "0" и "!0". Вы привели цитаты только для & и &&, что не раскрывает вопроса ;> Ну так недостающий пробел легко восполнить. Открываем Google, набираем ISO/IEC 9899-1999, скачиваем, открываем, search, >=, находим: Цитата 6.5.8 Relational operators 6 Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false. The result has type int. 6.5.9 Equality operators 3 The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence. Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 24 2008, 16:44
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Freeze Anti @ Jan 23 2008, 21:45)  Кстати, модель памяти я использую small. А можно ли увеличить пространство оперативки следующими методами: - объеденить булевые переменные в байт(регистр) и изменять их состояние побитно - а глобальные переменные собрать в структуру? В результате этого маневра, мы добъемся дефрагментированного расположения данных в ОЗУ. Правильно? А по поводу диапазона переменных и их типа я не совсем понял. Расскажите немного поподробней.
|
|
|
|
|
Jan 24 2008, 16:58
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата А можно ли увеличить пространство оперативки следующими методами: - объеденить булевые переменные в байт(регистр) и изменять их состояние побитно - а глобальные переменные собрать в структуру? Можно: - объеденить булевые переменные в байт(регистр) и изменять их состояние побитно Код typedef struct __Reg { char bit0: 1; char bit1: 1; .... char bit4567: 4: } Reg_t
void Fn(...) { Reg_t RegA; RegA.bit0 = 1; RegA.bit1 ^= RegA.bit0;
RegA.bit4567 = 5;
} -а глобальные переменные собрать в структуру Project->Compiler->Optimizations: Medium - включится галка на Static Clustering - это то ОНО и есть
--------------------
|
|
|
|
|
Jan 24 2008, 17:13
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(aesok @ Jan 21 2008, 23:05)  В функциях EEPROM_* - не должны разрешаться прерывания на выходе. Они должны востанавливать состояние состояние флага "I" таким каким оно было при входе в функцию. Я где-то читал, что во время записи в eeprom нужно отключать все прерывания, иначе, если во время операции записи в eeprom возникнет какое-либо прерывание, то возможно искажение записанной инфы. Как на самом деле? Цитата И вообще используйте библиотечные функции для доступа к EEPROM. В них небудет детских ошибок. А они есть? Я что-то не нашёл ни в справочной IAR и ни в справке по библиотеке DLIB. Где искать?
|
|
|
|
|
Jan 24 2008, 17:24
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(DiMonstr @ Jan 24 2008, 20:13)  Я где-то читал, что во время записи в eeprom нужно отключать все прерывания, иначе, если во время операции записи в eeprom возникнет какое-либо прерывание, то возможно искажение записанной инфы. Как на самом деле? На самом деле прерывания надо запрещать только перед вводом "магической" последовательности в регистр EECR: сохранить флаг I запретить прерывания (i.e. обнулить флаг I) установить в EECR бит EEMWE (master write enable) установить в EECR бит EEWE (write enable) восстановить флаг I В противном случае запись может просто не начаться. Цитата они есть? Я что-то не нашёл ни в справочной IAR и ни в справке по библиотеке DLIB. Где искать? В IAR их нет, потому что IAR предоставляет возможность работать с адресным пространством eeprom как с обычной памятью: Код __eeprom char x; __eeprom char y;
if (x) { y = x; } следовательно можно пользоваться просто указателями Код typedef __eeprom char EEPROM_CHAR; typedef EEPROM_CHAR *PEEPROM_CHAR; Пример записи 20 байт непосредственно в eeprom начиная с адреса 0x10, используя возможности IAR'a: Код void ee_test(void) { PEEPROM_CHAR pChar = (PEEPROM_CHAR)0x10; int i; for (i = 0; i < 20; i++) *pChar++ = (char)i; }
|
|
|
|
|
Jan 24 2008, 18:49
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(prottoss @ Jan 24 2008, 19:58)  Можно... Не знал, что структуры можно объявлять таким образом. А что означает цифра после переменной с двоеточием? Решил я протестить этот код. В отладчике я нифига ничего не увидел, в регистрах и ОЗУ значение переменной bit4 типа char в этой структуре не изменяется. Код if (Reg.bit0 == TRUE) Reg.bit1 = FALSE; else Reg.bit0 = TRUE; while(Reg.bit0) Reg.bit4++; Ещё момент. Допустим структура состоит из однотипных элементов типа Bool. Код typedef struct __Reg { Bool bit0: 1; Bool bit1: 2; Bool bit2: 3; char bit4: 4; } TReg; Это же битовая переменная (может принимать значение 0 или 1), а в ОЗУ она будет занимать целый байт. Так не рентабельно получается. Здесь маскированный подход думаю наиболее приемлем, например: Код U8 Status;
#define Busy 4 #define NoStop 3 #define Parity 2 #define Damage 1 #define Transaction 0 #define Bit(n) (1 << (n)) // макрос работы с битами
void main(void) { Status |= Bit(Busy); // установка бита в 1 Status &= ~Bit(Damage); //сброс бита в 0 if ((Status & Bit(Busz)) != 0) break; } Теперь 5 переменных у нас будут замаскированы в одном байте... сказка!
Сообщение отредактировал DiMonstr - Jan 24 2008, 18:53
|
|
|
|
|
Jan 24 2008, 19:06
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(DiMonstr @ Jan 25 2008, 01:49)  Не знал, что структуры можно объявлять таким образом. А что означает цифра после переменной с двоеточием? Решил я протестить этот код. В отладчике я нифига ничего не увидел, в регистрах и ОЗУ значение переменной bit4 типа char в этой структуре не изменяется. Код if (Reg.bit0 == TRUE) Reg.bit1 = FALSE; else Reg.bit0 = TRUE; while(Reg.bit0) Reg.bit4++; Я не знаю, что такое у ВАС TRUE/FALSE. Но запись Код typedef struct __Reg { char bit0: 1; char bit1: 1; char bit23: 2; char bit4567: 4: } Reg_t означает, что поля bitxx в структуре НЕ булевые переменные ...Это битовые переменные! Как к ним обращаться, я показал выше. И, кстати, продемонстрированная мною структура занимает тоже ровно 1 байт.
Сообщение отредактировал prottoss - Jan 24 2008, 19:08
--------------------
|
|
|
|
|
Jan 24 2008, 19:34
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(prottoss @ Jan 24 2008, 22:06)  Да-а-а!? Тогда это здоровско! Под булевым я имел ввиду тоже 0/1. Код #define FALSE (0==1) #define TRUE (1==1) Но я так и не врубился че значит цифра '1' в записи char bit0: 1; Может номер бита в байте? Но засомневался, т.к. попробовал и вылетела ошибка, если указать '0'. Под состояние бита тоже не прокатывает, т.к. здесь '4' char bit4567: 4; Непонятно короче.
|
|
|
|
|
Jan 24 2008, 21:25
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(prottoss @ Jan 24 2008, 23:17)  Размер поля в битах... Всё больше начинаешь понимать, что до профессионального уровня ещё шагать и шагать... Вот теперь ясно. Благодарю за разъяснения.
Сообщение отредактировал DiMonstr - Jan 24 2008, 21:25
|
|
|
|
|
Jan 25 2008, 13:31
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Сергей Борщ @ Jan 25 2008, 11:45)  Для начала вам нужно прочитать учебник по С. Выделить вечер и прочитать его от корки до корки. Если вы каждую элементарную вещь вроде битовых полей будете спрашивать на форуме - "шагать" будете медленно, а скоро вам просто перестанут отвечать. В учебнике, который я изучаю, про работу с битовыми полями таким образом ничего нет. К примеру элементы структуры по этому учебнику описываюся проще, тип_переменная. О таком синтаксисе ничего не сказано. Эта фишка (и не только) уже самого компилятора зарытая и описанная в виде макроса где-то в хидерах или библиотеках.
Сообщение отредактировал DiMonstr - Jan 25 2008, 13:33
|
|
|
|
|
Jan 25 2008, 14:09
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Сергей Борщ @ Jan 25 2008, 16:58)  Я не говорю, что ни в одной литературе не написано о битовых поолях. Вы бы сами какую книгу порекомендовали по Си?
Сообщение отредактировал DiMonstr - Jan 25 2008, 14:10
|
|
|
|
|
Feb 9 2008, 19:41
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(Сергей Борщ @ Jan 25 2008, 18:09)  Вы утверждали, что это "Эта фишка (и не только) уже самого компилятора зарытая". Т.е. снова, как и в начале ветки, во всем виноват компилятор а не ваше невежество.
Книга по С бывает одна: Керниган и Ритчи, "Язык программирования С". Второе (!) издание. Все остальные - ее толкования. Книга есть в интернете. Где искать - не подскажу, гугля в помощь. Оптимизировал проект. Добавил ещё функций. Кое-что переписал. НО!!! Проблема осталась не смотря на все усилия!!! Хоть головой бейся о монитор с клавой, но программа в контроллере не запускается!!! Не знаю где капать! Весь инет перерыл. Подобного ни у кого не было! Что делать???
|
|
|
|
|
Feb 9 2008, 22:09
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(DiMonstr @ Feb 10 2008, 00:24)  А может попробовать скомпилять проект в WinAVR? Да в принципе это последняя надежда  А нееет, есть ещё вариант переписать код на асме.... Есть еще вариант, если, как Вы здесь утверждаете, виноват компилятор и дело до main не доходит, если, как Вы опять же утверждаете, Вы знаете Асм, ну дык кто Вам мешал все это время не заниматься болтовней, а просто взять листинг до main, перенести его в студию и найти место где компилятор ошибся... И радостно нам об этом сообщить. Что то мне подсказывает, что "Если" получилось много, и часть из них Вы не осилили
|
|
|
|
|
Feb 9 2008, 23:17
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Feb 10 2008, 01:09)  Вы здесь утверждаете, виноват компилятор... Можно это утверждение игнорировать начисто - я бегло просмотрел этот код. Полный мрак, начиная с переопределенной точки входа прямо в main(), деклараций переменных в header-ах, конструкций switch( константа ), отсутсвие volatile, обилия кривых макросов, & и && - по барабану,..... В приложении, то, что подправлено за 15 минут - наверное до main() дойдет, но дальше  ....
Прикрепленные файлы
pwrc.rar ( 7.92 килобайт )
Кол-во скачиваний: 28
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Feb 10 2008, 09:28
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(zltigo @ Feb 10 2008, 02:17)  Я с Вами согласен. Сам ужаснулся, когда начал с самого начала просматривать код. Вот версия проекта, которая более менее доведена до ума. Зацените  C Вашей прошивкой работоспособность кода я оценить не смогу. Для этой прошивки в хидере settings.h какие значения определены следующим именам: #define IsCheckCRC #define IsCheckRAM #define IsCheckJUMP #define IsCheckAnalogScheme #define IsCheckBlock
Сообщение отредактировал DiMonstr - Feb 10 2008, 09:47
|
|
|
|
|
Feb 10 2008, 10:58
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Хинт: уберите весь (да, весь, вообще весь) код, до которого не доходит исполнение, оставьте только то место, на котором исполнение затыкается. Попытайтесь локализовать место, на котором программа затыкается.
ЗЫ. switch от (CurrentDevice) т.е. от константы - категорически не труъ, как уже было выше замечено. Уберите.
Ещё, хотелось бы Ваших пояснений, относительно вот этого участка кода (возможно, здесь одна из ошибок):
Value = slow_crc16(Value,(unsigned char __flash *)0, (unsigned long)&__checksum); /* здесь передаётся в третьем параметре указатель */ Value = slow_crc16(Value,(unsigned char __flash *)&zero,2); /* а здесь целое */
Что вообще должно быть здесь выполнено ?
|
|
|
|
|
Feb 10 2008, 12:32
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(forever failure @ Feb 10 2008, 13:58)  Хинт: уберите весь (да, весь, вообще весь) код, до которого не доходит исполнение, оставьте только то место, на котором исполнение затыкается. Попытайтесь локализовать место, на котором программа затыкается. В том-то и дело, что я незнаю до какого адреса доходит выполнение программы. Я делал так, сразу после main() инициализировал USART интерфейс и atmega передавала в цикле байты на комп, пока не получит ответа. Теперь после прошивки я точно мог узнать работает код или нет. Так и сделал, отключив сначала все функции тестирования. Заработало. Затем начал экспериментировать разрешая выполнение тестов и снова прошивая. Ну и что Вы думаете? Выполнение программы, то доходило до команды посылки байта, то через раз ничего не работало, то работало стабильно. Получается прога затыкается перед функцией main() на стадии инициализации стека, озу и т.д. Верно? Цитата ЗЫ. switch от (CurrentDevice) т.е. от константы - категорически не труъ, как уже было выше замечено. Уберите. Понял, сделаем. Цитата Ещё, хотелось бы Ваших пояснений, относительно вот этого участка кода (возможно, здесь одна из ошибок): Value = slow_crc16(Value,(unsigned char __flash *)0, (unsigned long)&__checksum); /* здесь передаётся в третьем параметре указатель */ Value = slow_crc16(Value,(unsigned char __flash *)&zero,2); /* а здесь целое */ Что вообще должно быть здесь выполнено ? Здесь производится подсчет CRC прошивки и сравнение с CRC, которая сохраняется в конец файла прошивки на стадии компиляции. Код unsigned short slow_crc16(unsigned short sum, unsigned char __flash *p, unsigned long len) { while (len--) { int i; unsigned char byte = *p++; for (i = 0; i < 8; ++i) { unsigned long osum = sum; sum <<= 1; if (byte & 0x80) sum |= 1; if (osum & 0x8000) sum ^= 0x1021; byte <<= 1; } } return sum; } Этот код к проблеме не имеет отношения, без него такая же лажа. Он был взят из "апноутов".
|
|
|
|
|
Feb 11 2008, 21:00
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Feb 10 2008, 02:17)  Можно это утверждение игнорировать начисто - я бегло просмотрел этот код. Полный мрак, начиная с переопределенной точки входа прямо в main(), деклараций переменных в header-ах, Нда..., Вы меня заинтриговали и я тоже глянул на код... Переопределение main это фигня, если автор точно знает что делает, декларация переменных в хедерах...., ну сам иногда пользуюсь, иногда это удобнее и правильнее...(в соответствующем контексте конечно...) Но примерно 30-50 вызовов функции EEPROM_write_byte, половина из которых вызывается из прерываний... Эта прога не заживет никогда, хотя автар будет еще долго утверждать что по частям у него все работало... АМИНЬ...
|
|
|
|
|
Feb 11 2008, 21:20
|

Местный
  
Группа: Свой
Сообщений: 482
Регистрация: 5-07-05
Из: Санкт-Петербург
Пользователь №: 6 528

|
Цитата(DiMonstr @ Feb 12 2008, 00:00)  Спасибо. Надеюсь Вас тут убелили, что не стоит делать хитроумные проверки в виде счётчика переходов до основной точки входа и, тем более, хаять компилятор...
--------------------
Для связи email: info собака qbit.su
|
|
|
|
|
Feb 12 2008, 17:44
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(bzx @ Feb 12 2008, 00:20)  Надеюсь Вас тут убелили, что не стоит делать хитроумные проверки в виде счётчика переходов до основной точки входа и, тем более, хаять компилятор... А вот и нет, не убедили. Я не понимаю почему не стоит делать проверки джампов до main(). Как раз там её и целесообразней сделать, чтобы ещё до начала фунциклирования кода выявить ошибку. Я не вижу в этом ничего криминального! В любых системах, перед её запуском производится тестирование оборудования. Цитата(singlskv @ Feb 12 2008, 00:00)  ...Но примерно 30-50 вызовов функции EEPROM_write_byte, половина из которых вызывается из прерываний... Эта прога не заживет никогда, хотя автар будет еще долго утверждать что по частям у него все работало... АМИНЬ... А в чем собственно проблема? И причем тут вызов EEPROM_write_byte. Да хоть 100 раз я вызову - коренным образом это ничего не изменит. Во-первых, я их использую для отладки. Во-вторых, вызов функции записи в eeprom из прерываний для меня не критичен. В-третьих, на ход выполнения кода это тоже никак не влияет, иначе зачем тогда eeprom? Что Вы этим хотели сказать? Конкретизируйте пожалуйста.
|
|
|
|
|
Feb 12 2008, 18:42
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(DiMonstr @ Feb 12 2008, 20:44)  Во-первых, я их использую для отладки. Во-вторых, вызов функции записи в eeprom из прерываний для меня не критичен. В-третьих, на ход выполнения кода это тоже никак не влияет, иначе зачем тогда eeprom? Если для Вас не критично что из-за вызова функции записи в EEPROM, прерывание может зависнуть в этом месте примерно на 3,5миллисекунды , и будут пропущены другие прерывания, тогда не вопрос, тогда у Вас все в порядке...
|
|
|
|
|
Feb 13 2008, 06:09
|
Местный
  
Группа: Участник
Сообщений: 256
Регистрация: 6-03-05
Из: Екатеринбург
Пользователь №: 3 112

|
Кстати, кто-нить смотрел checkjump.asm ? Особенно вот такое место впечатлило : TESTJMP_SUCCESS_BRID: INC R17 ;////////////////////////////////////////////////////////////////////////// ;// Формируем адрес перехода исходя из результатов тестов // SHL ecx, 1 // ADD R17, offset TESTJMP_FINISH; ;////////////////////////////////////////////////////////////////////////// ;// Переход в зависимости от результата // JMP R17 ;////////////////////////////////////////////////////////////////////////// ;// Програмные ловушки TESTJMP_FINISH: TESTJMP_FINISH_COMPLETE: END /*кгхм.... ну и куда дальше пошло исполнение ? прим. мое, f. f. */
Автор, если серьёзно хотите что-то продолжить, у вас есть два выбора: 1. Внимать советам более опытных участников форума и не упираться рогами в духе "а я вот хочу так и всё". 2. Продолжить самостоятельно заниматься этим сумеречным умопомрачением, но уже не задавать вопросы "почему у меня не заводится, наверно компилятор кривой ?"
[плохой вариант удалён]
Сообщение отредактировал IgorKossak - Feb 13 2008, 06:40
|
|
|
|
|
Feb 13 2008, 20:31
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(forever failure @ Feb 13 2008, 09:09)  Кстати, кто-нить смотрел checkjump.asm ? Особенно вот такое место впечатлило... Да этот тест ещё не дописан уважаемый!!! Не пугайтесь так. Приведенная Вами часть кода пока в разработке. Цитата(GDI @ Feb 13 2008, 10:39)  Потому что Си программа стартует с main(), а все что вы понаписали до функции main() это только определения функций, т.е. код , который может быть вызван, только из функции main() или из прерываний, которые инициализируются и разрешаются опять же из функции main(). А здесь я с Вами в корне не согласен! Как тут уже упоминалось, можно прицепить файл cstartup.s90 и написать код в нем. Вызов main() функции производиться из этого файла строкой: Код ?cstartup_call_main: XCALL main Здесь я и продумываю разместить свои тесты, т.е. до инициализации стека и массивов данных. Сегодня я провел такой эксперимент с прошивкой которая не запускается в атмеге. Вставил в этот файл свой код, который пару раз дергает один из выводов порта. Подключил к ноге анализатор и зашил прошивку. Код вставил сюда: Код ;---------------------------------------------------------------------------- ; Set up the CSTACK and RSTACK pointers. ;---------------------------------------------------------------------------- RSEG CODE:CODE:NOROOT(1) ?SETUP_STACK: SBI 0x11, 4 SBI 0x12, 4 CBI 0x12, 4 SBI 0x12, 4 CBI 0x12, 4 ;; Return address stack (RSTACK) LDI R16,LOW(SFE(RSTACK)-1) OUT 0x3D,R16 После запуска стало ясно, что выполнение программы даже до этого участка не доходит!!! Изменений сигнала на выводе порта не происходит! Выходит дело, что переход с нулевого адреса выполняется не по адресу PC+0x00F9: Код @00000000: __program_start ---- cstartup.s90 --------------------------------------------------------------------------------- 26: XJMP ?C_STARTUP +00000000: C0F8 RJMP PC+0x00F9 Relative jump @00000001: ??INTVEC 2 Или в результате компиляции рождается битая прошивка. А иначе как такое можно объяснить???!!! Что на это скажете?!
|
|
|
|
|
Feb 13 2008, 21:21
|

Местный
  
Группа: Свой
Сообщений: 482
Регистрация: 5-07-05
Из: Санкт-Петербург
Пользователь №: 6 528

|
Цитата(DiMonstr @ Feb 13 2008, 23:31)  Или в результате компиляции рождается битая прошивка. А иначе как такое можно объяснить???!!! Что на это скажете?! Откуда у Вас такая неуёмная страсть к мазохизму? Вам уже десятка два людей прямо говорят, перестаньте страдать фигнёй. Годика 2-3 непрерывно попишите чего-нибудь попроще на чистом C, тогда, возможно, и самостоятельно разберётесь что к чему и без посторонней помощи, которую Вы не хотите слышать.
--------------------
Для связи email: info собака qbit.su
|
|
|
|
|
Feb 14 2008, 06:10
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Цитата(forever failure @ Feb 14 2008, 07:36)  Прогонял я код и в AVR Studio и в IARовском отладчике. Правда в IAR я дебаггера так и не заставил шагать с 0x00 адреса. Всегда он начинает с main(). Ну да ладно... В общем в студии всё чисто, без криминала. Всё работает. Цитата(bzx @ Feb 14 2008, 00:21)  Откуда у Вас такая неуёмная страсть к мазохизму? Вам уже десятка два людей прямо говорят, перестаньте страдать фигнёй. Годика 2-3 непрерывно попишите чего-нибудь попроще на чистом C, тогда, возможно, и самостоятельно разберётесь что к чему и без посторонней помощи, которую Вы не хотите слышать.
Да и так уже почти год пишу на Си. Начинал с камешка AT90USB. Таких проблем там не было, а те что были разрулил. Это второй проект, причем на самом простом контроллере из AVR. И такая засада получилась...
|
|
|
|
|
Feb 14 2008, 08:48
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(DiMonstr @ Feb 14 2008, 08:10)  Да и так уже почти год пишу на Си. Тогда вернитесь к истокам. Создайте новый проект, напишите в нем моргалку светодиодом из четырех команд и вылизывая железо добейтесь ее устойчивой работы. Если даже такая простая программа работать не будет - надо менять или железо или профессию. Вы питание и землю на все ножки питания/земли процессора подали или только на одну пару? Потом постепенно добавите кусочки из своего нынешнего проекта. Проверять команды перехода - полная фигня. Что вы будете делать, если тест покажет ошибку? Будете крутиться в замкнутом цикле? Но какой командой вы цикл организуете, ведь переходы-то не работают! Запрещать переходить в main тоже не нужно - если переходы не работают, вы туда просто не попадете по XCALL main, ведь переходы-то не работают. Менять cstartup для выполнения кода перед main не нужно - почитайте про функцию __low_level_init() в IAR и секции .initX в avr-gcc.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 3 2008, 14:31
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Сергей Борщ @ Jan 11 2008, 11:11)  Первое, что нужно сделать - посмотреть в листинг и убедиться, что компилятор понял вас правильно. Это понятно, что компилятор обвинить проще простого. У меня подобное поведение наблюдалось однажды, когда ошибочно был установлен фуз BRST. А у студента - когда подтяжка ресета вместо питания была подключена к одному из портов. Он порт настраивает на вывод - контроллер ресетится.
В общем есть предложение поспорить на ящик пива, что компилятор снова не при чем, а виноваты недостаток знаний и опыта. А я часто сталкиваюсь с глюками ИАРа под МСП. В основном они однообразны и заключаются в непереходе по условию if, когда вроде бы всё очевидно. Я точно не помню, но было что-то типа такого: char i; ... if (i) do something else dо other Так вот, условие никогда не выполнялось, хотя i было явно не ноль. И так продолжалось до тех пор, пока я не переопределил условие типа i==0 или что-то типа этого, точно уже не помню. И случай не единичный. Но ничего , привык. Правда, теперь вот на mspgcc надо переходить, а он вообще не хочет работать (в смысле код) Хотя согласен, чаще всего ошибки в собственном коде.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Mar 3 2008, 19:51
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 26-10-06
Из: Россия, Пенза
Пользователь №: 21 706

|
Всех приветствую!!! Я нашел причину  И она зарыта была не в коде и не в компиляторе. А в фуз битах, мать их... FUSE BITS - ЭТО ТАКАЯ ГЕММОРОЙНАЯ ПОДСТРОЙКА КОНТРОЛЛЕРА, ЧТО ВРЕМЕНАМИ ХОЧЕТЬСЯ НАПИТЬСЯ И ЗАБЫТЬСЯ Жалко, что вспомнил я про эти биты поздновато. Хотя я об этом и не жалею. Пока искал косяк, исправил множество ошибок в коде, оптимизировал его, а также изучил фишки компилятора IAR. Короче дернул меня черт посмотреть как организована FLASH память. Я знал, что она состоит из двух секций: загрузочной и прикладной программ. Так вот, в документе я обнаружил, что по умолчанию размер BOOT области памяти установлен максимальный посредством фузов BOOTSZ. Я прикинул побыстрому - аха, глюки начинаются как раз, когда прошивка превышает размер в 6 КБ. Не долго думая я сократил размер этой области до минимума. И заработало!!! Оказывается у меня был запрограммирован фуз BOOTRST. Тем самым я переместил вектор сброса в BOOT сектор памяти, который и перетирался кодом прикладной программы. Только я вот до сих пор не понял, почему одна и таже прошивка могла запуститься, а могла и не запуститься. Наверное это зависило от того кода, который оказывался по адресу расположения вектора сброса.  В общем всем огромное спасибо и уважуха! Я много узнал с вашей момощью.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|