Страница 1 из 1

ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 01:16:41
modeler
Здравствуйте коллеги!
Есть один момент, который ввел меня в глубокий ступор:
ATMega8 с внешним кварцем 12Mhz, но на какой частоте она реально работает ХЗ :)
в общем фьюзы выставлены, кварц работает, осциллограф показывает на Xtal1 12МГц, НО даже вот такой незамысловатый код:

Код: Выделить всё

int main(){
   DDRC = 0b00010000; PORTC = 0b00000000;
   while(1){
      PORTC ^= 1 << 4;
      _delay_ms(5);
   }
}


приводит к странным результатам, а именно частота/период/длительность ровно в 4 РАЗА БОЛЬШЕ! :shock: причем независимо от величины задержки т.е. получается, что мега как бы работает на частоте 48МГц? :)
в принципе раньше я натыкался в attiny13 на другой эффект, но там было наоборот выходная частота была ниже в 2^x раз, но этим процессом можно было как-то управлять (сейчас уже не помню, какой-то регистр)
перерыл даташит на мегу, но каких-то вещей отвечающих за умножение не нашел да и в принципе раз USB протокол работает

вообще началось все с того что я хотел реализовать термометр типа http://eldigi.ru/articles/usb_termometr и прикол в том что
готовая прошивка залитая в МК работает, но когда я сам компилирую прошивку из проекта то получается хрень, т.е. прога не работает, стал разбираться и оказалось что все сигналы (в данном случае критические) на датчик идут с большей частотой
причем, в плане USB все как ни странно исправно работает в обоих прошивках. в результате создал новый проект с кодом который привел выше - таже хрень. очевидно что МК не может работать на такой частоте, т.е. видимо косяк где-то в самом delay, возможно что по какой-то неизвестной мне причине компилятор "думает" что выбран более медленный режим работы мк (получается 3МГц) и исходя из этих данных и генерируется другая меньшая (в 4 раза) задержка, только вот не могу понять причину такого поведения компилятора...
насколько я понимаю на delay влияют несколько факторов: тип/модель мк (могут быть специфичные асембленые костыли), частота (F_CPU=12000000) и собственно сам генератор (в данном случае кварц 12МГЦ)

может кто сталкивался и наступал уже на эти грабли?

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 06:43:53
Mishany
a в чем пишете?
по тому кусочку проги трудно что либо посоветовать.
для правильной работы delay много чего надо прописать...
либо кварц брак, либо fuse, как говориться чудес не бывает

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 11:29:36
vdavid
modeler, Это студия? Там в тулчейне есть известный баг в delay.h. В WinAvr его нет.
Почитайте, например, здесь http://www.avrfreaks.net/forum/bug-avr-lib-delayfunc?name=PNphpBB2&file=viewtopic&t=100131.
Попробуйте сделать вот это:
#define __DELAY_BACKWARD_COMPATIBLE__

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 14:13:04
modeler
да это 4-ая студия с тулчейном, недавно скачал 6-ую но пока не установил.
а что вообще посоветуете, что лучше для разработки под авр на си?

#define __DELAY_BACKWARD_COMPATIBLE__ - не поможет хоты бы потому что нигде в файлах тулчейна не встречается

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 14:53:49
vdavid
Ну не знаю. У меня нет тулчейна. Я пользуюсь WinAvr. На AvrFreaks советуют еще такое:
#define __HAS_DELAY_CYCLES 0
Скачал AVR Toolchain 3.3.0. __DELAY_BACKWARD_COMPATIBLE__ встречается в delay.h неоднократно.

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 15:23:47
modeler

Код: Выделить всё

int main(){
   DDRC = 0b00010000; PORTC = 0b00000000;
  38:   80 e1          ldi   r24, 0x10   ; 16
  3a:   84 bb          out   0x14, r24   ; 20
  3c:   15 ba          out   0x15, r1   ; 21
   while(1){
      PORTC ^= 1 << 4;
  3e:   90 e1          ldi   r25, 0x10   ; 16
  40:   85 b3          in   r24, 0x15   ; 21
  42:   89 27          eor   r24, r25
  44:   85 bb          out   0x15, r24   ; 21
{
   uint16_t __ticks;
   double __tmp = ((F_CPU) / 4e3) * __ms;
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__)
   extern void __builtin_avr_delay_cycles(unsigned long);
   __builtin_avr_delay_cycles(__tmp);
  46:   e5 ea          ldi   r30, 0xA5   ; 165
  48:   fe e0          ldi   r31, 0x0E   ; 14
  4a:   31 97          sbiw   r30, 0x01   ; 1
  4c:   f1 f7          brne   .-4         ; 0x4a <__SREG__+0xb>
  4e:   00 c0          rjmp   .+0         ; 0x50 <__SREG__+0x11>
  50:   00 00          nop
  52:   f6 cf          rjmp   .-20        ; 0x40 <__SREG__+0x1>

00000054 <_exit>:
  54:   f8 94          cli

00000056 <__stop_program>:
  56:   ff cf          rjmp   .-2         ; 0x56 <__stop_program>


вот во что разворачивается сишный код и судя по нему баг находится в глубинах __builtin_avr_delay_cycles, т.е. иными словами на данном тулчейне получить вменяемый delay не судьба!? кто так пишет!? :)

UPD: в общем немного покумекав подшаманил код util/delay.h (AVR studio 4.18 build 716 toolchain/arv-libc 1.7.0)
знаю, что возможно не самое лучшее решение, но зато без дополнительных заморочек в каждом проекте, а то пройдет год про баг забудешь и снова на те же грабли по второму разу наступишь :(

было:

Код: Выделить всё

void
_delay_ms(double __ms)
{
   uint16_t __ticks;
[color=#FF0000]   double __tmp = ((F_CPU) / 4e3) * __ms;[/color]
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__)
   extern void __builtin_avr_delay_cycles(unsigned long);
   __builtin_avr_delay_cycles(__tmp);
#else
   if (__tmp < 1.0)
      __ticks = 1;
   else if (__tmp > 65535)
   {
      //   __ticks = requested delay in 1/10 ms
      __ticks = (uint16_t) (__ms * 10.0);
      while(__ticks)
      {
         // wait 1/10 ms
         _delay_loop_2(((F_CPU) / 4e3) / 10);
         __ticks --;
      }
      return;
   }
   else
      __ticks = (uint16_t)__tmp;
   _delay_loop_2(__ticks);
#endif
}

void
_delay_us(double __us)
{
   uint8_t __ticks;
[color=#FF0000]   double __tmp = ((F_CPU) / 3e6) * __us;[/color]
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__)
   extern void __builtin_avr_delay_cycles(unsigned long);
   __builtin_avr_delay_cycles(__tmp);
#else
   if (__tmp < 1.0)
      __ticks = 1;
   else if (__tmp > 255)
   {
      _delay_ms(__us / 1000.0);
      return;
   }
   else
      __ticks = (uint8_t)__tmp;
   _delay_loop_1(__ticks);
#endif
}



стало:

Код: Выделить всё

void
_delay_ms(double __ms)
{
   uint16_t __ticks;
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__)
[color=#FF0000]   double __tmp = ((F_CPU) / 1e3) * __ms;[/color]
   extern void __builtin_avr_delay_cycles(unsigned long);
   __builtin_avr_delay_cycles(__tmp);
#else
[color=#FF0000]   double __tmp = ((F_CPU) / 4e3) * __ms;[/color]
   if (__tmp < 1.0)
      __ticks = 1;
   else if (__tmp > 65535)
   {
      //   __ticks = requested delay in 1/10 ms
      __ticks = (uint16_t) (__ms * 10.0);
      while(__ticks)
      {
         // wait 1/10 ms
         _delay_loop_2(((F_CPU) / 4e3) / 10);
         __ticks --;
      }
      return;
   }
   else
      __ticks = (uint16_t)__tmp;
   _delay_loop_2(__ticks);
#endif
}

void
_delay_us(double __us)
{
   uint8_t __ticks;
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__)
[color=#FF0000]   double __tmp = ((F_CPU) / 1e6) * __us;
[/color]   extern void __builtin_avr_delay_cycles(unsigned long);
   __builtin_avr_delay_cycles(__tmp);
#else
[color=#FF0000]   double __tmp = ((F_CPU) / 3e6) * __us;[/color]
   if (__tmp < 1.0)
      __ticks = 1;
   else if (__tmp > 255)
   {
      _delay_ms(__us / 1000.0);
      return;
   }
   else
      __ticks = (uint8_t)__tmp;
   _delay_loop_1(__ticks);
#endif
}


да как оказалось в _delay_us тоже баг, только длительность меньше не в 4 раза, а всего лишь в 3 :)

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 15:32:41
modeler
UPS: что-то выделение цветом в коде не сработало :(
в общем суть в том, что раз при #define __HAS_DELAY_CYCLES 0 задержка становится нормальной, стало быть нужно изменить вычисление __tmp в зависимости от условия


vdavid писал(а):Ну не знаю. У меня нет тулчейна. Я пользуюсь WinAvr. На AvrFreaks советуют еще такое:
#define __HAS_DELAY_CYCLES 0
Скачал AVR Toolchain 3.3.0. __DELAY_BACKWARD_COMPATIBLE__ встречается в delay.h неоднократно.


да вполне возможно что за 4 года :) они все таки пофиксили этот огроменный баг сравнимый с настоящей диверсией, но к сожалению я не готов к такому радикальному изменению/обновлению :)

да это #define __HAS_DELAY_CYCLES 0 я тоже попробовал после чего пришел в выводу в предыдущем посте, т.к. это тоже не совсем панацея, не будешь же в каждом проекте менять эту хрень да и забыть очень легко и просто... если уж я использую _delay_ms/_delay_us и подключаю util/delay.h, то он должен работать как delay а не как фишка ляжет!

Re: ATMega8 кварц 12Mhz

Добавлено: Сб окт 04, 2014 15:57:03
vdavid
Да тулчейн 3.3.0 (который я смотрел) шел со студией 4.19 еще в 2011 году. А дефайн для __HAS_DELAY_CYCLES никто Вам не мешает воткнуть прямо в delay.h.

Re: ATMega8 кварц 12Mhz

Добавлено: Вс окт 05, 2014 22:42:37
modeler
да, но IMHO я сделал лучше, т.к в зависимости от настроек проекта и опций компилятора по части оптимизации будет использоваться тот вариант который лучше (по задумке авторов тулчейна)
вообще честно говоря не понятна мотивация авторов по поводу разделения кода, т.е. если есть __builtin_avr_delay_cycles на кой надо было городить огород с кривым забором :)
причем как я понял использование delay требует включение оптимизации иначе они ничего не гарантируют :)
как в прочем и в том случае когда значение задержки меняется по ходу выполнения рпограммы

Re: ATMega8 кварц 12Mhz

Добавлено: Вс окт 05, 2014 22:59:26
ua1arn
на delay влияют несколько факторов: тип/модель мк (могут быть специфичные асембленые костыли), частота (F_CPU=12000000) и собственно сам генератор (в данном случае кварц 12МГЦ)

Ещё влияет уровень оптимизации. Поставьте -Os - и задержки станут соответствовать. У меня так предупреждение выдавалось при компиляции.