AVR: F_OSC,F_CPU och BAUDRATE [löst - tror jag]

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

AVR: F_OSC,F_CPU och BAUDRATE [löst - tror jag]

Inlägg av jesse »

Nu håller jag på att bli tokig igen.

Har gjort en massa ändringar i ett program. Bytt kristall från 19.66080 MHz till 3.6864 MHz samt ändrat och joxat o det mesta. En skillnad var även att jag valde att skala ner frekvensen för CPU till 1/4 av oscillatorfrekvensen för att spara ström. Så CPU kör på 0.9216 MHz (med hjälp av CLKPR).

Då börjar UART att köra på fel frekvens... den var inställd på 38.400 baud men kör i verkligheten på 19.200.

Det började med att jag upptäckte att F_CPU och F_OSC inte var samma sak. Enligt databladet till ATMega644 är F_OSC själva oscillatorfrekvensen medans F_CPU är den nerskalade CPU-frekvensen.
Eftersom jag hade använt F_CPU för att beräkna baudrate så blev ju det fel. Så jag skapade en ny symbol F_OSC som jag satte till oscillatorfrekvensen.

Så här ser initiering av UART ut:

Kod: Markera allt

#define F_OSC = 3686400UL
#define BAUDRATE = 38400UL

void uart0_init(void) { // ----- initiera UART0 -----
	#define	BAUD_PRESCALE (F_OSC/(16*BAUDRATE)-1)
	UBRR0L = BAUD_PRESCALE & 0xff; 
	UBRR0H = (BAUD_PRESCALE >> 8);
	UCSR0C = (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes
	UCSR0B = (1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0); // starta usart+recieve interrupt
	sei(); // aktivera global interruptflagga
}
Kollar man i disassembern så blir UBRR0 satt till 0x0005 vilket enligt databladet Table 16-10 ska ge 38.400 baud om U2Xn är 0 och F_OSC = 3.6864 MHz. Ändå kör den i 19.200 baud...

(U2X0 är en flagga i UCSR0A som dubblar UART-hastigheten om den är ettställd. UCSR0A rörs ej, så flaggan behåller sitt initieringsvärde som är 0).

Så nu undrar jag vad jag har glömt eller missat.... för den ska köra med 38400 baud med dessa settings! Och jag vill inte lösa problemet genom att skriva in fel klockfrekvens eller ändra i formlen.
Jag kollade för säkerhets skull på kristallen. Jodå, det står 3.6864.

Kan tillägga att jag använt exakt samma kod för UART i alla mina projekt i ett par år nu, och det har aldrig blivit fel förut.

EDIT: sjutton också! flyttade runt lite kommentarer i koden och kompilerade om. Nu kör den på 9600 baud... helt otroligt. Vad håller den på med? :shock: (UBRR0 är fortfarande 0x0005)

Nu börjar jag undra alltså... delas UART-frekvensen också till 1/4 när man sätter CLKPR så att F_CPU blir F_OSC/4.... ser ju ut så just nu, men det är väl en slump... :cry:
Senast redigerad av jesse 22 mars 2011, 09:56:08, redigerad totalt 1 gång.
Användarvisningsbild
AndLi
Inlägg: 18297
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av AndLi »

Har du ändrat säkringarna för kristall med? Minns inte exakt var brytgränsen går, men hade för mig att det var vid 8MHz.
Kan det bli så att kristallen svänger på någon av övertonerna istället?

Och något helt annat, du säger att du kör på 0.9MHz för att spara ström, har inte avr en ganska linjärt förhållande MHz/mA?
Då borde det väll vara bättre att köra fortast möjligt och gå och lägga sig och sova i djupaste möjliga sovläget så länge som möjligt.

edit: menar du allvar med att dra lite ström kanske du borde titta lite på vad norrmännen har att erbjuda... http://www.energymicro.com/
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av jesse »

Verkar som om man har skrivit fel i databladet....

USART baud-generator:
The USART Baud Rate Register (UBRRn) and the down-counter connected to it function as a
programmable prescaler or baud rate generator. The down-counter, running at system clock
(fosc), is loaded with the UBRRn value each time the counter has counted down to zero or when
the UBRRLn Register is written. A clock is generated each time the counter reaches zero. This
clock is the baud rate generator clock output (= fosc/(UBRRn+1)). The Transmitter divides the
baud rate generator clock output by 2, 8 or 16 depending on mode.

Definition av F_OSC:
fOSC XTAL pin frequency (System Clock).
Det måste ju betyda kristallfrekvensen och inget annat!
F_CPU nämns inte, men:
The ATmega164P/324P/644P has a system clock prescaler, and the system clock can be
divided by setting the ”CLKPR – Clock Prescale Register” on page 40. This feature can be used
to decrease the system clock frequency and the power consumption when the requirement for
processing power is low. This can be used with all clock source options, and it will affect the
clock frequency of the CPU and all synchronous peripherals. clkI/O, clkADC, clkCPU, and clkFLASH
are divided
Helvete vad dom rör ihop det... dom har alltså blandat ihop klockan på XTAL med systemklockan och kallat båda för fOSC. Hur ska man veta vad fOSC betyder när dom inte kan definiera det på ett vettigt sätt? Men baudraten ändrades x4 när jag ändrade CPU-frekvensen genom att återställa "system clock prescaler"... så jag tror jag börjar få grepp på hur det funkar nu (fast det inte funkade så för 20 minuter sedan!)
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av jesse »

Då borde det väll vara bättre att köra fortast möjligt och gå och lägga sig och sova
Njaee... i det här fallet så gör jag lite grejer 12 ggr / sekund. Men det är beroende av externa enheter, så det går inte fortare för att CPU kör fortare. Så jag behöver bara köra CPU tillräckligt fort för att den ska hänga med.
Kan det bli så att kristallen svänger på någon av övertonerna istället?
Jag har programmerat dem rätt och kristallen har hittills fungerat på samma frekvens.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av jesse »

Jag gjorde två fel:

1) förväxlade F_OSC och F_CPU pga dåligt datablad.
2) när jag körde med CPU-frekvens 1/4 av klockfrekvensen så skulle UBRR vara 1.5 vilket avrundades till 1. Därför blev det fel även när jag satte allt annat rätt.

två fel samtidigt kan ju ta lite tid att lösa... men jag tror jag fattar hur det ligger till nu.
snigelen
Inlägg: 815
Blev medlem: 8 maj 2009, 11:02:14
Ort: Lund

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av snigelen »

Det är nog bara ett litet spöke :) Men det är nog bara lite begreppsförvirring med XTAL och F_CPU. Systemklockan (den svänggrej man använder och eventuellt neddelad men prescaler) är ju den som klockar USARTen också.

Men med 0.9216MHz klocka (kalla den vad du vill ;-)) så kan du inte köra 38400 baud, det blir -25% fel med UBRR=1 (och 0.0% och 9600 baud då UBRR=5).

Edit: Efter ditt senaste inlägg har du nog löst det. Snart...
Användarvisningsbild
AndLi
Inlägg: 18297
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av AndLi »

Men om du gör det du ska, sover i väntan på de externa enheterna ska bli klara, hanterar det och sen sover vidare kan du sannolikt spara väldigt mycket ström.
Men det är kanske inte något du har ont om...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av jesse »

Får helt enkelt öka processorhastigheten till 1.8432 MHz , så blir det riktigt.
Som vanligt rörde jag till det i onödan :roll:
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av bearing »

Är det något i processorn som går på den icke nedskalade frekvensen?
Som jag förstått det är det ingen skillnad i koden mellan att använda 8MHz-kristall som skalas 1:8, jämfört med 1MHz-kristall som inte skalas alls.
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av bearing »

jesse skrev:Får helt enkelt öka processorhastigheten till 1.8432 MHz , så blir det riktigt.
Med U2Xn = 1 borde det väl gå att köra 38k4?
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: AVR: F_OSC,F_CPU och BAUDRATE

Inlägg av jesse »

Nej, jag trodde det också, tills jag fick fel baudrate när jag ändrade CPU-prescalern. Då gick jag in och kollade databladet, där jag hittade det vilseledande: "fOSC = XTAL pin frequency (System Clock)."

Vilket gjorde att jag försökte räkna ut baudrate från kristallfrekvensen istället för CPU-frekvensen.

Så "system clock" är alltså inte detsamma som "XTAL pin frequency"!
Gäller förstås även SPI och allt annat. Korkat skrivet i databladet med andra ord.

Bearing > "Med U2Xn = 1 borde det väl gå att köra 38k4?"

japp, men jag blev tveksam till att använda det då det tydligen minskar feltoleranserna. Om det har någon betydelse i praktiken eller inte vet jag inte, men jag vill inte få mer strul på sikt.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: AVR: F_OSC,F_CPU och BAUDRATE [löst - tror jag]

Inlägg av jesse »

Jaha... nu i efterhand råkade jag ut för ännu en ändring i baudrate - utan att ens ha pillat på siffrorna för varken processorfrekvens eller UART. Felet berodde på att jag hade stängt av optimeringen tidigare för att köra en grej i simulatorn. Det var antagligen samma sak som hände tidigare och som gjorde att jag inte fattade något då...

Då gick detta snett:

Kod: Markera allt

	CLKPR = 1 << CLKPCE;	// aktivera frekvensändring
	CLKPR = 0b010;		// dela F_OSC 3.6864 (1/4 = 0.9216 MHz) 
CLKPCE sätts för att kunna ändra övriga bitar i CLKPR.
När CLKPCE satts har man 4 klockcykler på sig att ändra i bitarna.
Utan optimering blir det fler än 4 cykler :doh:

I disassembler utan optimering ser det ut så här:

Kod: Markera allt

	CLKPR = 1 << CLKPCE;	// aktivera frekvensändring
000010F2  LDI R24,0x61		Load immediate 
000010F3  LDI R25,0x00		Load immediate 
000010F4  LDI R18,0x80		Load immediate 
000010F5  MOVW R30,R24		Copy register pair 
000010F6  STD Z+0,R18		Store indirect with displacement 
	CLKPR = 0b010;		// dela F_OSC 3.6864 (1/4 = 0.9216 MHz) 
000010F7  LDI R24,0x61		Load immediate 
000010F8  LDI R25,0x00		Load immediate 
000010F9  LDI R18,0x02		Load immediate 
000010FA  MOVW R30,R24		Copy register pair 
000010FB  STD Z+0,R18		Store indirect with displacement 
Så nu har jag ändra källkoden:

Kod: Markera allt

 	asm volatile(
		"push r16 \n"
		// CLKPR = 1 << CLKPCE;	// aktivera frekvensändring
		"LDI R16,0x80 \n"	//	Load immediate 
		"STS 0x0061,R16 \n"	//	Store direct to data space 
		//	CLKPR = 0b010;	//  dela F_OSC 3.6864 (1/4 = 0.9216 MHz) 
		"LDI R16,0b010 \n"	//	Load immediate 
		"STS 0x0061,R16 \n"	//	Store direct to data space 
		"pop r16"
	);
Skriv svar