UART
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
Bit | Maske Hex | Bedeutung |
0 | 0x00001 | rx FIFO leer |
1 | 0x00002 | rx FIFO voll |
2 | 0x00004 | tx FIFO leer |
3 | 0x00008 | tx FIFO voll |
4 | 0x00010 | tx FIFO wurde geschrieben |
5 | 0x00020 | tx Interrupt |
6 | 0x00040 | rx Paritätsfehler |
7 | 0x00080 | rx Framefehler (offene Leitung oder BREAK wird empfangen) |
8 | 0x00100 | rx Datenverlust |
9 | 0x00200 | Modemsignal dcd (wenn freigegeben) |
10 | 0x00400 | Modemsignal cts (wenn freigegeben) |
11 | 0x00800 | Modemsignal dsr (wenn freigegeben) |
12 | 0x01000 | rx_clk Schieberegister Takt Rx |
13 | 0x02000 | rx Schieberegister arbeitet nicht |
14 | 0x04000 | tx_clk Schieberegister Takt Tx (arbeitet ständig mit Datenrate!!) |
15 | 0x08000 | rst_uart (UART befindet sich noch im RESET) |
16 | 0x10000 | tx 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
Bit | Bedeutung | Reset |
0 | Rx Freigabe | 0 |
1 | Tx Freigabe | 0 |
2 | Paritätsprüfung freigeben | 0 |
3 | 0=ungerade / 1=gerade Parität | 0 |
4 | 0=ein / 1=zwei Stopbits | 0 |
7 bis 5 | Wort Länge | 111 |
8 Bit = 111 (0x00E0) | ||
7 Bit = 110 (0x00C0) | ||
6 Bit = 101 (0x00A0) | ||
5 Bit = 100 (0x0080) | ||
8 | nicht verwendet | |
12 bis 9 | Datenrate | 0000 |
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) | ||
13 | Freigabe des Rx Interrupt | 0 |
14 | Freigabe des Tx Interrupt | 0 |
15 | Sende BREAK (Tx ständig low = Startbit) | 0 |
Bitbelegung UART_MODEM
Bit | Bedeutung | Reset |
0 | Zustand DSR bzw. DTR, wenn Ausgang | 0 |
1 | Zustand RTS bwz. CTS, wenn Ausgang | 0 |
2 | Zustand DCD, wenn Ausgang | 0 |
3 | Richtung Port dcd, 1=Ausgang, 0=Eingang | 0 |
4 | Richtung Port rts, 1=Ausgang, 0=Eingang | 0 |
5 | Richtung Port dtr, 1=Ausgang, 0=Eingang | 0 |
17-6 | not used |
1. #include <uart.h>
... muss in der C-Quelle geladen werden, wenn man die Funktionen verwenden will.#ifndef UART_H_ #define UART_H_ #ifdef __cplusplus extern "C" { #endif #include <peripherals/uart.h> #include <peripherals/uart_light.h> #include <stdint.h> // section kept for compatibility with older projects, may be removed in the // future // Status Signale #define RX_EMPTY UART_RX_EMPTY #define RX_FULL UART_RX_FULL #define TX_EMPTY UART_TX_EMPTY #define TX_FULL UART_TX_FULL #define TX_IRQ_PRE UART_TX_IRQ_PRE #define TX_IRQ_FLAG UART_TX_IRQ_FLAG #define RX_P_ERR UART_RX_P_ERR #define RX_F_ERR UART_RX_F_ERR #define RX_D_ERR UART_RX_D_ERR #define M_DCD UART_M_DCD #define M_CTS UART_M_CTS #define M_DSR UART_M_DSR #define RX_CLK UART_RX_CLK #define RX_STOP UART_RX_STOP #define TX_CLK UART_TX_CLK #define RST_UART UART_RST_UART // UART noch im RESET, wenn = 1 #define TX_STOP UART_TX_STOP // Steuersignale #define RX_EN UART_RX_EN #define TX_EN UART_TX_EN #define PARI_EN UART_PARI_EN #define PARI_EVEN UART_PARI_EVEN // 0 = ungerade / 1 = gerade #define TWO_STOP UART_TWO_STOP // 0 = ein / 1 = zwei Stopbits #define DATA_LEN_5 UART_DATA_LEN_5 #define DATA_LEN_6 UART_DATA_LEN_6 #define DATA_LEN_7 UART_DATA_LEN_7 #define DATA_LEN_8 UART_DATA_LEN_8 #define BPS_115200 UART_BPS_115200 #define BPS_57600 UART_BPS_57600 #define BPS_38400 UART_BPS_38400 #define BPS_31250 UART_BPS_31250 // MIDI Datenrate #define BPS_19200 UART_BPS_19200 #define BPS_9600 UART_BPS_9600 #define BPS_4800 UART_BPS_4800 #define BPS_2400 UART_BPS_2400 #define BPS_1200 UART_BPS_1200 #define BPS_600 UART_BPS_600 #define BPS_300 UART_BPS_300 #define BPS_150 UART_BPS_150 #define BPS_75 UART_BPS_75 #define BPS_50 UART_BPS_50 #define BPS_7812 UART_BPS_7812 // Boot 68hc11 mit 7812,5 Baud #define RX_IE UART_RX_IE #define TX_IE UART_TX_IE #define TX_BREAK UART_TX_BREAK // Interruptfreigabe fuer UART light #define RXUL_IE (1<<9) #define TXUL_IE (1<<10) // Modem Outputs und Richtung #define DTR_DSR UART_DTR_DSR #define RTS_CTS UART_RTS_CTS #define DCD UART_DCD #define DCD_OUT UART_DCD_OUT #define RTS_OUT UART_RTS_OUT #define DTR_OUT UART_DTR_OUT typedef uart_regs_t uart_t; void uart_write (uart_t *uart, const uint18_t value); unsigned char uart_read (uart_t *uart); int uart_read_nb (uart_t *uart, unsigned char *value); void __attribute__((error("stdio_uart_open is no longer supported. Declare a global variable FILE * stdout = &UART_*_FILE instead"))) stdio_uart_open2(uart_t *uart); // end compatibility section 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); #define declare_UART_FILE(uart) { \ .base_addr = (void*) uart, \ .send_byte = (fun_stdio_send_byte) uart_send, \ .receive_byte = (fun_stdio_receive_byte) uart_receive, \ .receive_byte_nb = (fun_stdio_receive_byte_nb) uart_receive_nb \ } void __attribute__((error("stdio_uart_open is no longer supported. Declare a global variable FILE * stdout = &UART_*_FILE instead"))) stdio_uart_open(uart_regs_t *uart); #ifdef __cplusplus } #endif #endif /*UART_H_*/
2. #include <peripherals/uart.h>
... wird immer automatisch vom SpartanMC System geladen. Der Include muss nicht in der C-Quelle erfolgen.#ifndef __UART_H #define __UART_H #ifdef __cplusplus extern "C" { #endif #include// 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 (optional) #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) // Rueckgabewerte fuer 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; #ifdef __cplusplus } #endif #endif
2. #include <peripherals/uart_ligth.h>
... wird immer automatisch vom SpartanMC System geladen. Der Include muss nicht in der C-Quelle erfolgen.#ifndef UART_LIGHT_H_ #define UART_LIGHT_H_ #ifdef __cplusplus extern "C" { #endif #include// Status Signale #define UART_LIGHT_RX_EMPTY (1<<0) #define UART_LIGHT_RX_FULL (1<<1) #define UART_LIGHT_TX_EMPTY (1<<2) #define UART_LIGHT_TX_FULL (1<<3) #define UART_LIGHT_TX_IRQ_PRE (1<<4) #define UART_LIGHT_TX_IRQ_FLAG (1<<5) // Interruptfreigabe fuer UART light #define UART_LIGHT_RXIE (1<<9) #define UART_LIGHT_TXIE (1<<10) typedef struct { volatile uint18_t status; // read/write = Reset Tx Interrupt volatile uint18_t rx_data; // read = Reset Rx Interrupt volatile uint18_t tx_data; // write } uart_light_regs_t; 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); #define declare_UART_LIGHT_FILE(uart) { \ .base_addr = (void*) uart, \ .send_byte = (fun_stdio_send_byte) uart_light_send, \ .receive_byte = (fun_stdio_receive_byte) uart_light_receive, \ .receive_byte_nb = (fun_stdio_receive_byte_nb) uart_light_receive_nb \ } void __attribute__((error("stdio_uart_light_open is no longer supported. Declare a global variable FILE * stdout = &UART_LIGHT_*_FILE instead"))) stdio_uart_light_open(uart_light_regs_t * uart); #ifdef __cplusplus } #endif #endif /*UART_LIGHT_H_*/
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.
#ifndef SB_UART_LIGHT_0_INTERRUPT_SUPPORTED FILE * stdout = &UART_0_FILE; FILE * stdin = &UART_0_FILE; #else FILE * stdout = &UART_LIGHT_0_FILE; FILE * stdin = &UART_LIGHT_0_FILE; #endif
Testprogramme für die Interruptarbeit mit UART 2
Programm für die 2. UART als C-Quelle uart2.c , als Übersetzungsliste uart2.lst und im bin-Format spartanmc.bit und spartanmc.msk können hier geladen werden.
Programmieren mit iMpact wenn nur Jumper M1 geschlossen ist.
Die Konfiguration für den Spartan 3E Starter Kit auf der das Programm lauffähig ist kann mit der folgenden Konfigurationsdatei für jConfig erstellt werden.
Offene Fragen
- zur Zeit keine
WEB-Seiten mit Informationen zur Funktion der UART
http://www.sprut.de/electronic/interfaces/rs232/rs232.htmhttp://de.wikipedia.org/wiki/RS232
http://www.lammertbies.nl/comm/cable/de_RS-232.html#pins