/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Unions, bare så'n lige for at være sikker
Fra : Jesper H


Dato : 29-11-06 16:11

Hej NG

Jeg sidder med en 8bit mikroprocessor, og det siges at når man
compiler noget dertil, er det i Little Endian.
Mikroprocessoren kommunikerer med en anden enhed, som sender i Big
Endian. Den sender en strøm af bytes, som parvist hænger sammen:
XXYYZZAABBCCTT

Jeg vil bare lige høre, om følgende er muligt (beklager mulige
syntaks-fejl):
typedef union {
char input_str[14];
struct{
uint16_t t;
uint16_t c;
uint16_t b;
uint16_t a;
uint16_t z;
uint16_t y;
uint16_t x;
} package_t;

package_t buffer;
int8_t count = 13;
while (count >= 0)
{
buffer.input_str[count] = (input_byte);
count--;
}

Jeg er mest af alt i tvivl om compileren kunne finde på at zero-padde
den ene halvdel af de uint16_t'er, der er defineret i structen, eller
kan den godt fatte at t = input_str[1] << 8 + input_str[0]; ? Jeg ved
godt, at jeg kan bruge bitshifting, osv., men synes bare tidligere jeg
har oplevet, at det tog unødvendigt lang tid på en lille processor...

På forhånd tak for svar

Mvh
Jesper


 
 
Ukendt (29-11-2006)
Kommentar
Fra : Ukendt


Dato : 29-11-06 20:45


>Jeg sidder med en 8bit mikroprocessor, og det siges at når man
>compiler noget dertil, er det i Little Endian.
>Mikroprocessoren kommunikerer med en anden enhed, som sender i Big
>Endian. Den sender en strøm af bytes, som parvist hænger sammen:
>XXYYZZAABBCCTT


Ok, men du fik ikke skrevet hvilket af X'erne der er mest betydende byte.


>Jeg vil bare lige høre, om følgende er muligt
<cut>
> buffer.input_str[count] = (input_byte);
<cut>

Jo det er det da. Men det vil med garanti kun være mulig i den ene ende.
Enten vil protokoldokumentet passe på din processor eller afsenderens
processor.
(Du sagde de var forskellige endianmæssigt)


>Jeg er mest af alt i tvivl om compileren kunne finde på at zero-padde
>den ene halvdel af de uint16_t'er, der er defineret i structen,

jammen dem skriver du jo ikke til ! Så nej, ikke i det soruce du sendte.
Hvis du skriver 0 til en af integer'ne i structet, så vil det vel gå ud over
2 bytes i char arrayet, men det er jo en anden sag.

> men synes bare tidligere jeg
> har oplevet, at det tog unødvendigt lang tid på en lille processor...

Kører du 32khz eller sådan noget ?
Selv en 8 bit mikro kan ved 10Mhz kan altså godt få fyret nogle bitshift af
når det gælder.

Men stop lige op engang. Du er nu ved at finde ud af om nogle
spisfindigheder ved implementationen sætter dig i stand til at spare lidt
hist og pist.
Med mindre det viser sig at være et performance problem, og jeg tvivler, så
synes jeg du skal lave det portabelt, så du uden videre kan kompilere og
bruge det på en anden platform. Og det er med shift og or.



tpt





Jesper H (29-11-2006)
Kommentar
Fra : Jesper H


Dato : 29-11-06 21:37

Hej Troels

Tak for dit svar. Jeg har svaret ned gennem din mail:

Troels Thomsen skrev:
> >Jeg sidder med en 8bit mikroprocessor, og det siges at når man
> >compiler noget dertil, er det i Little Endian.
> >Mikroprocessoren kommunikerer med en anden enhed, som sender i Big
> >Endian. Den sender en strøm af bytes, som parvist hænger sammen:
> >XXYYZZAABBCCTT
>
>
> Ok, men du fik ikke skrevet hvilket af X'erne der er mest betydende byte.

Næh, men jeg læste et sted på nettet, at Big endian i
netværkssammenhæng betød at MSB (Most Significant Byte) blev sendt
først, og at det i hukommelsesmæssig sammenhæng betød, at den fik
den laveste adresse (altså "lå først"). Beklager misforståelsen

>
> >Jeg vil bare lige høre, om følgende er muligt
> <cut>
> > buffer.input_str[count] = (input_byte);
> <cut>
>
> Jo det er det da. Men det vil med garanti kun være mulig i den ene ende.
> Enten vil protokoldokumentet passe på din processor eller afsenderens
> processor.
> (Du sagde de var forskellige endianmæssigt)

Sandt nok. Men datastrømmen kommer fra den anden processor med MSB
først, så LSB for samme uint16_t, så MSB for næste uint16_t og
herefter sammes LSB. Derfor er det, at jeg tæller oppefra og ned, så
det bliver vendt rigtigt til little-endian-maskinen.

> >Jeg er mest af alt i tvivl om compileren kunne finde på at zero-padde
> >den ene halvdel af de uint16_t'er, der er defineret i structen,
>
> jammen dem skriver du jo ikke til ! Så nej, ikke i det soruce du sendte.
> Hvis du skriver 0 til en af integer'ne i structet, så vil det vel gå ud over
> 2 bytes i char arrayet, men det er jo en anden sag.

Hmm, ok, du har indirekte svaret på mit spørgsmål så Kan godt
se min formulering var uheldig. Det jeg mente var, om den første
uint16_t kun hørte til input_str[0] samt noget udefineret, og den
næste uint16_t hørte til input_str[1]. Men kan forstå sådan på
dig, at den første uint16_t har input_str[1] som sin MSB, og
input_str[0] som sin LSB, ligesom jeg også forventede.

> > men synes bare tidligere jeg
> > har oplevet, at det tog unødvendigt lang tid på en lille processor....
>
> Kører du 32khz eller sådan noget ?
> Selv en 8 bit mikro kan ved 10Mhz kan altså godt få fyret nogle bitshift af
> når det gælder.

Jeg kører 16MHz 8 bit mikro, og den har _meget_ travlt, og det er
ekstremt vigtigt at tingene foregår til tiden, og der er ikke
umiddelbart mulighed for at skifte til en hurtigere processor.
Derudover synes jeg til stadighed, at tiden for afvikling af en
interrupt service rutine bør holdes på et absolut minimum, for at
undgå at forsinke andre interrupts og i øvrigt forstyrre
hovedprocessen. Men hvis jeg skal være helt ærlig, er jeg ikke sikker
på hvor mange clock-cycles, den bruger på at lave ...
t = input_str[1] << 8 + input_str[0];
.... kontra hvor mange det tager bare at skrive værdierne direkte i
hukommelsen som jeg forsøger vha. union. Anyone?

> Men stop lige op engang. Du er nu ved at finde ud af om nogle
> spisfindigheder ved implementationen sætter dig i stand til at spare lidt
> hist og pist.
> Med mindre det viser sig at være et performance problem, og jeg tvivler, så
> synes jeg du skal lave det portabelt, så du uden videre kan kompilere og
> bruge det på en anden platform. Og det er med shift og or.

Det lyder også ganske fornuftigt. Men performance er bare meget
vigtigt netop i dette tilfælde, ellers plejer jeg også at bruge shift
og or. Synes bare nogle gange det er besværligt at optimere koden
bagefter, når det viser sig at den skranter (og jo, det har jeg
oplevet, selvom det var ganske fornuftigt kodet).
Ellers mener jeg også, at det med først nævnte metode kan laves, så
det er portabelt (hvis blot man angiver endian), omend det bliver noget
større og måske mere klodset.
>
>
> tpt

Mvh
Jesper


Ukendt (30-11-2006)
Kommentar
Fra : Ukendt


Dato : 30-11-06 20:45

> en anden enhed, som sender i Big Endian.

Ok du skrev sådan set SENDER i big endian, jeg læste det først sådan at den
anden processor tilfældigvis var big endian.

> Derfor er det, at jeg tæller oppefra og ned, så
> det bliver vendt rigtigt til little-endian-maskinen.

Smart nok, hvis det virker, og gør det vel ?

> Men kan forstå sådan på
>dig, at den første uint16_t har input_str[1] som sin MSB, og
> input_str[0] som sin LSB, ligesom jeg også forventede.

I princippet kan du ikke vide, uden at læse compilermanualen, om de padder
hver int med to bytes mere, således at startadresserne for alle integers går
op i 4, men da det er en 8 bit mikro, er det helt usansynligt.

>Jeg kører 16MHz 8 bit mikro, og den har _meget_ travlt,

Ok, af interesse : hvordan det?
Altså man kan have en processor der sådan i middel ikke laver en disse, men
som så har et barsk krav til reaktionstid på et bestemt event, som den så
ikke kan nå på ex 10 us. Er det sådan den har travlt, eller er det virkeligt
set over en større horisont at den har travlt ? Altså processerer data
langsommere end de kommer ind ? eller ?

>Derudover synes jeg til stadighed, at tiden for afvikling af en
>interrupt service rutine bør holdes på et absolut minimum, for at

Men alligevel bygger du protokolparseren ind i interruptfunktionen !
Checker du også crc interrupttime?
Hvis du mener dette alvorligt, så er det eneste du skal gøre interupttime at
smide karakterer ind i en circular buffer, og så lade en funktion du kalder
ofte (f.eks. ude i dit main loop hvis du har et sådant) pille karakterer ud
, parse dem, tage aktion, etc. Det synes jeg fungerer strålende. Du får
selvfølgelig lidt forsinkelse fra sidste byte er puttet i bufferen, til din
main funktion kommer rundt til check funkionen. Men dine funktioner i main
er vel ikke blokerende, så det bliver højst nogle få ms , eller ?

> hvor mange clock-cycles, den bruger på at lave ...
> t = input_str[1] << 8 + input_str[0];

Mikroprocessorer er meget deterministiske. Hvis din compiler kan lave
assembler listings, så kan du meget tit bare sammenligne antal assembler
linier de to eksempler genererer. Hvis du skal have det i ms, skal du lige
studere lidt. Svjh har eksempelvis en Atmel Mega 128 en clock to cycle ratio
på 4 , og alle instruktioner (næsten) er single cycle, så ved 4Mhz kører den
1 mio cycles per sek, dvs 1us per assembler instruktion.

Hvis du kan få vendt bytene i dit struct således at du bare kan losse dem
ind, så er det da svært at modstå fristelsen. Det kan jeg godt se. Især hvis
du har ret i at dette udgør en væstentlig del af performanceproblemet. Der
er altid flere ting der skal kigges på alligevel, når man skifter processor.

Hvilken processor taler vi om?

tpt




Jesper H (01-12-2006)
Kommentar
Fra : Jesper H


Dato : 01-12-06 09:14

Hej Troels:

Troels Thomsen wrote:
> > Derfor er det, at jeg tæller oppefra og ned, så
> > det bliver vendt rigtigt til little-endian-maskinen.
>
> Smart nok, hvis det virker, og gør det vel ?

Det ved jeg ikke, jeg håbede at gruppen kunne svare på det. Ville
gerne teste det selv, men der har lige været nogle andre problemer med
processoren, som gjorde jeg ikke kunne arbejde på den. Rent teoretisk
ville jeg da tro, at det kunne virke.

> > Men kan forstå sådan på
> >dig, at den første uint16_t har input_str[1] som sin MSB, og
> > input_str[0] som sin LSB, ligesom jeg også forventede.
>
> I princippet kan du ikke vide, uden at læse compilermanualen, om de padder
> hver int med to bytes mere, således at startadresserne for alle integers går
> op i 4, men da det er en 8 bit mikro, er det helt usansynligt.

Det ville jeg også tro.

> >Jeg kører 16MHz 8 bit mikro, og den har _meget_ travlt,
>
> Ok, af interesse : hvordan det?
> Altså man kan have en processor der sådan i middel ikke laver en disse, men
> som så har et barsk krav til reaktionstid på et bestemt event, som den så
> ikke kan nå på ex 10 us. Er det sådan den har travlt, eller er det virkeligt
> set over en større horisont at den har travlt ? Altså processerer data
> langsommere end de kommer ind ? eller ?

Kort fortalt: Processoren sidder på et såkaldt robostix-board, og
skal indsamle data fra en mængde sensorer, som virker vidt
forskelligt. Et magnetometer med SPI-interface (vha. bit-banging, da
Atmega'ens egen SPI-port bruges andetsteds), fire Hall-sensorer som
giver en puls ca. 30 gange i sekundet, en IMU der sender pakker 100
gange i sekundet, et R/C-modul skal også samples tidsmæssigt så
præcist som muligt (gøres vha. interrupts på op- og ned-flanker), og
PWM skal styres (hvilket dog foregår automatisk i hardwaren). Udover
det, vil et gumstix-board spørge ca 100 gange i sekundet over I2C
efter nye samples. Til hver eneste af sensorerne er der tilknyttet
noget relativt avanceret monitorering af sensoren, så vi kan finde ud
af, om sensoren er ok, ellers skal det rapporteres videre op i
systemet. Og udover det, skal den kunne beregne noget kontrol, så den
helikopter den er monteret på, ikke styrter ned. Normalt er det
Gumstix'ens opgave at beregne dette, men i nødstilfælde må
robostix'en tage over, ligesom det også er den, der skal assistere en
menneske-pilot, hvis denne vælger at styre helikopteren.
Jeg tror fint på, at det kan lade sig gøre (sagt på en anden måde,
vi har ikke rigtigt noget valg :-> ), øjnede bare lige en mulighed for
optimering, og udvidelse af min egen horisont omkring C.

> >Derudover synes jeg til stadighed, at tiden for afvikling af en
> >interrupt service rutine bør holdes på et absolut minimum, for at
>
> Men alligevel bygger du protokolparseren ind i interruptfunktionen !
> Checker du også crc interrupttime?
> Hvis du mener dette alvorligt, så er det eneste du skal gøre interupttime at
> smide karakterer ind i en circular buffer, og så lade en funktion du kalder
> ofte (f.eks. ude i dit main loop hvis du har et sådant) pille karakterer ud
> , parse dem, tage aktion, etc. Det synes jeg fungerer strålende. Du får
> selvfølgelig lidt forsinkelse fra sidste byte er puttet i bufferen, til din
> main funktion kommer rundt til check funkionen. Men dine funktioner i main
> er vel ikke blokerende, så det bliver højst nogle få ms , eller ?

Der er ingen blokerende kald i main, så det kan fint lade sig gøre.
Mht. til den cirkulære buffer, så er det helt klart også en
mulighed, men jeg kan måske ikke forstå hvordan den skulle kunne
være hurtigere end blot at læse dataene direkte ind i input_str (som
jo også er en streng-buffer).

> > hvor mange clock-cycles, den bruger på at lave ...
> > t = input_str[1] << 8 + input_str[0];
>
> Mikroprocessorer er meget deterministiske. Hvis din compiler kan lave
> assembler listings, så kan du meget tit bare sammenligne antal assembler
> linier de to eksempler genererer. Hvis du skal have det i ms, skal du lige
> studere lidt. Svjh har eksempelvis en Atmel Mega 128 en clock to cycle ratio
> på 4 , og alle instruktioner (næsten) er single cycle, så ved 4Mhz kører den
> 1 mio cycles per sek, dvs 1us per assembler instruktion.

Jeg skal se hvad jeg kan få compileren til. Det er da også muligt, at
compileren helt selv kan finde ud af, at den bare med det samme kan
putte input_str[1] ind i highbyten og input_str[0] ind i lowbyten,
hvordan det så end vender på den enkelte processor - jeg kender ikke
så meget til compilerens indre, men at bitshifte 8 pladser på en 8
bit processor overlader jo ikke meget til fantasien for en rimelig
compiler med bare nogenlunde optimering

AVRfreaks.net har en design note #007, hvor der står: "The AVR
Register file architecture allows handling and switching between Little
and Big Endian without any code overhead" - og de bruger bitshift og or
i et tilhørende eksempel. Så måske det er den rette løsning, hvis
jeg forstår dem rigtigt.

> Hvis du kan få vendt bytene i dit struct således at du bare kan losse dem
> ind, så er det da svært at modstå fristelsen. Det kan jeg godt se. Især hvis
> du har ret i at dette udgør en væstentlig del af performanceproblemet.. Der
> er altid flere ting der skal kigges på alligevel, når man skifter processor.
>
> Hvilken processor taler vi om?

http://gumstix.com/store/catalog/product_info.php?products_id=139

>
> tpt

Takker igen for dit svar, tror efterhånden det ender med bitshift og
or

Mvh
Jesper


Ukendt (03-12-2006)
Kommentar
Fra : Ukendt


Dato : 03-12-06 14:45



>Kort fortalt: Processoren sidder på et såkaldt robostix-board, og
>skal indsamle data fra en mængde sensorer, som virker vidt
>forskelligt.

Ok, der er fut i tingene.
Umiddelbart vil jeg gætte på at din sw spi totalt set stjæler mest tid. Jeg
synes i hvert fald jeg havde problemer med at få min til at køre ret meget
over 15khz uden den gav totalt meget jitter. Men jeg havde også andre
interrupt-syndere ...



> men jeg kan måske ikke forstå hvordan den skulle kunne
> være hurtigere end blot at læse dataene direkte ind i input_str

Protokol håndtering _generelt_ i interrupt rutinen tager tid, eksempelvis
crc check beregninger. Lige præcist at samle disse chars til en int, er nok
ikke noget at tale om.



> men at bitshifte 8 pladser på en 8
>bit processor overlader jo ikke meget til fantasien for en rimelig
>compiler med bare nogenlunde optimering

Ja det glemte jeg at kommentere.
Svjh er det ifølge standarderne garanteret at virke at skifte 8 bits op og
or'e de sidste 8 bytes på. Dette er fordi compileren vil promote
mellemresultatet til 'int' som er mindst 16 bits, uanset om det kører på en
8 bit micro.
Jeg synes dog at det ser pænere ud at caste til en 16 bits type før man
skifter 8 bits op.
At gange med 256 er heller ikke dumt, idet det altid vil være korrekt
matematisk. Jeg ville nok lige dobbelt checke i list filen at compileren
genkender dette og blot genererer assembler kode der flytter bytes rundt.
( Du har IKKE lyst til at kalde et eller andet sygt mul lib fra din
interrupt funktion ) Dette er compileren til Freescale hcs08 god til,
jeg ved ikke med din.

Der findes iøvrigt nogle intrinsic nibble, byte, word swap funktioner du kan
kalde explicit hvis du får brug for det.
Eller, de findes i IAR compileren til Mega128

tpt



Søg
Reklame
Statistik
Spørgsmål : 177577
Tips : 31968
Nyheder : 719565
Indlæg : 6409071
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste