Jump to content
    

Злополучная функция what_day()

Изначально там были int. Я char поставил для экономии. Проверил. Не помогло (в смысле, если на int все поменять). Да и логики в этом не вижу...
Логика тут простая - ваша экономия мнимая. Компилятор все равно приводит все вычисления к типу int, а временные переменные разместит в регистрах.

Share this post


Link to post
Share on other sites

Если это хоть как-то наведет на мысли... Глюк проявляется при входе при входе к определенным пунктам меню ("Редактирование параметров"). При этом редактирование и сохранение параметра идет как положено, за исключением того , что вместо кнопки "UP"-смещение на одно знакоместо происходит замена цифрой '6', а вместо "ESC", котороя возвращает в предыдущий п. меню происходит вставка цифры '2'. Некоторые пункты меню работают нормально. Напомню, что все это происходит, если вызвать функцию what_day();

Share this post


Link to post
Share on other sites

Это выходит за всякие рамки понимания и попахивает чертовщиной...

Написал третью функцию вычисления дня недели:

unsigned char what_day(unsigned int year, unsigned int month, unsigned int day)
{
  unsigned char YEAR[]={0, 2, 3, 4};
  unsigned char MONTH[]={0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
  unsigned char a, b, c, e, tmp;
  
  tmp = year - 1996;
  a = tmp & 3;
  b = (tmp >> 2) + (tmp & 0xfc);
  c = MONTH[month-1];
  
  if((a == 0) && (month > 2)) c++;
  a = YEAR[a];
  e = (a + b + c + day) % 7;
  return e;
}

Функцию переписал у Сергея Фролова. В ней нет тяжелых делений. Она работает. Но при вызове все равно приводит к тому глюку! :07:

 

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

//_____________________________________________________________________________
double quadratic(double a, double b, double c) 
{
  double d, x;
  d=b*b-4.*a*c;                 // Дискриминант
  if(d<0.) return 0;            // Уравнение не имеет корней
  if(d==0.) x=-b/(2.*a);        // Уравнение имеет один корень
  else  x=(-b+sqrt(d))/(2.*a);  // Уравнение имеет два корня, 
                        // но нужен только положительный
  return x;
}

//#############################################################################
// round down a number to the decimal place given by power
// e.g round(1.0256,-2) means round to 2nd decimal -> 1.03
//_____________________________________________________________________________
double round_to_pow(double x, int power)
{
   double inc, xnew;
   inc  = pow(10.0, (double)power);
   xnew = inc * (floor(x/inc + 0.5 + SMALL)); 
   return(xnew);
}

//---------------------------------------------------------------------------
int main()
{
volatile unsigned char day;
  day = (unsigned char)round_to_pow(quadratic(100, 200, 3), -5);

Так все нормально. В чем же может быть дело? Какие еще будут предложения?

 

PS. Одна деталь. Если убрать из what_day() (обеих вариантов) операцию % 7, то глюк исчезает. Как это объяснить? В дополнение к функции решения кв. уравнения добавил функцию по расчету давления и температуры цифрового датчика давления. Там точно громоздкие вычисления. И все прошло (глюка не вызвало). А здесь простая операция деления по модулю... :cranky:

Share this post


Link to post
Share on other sites

Но по какой-то непонятной причине вызов ее приводит к глюкам программы. В частности, при входе в пункт меню невозможно из него выйти, при этом программа реагирует не так как задумано. Должен сказать, что проект использует ОС (scmRTOS) и ОЗУ использовано на 90%. Контроллер Mega324P (2кБ ОЗУ). Отладочными средствами (JTAG) пользоваться не представляется возможным. Это похоже на переполнение стека. Но. Почему это происходит, если вызов достаточно простой функции вставить в начале функции main (до запуска ОС):

int main()
{
  what_day(2008, 6, 6);
.....................

Больше нигде в процессах она не используется. Пробовал менять размеры CSTACK (100...200) и RSTACK (32...64).

Не помогло, не в этом причина . из Вашего мэп

CSTACK               DATA          00000100 - 000001FF         100   dse    0
RSTACK               DATA          00000200 - 0000023F          40   dse    0

Теперь мысль, может бредовая но всё-же- может Вы запретили компилятору какие-то регистры в которых компилятор хранит остаток от деления? не знаю как ИАР но в код вижине остаток хранится в 26 регистре. Пример для КВ

//=========================================================
void prog3(char ch)
{
    ch=ch+2;
    ch=ch/3;
    ch=ch%3;
}
void prog4(char ch)
{
    ch=ch/3;
    ch=ch%3;
}

??? Лишние инструкции
??? Оптимальнее было-бы так - 
_prog3:
    LD   R30,Y
    SUBI R30,-LOW(2)
    ST   Y,R30
_prog4:
    LD   R26,Y
    LDI  R30,LOW(3)
    RCALL __DIVB21U
    ST   Y,R30
    LD   R26,Y
    LDI  R30,LOW(3)
    RCALL __MODB21U
    ST   Y,R30
    ADIW R28,1
    RET

Share this post


Link to post
Share on other sites

Недавно в яре натолкнулся под авр использовал функцию % и прога пошла лесом... как только закоментировал строчку- все заработало. В листинге не разбирался- не было времени. Теперь жалею

Share this post


Link to post
Share on other sites

Не помогло, не в этом причина . из Вашего мэп

CSTACK               DATA          00000100 - 000001FF         100   dse    0
RSTACK               DATA          00000200 - 0000023F          40   dse    0

Не понял. Что Вы имели в виду?

 

Теперь мысль, может бредовая но всё-же- может Вы запретили компилятору какие-то регистры в которых компилятор хранит остаток от деления?
Регистры я не трогаю.

 

Заменил в функции операцию % 7 на -= 7:

  day = a + year + c + day;// % 7;
  while(day >= 7)  day -= 7;
  
  return day;

Проблема решилась частично: если вызвать эту функцию из main() , то глюк пропал. Но если вызвать ее из другой функции rtc_set_time(), то глюк имеет место быть... Не знаю что и думать. Варианты исчерпались. Пойду-ка я спать.

 

 

PS2. Все! Наконец-то поборол глюк.

Переписал в очередной раз функцию. Прям целая коллекция функций получилась :)

unsigned char what_day(unsigned int year, unsigned int month, unsigned int date)
{
  signed int c=0;
  unsigned char day;
  
  if((date>=1)&&(date<=31)&&(month>=1)&&(month<=12)&&(year>=1582)&&(year<=4903))
  {  
    if(month < 3)
    {
      month += 10;    // Месяц январь или февраль?
      year -= 1;
    }
    else
    {
      month -= 2;     // Остальные месяцы
      
      while(year >= 100)
      {
        c++;          // Вычисляем столетие
        year -= 100;  // Находим год в столетии
      }
      
      day = (unsigned char)((26*month-2)/10 + date + (year>>2) + year + (c>>2) - 2*c);
      while(day >= 7) day -= 7;  // Вычисляем день недели
    }
  }
  return day;
}

Сейчас все работает как положено. Хотя неприятный осадок остался... Нет ответов на вопросы - почему такое произошло?

Edited by alux

Share this post


Link to post
Share on other sites

Посмотрите, какие регистры использует подпрограмма взятия остатка от деления: возможно, ошибка в несохранении компилятором значения регистра, используемого вызывающим кодом.

Share this post


Link to post
Share on other sites

Не понял. Что Вы имели в виду?

использование функциями CSTACK и RSTACK я всегда смотрю в листинге. файл с расширением .lst.

вот отрывок, удобно

 Maximum stack usage in bytes:

     Function           CSTACK RSTACK
     --------           ------ ------
     lcd_EN_toggle          0      2
     lcd_command            1      2
       -> lcd_waitcmd       1      2
       -> lcd_write         1      2
       -> lcd_waitcmd       1      2

а нащёт остатка от деления и рассположения в регистрах надо будет всё же подумать, может попробовать намного пошаманить с инлайн ассемблером ? Сообщите о результатах. Сам тоже попробую

Share this post


Link to post
Share on other sites

Если у вас scmRTOS, то размеры каких стеков вы крутите? Там ведь у каждого процесса свои стеки.

 

PS: time.h использовал как-то. плохо совместимая с экономией памяти вещь.

Share this post


Link to post
Share on other sites

Недавно в яре натолкнулся под авр использовал функцию % и прога пошла лесом... как только закоментировал строчку- все заработало. В листинге не разбирался- не было времени. Теперь жалею

Странно... Использовал скопипастленную с сахары функцию

unsigned long DateTimeToLong(TDataTime* pdt){
byte month;
word year;
unsigned long c, ya;
unsigned long res;

month = BCDtoBin(pdt->Month);
year = BCDtoBin(pdt->Year)+2000;

if(month > 2){
month -= 3;
}/*if*/ 
else {
month += 9;
year--;
}/*else*/

c = (year / 100L);
ya = (year - (100L * c));
res = (146097L * c)/4L + (1461L * ya) /4L + (153L * month + 2L)/5L + BCDtoBin(pdt->Date); 
pdt->Day=(res+2)%7;
return (res - 720000L) * 1440L + (BCDtoBin(pdt->Hour) * 60L + BCDtoBin(pdt->Min));
}

Никаких проблем, хотя оптимальности и экономии никакой. IAR AVR 4.30 Значения CSTACK и RSTACK по умолчанию, т.е минимальные.

Share this post


Link to post
Share on other sites

Проблема решилась частично: если вызвать эту функцию из main() , то глюк пропал. Но если вызвать ее из другой функции rtc_set_time(), то глюк имеет место быть...
Всё-таки не исключено, что стек. В любой другой функции стека меньше по сравнению с main, т.к. они вызываются после main.

 

Если у вас scmRTOS, то размеры каких стеков вы крутите? Там ведь у каждого процесса свои стеки.
Действие происходит ещё до запуска ОС, на этапе инициализаций.

 

PS. Либо дайте уже нормальный листинг, либо этот телепатический сеанс затянется надолго. Нужен листинг этой "злополучной" функции и карту ОЗУ со стеком и рядом с ними.

Share this post


Link to post
Share on other sites

Нужен листинг этой "злополучной" функции и карту ОЗУ со стеком и рядом с ними.

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

Вызов функции what_day() происходит из rtc_set_time(), которая в свою очередь вызывается из rtc_Init().

gluk.rar

no_gluk.rar

Share this post


Link to post
Share on other sites

Вызов функции деления до сих пор присутствует.

 

Ещё нужен листинг функций PROLOGUE6_L09, S_EC_MUL_L02, US_DIVMOD_L02. Ищется через поиск слова в директории со всеми листингами.

Share this post


Link to post
Share on other sites

Вызов функции деления до сих пор присутствует.

day = (unsigned char)((26*month-2)/10 + date + (year>>2) + year + (c>>2) - 2*c);

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

 

Ещё нужен листинг функций PROLOGUE6_L09, S_EC_MUL_L02, US_DIVMOD_L02. Ищется через поиск слова в директории со всеми листингами.
Поиск по этим словам в директории list или проекта дает только вызовы этих функций:

//NOTE: This module defines or uses C++ features that are not
//      accessible from assembler code. Assembling this file will
//      not produce an equivalent object file to the one produced
//      by the C++ compiler.

        EXTERN ?EPILOGUE_B6_L09
        EXTERN ?EPILOGUE_B8_L09
        EXTERN ?PROLOGUE6_L09
        EXTERN ?PROLOGUE8_L09
....................
        EXTERN ?US_DIVMOD_L02

..................
        CALL    ?US_DIVMOD_L02

Я не нашел нигде их определения. Судя по замечанию сверху - их ассемблерные инструкции не доступны.

Share this post


Link to post
Share on other sites

Тогда выкладывайте HEX-файл. Функция деления - она общая для деления и остатка, кстати.

 

В MAP-файле с глюком указано, что последний адрес в раме = 087B, что вроде бы выходит за пределы чипа. Под рукой есть только описание mega323, у которого тоже 2 КБ и адреса в раме заканчиваются на 085F. Может файл линковки неправильный. Тоже выложите посмотреть.

Edited by GetSmart

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...