Sida 3 av 3
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 15:00:47
av stekern
Kompilatorutvecklingen går framåt, exemplet där verkar inte stämma längre.
Kod: Markera allt
#include <stdint.h>
uint32_t foo(uint16_t a, uint16_t b)
{
return (uint32_t)a * (uint32_t)b;
}
ger:
Kod: Markera allt
$ avr-gcc -mmcu=atmega48 -O2 -S multest.c -o -
.file "multest.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.global foo
.type foo, @function
foo:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
movw r20,r24
movw r18,r22
rcall __umulhisi3
/* epilogue start */
ret
.size foo, .-foo
Kollar man på libcallet som görs så ser __umulhisi3 ut såhär:
Kod: Markera allt
$ avr-objdump -d /usr/lib/gcc/avr/4.5.3/avr4/libgcc.a
.
.
00000000 <__umulhisi3>:
0: 53 9f mul r21, r19
2: c0 01 movw r24, r0
4: 42 9f mul r20, r18
6: b0 01 movw r22, r0
8: 52 9f mul r21, r18
a: 70 0d add r23, r0
c: 81 1d adc r24, r1
e: 11 24 eor r1, r1
10: 91 1d adc r25, r1
12: 34 9f mul r19, r20
14: 70 0d add r23, r0
16: 81 1d adc r24, r1
18: 11 24 eor r1, r1
1a: 91 1d adc r25, r1
1c: 08 95 ret
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 15:05:48
av stekern
Sorry, jag såg nu att det var signed multiplikation i exemplet, men likvärdigt resultat uppnås
även där med ett rcall till __mulhisi3 istället.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 15:45:40
av bearing
superx skrev:Testade lite med avr-gcc här.
Kod: Markera allt
uint16_t interp1(const uint8_t x, const uint8_t A, const uint8_t B, const uint8_t M)
{
uint8_t AB = A-B;
uint16_t V = B + (AB)*x/M;
return V;
}
Ger 1 multiplikation
Kod: Markera allt
uint16_t interp2(const uint8_t x, const uint8_t A, const uint8_t B, const uint8_t M)
{
uint16_t V = B + (A-B)*x/M;
return V;
}
Ger 3 multiplikationer. Jag antar att det beror på att man i det övre fallet själv tar ansvar för att A-B inte slår runt. Går detta att utläsa av standarden?
EDIT: Ändrade AB från signed till unsigned
Det första exemplet måste ju göra en 8-bit multiplikation, så resultatet blir antagligen fel. Du behöver tala om för kompilatorn att högerledet ska utföras med 16 bitar.
Man måste väl göra 3 mul på en 8-bit processor ifall produkten och faktorerna är 16-bit.
Tror att avr-gcc går utanför standarden för att koden ska bli effektivare på en AVR.
EDIT: glöm detta inlägg. Nu fattar jag. Mul-instruktionen ger ju ett 16-bit resultat, och dina faktorer var 8 bit.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 17:16:04
av stekern
superx skrev:Spännande exempel! Gäller att se upp när man blandar signed och unsigned verkar det som.
Testade lite med avr-gcc här.
Kod: Markera allt
uint16_t interp1(const uint8_t x, const uint8_t A, const uint8_t B, const uint8_t M)
{
uint8_t AB = A-B;
uint16_t V = B + (AB)*x/M;
return V;
}
Ger 1 multiplikation
Kod: Markera allt
uint16_t interp2(const uint8_t x, const uint8_t A, const uint8_t B, const uint8_t M)
{
uint16_t V = B + (A-B)*x/M;
return V;
}
Ger 3 multiplikationer. Jag antar att det beror på att man i det övre fallet själv tar ansvar för att A-B inte slår runt. Går detta att utläsa av standarden?
EDIT: Ändrade AB från signed till unsigned
Förklaringen går mycket riktigt att hitta i standarden, närmare bestämt under kapitel 6.3.1.1 Boolean, characters, and integers paragraf 2:
"The following may be used in an expression wherever an int or unsigned int may
be used:
— An object or expression with an integer type whose integer conversion rank is less
than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions.48) All other types are unchanged by the integer promotions."
Som vi vet är en int 16 bitar i avr-gcc, så för det nedre exemplet ger detta oss att:
uint16_t V = B + ((int16_t)A-(int16_t)B)*x/M;
(int16_t)A-(int16_t)B kommer givetvis även de resultera i en int16_t
För det övre exemplet får vi:
uint16_t V = B + ((int16_t)AB)*x/M;
Men eftersom du talat om för kompilatorn att AB är trunkerat till uint8_t så har du gett den frihet att agera utifrån det.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 17:31:26
av bearing
Kan man lägga till (uint8_t) eller liknande i det nedre exemplet, så att det utförs på samma sätt som det över exemplet?
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 17:52:48
av stekern
Ja, uint16_t V = B + ((uint8_t)(A-B))*x/M; ger ju givetvis samma slutresultat.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 18:40:52
av superx
Heja stekern! det där hade jag inte koll på, men det förklarar ju ett och annat. Tack för att du tar dig tid!
Ja, helt enkelt är det iaf inte att skriva C-kod som kompilerar till det som man tänkt sig alla gånger.
Jag har egentligen mest haft problem av den här typen på plattformar med extra stor ackumulator och MAC-instruktioner (multiply-accumulate), där man gärna vill behålla alla delresultaten i ackumulatorn för att undvika rundningar.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 18:57:56
av Wedge
Whohooo! Den förbättrade algoritmen drog ned tiden från 2,4 ms till 0,9 ms. Verkligen inte illa pinkat!

I båda tiderna ingår lite annat enkel dataskyfflande som måste göras, så om vi gissar att interpolerandet gått från ca 2 till 0,5 ms ... 4 ggr snabbare!
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 19:03:55
av bearing
Är det flera interpoleringar, eller tar funktionsanropet 0,5ms?
Det låter väldigt mycket isf.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 19:10:29
av Wedge
Det är 16 RGB-dioders färg som ska beräknas. 48 interpoleringar totalt. Dvs storleksordningen 10 mikrosekunder per interpolering. Helt OK siffror, tycker jag.
EDIT: 10, inte 100

Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 19:11:23
av stekern
superx skrev:Jag har egentligen mest haft problem av den här typen på plattformar med extra stor ackumulator och MAC-instruktioner (multiply-accumulate), där man gärna vill behålla alla delresultaten i ackumulatorn för att undvika rundningar.
Just DSP operationer har väl traditionellt varit lämnat åt att skrivas i assembler,
så att man får jobba lite extra för att få kompilatorerna att förstå vad man vill där kan jag mycket väl tänka mig.
Det blir säkert bättre på den fronten framöver, det samma gäller även vector instruktioner.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 23:05:01
av superx
Wedge, är M variabel i ditt fall, och i så fall varför? Om den är känd vid kompileringen kan du säkert snabba upp den där uträkningen en del till.
Re: Interpolationsknas på Arduino
Postat: 25 oktober 2012, 23:22:09
av Wedge
M är variabel, ja. Den bestämmer hur lång en övergång från en färg till en annan ska vara. Sen räknar x ned från M till 0, ett steg för varje interrupt.