Atmel AVR Mikrocontroller mit OpenSuse: RS232-Ansteuerung

RS232-Ansteuerung mit dem AVR kann durch direktes Ansteuern zweier Pins und entsprechendem Code per Hand gemacht werden. Dies ist allerdings aufwendig und nicht notwendig, weil in den meisten AVRs ein UART enthalten ist (manchmal auch zwei), der das Low Level RS232 Handling (Bitschiebereien) schon erledigt. Man muss dann nur noch komfortabel mit Byte-Werten statt mit Bitverschiebungen operieren.

Keine serielle Schnittstelle am PC? Es gibt für unter 10 Euro Kabel, die als Adapter zwischen RS232 und USB dienen können. Unter Linux klinkt sich eine solches Kabel in den Gerätebaum z.B. als „/dev/ttyUSB0“ ein und kann dann genauso wie eine „echte“ serielle Schnittstelle genutzt werden. Bei meinem OpenSuse 11.2 sieht die Einbindung (mittels dmesg ausgegeben) wie folgt aus:

[ 3529.694778] usbserial: USB Serial Driver core
[ 3529.705376] USB Serial support registered for ch341-uart
[ 3529.705409] ch341 6-1:1.0: ch341-uart converter detected
[ 3529.718371] usb 6-1: ch341-uart converter now attached to ttyUSB0
[ 3529.718650] usbcore: registered new interface driver ch341

Die Ansteuerung des UARTs kann mittels Interrupt oder Polling erfolgen.

RS232 mit Polling

Das Polling kann unter C elegant gelöst werden, indem die Funktion fdevopen() genutzt wird. Dieser Funktion werden die beiden grundlegenden Funktionen für das Schreiben und Lesen einzelner Zeichen übergeben. Von da an werden diese Funktionen von den restlichen Funktionen aus „stdio.h“ benutzt, z.B. printf() oder scanf(). Wenn man nur Schreiben will, braucht man die Lesefunktion nicht implementieren und auch nicht übergeben.

In der main() Funktion wird fdevopen() aufgerufen. Die Funktion ioinit() initialisiert den UART.

int main(void) {
     unsigned int c;
 
     ioinit();     fdevopen(uart_putchar, uart_getchar ); 
 
     printf("nnMotor testnn");
 
     for(;;) {
         // input processing via rs232
         c = getchar();
         printf("you entered: %c, %un", c, c);
     }
}

Die Funktion ioinit():

void ioinit(void) {
     UCSRB = _BV(TXEN) | _BV(RXEN); /* tx/rx enable */
     UBRR = (F_CPU / (16 * 19200UL)) - 1; /* 19200 Bd */
     /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
#if defined(TWPS0)
     /* has prescaler (mega128 & newer) */
     TWSR = 0;
#endif
     TWBR = (F_CPU / 100000UL - 16) / 2;
}

Hier die Implementierung der beiden Funktionen für Schreiben und Lesen, welche die UART nutzen (getestet auf ATmega8, bei anderen Chips können sich die  Registernamen unterscheiden):

int uart_putchar(char c, FILE *notused ) {
     if (c == 'n')
         uart_putchar('r',notused);
     loop_until_bit_is_set(UCSRA, UDRE); 
     UDR = c;
     return 0;
}
 
int uart_getchar(FILE *notused) {
     unsigned char c;
 
     loop_until_bit_is_set (UCSRA,RXC); // Wait until a char is received
     c = UDR;
     //uart_putchar (c,NULL);
     return c;
}

uart_putchar() und uart_getchar() können beispielsweise auch so geschrieben werden, dass sie nicht den UART nutzen, sondern z.B. auf ein LCD-Display ausgeben. Das „tolle“ an der ganzen Sache ist, dass dann die Standard-C-IO-Funktionen genutzt werden können.

Wenn Zeichen nur fehlerhaft kommen (Pollin-Board): Sicherstellen, dass die Versorgungsspannung hoch genug ist. Wenn ein AVR via 7805 seine Spannung erhält, die Spannung die in den 7805 hineingeht aber zu niedrig ist (also z.B. auch nur 5V), funktioniert der AVR zwar selbst noch ganz gut, die serielle Schnittstelle ist dann aber nicht mehr fehlerfrei.

RS232 mit Interrupts

Peter Fleury hat eine Bibliothek geschrieben, die Interrupts benutzt und damit nebenläufig zur eigentlichen Anwendung genutzt werden kann.

Ich benutze diese Bibliothek eigentlich immer, weil damit ähnlich wie beim log4j von Java Logging-Ausgaben produziert werden können, so dass man über den Programmverlauf informiert ist. Dazu kann man auf einem PC ein Terminalprogramm (z.B. das schreckliche Standardprogramm bei Windows XP, „Hyperterminal“) laufen lassen und die Ausgaben mitverfolgen. Ist kein Terminal angeschlossen, stört dies den Programmablauf nicht. Allerdings wird der Code etwas langsamer laufen.

Im folgenden Codeauszug ist die Nutzung der Bibliothek dargestellt. „interrupt.h“ und signal.h müssen eingebunden werden, da die Bibliothek Interrupts und Signale benutzt.

Die UART_BAUD_RATE gibt die zu nutzende Baudrate an (das Terminalprogramm muss passen eingestellt werden). In zwei Trivialmakros habe ich mir die häufigsten Aufrufe gekapselt: DI() initialisiert die Bibliothek, DO() gibt einen String mittels uart_puts() aus.

#include "../uart/uart.h"
#include <avr/interrupt.h>
#include <avr/signal.h>
#define UART_BAUD_RATE      19200     /* 9600 baud */
 
#define DI() uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,XTAL_CPU) )
#define DO( m ) uart_puts(m)

...

DI();
/*
 * now enable interrupt, since UART library is interrupt controlled
*/
sei();
DO("after init usartnr");
/* initialize display, cursor off */
lcd_init(LCD_DISP_ON);
 
DO("after init lcdnr");

Im Codebeispiel wird die Bibliothek initialisiert mittels DI() und Interrupts freigegeben (sei()). Danach kann man mittels DO() Ausgaben an das Terminal senden. Dies wird im Beispiel vor und nach dem Funktionsaufruf lcd_init() gemacht.

Die Bibliothek muss im Makefile als zusätzliche Bibliothek eingetragen werden. Die Funktionsprototypen stehen alle im Header „uart.h“, den man im eigenen Programm eintragen muss.


Ausgaben des AVR Controllers mittels der UART-Bibliothek auf einem Terminalprogramm  (Fotografie vom Bildschirm, daher die schlechte Qualität)

Willem Programmer with Linux

Hint: This is an historical article. Nowadays I would not recommend the Willem Programmer anymore. I replaced it after having many trouble with large EPROMs. My new Eprommer is a Batronix BX32P with works perfectly with Linux.

There is a hardware design called „Willem Programmer“ which is continuously developed further by several people. It seems that the company „KEE Electronics“ provides the software and some hardware versions today. The original design may come from the company Sivava which also sells a version of the programmer.

I bought a Willem 5.0E Programmer from some chinese source. This hardware looks different from e.g. the kee one.

There are versions with parallel connector and others with pure USB connector. The parallel versions are cheaper.

The programmer comes with a software for windows. Before buying, I checked the Internet and found that there is a reimplementation for Linux, called „geepro„.

Hardware preparation

My version of the programmer is controlled via parallel port and uses a USB cable for power connection. So it can only be used with a PC that has a parallel port. I added a cheap PCI-card with a parallel connector to my PC, so the hardware setup is simple.

Install geepro

Just download the software (Link here). It must be compiled from source. The installation consists of three steps (configure, buiild, install). See its README file. If the configure part lists libraries that are missing, use your packaging tool to add these (development versions of) libraries. On a clean OpenSuse 13.1, I had to install 3 additional libraries.
After successful build, I installed the software to /usr/local. The install step listed an error „No such file or directory: ‚/usr/local/lib/geepro/drivers/altera_byteblaster.driver‘ but repeating the install step several times succeeded 🙂

Use geepro to control willem programmer

There seems to be no documentation for using geepro.

After installation of geepro, you can start the software by typing „/usr/local/geepro“. It comes up with a user interface. Select „Willem 4.0“ as programmer, select the device (for me „parallel port parport0) and test the connection. A LED should flash on the programmer and the test should give a „connection ok“ dialogue box.


Then Select a chip. After selection, the required switches are listed as a picture on the user interface („Chip“ tab). Adjust all switches as requested and then insert the chip. Then, its content can be read or written („Buffer“ tab).
The content can also be manipulated in several ways.

There is also a „HW Test“ pad. I haven’t used it so far.