UART

Die aktuellen Versionen aller Verilog Dateien finden Sie im SubVersion hier(external link).



Das UART-Übertragungsverfahren sieht vor, das zunächst ein dem Ruhepegel der Leitung (in diesem Fall 1) entgegengesetztes Startbit Übertragen wird, also eine Null. Danach werden fünf bis acht Datenbits und optional ein Paritätsbit gesendet. Die Parität bezieht sich auf das Hamminggewicht der Datenbits inklusive Paritätsbit und kann dementsprechend "gerade" oder "ungerade" sein. Das Paritätsbit muss die Datenbits zu der für die Übertragung gewählten Parität ergänzen, ansonsten werden die Daten als fehlerhaft angezeigt. Am Schluss werden ein oder zwei Stoppbits übertragen, die dem Pegel des Ruhezustandes entsprechen, also logische Einsen. Bei der Übertragung wird das niederwertigste Bit zuerst gesendet. Im Ruhezustand kann eine Übertragung beliebig lange angehalten werden. Die Uart besitzt auch je einen FIFO für den Datenempfang und für das Senden. Die Größe kann getrennt in den Werten von zweier Potenzen eingestellt werden. Die maximale Größe wird durch die Ressourcen des FPGA begrenzt. Die Größe der FIFOs kann nur während der Erstellung eines Projekts im Systembilder festgelegt werden. Die Werte für die Vorteiler der einzelnen Datenraten werden dabei auch automatisch für die bei der Konfiguration anzugebende Takt Frequenz ermittelt.

Für den Bootlader und die STDIO wird die UART auf folgende Werte eingestellt:

Datenrate: (Baud)115200 Kbit/sec
Bitanzahl:8 Bit
Parität:keine
Stoppbits:>=1
Hardwareprotokoll (Flow Control):keins
Softwareprotokoll (Flow Control):keins

Die Daten werden damit bei 2 Stoppbits in folgender Form übertragen:


Durch das ISE bei der Übersetzung von transiver.v ermittelte Teiler
Ergebnisse einer Teilerberechnung mit Excel für die Datei transiver.v

Register

Offset Register Zugriff
0 UART_Status read
1 UART_FIFO_READ (RESET Rx Interrupt) read
2 UART_FIFO_WRITE write
3 UART_CTRL write
3 UART_Status (RESET Tx Interrupt) read
4 UART_MODEM (optional) write


Bitbelegung UART_Status

BitMaske HexBedeutung
00x00001rx FIFO leer
10x00002rx FIFO voll
20x00004tx FIFO leer
30x00008tx FIFO voll
40x00010tx FIFO wurde geschrieben
50x00020tx Interrupt
60x00040rx Paritätsfehler
70x00080rx Framefehler (offene Leitung oder BREAK wird empfangen)
80x00100rx Datenverlust
90x00200Modemsignal dcd (wenn freigegeben)
100x00400Modemsignal cts (wenn freigegeben)
110x00800Modemsignal dsr (wenn freigegeben)
120x01000rx_clk Schieberegister Takt Rx
130x02000rx Schieberegister arbeitet nicht
140x04000tx_clk Schieberegister Takt Tx (arbeitet ständig mit Datenrate!!)
150x08000rst_uart (UART befindet sich noch im RESET)
160x10000tx Schieberegister arbeitet nicht

Soll die Datenrate zwischen mehreren Übertragungen verändert werden, dann muss vorher der Ruhezustand der UART abgefragt werden und erst dann kann man die neue Datenrate einstellen. Der Ruhezustand ist vorhanden, wenn die UART sich nicht mehr im RESET (rst_uart = 0) befindet, der Rx Fifo leer ist und das Rx Schieberegister nicht arbeitet und auch der Tx Fifo leer ist und das Tx Schieberegister nicht arbeitet. Das Statusregister muss also mit der Maske 0x1A005 gelesen und das Ergebnis mit 0x12005 verglichen werden. Liegt genau dieser Wert vor, dann kann die neue Datenrate eingestellt werden.

Bitbelegung UART_CTRL

BitBedeutungReset
0Rx Freigabe0
1Tx Freigabe0
2Paritätsprüfung freigeben0
30=ungerade / 1=gerade Parität0
40=ein / 1=zwei Stopbits0
7 bis 5Wort Länge111
8 Bit = 111 (0x00E0)
7 Bit = 110 (0x00C0)
6 Bit = 101 (0x00A0)
5 Bit = 100 (0x0080)
8nicht verwendet
12 bis 9Datenrate0000
115200 = 0000 (0x0000)
057600 = 0001 (0x0200)
038400 = 0010 (0x0400)
031250 = 0011 (0x0600) (MIDI Datenrate)
019200 = 0100 (0x0800)
009600 = 0101 (0x0A00)
004800 = 0110 (0x0C00)
002400 = 0111 (0x0E00)
001200 = 1000 (0x1000)
000600 = 1001 (0x1200)
000300 = 1010 (0x1400)
000150 = 1011 (0x1600)
000075 = 1100 (0x1800)
000050 = 1101 (0x1A00)
007812,5 für alle anderen Werte (Boot 68hc11)
13Freigabe des Rx Interrupt0
14Freigabe des Tx Interrupt0
15Sende BREAK (Tx ständig low = Startbit)0

Bitbelegung UART_MODEM

BitBedeutungReset
0Zustand DSR bzw. DTR, wenn Ausgang0
1Zustand RTS bwz. CTS, wenn Ausgang0
2Zustand DCD, wenn Ausgang0
3Richtung Port dcd, 1=Ausgang, 0=Eingang0
4Richtung Port rts, 1=Ausgang, 0=Eingang0
5Richtung Port dtr, 1=Ausgang, 0=Eingang0
17-6not used


1. #include <periperals/uart.h>

... wird immer automatisch vom SpartanMC System geladen. Der Include muss nicht in der C-Quelle erfolgen.
#ifndef __UART_H
#define __UART_H

#include <stdint.h>

// Status Signale
#define UART_RX_EMPTY    (1<<0)
#define UART_RX_FULL     (1<<1)
#define UART_TX_EMPTY    (1<<2)
#define UART_TX_FULL     (1<<3)
#define UART_TX_IRQ_PRE  (1<<4)
#define UART_TX_IRQ_FLAG (1<<5)
#define UART_RX_P_ERR    (1<<6)
#define UART_RX_F_ERR    (1<<7)
#define UART_RX_D_ERR    (1<<8)
#define UART_M_DCD       (1<<9)
#define UART_M_CTS       (1<<10)
#define UART_M_DSR       (1<<11)
#define UART_RX_CLK      (1<<12)
#define UART_RX_STOP     (1<<13)
#define UART_TX_CLK      (1<<14)
#define UART_RST_UART    (1<<15)     // UART noch im RESET, wenn = 1
#define UART_TX_STOP     (1<<16)


// Steuersignale
#define UART_RX_EN       (1<<0)
#define UART_TX_EN       (1<<1)
#define UART_PARI_EN     (1<<2)
#define UART_PARI_EVEN   (1<<3)      // 0 = ungerade / 1 = gerade
#define UART_TWO_STOP    (1<<4)      // 0 = ein / 1 = zwei Stopbits

#define UART_DATA_LEN_5  (4<<5)      // 0x00080
#define UART_DATA_LEN_6  (5<<5)      // 0x000A0
#define UART_DATA_LEN_7  (6<<5)      // 0x000C0
#define UART_DATA_LEN_8  (7<<5)      // 0x000E0

#define UART_BPS_115200  (0<<9)      // 0x00000
#define UART_BPS_57600   (1<<9)      // 0x00200
#define UART_BPS_38400   (2<<9)      // 0x00400
#define UART_BPS_31250   (3<<9)      // 0x00600 MIDI Datenrate
#define UART_BPS_19200   (4<<9)      // 0x00800
#define UART_BPS_9600    (5<<9)      // 0x00A00
#define UART_BPS_4800    (6<<9)      // 0x00C00
#define UART_BPS_2400    (7<<9)      // 0x00E00
#define UART_BPS_1200    (8<<9)      // 0x01000
#define UART_BPS_600     (9<<9)      // 0x01200
#define UART_BPS_300     (10<<9)     // 0x01400
#define UART_BPS_150     (11<<9)     // 0x01600
#define UART_BPS_75      (12<<9)     // 0x01800
#define UART_BPS_50      (13<<9)     // 0x01A00
#define UART_BPS_7812    (14<<9)     // 0x01C00 Boot 68hc11 mit 7812,5 Baud

#define UART_RX_IE       (1<<13)
#define UART_TX_IE       (1<<14)
#define UART_TX_BREAK    (1<<15)

// Modem Outputs und Richtung
#define UART_DTR_DSR     (1<<0)
#define UART_RTS_CTS     (1<<1)
#define UART_DCD         (1<<2)
#define UART_DCD_OUT     (1<<3)
#define UART_RTS_OUT     (1<<4)
#define UART_DTR_OUT     (1<<5)

// Rückgabewerte für non blocking read
#define UART_OK          0
#define UART_NO_DATA     1

typedef struct {
    volatile uint18_t   status;     // read
    volatile uint18_t   rx_data;    // read (Reset Rx Interrupt)
    volatile uint18_t   tx_data;    // write
    volatile uint18_t   ctrl_stat;  // write (or read = status & Reset Tx Interrupt)
    volatile uint18_t   modem;      // write (optional)
} uart_regs_t;

#endif

2. #include <uart.h>

... muss in der C-Quelle geladen werden, wenn man die Funktionen verwenden will.
#ifndef UART_H_
#define UART_H_

void uart_wait_idle(uart_regs_t *uart);
void uart_send(uart_regs_t *uart, const unsigned char value);
unsigned char uart_receive(uart_regs_t *uart);
int uart_receive_nb (uart_regs_t *uart, unsigned char *value);

void uart_light_send (uart_light_regs_t *uart, unsigned char value);
unsigned char uart_light_receive (uart_light_regs_t *uart);
int uart_light_receive_nb (uart_light_regs_t *uart, unsigned char *value);

void stdio_uart_open(uart_regs_t *uart);
void stdio_uart_light_open(uart_light_regs_t *uart);

#endif


Wird im Programm #include <uart.h> verwendet, dann können die oben stehenden Funktionen genutzt werden.

1. uart_wait_idle(UART_0);
Die Funktion wartet auf den Ruhezustand von Rx, Tx und RESET der UART_0. Es werden die Bits 0,2,13,15 und 16 vom UART_Status überwacht. Die Funktion sollte vor der Initialisierung der UART gerufen werden, damit vorher alle Datentransfer Operationen mit der alten Einstellung beendet werden können. Diese Funktion darf nicht mit einer UART_light aufgerufen werden!

2. uart_send(UART_0, 'A');
Die Funktion sendet das Zeichen 'A' an die UART_0. Wurde stdio auf die UART_0 gesetzt, dann verwendet putchar(zeichen) diese Funktion.

3. zeichen = uart_receive(UART_0);
Die Funktion wartet auf ein Zeichen von UART_0. Wurde stdio auf die UART_0 gesetzt, dann verwendet zeichen = getchar() diese Funktion.

4. status = uart_receive_nb(UART_0, &zeichen);
Die Funktion wartet nicht auf ein Zeichen. War ein Zeichen vorhanden, dann ist der Status 0 und das Zeichen wird auf die Variable zeichen geschrieben. Wurde stdio auf die UART_0 gesetzt, dann verwendet status = getchar_nb(&zeichen) diese Funktion.

5. stdio_uart_open(UART_0);
Die UART_0 wird als stdio Gerät festgelegt. Die Funktion kann auch zur Laufzeit die stdio Funktionen auf eine andere UART umgeleiten.

Die Funktionen für die UART_light werden nur benötigt, wenn es einmal Unterschiede beim Polling von UART und UART_light geben sollte.

Testprogramme für die Interruptarbeit mit UART 2


Programm für die 2. UART als C-Quelle uart2.c(external link), als Übersetzungsliste uart2.lst(external link) und im spho-Format spartanmc_0.sph(external link) können hier geladen werden.

Konfiguration im binären Format für den Spartan 3E Starter Kit auf der das Programm lauffähig ist.

Die Konfiguration hat 3 Speicherblöcke und kann hier aus der TAR.GZ-Datei(external link) unter /spartanmc-projects-master/praktikum_prog_mc/foerderband/3estk/ oder einzeln aus dem GIT geladen werden.

Offene Fragen

  • zur Zeit keine

WEB-Seiten mit Informationen zur Funktion der UART

http://www.sprut.de/electronic/interfaces/rs232/rs232.htm(external link)
http://de.wikipedia.org/wiki/RS232(external link)
http://www.lammertbies.nl/comm/cable/de_RS-232.html#pins(external link)


SpartanMC