Hallo,
erstmals möchte ich nun 2 UART's mit einem ATmega2560 nutzen. Für den
UART0 habe ich mir sämtlich Ausgabe Funktionen bereits geschrieben und
möchte nun UART1 (später vlt. auch noch 2 und 3) mit diesen Funktionen
nutzen.
Im Kern münden alle Ausgaben von UART0 in dieser Funktion:
1
voiduart0_char(charchrtx)
2
{
3
uart0_buf_tx[pin]=chrtx;
4
pin++;
5
pin=pin&(UART0_TX_BUFFER_SIZE-1);
6
7
SET_BIT(UCSR0B,UDRIE0);
8
}
Die die nun diese Funktion aufrufen, sehen so aus (um eine
stellvertreten zu zeigen)...
1
voiduart0_str(char*buftx)
2
{
3
while(*buftx)uart0_char(*buftx++);
4
}
Jetzt wird man ja wohl kaum ALLE 4x schreiben um damit sinnlos den
Speicher voll zu machen sondern es wird sicher einen Weg geben, wie man
die Ausgabefunktion so umbauen kann, dass die universell nutzbar für
UART0, UART1, UART2 und UART3 wird.
Wie stellt man das nun an?
Baut man sich einen "switch/case" Block mit ein oder wie macht ihr das?
Grüße AVRli...
Hui, das kann aber knallen bei (extrem) hoher Interrupt Last.
Das sollte besser so aussehen:
1
unsignedchartemp=pin;
2
uart0_buf_tx[temp]=chrtx;
3
temp++;
4
pin=temp&(UART0_TX_BUFFER_SIZE-1);
Dann wird nämlich pin nicht mal kurz auf einen ungültigen Wert gesetzt.
AVRli .. schrieb:> Wie stellt man das nun an?
Man legt eine Struktur an, die sowohl den UART als auch die nötigen
Puffer enthält.
Ungefähr so:
1
voiduart0_char(uart_buffer_t*uartbuf,charchrtx)
2
{
3
unsignedchartemp=uartbuf->pin;
4
uartbuf->uart0_buf_tx[temp]=chrtx;
5
temp++;
6
uartbuf->pin=temp&(UART0_TX_BUFFER_SIZE-1);
7
SET_BIT(uartbuf->uart->UCSR0B,UDRIE0);
8
}
Oft hat sich der Hersteller dafür schon was überlegt, denn er muss ja
Beispielcode liefern.
Habe vergessen zu erwähnen: Bei 4 schnellen UARTs will man DMA nutzen,
und müsste dann einiges umbauen. Dann hat man eventuell doch den Code
viermal - weil er jedesmal was anderes tut.
Ich verstehe, worauf du hinaus willst.
a) Man kann sich Strukturen anlegen, die Zeiger auf die Register des
jeweiligen UART enthalten, sowie ggf. die Puffer. Dann übergibst du der
Funktion uart_str() als ersten Parameter die Adresse dieser Struktur.
Dieses Konstrukt bringt aber auch einen gewissen Overhead mit sich. Ganz
ehrlich: Ich würde ernsthaft überlegen, die paar Zeilen Code doch
einfach zu kopieren.
b) Du baust in deine Funktionen switch/case Konstrukte ein, die abhängig
von der UART-Nummer auf unterschiedliche Register zugreifen. Etwa so:
1
voiduart_char(uint8_5uartNr,charchrtx)
2
{
3
switch(uartNr)
4
{
5
case0:
6
uart0_buf_tx[pin]=chrtx;
7
pin++;
8
pin=pin&(UART0_TX_BUFFER_SIZE-1);
9
SET_BIT(UCSR0B,UDRIE0);
10
break;
11
case1:
12
...
13
case2:
14
...
15
case3:
16
...
17
}
18
}
Ist aber letztendlich auch nicht viel schöner, als code zu kopieren.
AVRli .. schrieb:> Jetzt wird man ja wohl kaum ALLE 4x schreiben um damit sinnlos den> Speicher voll zu machen
Flash ist meistens nicht das Problem, daher ist es schon sinnvoll, den
Code zu kopieren. Ansonsten müßte man wertvollen SRAM opfern, um für
jedes 8Bit-Register einen 16Bit-Pointer anzulegen. Und die Funktionen
müßten dann auch erst ein Pointerregister (X,Y,Z) laden (+Push/Pop
Overhead), anstatt direkt auf das IO-Register zuzugreifen. D.h. die
Laufzeit wird größer und Flash wird auch kaum gespart.
Nehme immer XMEGA, weiß nicht ob das mit mega auch geht:
#include <avr/io.h>
ini_usart(USART_t *myusart)
{
myusart->CTRLA=0;
...
}
int main(void)
{
ini_usart(&USARTC0);
while (1)
{
}
}
Bei Xmega Controllern hast du den Vorteil, dass die Register von allen
gleichartigen Funktionseinheiten gleich aufgebaut sind und in der selben
Reihenfolge angeordnet sind.
Dort kann man die Register selbst als Struct anlegen (was die avr-libc
auch tut) und braucht der Funktion nur einen Zeiger auf das erste
Register zu übergeben.
Leider ist es bei ATmegas nichtso einfach, dort sind die Register
"Hysterisch" gewachsen, wie ein Ex-Chef von mir zu sagen pflegte.
Hi
>Leider ist es bei ATmegas nichtso einfach, dort sind die Register>"Hysterisch" gewachsen, wie ein Ex-Chef von mir zu sagen pflegte.
Bei allen neueren ATMegas ist da nichts 'hysterisches'. Da sind die
USART-Register recht einheitlich angeordnet.
MfG Spess
Es ist zwar nicht explizit im Post des TO zu erkennen, doch bei solchen
Fragen kann es eigentlich nur um C gehen. Trotzdem der Hinweis: in C++
löst man das mit templates.
AVRli .. schrieb:> Jetzt wird man ja wohl kaum ALLE 4x schreiben um damit sinnlos den> Speicher voll zu machen
Die paar Bytes für viermal die UART-Routinen machen das Kraut
nun wirklich nicht fett. Aber dafür effizient schnell. Ich
verstehe nicht wie man so verblendet auf diese Art von Erspar-
nis aus ist wo man doch wie die Made im Speck leben kann.
Du hast im ATMega256 genug (Code-) Speicher dafür. Was viel
mehr (RAM-) Speicher kostet sind die Buffer die du sowieso
viermal anlegen musst.
Danke für alle Anregungen!
Es scheint also keine generelle, einfache Lösung möglich zu sein.
Da mein Programm aber wie an einem Faden abläuft und ich der Reihe nach
die UART's aus dem MAIN bedienen werde, finde ich den Weg mit der Ziel
UART Variablen gar nicht so schlecht. Da muss ich dann jeder Routine...
1
voiduart0_char(charchrtx);
2
voiduart0_sp(void);
3
voiduart0_cr(void);
4
voiduart0_crlf(void);
5
voiduart0_0x(void);
6
voiduart0_buf(char*buftx,uint16_tcnt);
7
voiduart0_str(char*buftx);
8
voiduart0_str_P(PGM_Pstr);
9
voiduart0_str_P_FAR(uint_farptr_tstr);
10
voiduart0_byte_P(PGM_PbyteOut);
11
voiduart0_byte_in_hex_P(PGM_PbyteOut);
12
13
voiduart0_uint8(uint8_tvalue,uint8_twidth);
14
voiduart0_int8(int8_tvalue,uint8_twidth);
15
voiduart0_uint8_bin(uint8_tvalue,uint8_twidth);
16
voiduart0_uint8_hex(uint8_tvalue,uint8_twidth);
17
voiduart0_uint16(uint16_tvalue,uint8_twidth);
18
voiduart0_int16(int16_tvalue,uint8_twidth);
19
voiduart0_uint16_bin(uint16_tvalue,uint8_twidth);
20
voiduart0_uint16_hex(uint16_tvalue,uint8_twidth);
21
voiduart0_uint32(uint32_tvalue,uint8_twidth);
22
voiduart0_int32(int32_tvalue,uint8_twidth);
... "nur" um eine 8 Bit Variable erweitern und diese bis zur Übergabe in
den eigentlichen Buffer mitgeben. Beim übergeben in den eigentlichen
Sendebuffer darüber entscheiden, in welchen es letztendlich geht?
Alternativ eine global sichtbare Variable mit der man vor dem
Einschreiben "umschaltet"?
Ich möchte das einmal sinnvoll und so Ressourcensparend wie möglich
umbauen.
Gruß AVRli...
__IOuint32_tISR;/*!< USART Interrupt and status register, Address offset: 0x1C */
11
__IOuint32_tICR;/*!< USART Interrupt flag Clear register, Address offset: 0x20 */
12
__IOuint16_tRDR;/*!< USART Receive Data register, Address offset: 0x24 */
13
uint16_tRESERVED1;/*!< Reserved, 0x26 */
14
__IOuint16_tTDR;/*!< USART Transmit Data register, Address offset: 0x28 */
15
uint16_tRESERVED2;/*!< Reserved, 0x2A */
16
}USART_TypeDef;
Damit kann man beliebig viele UARTs mit dem selben Code ansprechen, da
sich nur der Pointer für den jeweiligen UART ändert.
Geht natürlich auch mit allen anderen Schnittstellen genauso.
AVRli .. schrieb:> Ich möchte das einmal sinnvoll und so Ressourcensparend wie möglich> umbauen.
Ja .... lieber sinnlos zu Tode gespart als das Ziel schnell
erreicht. Ach so ... das Ziel ist auf dem ATMega256 so wenig
wie möglich Platz zu brauchen? Na dann ....
Man hat ja sonst nix zu tun. Beschäftigungstherapie damit man
weg von der Strasse ist. Luxusproblem.
> ... "nur" um eine 8 Bit Variable erweitern und diese bis zur Übergabe> in den eigentlichen Buffer mitgeben.
Ich würde diese Funktionen ja nur einmal schreiben und als ersten
Parameter einen Zeiger auf den Buffer übergeben. Der Buffer wäre dann
eine Struktur mit Byte-Array sowie Zeiger auf Anfang und Ende.
Mitlesa:
> Die paar Bytes für viermal die UART-Routinen machen das Kraut> nun wirklich nicht fett.
Du mußt dann aber auch jede Änderung 4x machen, hast Du dann noch viele
andere Hardware-Einheiten in der "Mache" wird's schnell fitzig.
Lama:
> Nur um mal die AVR-Leute ein wenig zu ärgern...
xmega ist auch avr, siehe oben, nur mal die STM-Leute ein wenig zu
ärgern (habe selbst mal STM probiert), schon mal das ATMEL-Studio
angesehen?
J Zimmermann schrieb:> Du mußt dann aber auch jede Änderung 4x machen, hast Du dann noch viele> andere Hardware-Einheiten in der "Mache" wird's schnell fitzig.
Ja schon klar. Die UART-Programmiererei ist ja soooo kompliziert
da muss man schon aufpassen, die Entwicklung kann sich über
Jahre hinweg erstrecken.
AVRli .. schrieb:> void uart0_char(char chrtx);> void uart0_sp(void);> usw.
Du brauchst je UART nur die 4 Grundfunktionen:
uart_x_init();
uart_x_get_status();
uart_x_putchar();
uart_x_getchar();
Und die 8 Interrupthandler für die FIFO-Buffer.
Die ganzen Formatierungsfunktionen schreibt man natürlich nur einmal, da
sie ja nicht mehr auf UART-Register zugreifen, sondern auf Variablen
oder Arrays.
Peter D. schrieb:> AVRli .. schrieb:>> void uart0_char(char chrtx);>> void uart0_sp(void);>> usw.>> Du brauchst je UART nur die 4 Grundfunktionen:> uart_x_init();> uart_x_get_status();> uart_x_putchar();> uart_x_getchar();> Und die 8 Interrupthandler für die FIFO-Buffer.
Oh je! X x copy-n-paste!
Ist das nicht Grund genug, sich mal mit C++/templates auseinander zu
setzen?
J Zimmermann schrieb:> xmega ist auch avr
Ja, ist mir bekannt. Daher auch mein Einleitungssatz. Aber speziell für
die Leute, die vor AVR-Liebe schon beinahe Blind durch die Gegend
laufen: xmega = avr = "für die Leistung überteuert und altmodisch, wird
aber am Leben erhalten für die Leute die sonst nichts anderes
programmieren können".
Hat man ja mit der 8051 auch so gemacht.
:-)
J Zimmermann schrieb:> nur mal die STM-Leute ein wenig zu> ärgern
Wird für einen AVR-Menschen sehr schwer fallen :-)
J Zimmermann schrieb:> schon mal das ATMEL-Studio> angesehen?
Nicht nur angesehen, sondern früher jahrelang damit arbeiten müssen.
G-R-A-U-S-A-M. (DebugWire ist ja wohl in dem Zusammenhang auch der Witz
des Jahrhunderts, das hat Atmel selbst mit der EIGENEN IDE jahrelang
nicht sauber ans Laufen bekommen. Toll das z.B. der 328P nur den als
"Debug-Schnittstelle" hat)
Schon mal aus dem Profi-Bereich was probiert? Keil z.B. ist für die
kleinen STM32F0 kostenlos. Dass du auch mal was anderes gesehen hast als
den heißgeliebten ATMEL-Studio. Sowas soll den eigenen Horizont
erweitern habe ich mal gehört.
@AVRli
Du bist meiner Meinung nach bei den Grenzen des Copy & Past angekommen.
Jetzt ist ein sinnvoller Zeitpunkt gekommen, Dich mal mit dem Prozessor
zu beschäftigen.
Soweit mir bekannt, haben diese Prozessoren, für jeden UART, einen
eigenen Registersatz. Dieser spiegelt dann auch den aktuellen Status.
Ist z.B. der Sendepuffer von UART1 leer, so wird ein Flag gesetzt. So
weit, so gut. Bist Du aber jetzt neugierig, wie es um UART2 steht, so
musst Du ein anderes Flag abfragen. Dieses hat entweder eine andere
Bitposition, im gleichen Register oder eine komplett andere Adresse.
Die Abfrage: Puffer leer ist also unsinnig.
Entweder Du verpackst das Ganze in eine Klasse oder Du verwendest
passende Parameter für die jeweiligen Ports.
Wilhelm M. schrieb:> Oh je! X x copy-n-paste!
Naja, man könnte ein Include-File schreiben und 4-mal includieren:
1
#define UART_NO 0
2
#include<uart_x.inc>
3
#undef UART_NO
Wilhelm M. schrieb:> Ist das nicht Grund genug, sich mal mit C++/templates auseinander zu> setzen?
Wenn ich "templates" lese, kriege ich immer so nen Hals :-)
Hast Du mal nen Link auf Beispielcode, wie das bei der AVR-UART aussehen
könnte?
Also mit Interrupthandlern für die FIFOs.
Um auch mal konstruktiv mitzuwirken:
Erstelle dir einen Struct, in dem jeweils ein Pointer auf den
Datenregister, sowie auf die benötigten Registerbits zeigt. Erzeuge
diese Variable so oft wie du UARTs hast und initialisiere sie korrekt.
Schreibe die passenden get und set-Funktionen und fasse sie in einer
generischen Funktion zusammen.
Rest dann analog zu dem oben von mir geposteten Lösung, nur dass du
statt dem USART_TypeDef einen Funktionspointer verwendest.
Funktioniert dann auch mit beliebig vielen Schnittstellen, ist aber
definitiv langsamer als alles "klassisch" mit eigenem Code zu behandeln.
Hier stößt der AVR halt an die Grenze, dass die Register nicht im
Adressraum gemappt sind.
Natürlich kann man in den jeweiligen structs auch die Buffer, eigene
Statusbits, etc. unterbringen.
>> Man kann sich Strukturen anlegen, die Zeiger auf die Register>> des jeweiligen UART enthalten...> Erstelle dir einen Struct, in dem jeweils ein Pointer auf den> Datenregister, sowie auf die benötigten Registerbits zeigt...
Erzähle mal etwas Neues.
Weils grad aktuell ist und wenn Du kein C++ willst:
Packe alle öffentlichen Uart-Funktionen (und Flags, Speicher etc, was
ein einzelner Uart so braucht) in eine Struktur struct sUart in uart.h;
Packe alle uart0_-Funktionen static in eine uart0.c, z.B. _chr statt
uart0_char.
Alle Register-Definitionen (hier z.B. TX_REG_UART0) stehen in Uart0.h
Die uart0.c enthält dann z.B.:
1
#include<uart.h>
2
#include<Uart0.h>
3
4
staticconststructsUartUart0;
5
static...;/* was auch immer noch */
6
7
staticvoidchr(charc)
8
{
9
...
10
TX_REG_UART0=c;
11
...
12
}
13
14
/* einzige globale Funktion */
15
conststructsUart*GetUart0(...)
16
{
17
return&Uart0;
18
}
19
20
staticconststructsUart0Uart0=
21
{
22
_chr;
23
_init;
24
_...;
25
};
Diese Datei lässt Du von Deiner Build-Umgebung kopieren, nach uart1.c,
uart2.c und uart3.c, wobei alle Uart0 durch Uart1/2/3 ersetzt werden
(Textfresser, z.B. sed, awk oder cmd-kommandos ...)
Der Vorteil:
- Die Routinen sind maximal schnell, klein und lesbar (weil direkte
Umsetzung, keine Indirektionen oder Switche)
- Gut, der Code ist 4mal da, aber insgesamt in Summe weniger als doppelt
so groß. Zudem kannst Du den Code in eine Lib packen. Wenn Du dann in
einem Projekt nur 2 Uarts brauchst, geht es kaum schneller oder kleiner.
- Du kannst Breakpoints auf einen dedizierten Uart setzen
- Du kannst einfach und elegant verschiedene Implementierungen parallel
vorhalten, die per verschiedenen GetUartX ausgewählt werden. z.B.
GetUart0_DMA() oder GetUart0_Blockierend().
Im Code sieht es dann z.B. so aus:
1
structsUartmyUart=GetUart0();
2
3
myUart->init(9600,8,1);
4
myUart->chr('A');
du kannst statt GetUart0 auch die Struktur global machen, dann sieht der
Code so aus:
Peter D. schrieb:> Du brauchst je UART nur die 4 Grundfunktionen:> uart_x_init();> uart_x_get_status();> uart_x_putchar();> uart_x_getchar();> Und die 8 Interrupthandler für die FIFO-Buffer.>> Die ganzen Formatierungsfunktionen schreibt man natürlich nur einmal, da> sie ja nicht mehr auf UART-Register zugreifen, sondern auf Variablen> oder Arrays.
Darum geht es mir, richtig. Ich möchte nicht alle Schreibroutinen im
maximalen Fall 4x pflegen und hinterherrennen. Wenn was auffällt oder
vlt. noch was hinzukommt, möchte ich es universell für alle 4 einsetzen
können. Ob ich es dann überhaupt brauche, also alle Routinen für alle 4
UART'S, darüber möchte ich mir keine Gedanken machen müssen.
Bei den 4 Zugriffsfunktionen uart_x_ wird sich wohl nicht viel ändern.
Die Register sind festgelegt und der einzelne UART0 macht seinen Dienst
ja bereits sehr gut.
Achim S. schrieb:> Weils grad aktuell ist und wenn Du kein C++ willst:>> Packe alle öffentlichen Uart-Funktionen (und Flags, Speicher etc, was> ein einzelner Uart so braucht) in eine Struktur struct sUart in uart.h;
Der Ansatz mit den Strukturen finde ich auch nicht schlecht, wirkt
aufgeräumter. Wenn ich es nun aber richtig verstanden habe, "kostet" das
vlt. längere Ausführungszeiten durch die Pointer auf die Funktionen?
(Wie groß sind die dann eigentlich 16 oder vlt. sogar 24 oder noch
größer?)
Mit Funktionen die in Strukturen mitgegeben werden habe ich noch nichts
gemacht, das wäre was neues für mich.
AVRli .. schrieb:> "kostet" das> vlt. längere Ausführungszeiten durch die Pointer auf die Funktionen?
nicht bei gleichen Randbedingungen, z.B. globale Objekte:
Uart_char(&Uart1, 'a'); kostet einen Ptr (&Uart1) auf den Stack legen
und drüben wieder runternehmen und alles indirekt verarbeiten.
Uart1.chr('a'); kostet eine Indirektion (Uart1.chr auslesen und
hinspringen, statt direkt zur Adresse von Uart_char), spart aber
mindestens 2 Stack-Operationen und ggf. mehrfache Indirektion in der
Funktion. .
Insgesamt wird der Code schneller, meist sogar deutlich schneller (weil
vieles zur Compilezeit eindeutig ist). Ich habe das sogar auf 18er Pics
so gemacht, die lange keine und später nur eingeschränkte und teure
Funktionspointer hatten.
Lama:
> für die Leute die sonst nichts anderes programmieren können
ertappt!
> früher jahrelang
eben
> Schon mal aus dem Profi-Bereich was probiert?
Als Entwicklungs-Ing. - noch nie!
Vielen Dank für diese sehr sachlichen Bemerkungen.
J Zimmermann schrieb:>> für die Leute die sonst nichts anderes programmieren können> ertappt!
Wusste ichs doch, deine Kompetenz strahlt förmlich
J Zimmermann schrieb:>> früher jahrelang> eben
Ja, danach auf was brauchbares umgestiegen.
J Zimmermann schrieb:>> Schon mal aus dem Profi-Bereich was probiert?> Als Entwicklungs-Ing. - noch nie!
So, wie du auch die STM32 mal "probiert" hast? Na dann...
--> Wenn du schon versuchst ironisch zu sein, dann mach es richtig.
Zumindest das solltest du ja hinbekommen :-)
Achim S. schrieb:> Uart1.chr('a'); kostet eine Indirektion (Uart1.chr auslesen und> hinspringen, statt direkt zur Adresse von Uart_char), spart aber> mindestens 2 Stack-Operationen und ggf. mehrfache Indirektion in der> Funktion. .
Das klingt gut!
Dann habe ich noch 3 Fragen...
1. nehmen wie mal an ich habe in der struct Definition einen rx_buffer,
mit RX_BUFFER_SIZE definiert, wie kann man die Größe dann von "außen"
beliebig festlegen?
1
structsUart=
2
{
3
...
4
charrx_buffer[];
5
...
6
}
7
8
#define RX_BUFFER_SIZE 128
9
10
staticconststructsUartUart0;
Ich weiß wie groß der sein muß, einer muss 256 Zeichen vorhalten können,
ein anderer auf UART1 halt nur 64 Zeichen.
Kann man das berücksichtigen oder muß man alle Buffer die gleiche Größe
bei der Struct Lösung verpassen?
2.
Die Formatierungsroutinen bekommen dann alle eine Erweiterung bei der
Übergabe, welche auf die entsprochene z.B. UART0 Struct zeigt?
1
Uart_str(&Uart0,"Auch mal an die frische Luft gehen!");
3.
Wie behandel ich Variablen, die ich bisher als volatile deklariert habe?
pos_uart_tx_buf und pos_uart_rx_buf sind ja solche.
Sind die durch die STRUCT Deklaration automatisch immer volatile?
Grüße AVRli...
Habe mich "durchgebissen" und es läuft! ;-)
Buffer ist natürlich doch einstellbar, wenn man in der Struct nur den
Zeiger auf diesen aufnimmt und ihn dann intern einfach festlegt.
Funktionen habe ich die von Euch angesprochenen realisiert.
Läuft nun mit zwei UART's und weil es mich interessiert hat, die
Erweiterung schlägt mit 630 Byte mehr Programmspeicher zu buche.
Ich versuche da noch etwas zu optimieren, vielleicht geht noch was.
Danke, zumindest bis hier hin, an alle konstruktiven Kommentare!
Grüße AVRli...
Nachtrag... editieren geht nicht mehr...
Ich glaube ich habe noch einen Bock drin...
Denn die 640 Byte mehr, kommen mir etwas viel vor, die sind auch dazu
gekommen, wenn ich nur einen UART nutzen würde.
Ich habe mir eine STRUCT angelegt mit:
1
structsUart
2
{
3
/*Buffer, Variablen und Zeiger auf die
4
Funktionen init und put_char */
5
};
6
typedefconststructsUart*UART_P;
7
8
externstructsUartUART0;
Die Funktion mit der ein Zeichen in den TX Buffer geschrieben wird sieht
so aus.
1
staticvoid_uart0_put_char(charchrtx)
2
{
3
staticuint8_tpin;
4
5
pin=UART0.pos_in_tx;
6
UART0.buf_tx[pin]=chrtx;
7
pin++;
8
pin=pin&(UART0_TX_BUFFER_SIZE-1);
9
UART0.pos_in_tx=pin;
10
11
SET_BIT(UCSR0B,UDRIE0);
12
}
Um nun eine Zeichenkette einzuspielen nutze ich...
1
voiduart_char(UART_Puart,charchrtx)
2
{
3
uart->put_char(chrtx);
4
}
5
6
voiduart_str(UART_Puart,char*buftx)
7
{
8
while(*buftx)uart->put_char(*buftx++);
9
}
Aus meinem Main übergebe ich nun wie folgt...
1
uart_Str(&UART0,"Zeichenkette");
Alle anderen Funktionen wo ich die Werte übergebe haben auch diesen
UART_P als ersten Parameter erhalten.
Grüße AVRli...
AVRli .. schrieb:> 1. nehmen wie mal an ich habe in der struct Definition einen rx_buffer,> mit RX_BUFFER_SIZE definiert, wie kann man die Größe dann von "außen"> beliebig festlegen?
Das ist ein ganz eigenes Thema, die Größe von Puffern.
Wenn der Treiber keine "Standardgröße" haben soll, dann
- per malloc reservieren --> sehr unschön in kleinen embedded
- vom Aufrufer bereitstellen lassen. Also z.B. in main
1
staticunsignedcharbuf[128];
2
3
Uart0.init(9600,8,1,buf,sizeof(buf));
> 2.> Die Formatierungsroutinen bekommen dann alle eine Erweiterung bei der> Übergabe, welche auf die entsprochene z.B. UART0 Struct zeigt?> Uart_str(&Uart0, "Auch mal an die frische Luft gehen!");
eigentlich sollte solche Routinen Teil von Uart0 sein, also
1
Uart0.str("...");.
Und wenn nicht, dann übergib nur, was die Funktion braucht, hier also
.chr:
1
Uart_str(Uart0.chr,"...");/* beachte das fehlende &, da chr ein ptr */
> 3.> Wie behandel ich Variablen, die ich bisher als volatile deklariert habe?> pos_uart_tx_buf und pos_uart_rx_buf sind ja solche.
Die gehören nicht in die Struktur, denn die enthält nur vom Nutzer zu
verwendende Elemente, keine Internas.
in uart0.c steht entweder
1
staticvolatileunsignedcharpos_uart_tx_buf@0x4711;/* oder wie Du das Register kennzeichnest*/
Dsnn ist die Übergabe der gesamten Structur nicht richtig...
Gut ich danke Dir für Deine Antwort. Ich schau mir das heute Abend
wieder an und werde dann nochmal umbauen.
Gut wäre dann, wenn ich einen Typen hätte, der dann &UART0.put_char
abbildet, das wäre kürzer zu schreiben bei den ganzen Aufrufen.
Kannst Du vlt. noch ganz kurz auf die Zusammenhänge mit "static const
struct" eingehen?
Das habe ich noch nie so verwendet. Vlt. ist ja das auch schon ein Grund
warum es nun so "aufgebläht" wurde.
Ich kenne...
const char pgm_ans_invalid[] PROGMEM = "invalid command";
Das macht man wohl so weil sich der Inhalt nie ändern wird?
Grüße AVRli...
J Zimmermann schrieb:> wow, Deine Kenntnis Anderer ist bemerkenswert, vielleicht sollte eine> Rubrik "Übersinnnliches" oder "Hellsehen" für Dich eingerichtet werden?
Was ist los Jacqueline? Tage?
Langsam wirst du irrational :-)
J Zimmermann schrieb:> Mitlesa:>> Die paar Bytes für viermal die UART-Routinen machen das Kraut>> nun wirklich nicht fett.>> Du mußt dann aber auch jede Änderung 4x machen, hast Du dann noch viele> andere Hardware-Einheiten in der "Mache" wird's schnell fitzig.
Welche Änderung denn, es sind Low level Routinen ?
Meinst du, die Register Adressen ändern sich irgendwann ?
Aber wenn man sonst nichts zu tun hat...
Peter D. schrieb:> Flash ist meistens nicht das Problem, daher ist es schon sinnvoll, den> Code zu kopieren. Ansonsten müßte man wertvollen SRAM opfern, um für> jedes 8Bit-Register einen 16Bit-Pointer anzulegen. Und die Funktionen> müßten dann auch erst ein Pointerregister (X,Y,Z) laden (+Push/Pop> Overhead), anstatt direkt auf das IO-Register zuzugreifen. D.h. die> Laufzeit wird größer und Flash wird auch kaum gespart.
Ja, aber bei nur 256KB muss man schon gewaltig sparen.
Egal wie langsam es wird und wieviel mehr RAM man verbraucht - mit
FLASH muss man sparsam umgehen...
Es funktioniert ja nun soweit, das Einzige ist in der Tat, dass ein
Aufruf von z.B.
1
uart_cr(&UART0);
Nun 6 Byte, (zuvor 2 Byte) FLASH verbraucht. Da fehlt mir das Wissen,
was da nun genau passiert und ob man da noch was machen kann.
Wenn ich einen weiteren UART einbinde, erhöht sich der RAM Verbrauch um
260 Byte, wobei davon 128 RX und 128 TX Buffer sind.
Beide UART's lassen sich mit den gleichen Routinen ansprechen...
1
uart_cr(&UART0);
2
uart_cr(&UART1);
Ich möchte mich nun auch nicht verzetteln, der Flash "Verbrauch" ist das
eine (nicht ganz so schlimm) doch Geschwindigkeit büße ich mit +4 Byte
pro Ausgabe schon ein. Wenn man das noch verbessern könnte...
Gruß AVRli...
Ich werfe mal das Thema "schreib die Funktionen doch als Makros und
instanziiere dann viermal" in den Raum und verschwinde dann leise
wieder, nachdem ich Wilhelm einmal zuzwinkerte. :-)
Die 6 Bytes werden ein "pop arg" und ein "push arg" oder sowas sein,
wobei der restliche Unterschied nicht weiter auffällt. Oder so. ;-)