123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969 |
- MODULE Uart;
- (**
- AUTHOR: Alexey Morozov, HighDim GmbH, 2013
- PURPOSE: implementation of the driver for Xilinx Zynq UART PS controller
- *)
- IMPORT
- SYSTEM, Platform, Board, Device, Interrupts, UartConstants, Trace;
- CONST
- DefaultBaudrate* = 115200; (** defauilt UART baudrate *)
- UartNb* = 2;
-
- UartBaseAddr0* = ADDRESS(0E0000000H);
- UartBaseAddr1* = ADDRESS(0E0001000H); (* base address for all UART controllers present in the system *)
- UartModemPinsConnected0* = FALSE;
- UartModemPinsConnected1* = FALSE;
- UartInputClockHz* = Board.UartInputClockHz;
- (** Register offsets for the UART controller *)
- XUARTPS_CR_OFFSET = 000H; (** Control Register [8:0] *)
- XUARTPS_MR_OFFSET = 004H; (* Mode Register [9:0] *)
- XUARTPS_IER_OFFSET = 008H; (* Interrupt Enable [12:0] *)
- XUARTPS_IDR_OFFSET = 00CH; (* Interrupt Disable [12:0] *)
- XUARTPS_IMR_OFFSET = 010H; (* Interrupt Mask [12:0] *)
- XUARTPS_ISR_OFFSET = 014H; (* Interrupt Status [12:0]*)
- XUARTPS_BAUDGEN_OFFSET = 018H; (* Baud Rate Generator [15:0] *)
- XUARTPS_RXTOUT_OFFSET = 01CH; (* RX Timeout [7:0] *)
- XUARTPS_RXWM_OFFSET = 020H; (* RX FIFO Trigger Level [5:0] *)
- XUARTPS_MODEMCR_OFFSET = 024H; (* Modem Control [5:0] *)
- XUARTPS_MODEMSR_OFFSET = 028H; (* Modem Status [8:0] *)
- XUARTPS_SR_OFFSET = 02CH; (* Channel Status [14:0] *)
- XUARTPS_FIFO_OFFSET = 030H; (* FIFO [7:0] *)
- XUARTPS_BAUDDIV_OFFSET = 034H; (* Baud Rate Divider [7:0] *)
- XUARTPS_FLOWDEL_OFFSET = 038H; (* Flow Delay [5:0] *)
- XUARTPS_TXWM_OFFSET = 044H; (* TX FIFO Trigger Level [5:0] *)
- (* Control Register Bit Definition
- The Control register (CR) controls the major functions of the device.
- *)
- XUARTPS_CR_STOPBRK = 000000100H; (* Stop transmission of break *)
- XUARTPS_CR_STARTBRK = 000000080H; (* Set break *)
- XUARTPS_CR_TORST = 000000040H; (* RX timeout counter restart *)
- XUARTPS_CR_TX_DIS = 000000020H; (* TX disabled. *)
- XUARTPS_CR_TX_EN = 000000010H; (* TX enabled *)
- XUARTPS_CR_RX_DIS = 000000008H; (* RX disabled. *)
- XUARTPS_CR_RX_EN = 000000004H; (* RX enabled *)
- XUARTPS_CR_EN_DIS_MASK = 00000003CH; (* Enable/disable Mask *)
- XUARTPS_CR_TXRST = 000000002H; (* TX logic reset *)
- XUARTPS_CR_RXRST = 000000001H; (* RX logic reset *)
-
- CTRLSTOPBRK = 8; (* Stop transmission of break *)
- CTRLSTARTBRK = 7; (* Set break *)
- CTRLTORST = 6; (* RX timeout counter restart *)
- CTRLTX_DIS = 5; (* TX disabled. *)
- CTRLTX_EN = 4; (* TX enabled *)
- CTRLRX_DIS = 3; (* RX disabled. *)
- CTRLRX_EN = 2; (* RX enabled *)
- CTRLTXRST = 1; (* TX logic reset *)
- CTRLRXRST = 0; (* RX logic reset *)
- (* Mode Register Bit Definition
- The mode register (MR) defines the mode of transfer as well as the data
- format. If this register is modified during transmission or reception,
- data validity cannot be guaranteed.
- *)
- XUARTPS_MR_CCLK = 000000400H; (* Input clock selection *)
- XUARTPS_MR_CHMODE_R_LOOP = 000000300H; (* Remote loopback mode *)
- XUARTPS_MR_CHMODE_L_LOOP = 000000200H; (* Local loopback mode *)
- XUARTPS_MR_CHMODE_ECHO = 000000100H; (* Auto echo mode *)
- XUARTPS_MR_CHMODE_NORM = 000000000H; (* Normal mode *)
- XUARTPS_MR_CHMODE_SHIFT = 8; (* Mode shift *)
- XUARTPS_MR_CHMODE_MASK = 000000300H; (* Mode mask *)
- XUARTPS_MR_STOPMODE_2_BIT = 000000080H; (* 2 stop bits *)
- XUARTPS_MR_STOPMODE_1_5_BIT = 000000040H; (* 1.5 stop bits *)
- XUARTPS_MR_STOPMODE_1_BIT = 000000000H; (* 1 stop bit *)
- XUARTPS_MR_STOPMODE_SHIFT = 6; (* Stop bits shift *)
- XUARTPS_MR_STOPMODE_MASK = 0000000A0H; (* Stop bits mask *)
- XUARTPS_MR_PARITY_NONE = 000000020H; (* No parity mode *)
- XUARTPS_MR_PARITY_MARK = 000000018H; (* Mark parity mode *)
- XUARTPS_MR_PARITY_SPACE = 000000010H; (* Space parity mode *)
- XUARTPS_MR_PARITY_ODD = 000000008H; (* Odd parity mode *)
- XUARTPS_MR_PARITY_EVEN = 000000000H; (* Even parity mode *)
- XUARTPS_MR_PARITY_SHIFT = 3; (* Parity setting shift *)
- XUARTPS_MR_PARITY_MASK = 000000038H; (* Parity mask *)
- XUARTPS_MR_CHARLEN_6_BIT = 000000006H; (* 6 bits data *)
- XUARTPS_MR_CHARLEN_7_BIT = 000000004H; (* 7 bits data *)
- XUARTPS_MR_CHARLEN_8_BIT = 000000000H; (* 8 bits data *)
- XUARTPS_MR_CHARLEN_SHIFT = 1; (* Data Length shift *)
- XUARTPS_MR_CHARLEN_MASK = 000000006H; (* Data length mask *)
- XUARTPS_MR_CLKSEL = 000000001H; (* Input clock selection *)
- (** Interrupt Registers
- Interrupt control logic uses the interrupt enable register (IER) and the
- interrupt disable register (IDR) to set the value of the bits in the
- interrupt mask register (IMR). The IMR determines whether to pass an
- interrupt to the interrupt status register (ISR).
- Writing a 1 to IER Enbables an interrupt, writing a 1 to IDR disables an
- interrupt. IMR and ISR are read only, and IER and IDR are write only.
- Reading either IER or IDR returns 0x00.
- All four registers have the same bit definitions.
- *)
- XUARTPS_IXR_TOVR = 000001000H; (** Tx FIFO Overflow interrupt *)
- XUARTPS_IXR_TNFUL = 000000800H; (** Tx FIFO Nearly Full interrupt *)
- XUARTPS_IXR_TTRIG = 000000400H; (** Tx Trig interrupt *)
- XUARTPS_IXR_DMS = 000000200H; (** Modem status change interrupt *)
- XUARTPS_IXR_TOUT = 000000100H; (** Timeout error interrupt *)
- XUARTPS_IXR_PARITY = 000000080H; (** Parity error interrupt *)
- XUARTPS_IXR_FRAMING = 000000040H; (** Framing error interrupt *)
- XUARTPS_IXR_OVER = 000000020H; (** Overrun error interrupt *)
- XUARTPS_IXR_TXFULL = 000000010H; (** TX FIFO full interrupt. *)
- XUARTPS_IXR_TXEMPTY = 000000008H; (** TX FIFO empty interrupt. *)
- XUARTPS_IXR_RXFULL = 000000004H; (** RX FIFO full interrupt. *)
- XUARTPS_IXR_RXEMPTY = 000000002H; (** RX FIFO empty interrupt. *)
- XUARTPS_IXR_RXOVR = 000000001H; (** RX FIFO trigger interrupt. *)
- IRQTOVR = 12; (** Tx FIFO Overflow interrupt *)
- IRQTNFUL = 11; (** Tx FIFO Nearly Full interrupt *)
- IRQTTRIG = 10; (** Tx Trig interrupt *)
- IRQDMS = 9; (** Modem status change interrupt *)
- IRQTOUT = 8; (** Timeout error interrupt *)
- IRQPARITY = 7; (** Parity error interrupt *)
- IRQFRAMING = 6; (** Framing error interrupt *)
- IRQOVER = 5; (** Overrun error interrupt *)
- IRQTXFULL = 4; (** TX FIFO full interrupt. *)
- IRQTXEMPTY = 3; (** TX FIFO empty interrupt. *)
- IRQRXFULL = 2; (** RX FIFO full interrupt. *)
- IRQRXEMPTY = 1; (** RX FIFO empty interrupt. *)
- IRQRXFIFO = 0; (** RX FIFO trigger interrupt. *)
-
- XUARTPS_IXR_MASK = 000001FFFH; (** Valid bit mask *)
- (** Channel Status Register
- The channel status register (CSR) is provided to enable the control logic
- to monitor the status of bits in the channel interrupt status register,
- even if these are masked out by the interrupt mask register.
- *)
- XUARTPS_SR_TNFUL = 000004000H; (** TX FIFO Nearly Full Status *)
- XUARTPS_SR_TTRIG = 000002000H; (** TX FIFO Trigger Status *)
- XUARTPS_SR_FLOWDEL = 000001000H; (** RX FIFO fill over flow delay *)
- XUARTPS_SR_TACTIVE = 000000800H; (** TX active *)
- XUARTPS_SR_RACTIVE = 000000400H; (** RX active *)
- XUARTPS_SR_DMS = 000000200H; (** Delta modem status change *)
- XUARTPS_SR_TOUT = 000000100H; (** RX timeout *)
- XUARTPS_SR_PARITY = 000000080H; (** RX parity error *)
- XUARTPS_SR_FRAME = 000000040H; (** RX frame error *)
- XUARTPS_SR_OVER = 000000020H; (** RX overflow error *)
- XUARTPS_SR_TXFULL = 000000010H; (** TX FIFO full *)
- XUARTPS_SR_TXEMPTY = 000000008H; (** TX FIFO empty *)
- XUARTPS_SR_RXFULL = 000000004H; (** RX FIFO full *)
- XUARTPS_SR_RXEMPTY = 000000002H; (** RX FIFO empty *)
- XUARTPS_SR_RXOVR = 000000001H; (** RX FIFO fill over trigger *)
- SR_TNFUL = 14; (** TX FIFO Nearly Full Status *)
- SR_TTRIG = 13; (** TX FIFO Trigger Status *)
- SR_FLOWDEL = 12; (** RX FIFO fill over flow delay *)
- SR_TACTIVE = 11; (** TX active *)
- SR_RACTIVE = 10; (** RX active *)
- SR_DMS = 9; (** Delta modem status change *)
- SR_TOUT = 8; (** RX timeout *)
- SR_PARITY = 7; (** RX parity error *)
- SR_FRAME = 6; (** RX frame error *)
- SR_OVER = 5; (** RX overflow error *)
- SR_TXFULL = 4; (** TX FIFO full *)
- SR_TXEMPTY = 3; (** TX FIFO empty *)
- SR_RXFULL = 2; (** RX FIFO full *)
- SR_RXEMPTY = 1; (** RX FIFO empty *)
- SR_RXOVR = 0; (** RX FIFO fill over trigger *)
- (* The following constant defines the amount of error that is allowed for
- a specified baud rate. This error is the difference between the actual
- baud rate that will be generated using the specified clock and the
- desired baud rate.
- *)
- XUARTPS_MAX_BAUD_ERROR_RATE = 3; (* max % error allowed *)
-
- UARTBUFLEN = 2048;
-
- PSUART0 = 0;
- PSUART1 = 1;
-
- TYPE
- UARTBuffer = ARRAY UARTBUFLEN OF SYSTEM.BYTE;
- UartDesc* = RECORD ( Device.DeviceDesc )
- id: LONGINT;
- baseAddr: LONGINT; (* Adress of Base register *)
- clockFrequency: LONGINT; (* the clock used for the UART *)
- in, out, oin, oout: LONGINT; (* And and Out index in in (in, out) and outbuffer (oin, oout) *)
- baudrate: LONGINT; (* Baudrate *)
- parity: LONGINT; (* Parity *)
- databits: LONGINT; (* Number of data bits *)
- trace: BOOLEAN; (* shall debug output be printed via Log? *)
- open: BOOLEAN; (* Is the uart already initialised and open? *)
- irqCnt: LONGINT;
- irqEnabled: BOOLEAN; (* true, if this UART is handled by interrupts *)
- inbuffer, outbuffer: UARTBuffer; (* receive and sendbuffer *)
- timeoutActive : BOOLEAN; (* if the timeout counter has been set *)
- txIrqActive : BOOLEAN;
- END;
-
- UartCfg = RECORD
- addr : LONGINT;
- clock : LONGINT;
- END;
-
- Uart* = POINTER TO UartDesc;
-
- VAR
- uarts: ARRAY 2 OF Uart;
- (**
- Initialize a UART controller given its configuration information
- *)
- PROCEDURE Init*( VAR uart: Uart; CONST cfg: UartCfg);
- VAR
- res: LONGINT;
- BEGIN
-
- uart.baseAddr := cfg.addr;
- uart.clockFrequency := cfg.clock;
- (* disable all UART interrupts *)
- SYSTEM.PUT32( uart.baseAddr+XUARTPS_IDR_OFFSET, 0FFFFFFFFH );
- uart.irqEnabled := FALSE;
- (* Set the default baudrate *)
-
- (*Trace.StringLn("Entering SetBaudrate.");
- SetBaudrate( uart, DefaultBaudrate, res);*)
-
- END Init;
-
- PROCEDURE DoIrq( CONST no : LONGINT );
- VAR
- uart : Uart;
- reg, ireg : SET;
- cnt : LONGINT;
- tort : BOOLEAN;
- BEGIN
-
- tort := FALSE;
-
- IF ( GetUartByIndex( no, uart )) THEN
-
- (* check the timout flag and the fifo flag first *)
- SYSTEM.GET( uart.baseAddr+XUARTPS_ISR_OFFSET, ireg );
-
- IF (IRQRXFIFO IN ireg ) OR (IRQTOUT IN ireg ) THEN
-
- SYSTEM.GET( uart.baseAddr+XUARTPS_SR_OFFSET, reg );
-
- WHILE ( ~(SR_RXEMPTY IN reg )) DO
- uart.inbuffer[ uart.in ] := CHR( SYSTEM.GET32( uart.baseAddr+XUARTPS_FIFO_OFFSET ));
- uart.in := ( uart.in + 1 ) MOD UARTBUFLEN;
- SYSTEM.GET( uart.baseAddr+XUARTPS_SR_OFFSET, reg );
- END;
-
- (* clear the flags now *)
- uart.timeoutActive := FALSE;
-
- END;
-
- IF ( IRQTXEMPTY IN ireg ) THEN
-
- cnt := 0;
-
- (* there is still data in the TX buffer, send it to the FIFO *)
- WHILE ( uart.oin # uart.oout ) & ( cnt < 60 ) DO
-
- SYSTEM.PUT32( uart.baseAddr+XUARTPS_FIFO_OFFSET, ORD(uart.outbuffer[uart.oout]) );
- uart.oout:= ( uart.oout+1 ) MOD UARTBUFLEN;
-
- INC( cnt )
-
- END;
-
- (* Trace.String("d");*)
-
- IF ( uart.oin = uart.oout ) THEN
- (* set the flag to get the TX monitor to check the FIFO again *)
- uart.txIrqActive := FALSE;
-
- (* disable the TX interrupt *)
- SYSTEM.GET( uart.baseAddr+ XUARTPS_IER_OFFSET, reg );
- reg := reg - { IRQTXEMPTY };
- SYSTEM.PUT( uart.baseAddr+ XUARTPS_IER_OFFSET, reg );
-
- (* Trace.String("(di)"); *)
-
- END;
- END;
-
- SYSTEM.PUT( uart.baseAddr+XUARTPS_ISR_OFFSET, ireg );
- END;
- END DoIrq;
-
- PROCEDURE PSUartIrqHandler( irq: LONGINT );
- BEGIN
- (* check the IRQ source *)
- IF ( irq = Interrupts.PSUART0IRQ ) THEN
- DoIrq( 0 );
- ELSIF ( irq = Interrupts.PSUART1IRQ ) THEN
- DoIrq( 1 );
- ELSE
- Trace.StringLn("PSUart: Unknown IRQ call!");
- END;
- END PSUartIrqHandler;
- (**
- Set UART baudrate
- res: error code, 0 in case of success
- *)
- PROCEDURE SetBaudrate*( VAR uart: Uart; CONST baudrate: LONGINT; VAR res: LONGINT );
- VAR
- reg: SET;
- inputClk: LONGINT;
- valBAUDDIV, valBRGR, calcBaudrate, baudError: LONGINT;
- bestError, bestBRGR, bestBAUDDIV: LONGINT;
- BEGIN
-
- bestError := MAX(LONGINT);(*1000;*)
-
- (*
- Make sure the baud rate is not impossilby large.
- Fastest possible baud rate is Input Clock / 2
- *)
- Trace.String("Entering SetBaudrate : "); Trace.Int( baudrate, 10 ); Trace.Ln;
- IF baudrate*2 > uart.clockFrequency THEN res := 1; RETURN; END;
- inputClk := uart.clockFrequency;
- Trace.String("Input Clock is : "); Trace.Int( inputClk, 10 ); Trace.Ln;
- (* Check whether the input clock is divided by 8 *)
- SYSTEM.GET( uart.baseAddr+XUARTPS_MR_OFFSET, reg );
- IF XUARTPS_MR_CLKSEL IN reg THEN
- Trace.StringLn("Input Clock is Divided by 8");
- inputClk := inputClk DIV 8;
- END;
-
- (* Determine the Baud divider. It can be 4 to 254.
- Loop through all possible combinations *)
- FOR valBAUDDIV := 4 TO 255 DO
- (* Calculate the value for BRGR register *)
- valBRGR := inputClk DIV (baudrate * (valBAUDDIV + 1));
- IF ( valBRGR > 0 ) THEN
-
- (* Calculate the baud rate from the BRGR value *)
- calcBaudrate := inputClk DIV (valBRGR * (valBAUDDIV + 1));
-
- (* Avoid unsigned integer underflow *)
- IF baudrate > calcBaudrate THEN
- baudError := baudrate - calcBaudrate;
- ELSE
- baudError := calcBaudrate - baudrate;
- END;
- (*
- Find the calculated baud rate closest to requested baud rate.
- *)
- IF baudError < bestError THEN
- bestBRGR := valBRGR;
- bestBAUDDIV := valBAUDDIV;
- bestError := baudError;
- END;
- END;
- END;
- (*
- Make sure the best error is not too large.
- *)
- IF (bestError * 100) DIV baudrate > XUARTPS_MAX_BAUD_ERROR_RATE THEN (* baudrate error *)
- Trace.String("Baud Error : "); Trace.Int(( bestError *100 ) DIV baudrate, 3 ); Trace.StringLn("; Bailing out, Error too large.");
- res := 1; RETURN;
- END;
- (*
- Disable TX and RX to avoid glitches when setting the baud rate.
- *)
-
- Trace.String("CD : "); Trace.Int( bestBRGR, 10 ); Trace.Ln;
- Trace.String("DIV : "); Trace.Int( bestBAUDDIV, 10 ); Trace.Ln;
- Trace.String("Actual baudrate: "); Trace.Int(inputClk DIV (bestBRGR * (bestBAUDDIV + 1)), 0); Trace.Ln;
-
- (* INVESTIGATE: Unclear why this works for UART1, but not for UART0 *)
- IF ( uart.id # 0 ) THEN
- Enable( uart, FALSE );
- END;
-
- (* write baudrate settings *)
- SYSTEM.PUT( uart.baseAddr+XUARTPS_BAUDGEN_OFFSET, bestBRGR );
- SYSTEM.PUT( uart.baseAddr+XUARTPS_BAUDDIV_OFFSET, bestBAUDDIV );
-
- IF ( uart.id # 0 ) THEN
- Enable( uart, TRUE );
- END;
-
- uart.baudrate := baudrate;
- END SetBaudrate;
- (** Enable/Disable the transmitter and receiver of the UART *)
- PROCEDURE Enable*( CONST uart: Uart; enable: BOOLEAN );
- VAR reg: SET;
- tmp : LONGINT;
- BEGIN
- SYSTEM.GET(uart.baseAddr+XUARTPS_CR_OFFSET, reg );
- IF enable THEN
- reg := reg + { CTRLTX_EN, CTRLRX_EN } - { CTRLTX_DIS, CTRLRX_DIS };
- ELSE
- reg := reg + { CTRLTX_DIS, CTRLRX_DIS } - { CTRLTX_EN, CTRLRX_EN };
- END;
- SYSTEM.PUT( uart.baseAddr+XUARTPS_CR_OFFSET, reg );
- (* set the timeout counter of the UART to 255, used for transfering small amount of data to the buffer before the FIFO trigger level is reached *)
- SYSTEM.PUT( uart.baseAddr+XUARTPS_RXTOUT_OFFSET, 255 );
-
- END Enable;
-
- (* select the UART by index, return TRUE if successful *)
- PROCEDURE GetUartByIndex( CONST no : LONGINT; VAR uart : Uart ) : BOOLEAN;
- VAR
- ret : BOOLEAN;
- BEGIN
- uart := NIL;
- ret := FALSE;
-
- IF ( no = 0 ) OR ( no = 1 ) THEN
- uart := uarts[ no ];
- ret := TRUE;
- END;
-
- RETURN ret;
-
- END GetUartByIndex;
-
-
- PROCEDURE EnableIrqMode*( CONST no : LONGINT; FifoLevel : LONGINT );
- VAR
- reg : SET;
- uart : Uart;
- BEGIN
- IF ( GetUartByIndex( no, uart )) THEN
-
- IF ( uart.id = 0 ) THEN
- Interrupts.EnableIrq( Interrupts.PSUART0IRQ );
- ELSE
- Interrupts.EnableIrq( Interrupts.PSUART1IRQ );
- END;
-
- (* set the fifo RX trigger level to 32 *)
- SYSTEM.PUT( uart.baseAddr+XUARTPS_RXWM_OFFSET, 32 );
-
- (* set the bits in the enable register *)
- SYSTEM.PUT( uart.baseAddr+ XUARTPS_IER_OFFSET, { IRQTOUT, IRQRXFIFO } );
-
- (* read back the mask register *)
- SYSTEM.GET( uart.baseAddr+ XUARTPS_IMR_OFFSET, reg );
- Trace.String("Uart IRQ Mask : "); Trace.Bits( reg, 0, 32 ); Trace.Ln;
- (* clear the interrupt status register *)
- SYSTEM.GET( uart.baseAddr+ XUARTPS_ISR_OFFSET, reg );
- reg := reg - { IRQTOUT, IRQRXFIFO };
- SYSTEM.PUT( uart.baseAddr+ XUARTPS_ISR_OFFSET, reg );
-
- Trace.String("Writing back Status Reg with : "); Trace.Bits( reg, 0, 32 ); Trace.Ln;
-
- (* setup the timeout counter on the IRQ register *)
-
- END;
-
- END EnableIrqMode;
-
- PROCEDURE ShowIrqStatus*(CONST no : LONGINT );
- VAR
- reg : SET;
- uart : Uart;
- BEGIN
- IF ( GetUartByIndex( no, uart )) THEN
- SYSTEM.GET( uart.baseAddr+XUARTPS_ISR_OFFSET, reg );
- Trace.String("IRQ Status ("); Trace.Int( no, 1 ); Trace.String(") : "); Trace.Bits( reg, 0, 32 ); Trace.Ln;
- SYSTEM.GET( uart.baseAddr+ XUARTPS_IER_OFFSET, reg );
- Trace.String("IRQ Enable ("); Trace.Int( no, 1 ); Trace.String(") : "); Trace.Bits( reg, 0, 32 ); Trace.Ln;
- SYSTEM.GET( uart.baseAddr+ XUARTPS_IDR_OFFSET, reg );
- Trace.String("IRQ Disable("); Trace.Int( no, 1 ); Trace.String(") : "); Trace.Bits( reg, 0, 32 ); Trace.Ln;
- SYSTEM.GET( uart.baseAddr+ XUARTPS_IMR_OFFSET, reg );
- Trace.String("IRQ Mask ("); Trace.Int( no, 1 ); Trace.String(") : "); Trace.Bits( reg, 0, 32 ); Trace.Ln;
- END;
-
- END ShowIrqStatus;
-
- PROCEDURE ShowUartSettings*( CONST no : LONGINT );
- CONST
- OFF = 16;
- VAR
- uart : Uart;
- reg : SET;
- cd, bdiv : LONGINT;
- sampleClk, baudClk : REAL;
- BEGIN
- IF ( GetUartByIndex( no, uart )) THEN
-
- SYSTEM.GET( uart.baseAddr+XUARTPS_BAUDGEN_OFFSET , cd );
- SYSTEM.GET( uart.baseAddr+XUARTPS_BAUDDIV_OFFSET , bdiv );
- SYSTEM.GET( uart.baseAddr+XUARTPS_CR_OFFSET, reg );
-
- sampleClk := UartInputClockHz / bdiv;
- baudClk := UartInputClockHz / ( cd * ( bdiv + 1));
- Trace.Ln;
- Trace.Ln;
- Trace.StringLn("*** PS UART Settings ***");
- Trace.Ln;
-
- Trace.StringA("Uart No", OFF, TRUE ); Trace.Int( no, 1 ); Trace.Ln;
-
- Trace.StringA("TX Enable", OFF, TRUE ); Trace.Bits( reg, CTRLTX_EN, 1 ); Trace.Ln;
- Trace.StringA("TX Disable", OFF, TRUE ); Trace.Bits( reg, CTRLTX_DIS, 1 ); Trace.Ln;
- Trace.StringA("RX Enable", OFF, TRUE ); Trace.Bits( reg, CTRLRX_EN, 1 ); Trace.Ln;
- Trace.StringA("RX Disable", OFF, TRUE ); Trace.Bits( reg, CTRLRX_DIS, 1 ); Trace.Ln;
- Trace.StringA("TX TO Rst", OFF, TRUE ); Trace.Bits( reg, CTRLTORST, 1); Trace.Ln;
- Trace.StringA("CD Value", OFF, TRUE ); Trace.Int( cd, 8 ); Trace.Ln;
- Trace.StringA("BD Value", OFF, TRUE ); Trace.Int( bdiv, 8 ); Trace.Ln;
- Trace.StringA("Sample Clk [Hz]", OFF, TRUE ); Trace.Real( sampleClk, 0, 8 ); Trace.Ln;
- Trace.StringA("Baud Clk [Hz]", OFF, TRUE ); Trace.Real( baudClk, 0, 8 ); Trace.Ln;
-
- Trace.Ln;
-
- END;
- END ShowUartSettings;
-
- (**
- Send data to the UART
- *)
- PROCEDURE Send*(CONST uart: Uart; CONST buf: ARRAY OF CHAR; offs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT);
- VAR csr: SET;
- BEGIN
- res := 0;
- IF uart.irqEnabled THEN
- (*
- Disable the UART transmit interrupts to allow this call to stop a
- previous operation that may be interrupt driven.
- *)
- SYSTEM.PUT32(uart.baseAddr+XUARTPS_IDR_OFFSET,XUARTPS_IXR_TXEMPTY+XUARTPS_IXR_TXFULL);
- HALT(100); (*! Not yet implemented! *)
- ELSE
- WHILE len > 0 DO
- csr := SYSTEM.VAL(SET,SYSTEM.GET32(uart.baseAddr+XUARTPS_SR_OFFSET)); (* current state of Channel Status Register *)
- IF csr * SYSTEM.VAL(SET,XUARTPS_SR_TXFULL) # SYSTEM.VAL(SET,XUARTPS_SR_TXFULL) THEN (* there is place for at minimum one byte in TX FIFO *)
- SYSTEM.PUT32(uart.baseAddr+XUARTPS_FIFO_OFFSET,ORD(buf[offs]));
- INC(offs); DEC(len);
- IF (len > 0) & (csr * SYSTEM.VAL(SET,XUARTPS_SR_TNFUL) # SYSTEM.VAL(SET,XUARTPS_SR_TNFUL)) THEN (* there is place for at minimum two bytes in TX FIFO *)
- SYSTEM.PUT32(uart.baseAddr+XUARTPS_FIFO_OFFSET,ORD(buf[offs]));
- INC(offs); DEC(len);
- END;
- END;
- END;
- END;
- END Send;
- (**
- Receive data from the UART
- *)
- PROCEDURE Receive*(CONST uart: Uart; VAR buf: ARRAY OF CHAR; offs, size, min: LONGINT; VAR len, res: LONGINT);
- BEGIN
- res := 0;
- len := 0;
- min := MIN(size,min);
- WHILE (min > 0) OR UartAvailable(uart) DO
- WHILE (size > 0) & (SYSTEM.VAL(SET,SYSTEM.GET32(uart.baseAddr+XUARTPS_SR_OFFSET)) * SYSTEM.VAL(SET,XUARTPS_SR_RXEMPTY) # SYSTEM.VAL(SET,XUARTPS_SR_RXEMPTY)) DO
- buf[offs] := CHR(SYSTEM.GET32(uart.baseAddr+XUARTPS_FIFO_OFFSET));
- DEC(min); DEC(size); INC(offs); INC(len);
- END;
- END;
- END Receive;
- (** Send a single character to the UART
- Remarks:
- blocks until the transmit buffer is not full
- *)
- PROCEDURE SendChar*(CONST uart: Uart; ch: CHAR; VAR res: LONGINT);
- BEGIN
- (* Wait until there is space in TX FIFO *)
- WHILE SYSTEM.VAL(SET,SYSTEM.GET32(uart.baseAddr+XUARTPS_SR_OFFSET)) * SYSTEM.VAL(SET,XUARTPS_SR_TXFULL) = SYSTEM.VAL(SET,XUARTPS_SR_TXFULL) DO
- END;
- (* Write the byte into the TX FIFO *)
- SYSTEM.PUT32( uart.baseAddr+XUARTPS_FIFO_OFFSET,ORD(ch));
-
- END SendChar;
- (** Receive a single character from UART
- Remarks:
- blocks until a character is available
- *)
- PROCEDURE ReceiveChar*( CONST uart: Uart; VAR res: LONGINT ): CHAR;
- BEGIN
- (* wait until data is available *)
- WHILE SYSTEM.VAL(SET,SYSTEM.GET32(uart.baseAddr+XUARTPS_SR_OFFSET)) * SYSTEM.VAL(SET,XUARTPS_SR_RXEMPTY) = SYSTEM.VAL(SET,XUARTPS_SR_RXEMPTY) DO
- END;
- RETURN CHR(SYSTEM.GET32(uart.baseAddr+XUARTPS_FIFO_OFFSET));
- END ReceiveChar;
- (** Returns TRUE if there is at least 1 char in the receive buffer *)
- PROCEDURE UartAvailable*(CONST uart: Uart): BOOLEAN;
- VAR
- reg : SET;
- BEGIN
- SYSTEM.GET( uart.baseAddr+XUARTPS_SR_OFFSET, reg );
- IF ( SR_RXEMPTY IN reg ) THEN
- RETURN FALSE;
- ELSE
- RETURN TRUE;
- END;
- END UartAvailable;
-
- (* close the device *)
- PROCEDURE Close(dev: Device.Device);
- BEGIN
- Trace.String("In Uart close, adr : "); Trace.Hex( dev(Uart).baseAddr, -8 ); Trace.String(", id is : "); Trace.Int( dev(Uart).id, 2 ); Trace.Ln;
- IF dev(Uart).open = TRUE THEN
- Enable( dev(Uart), FALSE );
- dev(Uart).open := FALSE
- END
- END Close;
- (* Bytes available for read *)
- PROCEDURE Available( dev: Device.Device ): LONGINT;
- BEGIN
- (*DoUart( dev(Uart));*)
- RETURN (dev(Uart).in - dev(Uart).out) MOD UARTBUFLEN;
- END Available;
- (* Get the number of bytes that are free in the send buffer *)
- PROCEDURE Free( dev: Device.Device ): LONGINT;
- VAR
- avail: LONGINT;
- BEGIN
- avail := UARTBUFLEN - 1 - ((dev(Uart).oin - dev(Uart).oout) MOD UARTBUFLEN );
- RETURN avail
- END Free;
-
- PROCEDURE Write( dev: Device.Device; CONST buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
- VAR
- end, free: LONGINT;
- uart: Uart;
- BEGIN
- IF (len > 0) & (ofs >= 0) THEN
- uart := dev(Uart);
- free := Free(dev);
- IF free < len THEN len := free END;
- end := ofs + len;
- WHILE ofs < end DO
- uart.outbuffer[ uart.oin ] := buf[ ofs ];
- uart.oin := ( uart.oin + 1 ) MOD UARTBUFLEN;
- INC( ofs )
- END;
- ELSE
- len := 0
- END;
-
- (* HACK
- DoUart( uart );
- *)
-
- END Write;
- PROCEDURE Read( dev: Device.Device; VAR buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
- VAR
- end, available: LONGINT;
- uart: Uart;
- BEGIN
-
- (* HACK
- uart := dev(Uart);
- DoUart( uart );
- *)
-
- IF (len > 0) & (ofs >= 0) THEN
- uart := dev(Uart);
- available := Available(dev);
- IF available < len THEN len := available END;
- end := ofs + len;
- WHILE ofs < end DO
- buf[ofs] := uart.inbuffer[ uart.out ];
- uart.out := ( uart.out + 1 ) MOD UARTBUFLEN;
- INC( ofs )
- END;
- ELSE
- len := 0
- END
- END Read;
- PROCEDURE Flush( dev: Device.Device );
- VAR
- base: LONGINT;
- value : SET;
- BEGIN
- base := dev(Uart).baseAddr;
- Trace.String("*** Entering Flush : "); Trace.Hex( base, -8 ); Trace.Ln;
- REPEAT UNTIL Free( dev(Uart) ) = UARTBUFLEN - 1;
- REPEAT SYSTEM.GET( base+XUARTPS_SR_OFFSET, value ) UNTIL SR_TXEMPTY IN value;
- END Flush;
- PROCEDURE EmptyFifo( CONST no : LONGINT );
- VAR
- used, res: LONGINT;
- uart : Uart;
- BEGIN
- IF ( GetUartByIndex( no, uart )) THEN
- IF ( UartAvailable( uart )) THEN
- used := ( uart.in - uart.out ) MOD UARTBUFLEN;
- IF used < UARTBUFLEN - 1 THEN
- uart.inbuffer[ uart.in ] := ReceiveChar( uart, res );
- uart.in := ( uart.in + 1 ) MOD UARTBUFLEN;
- INC(used)
- END;
- END;
- END;
- END EmptyFifo;
- PROCEDURE CheckRxFifo( uart: Uart);
- VAR
- reg : SET;
- BEGIN
- IF ( UartAvailable( uart ) ) & ~uart.timeoutActive THEN
- (* Trace.String("(cr)"); *)
- (* if there is a char in the FIFO, set the timeout counter to IRQ on timeout *)
- SYSTEM.GET( uart.baseAddr+XUARTPS_CR_OFFSET, reg );
- reg := reg + { CTRLTORST };
- SYSTEM.PUT( uart.baseAddr+XUARTPS_CR_OFFSET, reg );
- uart.timeoutActive := TRUE;
- END;
- END CheckRxFifo;
- PROCEDURE CheckTxBuffer( uart : Uart );
- VAR
- reg : SET;
- BEGIN
-
- (* Trace.String("(ct)"); *)
-
- IF ( uart.oin # uart.oout ) & ( ~uart.txIrqActive ) THEN
-
- (* there is data in the buffer, arm the IRQ to trigger on empty TX FIFO *)
- SYSTEM.GET( uart.baseAddr+ XUARTPS_IER_OFFSET, reg );
- reg := reg + { IRQTXEMPTY };
- SYSTEM.PUT( uart.baseAddr+ XUARTPS_IER_OFFSET, reg );
-
- (* Trace.String("(ei)"); *)
- uart.txIrqActive := TRUE;
-
- UartHandler( uart, 2 );
-
- END;
- END CheckTxBuffer;
-
- PROCEDURE UartHandler( uart: Uart; CONST size : LONGINT );
- VAR
- res, k: LONGINT;
- BEGIN
-
- INC( uart.irqCnt );
- k := 0;
-
- WHILE ( uart.oin # uart.oout ) & ( k < size ) DO
-
- (*
- SendChar( uart, uart.outbuffer[uart.oout], res ); (* put to fifo *)
- Trace.String("out="); Trace.Hex( uart.out , -8 ); Trace.Ln;
- Trace.String("add="); Trace.Hex( ADDRESSOF( uart.outbuffer ), -8 ); Trace.Ln;
- *)
- SYSTEM.PUT32( uart.baseAddr+XUARTPS_FIFO_OFFSET, ORD( uart.outbuffer[ uart.oout ] ));
- uart.oout:= ( uart.oout+1 ) MOD UARTBUFLEN;
-
- INC(k)
-
- END;
- END UartHandler;
- PROCEDURE Command( dev: Device.Device; cmd, param: LONGINT; VAR res: LONGINT );
- VAR
- reg: SET;
- uart: Uart;
- BEGIN
- res := 0;
- uart := dev(Uart);
- CASE cmd OF
- UartConstants.SETBAUDRATE: uart.baudrate := param
- | UartConstants.SETPARITY: uart.parity := param
- | UartConstants.SETDATABITS: uart.databits := param
- END
- END Command;
-
- PROCEDURE DoUartCheck*();
- VAR
- uart : Uart;
- BEGIN
-
- CheckRxFifo( uarts[0] );
- CheckTxBuffer( uarts[0] );
-
- CheckRxFifo( uarts[1] );
- CheckTxBuffer( uarts[1] );
- END DoUartCheck;
- PROCEDURE Open( dev: Device.Device );
- VAR
- uart: Uart;
- res: LONGINT;
- BEGIN
-
- Trace.StringLn("Entering Open().");
-
- uart := dev(Uart);
-
- Trace.String("Open is trying to open id : "); Trace.Int( uart.id, 2); Trace.String(", "); Trace.Hex( uart.baseAddr, -8 ); Trace.Ln;
-
-
- IF ( uart = NIL ) THEN Trace.StringLn("Uart.Open( dev ) is nil"); END;
- IF ( uart.open ) THEN Trace.StringLn("Uart.Open( dev ) is open"); END;
-
- IF (uart # NIL) & (~uart.open) THEN
-
- Trace.StringLn("Setting baudrate and opening Uart.");
-
- (* reset the pointers to the ring buffer *)
- uart.in := 0;
- uart.out := 0;
- uart.oin := 0;
- uart.oout := 0;
-
- SetBaudrate( uart, uart.baudrate, res );
- Enable( uart, TRUE );
-
- uart.open := TRUE;
-
- ELSE
- Trace.StringLn("Uart.Open(dev) failed.");
- END
- END Open;
-
- (**
- Install all UART controllers present in the system (according to the constants set in Platform); to be called by the Kernel
- *)
- PROCEDURE Install*;
- VAR
- cfg: UartCfg;
- i, res: LONGINT;
- BEGIN
-
- Trace.StringLn("Entering UART install");
-
- FOR i := 0 TO UartNb-1 DO
-
- Trace.String("Init PSUART "); Trace.Int( i, 1 ); Trace.Ln;
-
- NEW( uarts[i] );
-
- (* init the object with the base initializer *)
- Device.InitDevice( uarts[ i ] );
-
- (* assign the function calls *)
- uarts[ i ].Open := Open;
- uarts[ i ].Close := Close;
- uarts[ i ].Write := Write;
- uarts[ i ].Read := Read;
- uarts[ i ].Available := Available;
- uarts[ i ].Free := Free;
- uarts[ i ].Command := Command;
- uarts[ i ].Flush := Flush;
- uarts[ i ].id := i;
-
- uarts[ i ].in := 0;
- uarts[ i ].out := 0;
- uarts[ i ].oin := 0;
- uarts[ i ].oout := 0;
-
- uarts[ i ].timeoutActive := FALSE;
- uarts[ i ].txIrqActive := FALSE;
-
- IF i = 0 THEN
- cfg.addr := UartBaseAddr0;
- ELSE
- cfg.addr := UartBaseAddr1;
- END;
- cfg.clock := UartInputClockHz;
-
- Trace.StringLn("Entering Init for PSUART");
-
- Init( uarts[i], cfg );
-
- Trace.StringLn("Exit Init().");
- (*IF ( i # 0 ) THEN
- SetBaudrate( uarts[i], 115200, res );
- Enable( uarts[i], FALSE ); (* disable *)
- uarts[ i ].open := FALSE;
- END;*)
-
- END;
-
- Interrupts.InstallHandler( PSUartIrqHandler, Interrupts.PSUART0IRQ );
- Interrupts.InstallHandler( PSUartIrqHandler, Interrupts.PSUART1IRQ );
-
- Device.Install( uarts[ PSUART0 ], "PSUART0" );
- Device.Install( uarts[ PSUART1 ], "PSUART1" );
-
- END Install;
-
- PROCEDURE Show*();
- BEGIN
- ShowUartSettings( 0 );
- ShowIrqStatus( 0 );
- ShowUartSettings( 1 );
- ShowIrqStatus( 1 );
- END Show;
- BEGIN
- END Uart.
- Uart.Show
|