Sida 2 av 13
Re: lite undringar om AVR progrannering i C
Postat: 20 oktober 2009, 17:09:58
av Johanb
Ok, två orelaterade tips, kolla skillnaden mellan PINx och PORTx och läs på om volatile

Har drivit mig till vansinne några gånger

Re: lite undringar om AVR progrannering i C
Postat: 20 oktober 2009, 19:57:35
av jesse
Jo, jag har ju prorgammerat ganska mycket i assembler innan och skillnaden mellan PINx och PORTx drev mig till vansinne i början.
Jag körde t.ex.
vad som hände var att om några av bitarna var input med pull-up och ingången var låg just då så lästes en nolla in (genom PINB) för att sedan skickas ut med PORTB vilket resulterade i att jag avaktiverade pull-up motståndet och ingången blev flytande vilket gav upphov till oväntade fenomen. Det var svårt att felsöka detta! Rätt kod är naturligtvis:
Då läser jag in värdet i den latch som finns i porten, inte portens ingångar.
Volatile: har försökt läsa lite om det men har nog inte fattat vidden av dess betydelse, och framför allt när det bör användas? Men det kanske kommer så småningom. Det innebär väl helt enkelt att variabeln får en fast adress i minnet och är alltid uppdaterad där, så du kan läsa av det rätta värdet där?
Re: lite undringar om AVR progrannering i C
Postat: 20 oktober 2009, 21:13:18
av henkebenke
Nja, volatile innebär att kompilatorn inte får optimera variabeln då den kan ändras på ett för kompilatorn oförutsägbart sätt, tex ett register för en periferienhet eller en variabel som ändras i ett interrupt.
Re: lite undringar om AVR progrannering i C
Postat: 21 oktober 2009, 00:01:24
av speakman
MicaelKarlsson skrev:Jag brukar för enkelhets skull skriva så här:
Varför inte:
Kod: Markera allt
#define RELAY_1_PORT PORTC
#define RELAY_1_PIN 1
...
bit_set(RELAY_1_PORT, RELAY_1_PIN);
...
Skulle ge betydligt högre C-poäng imo.
Fast personligen hade jag nog skrivit en funktion som gör samma sak och definerat den med inline.
Re: lite undringar om AVR progrannering i C
Postat: 21 oktober 2009, 00:24:49
av sodjan
> När jag ändå är igång och frågar ... kan man göra bitvis operationer i C på enstaka bitar som motsvarar
> t.ex. sbr r0,bit eller sbi port,bit och cbi port,bit... lite onödigt att gå omvägen att ladda ner och göra
> or / and för att sedan spara igen, t.ex.
Du kan göra direkt bitoperationer på register/adresser som ligger inom "räckhåll" för bit-instruktionerna.
Och det har igentligen ingenting med C att göra, även om kompilatorn skulle kunna anpassa koden
beroende på var registret ligger. Det blir alltså olika assembler/maskin kod från fall till fall. Har
ingen aning om hur det är med det, men kolla assembler listningen från kompilatorn.
Om det nu var det du undrade över, det var inte helt tydligt...
Re: lite undringar om AVR progrannering i C
Postat: 21 oktober 2009, 13:01:44
av MicaelKarlsson
speakman skrev:
Skulle ge betydligt högre C-poäng imo.
Kan så vara men det fungerar och det är det jag vill uppnå. Men smaken är ju som det vi sitter på!!

Re: lite undringar om AVR progrannering i C
Postat: 21 oktober 2009, 22:30:43
av jesse
Sodjan: det jag undrade var väl hur man skriver koden i C för att vara säker på att den blir optimerad. Jag har haft en föreställning (fördom) om högnivåspråk att de sällan arbetar med några som helst operationer under 16-bitars bredd (t.ex.
boolean är inte en bits variabel utan en int - dvs antagligen 32 bitar, varav 31 inte används!) och jag trodde att man skulle behöva skriva på något särskilt sätt för att koden skulle optimeras, men det verkar ju funka väldigt bra med "vanlig" C-kod.
Jag har testat lite och här ett exempel på vad jag får ut:
o-optimerad kompilering ( -O0 ) :
Kod: Markera allt
PORTB|=(1<<2);
10c: a5 e2 ldi r26, 0x25 ; 37
10e: b0 e0 ldi r27, 0x00 ; 0
110: e5 e2 ldi r30, 0x25 ; 37
112: f0 e0 ldi r31, 0x00 ; 0
114: 80 81 ld r24, Z
116: 84 60 ori r24, 0x04 ; 4
118: 8c 93 st X, r24
(det var ungefär så jag befarade att det alltid skulle se ut!)
När jag sen kör optimering ( - Os ) så blir det mycket bättre...
Kod: Markera allt
PORTB|=(1<<2);
d0: 2a 9a sbi 0x05, 2 ; 5
d2: 80 e0 ldi r24, 0x00 ; 0
d4: 90 e0 ldi r25, 0x00 ; 0
och detta är ju så bra det kan bli:
Kod: Markera allt
void UART_send( unsigned char data ){
while ( !( UCSR0A & (1<<UDRE0)) );
f0: 80 91 c0 00 lds r24, 0x00C0
f4: 85 ff sbrs r24, 5
f6: fc cf rjmp .-8 ; 0xf0 <main+0x3c>
UDR0 = data;
f8: 50 93 c6 00 sts 0x00C6, r21
så jag är mycket nöjd med kompilatorn.
Men vad jag har sett (minns inte var nu) så har folk gjort nån slags
struct som verkar innehålla 8 st bitvärden och skulle då rymmas i en byte, men det kanske inte optimerar någonting, bara ett sätt att krångla till (eller förenkla) koden?
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 00:49:32
av speakman
Det beror väl på *hur* man vill att den optimerar. En 32-bitars MCU jobbar ju betydligt snabbare med 32-bitars värden oavsett om den bara används till en flagga. Gör man som du, optimerar med -Os, så har man ju begärt att det är koden som ska bli liten, och hastigheten får komma i andra hand.
De flesta större C-kompilatorer optimerar nog så pass effektivt att jag nog kan påstå att det är marginellt mer man kan åstadkomma den manuella vägen.
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 08:51:48
av jesse
Ofta vill man ju optimera en viss rutin för hastighet och resten för att minska koden. Annars går det väl ofta hand i hand - färre instruktioner tar ofta kort tid att utföra än många instruktioner.
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 08:58:07
av sodjan
Nja, det är ofta tvärtom. Kod som expanders till sekvensiell kod istället
för loopar eller subrutiner är oftast snabbare. Det är en av de vanligaste
metoderna att snabba upp kod. Men om du menar färre instruktioner därför
att man plockar bort *onödiga* instruktioner så har du ju rätt...
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 13:36:25
av speakman
jessa: Jag var lite otydlig, men det jag menar är att optimera för minimal minnesanvändning ofta innebär bitmaskning för flaggor, vilket oftast är mer kostsamt i antal instruktioner än att använda hela ord. Även om vissa arkitekturer har instruktioner för att hantera den biten så innebär dessa instruktioner inte sällan ett större antal klockcyklar istället. Därför föredrar C-kompilatorer oftast att köra med hela ord.
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 13:56:16
av Icecap
Som Speakman skriver: bits som flaggor sparar RAM-minne men kostar programminnne istället.
Jag har testat just skillnaden på att ha en flagga som bit eller byte och skillnaden var åtskilliga bytes program, har för mig att det var 16 bytes eller rättare 8 programwords eftersom det var en 16-bit processor.
Jag testade även skillnaden på:
A = B && true; // Kolla om B är 0 eller icke-noll
och
if(B) A = true;
else A = false;
och det siste sparade många bytes kod.
(A och B är bytes i detta fall)
Efter det har jag skippat bit-flaggor om inte extrema minnesproblem finns.
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 18:15:29
av jesse
minimal minnesanvändning ofta innebär bitmaskning för flaggor
Det var ju intressant.. jag använder ju dels några få flaggor som signaler från interrupt (nedräknande klocka, eller uart t.ex.), men jag kommer också att ha behov av ca 1536 flaggor som speglar olika tillstånd i omgivningen (larm, spänningsnivåer, utgångar mm) som ska grupperas i 8 x 192 stycken. I det fallet kommer jag att köra bitvis , annars har jag inget minne kvar alls!
Icecap: det var ju också tänkvärt, tack för inlägget.
Nu till dagens grubbel:
sitter med ett terminalprogram och snackar med min atmega324P. funkar precis som jag tänkt när den är o-optimerad. Men när jag kör -Os så fattar den ingenting... (har inte lyckats hitta var det klickar - simulatorn fungerar ju inte så bra heller på optimerad kod). Men
jag har inte skrivit någonting som är tidskristiskt eller på annat vis borde vara påverkat av optimeringen - det är ren logik! Lik förbannat ändrar den beteende helt...

Simulatorn beter sig precis som hårdvaran - den gör också precis samma "fel" som processorn när koden är optimerad
Jag brukar kompilera helt o-optimerat för att jag ska kunna följa koden i simulatorn - men då kunde jag inte ändra CPU-klockans frekvens. Ändringen av frekvens kräver nämligen att jag skriver till ett register två gånger inom loppet av 4 klockpulser. Och det tog 5 klockpulser att skriva till ett register när koden inte var optimerad...
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 18:27:36
av Icecap
För att skriva dessa 2gg inom mycket få CPU-klockor använder du ASM, ett typisk ställe där man gör så för att optimera i alla lägen.
Och om programmet blir oanvändbart vid att optimeras är det ett fel någonstans.
Re: lite undringar om AVR progrannering i C
Postat: 22 oktober 2009, 18:35:06
av jesse
jo, jag gjorde det :
Kod: Markera allt
MCUCR = 0x80; // avaktivera JTAG
asm volatile("ldi r24,0x80;");// två gånger
asm volatile("out 0x35, r24;"); // MCUCR = 0x80;
men man vill ju
kunna optimera koden, även om det är gott om utrymme än så länge...