Страница 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- ... c&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 - и задержки станут соответствовать. У меня так предупреждение выдавалось при компиляции.