Ich möchte ein Logikanalysator bauen. Die Routine zum abfragen der Ports
möchte ich in Assembler als eine eigene Datei programmieren. Wie komme
ich in C an die 100 Byte Variablen? Wie in C auf Prog zugreifen?
Anlegen in Assembler mit: tab: .Byte 100
Aufruf und Zugriff in C ?
otto schrieb:
> Die Manual-libc ist bestandteil von winavr,bin aber nicht klar gekommen.
Womit denn genau nicht?
Gerade bei IO-Ports bringt das Ausweichen auf Assembler übrigens
nicht viel. Das lohnt eher bei esoterischen Operationen, die von
C schlecht abgedeckt werden, wie vielleicht einer Multiplikation
zweier 8-bit-Zahlen zu einem 16-bit-Ergebnis (C würde beide zuvor
auf 16 bits ausdehnen und dann multiplizieren).
Also ich möchte eine hohe Abtastrate erzielen.
1 Takt zum lesen vom Port | 2 Takte zum speichern im Sram | 1 Takt für
Sprung wenn nicht gleich (breq) macht 4 Takte pro Lauf. Bei 20 MHz
gleich 5 Mhz also 200 n/s Abtastrate. Für C habe ich keine
Berechnungsgrundlage.Hast Du so etwas? Wie schnell wäre ich, wenn ich
alles in C schreibe mit Zeiger auf Puffer dann erhöhen,speichern und
vergeilechen.
Ich find in der Manual-libc nicht die Übergabe, sowie Aufruf,habe mich
schon doof geklickt. Ist es viel Text mir mitzuteilen wie es geht?
Hans Otto schrieb:
> 1 Takt zum lesen vom Port | 2 Takte zum speichern im Sram | 1 Takt für> Sprung wenn nicht gleich (breq) macht 4 Takte pro Lauf.
Und worauf genau soll sich dann das "wenn nicht gleich" beziehen?
Ja ich habe auf die schnelle ein Fehler gemacht.
;Bei 20 MHz Systemtakt und 100 Werte im SRAM
tab: .BYTE 100
;
ldi ZL,LOW(tab)
ldi ZH,HIGH(tab)
ldi r16,100
lab1: in r17,PIND
st Z+,r17
dec r16
brne lab1
5 Takte pro Lauf also 250 ns, und wie schnell ist der C Compiler?
Hallo,
ich will Dir nicht den Spaß verderben, aber 100 Werte nutzen praktisch
nichts. Für ein halbwegs nutzbares Ergebnis brauchst Du mindest 4,
besser 8-10 Takte für ein zu sampelndes Ereignis.
Bei 1k Speicher wären also z.B. bei serieller Übertragung ca. 100 Bit
halbwegs auswertbar. Das bedingt aber eine Triggerlogik, die den
Zeitpunkt dazu auch erkennt.
8 Kanäle mit Pre-/Posttrigger-Sample und Auswertung der Triggerdaten
habe ich bis 1MHz Samplerate bei 16MHz Takt für einen Mega16 hier,
Auswertung auf dem PC mit der Software von LoLa, Samplebuffer 1,75kB.
Ist allerdings komplett in ASM.
Ansonsten
http://www.avr.roehres-home.de/logikanalyzer/index.html
falls es Dich interessiert.
Gruß aus Berlin
Michael
>Ich find in der Manual-libc nicht die Übergabe, sowie Aufruf,habe mich>schon doof geklickt. Ist es viel Text mir mitzuteilen wie es geht?
Definition im Assembler-File:
>* .global (or .globl) declares a public symbol that is visible to the linker >(e.g. function entry point, global variable)
also:
*.s
1
.global tab
2
tab: .BYTE 100
*.c
1
externunsignedchartab[100];
oder umgekehrt, definition im C-File:
>* .extern declares a symbol to be externally defined; this is effectively a >comment only, as gas treats all undefined symbols it encounters as globally >undefined anyway
*.c
So etwas tolles habe ich noch nicht gesehen, aber für mich zuviel
Aufwand.Ich möchte nur die Zeiten zwischen 8 Signalen beweisen, bzw.
Prellen aufspüren.Ein Beispiel wäre ein LCD Display das die Signale zum
richtigen Zeitpunt bekommt.usw. Aber Deine Sache ist Markt reif. Super
Aufmachung tolle Software.Ich muß Zugegeben das hier nur Pegel abgefragt
werden und vom analysieren weit weg ist.
Jörg G. schrieb:
> Auftritt: die Hassliebe der (Gcc-) C-Programmierer, der *inline-Asm*> Ich bin mir aber nicht 100% sicher, dass z.B. "st z+, r" so korrekt> übersetzt wird (und ich hab keine Lust zum testen/simulieren).
Da fehlt glaub ein a, sonst gibt das r30+ oder so anstatt z+.
Oliver schrieb:
> Definition im Assembler-File:>>* .global (or .globl) declares a public symbol that is visible to the linker>>(e.g. function entry point, global variable)>> also:> *.s>
1
> .global tab
2
> tab: .BYTE 100
3
>
>> *.c>
1
>externunsignedchartab[100];
2
>
Nicht eher so?
1
.data
2
.global tab
3
tab: .skip 100
Ansonsten ist tab nur ein Byte, das zu 100 initialisiert ist...
Johann
Wenn ich das jetzt alles richtig gelesen habe muss ich wie folgt
eintragen.
*s
.global tab
*.c
extern unsigned char tab[100];
ptr = &tab;
ist der Aufruf der Assembler Datei richtig?
extern void prog(void);
Hans Otto schrieb:
> ptr = &tab;
Wofür denn das?
Aber s. o., du schlägst den Compiler ohnehin nur minimal mit so'nem
primitiven Beispiel:
foo.c:
1
#include<avr/io.h>
2
3
uint8_ttab[100];
4
5
void
6
fill_buf(void)
7
{
8
uint8_ti;
9
uint8_t*p;
10
11
for(i=100,p=tab;i!=0;i--)
12
*p++=PIND;
13
}
Generierter Assemblercode:
1
.global fill_buf
2
.type fill_buf, @function
3
fill_buf:
4
/* prologue: function */
5
/* frame size = 0 */
6
ldi r30,lo8(tab)
7
ldi r31,hi8(tab)
8
.L2:
9
in r24,41-32
10
st Z+,r24
11
ldi r24,hi8(tab+100)
12
cpi r30,lo8(tab+100)
13
cpc r31,r24
14
brne .L2
15
/* epilogue start */
16
ret
17
.size fill_buf, .-fill_buf
18
.comm tab,100,1
Damit siehst du dann auch gleich die notwendige Syntax für den
Assemblercode...
Dass du ihn überhaupt schlägst, dürfte an den teilweise für den AVR
nicht mehr so guten ,,besonders schlauen'' Optimierungen liegen, die
GCC 4.3 offensichtlich vorrangig für unsere Desktop-Maschinen mit
ihren registermäßig verkrüppelten Prozessoren vornimmt: um die
Variable i nicht in einem Register führen zu müssen, wird der
Vergleich lieber auf die letzte zu beschreibende Adresse implementiert.
Ältere GCC-Versionen verhalten sich da sehr wahrscheinlich noch
besser (beim AVR).
Wenn es um Geschwindigkeit geht, fällt vor allem auf, daß rund 50% der
Zeit in der Schlaufe vertrödelt werden.
Wir schreiben also folgendes C-Programm:
1
#include<stdint.h>
2
3
externvoidscan(uint8_t*);
4
5
uint8_tscan_buf[SCAN_SIZE];
6
7
intmain()
8
{
9
scan(scan_buf);
10
return0;
11
}
Die Funcktion scan() ist in Assembler implementiert. Sie expandiert ein
Makro, das SCAN_SIZE mal den Port liest und den Wert speichert: