Hallo allerseits,
ich bräuchte Hilfe bei einer C funktion.
Folgendes:
Ich muss mit 2Mhz bei 16Mhz F_CLK samplen.
dazu habe ich folgenden C code.
dise generiert folgenden ASM code.
Wie kann ich diesen ASM code umändern und in C oder extern in ASM
einbetten.
Sollte von C aufgerufen werden.
aus dem Mapfile ist ersichtlich, dass captured_data 0x600 ist.
Auch verstehe ich den Code zum incrementieren der Variable nicht ganz,
ist aber irrelevant.
Wie komme ich zum gewünschten Code dass dieser functioniert.
Danke.
C code:
1
void capture_()
2
{
3
byte i,j; word x;
4
x=0; i=0; x=data_size-1;
5
j=data_size - ((data_size / 256) * 256);
6
#if data_size >= 256
7
while(--i)
8
{
9
captured_data[x--] = PINC;
10
}
11
#endif
12
#if data_size >= 256*2
13
for(;--i;)
14
{
15
captured_data[x--] = PINC;
16
}
17
#endif
18
#if data_size >= 256*3
19
while(++i)
20
{
21
captured_data[x--] = PINC;
22
}
23
#endif
24
#if data_size >= 256*4
25
for(;--i;)
26
{
27
captured_data[x--] = PINC;
28
}
29
#endif
30
#if data_size >= 256*5
31
while(i--)
32
{
33
captured_data[x--] = PINC;
34
}
35
#endif
36
#if data_size >= 256*6
37
while(i--)
38
{
39
captured_data[x--] = PINC;
40
}
41
#endif
42
#if data_size - ((data_size / 256) * 256)> 0
43
while(j--)
44
{
45
captured_data[x--] = PINC;
46
}
47
#endif
48
flag|=(captured);
49
}
ASM code:
1
/* frame size = 0 */
2
/* stack size = 0 */
3
.L__stack_usage = 0
4
ldi r30,lo8(captured_data+1536)
5
ldi r31,hi8(captured_data+1536)
6
mov r25,r30
7
com r25
8
.L63:
9
mov r24,r25
10
add r24,r30
11
breq .L73
12
in r24,0x6
13
st -Z,r24
14
rjmp .L63
15
.L73:
16
ldi r30,lo8(captured_data+1281)
17
ldi r31,hi8(captured_data+1281)
18
mov r25,r30
19
com r25
20
.L65:
21
mov r24,r25
22
add r24,r30
23
breq .L74
24
in r24,0x6
25
st -Z,r24
26
rjmp .L65
27
.L74:
28
...
gewünschter Code, r?? ist eine word variable und folgendermassen
definiert
word i = -data_size ; // data_size ist eine preprozessor constante.
Wenn du C-Code hast, warum schreibst du dann nicht alles in C?
Zur Sache: im Netz findest du etliche Tutorials, wie du ASM in C und
umgekehrt einfügen kannst. Das erklärt man nicht nebenbei, sonder sollte
man sich aneignen - sofern man es braucht.
Eben ist das nicht, was man auf die schnelle lernt.
Weiters ist dies eher eine Ausnahme, normalerweise mache ich nichts
mit avr asm. Wieso ich es nicht in C machen kann, weil ich da auf 9
cyclen
komme, und ich nur 8 brauchen darf, ich brauche 2Mhz, und nicht 1.77Mhz
bei
16Mhz OSC.
Ich bin auf sowas gekommen, aber dies geht nicht.
Ich denke, dass 2MSample auch mit 16MHz Clock nicht gehen. Auch wenn's
gehen wuerde, was willst mit so vielen Daten ? Abspeichern ? Verarbeiten
? Das Lesen von 2 Byte dauert 2 Takte, bleiben noch 6...
Auch mit externem ADC. Nimm eine schnellere Maschine, keinen 8 bitter,
sondern vielleicht einen 32 bitter, der mit 40..80MHz laeuft.
@peda, habe ich wirklich falsch recherchiert, laut online doc rechne ich
8 cyclen.
Funktion ist von decompilierten C code und wurde von mir verändert.
.L63:
in r24,0x6 ; 1 cyclen
st -Z,r24 ; 2 cyclen
adiw r27:r26,1 ; 2 cyclen
brcs .L73 ; 1 cyclen bei skip, 2 bei jmp
rjmp .L63 ; 2 cyclen
.L73:
Ja, es genügt mir, wenn ich ca 800uS nach der Triggerung abspeichere und
dann über rs232 in 140ms hochlade.
Hallo,
Peter D. schrieb:> chris schrieb:>> Ich muss mit 2Mhz bei 16Mhz F_CLK samplen.>> Das geht nicht.
naja...
loop:
in r16,PORTB 1 Takt
st Z+,r16 2 Takte
cp ZH,Ende 1 Takt
brne loop 2 Takte bei Rücksprung
sind 6 Takte, bei 16MHz also 2,667MHz Samplerate.
Bei 8 Takten kann mit CP/CPC/BRCC auch auf ein beliebeiges Ende
gestestet werden. Vorbelegungen müssen vorher passieren, wenn er extern
triggern will, muß eben direkt vor dem Loop noch eine Schleife, die nur
auf den Pin testet. Der Samplestart ist dann maximal 3 Takte nach dem
externen Ereignis.
Sind auf einem Mega1284 mit seinen 16k Ram sinnvoll vermutlich 15k
Daten.
Ob es für den gewünschten Zweck sinnvoll ist, muß er wissen.
Wie man es aus C aufruft? Keine Ahnung...
Gruß aus Berlin
Michael
> Das geht nicht.
Wenn es absolut sein muss, geht es noch schneller, indem man die
Schleife ausschreibt (ein ATmega1284 z.B. hat ja 128 KiB flash):
in r16,PINa
sts data+0,r16
in r16,PINa
sts data+1,r16
...
...
Sind 3 Takte pro Byte.
Ist man, z.B. als Assemblerprogrammierer, Herr über Stack &
Stackpointer, geht es mit Vervielfachung eines Macros auch einfacher und
kürzer, wenn auch (natürlich) nicht schneller:
S. Landolt schrieb:> in r16,PINa> sts data+0,r16> in r16,PINa> sts data+1,r16
mit einem Pointer braucht man auch nur 4 Byte/gesampeltes Byte. Nach der
Masche hatte ich tatsächlich mal einen kleinen Logikanalyer gebaut,
finde das Projekt aber nicht mehr. Sah aber ungefähr so aus:
@yalu, die Lösung ist gut, danke für den Hinweis.
Mittlerweile konnte ich es auch mit inline assembling machen,
bekam das mit der Variablenübergabe nicht hin, aber so geht es auch,
auf die harte tour.
Wieso ich warscheinlich selbst nicht draufgekommen bin.
Vorher hatte ich von die Daten von 0 bis data_size raufgezählt.
Bin dann beim optimieren des Assemblercodes dann draufgekommen dass
ein Abspeicher vom Ende zum Beginn eine Instruction spart, hatte da aber
nicht die anfänglichen Tests wiederholt und so hatte ich die saubere
Lösung
übersehen.
Danke nochmals.
S. Landolt schrieb:> Stimmt, Ihre Lösung ist einfacher. Und wir kommen beide auf 3> Takte/Byte.
Gerne auch "du". Auf die Idee mit push bin ich damals aber auch nicht
gekommen. Finde ich auch nicht schlecht. Evtl. kann man aber auch den
Stackpointer in den Registerbereich legen (z.B. auf R14:R15). Dann
könnte man nach wie vor Funktionen und Interrupts nutzen.
avr schrieb:> Dann> könnte man nach wie vor Funktionen und Interrupts nutzen.
Interrupts in einem Programm wo Zyklen von Hand gezählt werden? Das will
man an der Stelle nicht haben.
Und weil eh' ein cli; davor steht kann man auch den Stack Pointer
sichern und vor dem Einschalten der Interupts wiederherstellen.
Jim M. schrieb:> Interrupts in einem Programm wo Zyklen von Hand gezählt werden? Das will> man an der Stelle nicht haben.
Wer sagt denn dass die Interrupts auftreten wenn die kritische Routine
läuft? Natürlich deaktiviert man sie davor. Stackpointer sichern macht
aber ganz bestimmt keinen Sinn, wenn man ihn einfach auf ein paar
CPU-Register legen kann.
Chris S. schrieb:> @peda, habe ich wirklich falsch recherchiert, laut online doc rechne ich> 8 cyclen.
Was ich damit meinte, daß dabei der MC nichts sinnvolles mehr machen
kann.
Typisch haben MCs bei mir immer mehrere Tasks gleichzeitg auszuführen.
Mich würde daher brennend interessieren, wozu braucht man denn so ein
merkwürdiges Programm?
Peter D. schrieb:> Mich würde daher brennend interessieren, wozu braucht man denn so ein> merkwürdiges Programm?
Ich könnte mir vorstellen, dass das eine Art Low Cost Logic Analyser
wird.
Aber ich bin auch mal ehrlich neugierig gespannt, was das werden soll!
Peter D. schrieb:> Was ich damit meinte, daß dabei der MC nichts sinnvolles mehr machen> kann.
Stimmt schon. Aber bei 2MHz und 15k ist der Speicher eh in 7.5msec voll.
Da kann man noch eine Menge anderen Kram abhandeln.
Peter D. schrieb:> Chris S. schrieb:>> @peda, habe ich wirklich falsch recherchiert, laut online doc rechne ich>> 8 cyclen.>> Was ich damit meinte, daß dabei der MC nichts sinnvolles mehr machen> kann.Chris S. schrieb:> Ja, es genügt mir, wenn ich ca 800uS nach der Triggerung abspeichere und> dann über rs232 in 140ms hochlade.
D.h. der Controller ist für weniger als 1ms blockiert. Alles, was keine
Reaktionszeit von weniger als 1ms braucht, kann also problemlos nebenher
erledigt werden.
Gefordert wurde prinzipiell ein i2c tool incl Logic analyzer.
Die hatten mein pickit2 mit LA SW gesehen, als ich das Problem beseitigt
hatte,
und wollen nun auch sowas.
Txtzyme, petit_fat, i2c/rs232/lin/... wobei petit_fat nur für
Datenlogger
von interesse ist.
Da sich das Project als Datenlogger inkl protocol decoder hergibt, will
ich
es in diesem Sinne erweitern.
Da die RLE LA mit max 1Mhz funktioniert, wollte ich die ohne RLE mit max
2Mhz und weil es den anschein hatte dass es gehen müsste.
Ein reines Abspeichern von Port braucht mir zuviel Flash.
Gruß
Chris
@peda
Hallo Peter, da ich deinen Code für i2c benutze, ist mir aufgefallen,
dass clock stretching nur teilweise implementiert wurde, fehlt bei start
und stop, und auch die
Filterung der I2C Leitung fehlt. Ich habe mal was versucht den Code
abzuändern.
was hälst du davon, braucht aber auch etwas mehr Zeit.
1
#define CONCAT__(a,b) a##b
2
#define CONCAT_(a,b) CONCAT__(a,b)
3
#define CONCAT(a,b) CONCAT_(a,b)
4
5
;******----- Adapt these SCA and SCL port and pin definition to your target !!
Chris S. schrieb:> bekam das mit der Variablenübergabe nicht hin
In welchem Kontext denn? Ohne Kontext kann ich das asm nicht
compilieren, und da konkret zu zeigen wie's geht ist dann nicht
drin... Z.B: weil die Variablen nicht deklariert sind etc.
Hier eine sehr frühe Version mit nur der LA Funktionalität welche
compilierbar ist.
Sei es in la8.h sowie in la.c war ich nicht imstande auf das Array
captured_data sowie data_size, was eine konstante hier ist, habe es aber
auch als veriable versucht, im inline ASM zu übergeben.
Die Lösung was ich geschafft habe ist die Register as used temp register
zu deklarieren und die Variable in ASM selbs zu laden, eigentlich
sollten
die variablen aber z.B. als %[data] oder auch mit %0 ansprechbar sein
und irgendwie im
inline assembler übergeben werden, was ich nicht geschafft hatte.
"ldi r30,lo8(captured_data+1536) \n\t"
"ldi r31,hi8(captured_data+1536) \n\t"
"ldi r24,hi8(-data_size) \n\t"
"ldi r25,lo8(-data_size) \n"
"L_loop%=: \n\t"
"in _tmp_reg_,0x6 \n\t"
"st -Z,__tmp_reg__ \n\t"
"adiw r24,1 \n\t"
"brcs L_done%=\n\t"
"rjmp L_loop%=\n"
"L_done%=: \n\t"
::: "r31","r30","r24","r25"