Zynq.PsUart.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. (**
  2. AUTHOR: Alexey Morozov, Timothee Martiel
  3. PURPOSE: driver implementation for Xilinx Zynq UART PS controller
  4. *)
  5. MODULE PsUart;
  6. IMPORT SYSTEM, PsUartMin, PsUartInterrupts, Trace;
  7. CONST
  8. (** Receive errors - compatible with A2 Serials *)
  9. OverrunError* = 10;
  10. ParityError* = 11;
  11. FramingError* = 12;
  12. BreakInterrupt* = 13;
  13. DefaultRxBufSize* = 4096;
  14. DefaultTxBufSize* = 4096;
  15. ReceiveTimeoutInUs* = 500; (** Receive timeout in microseconds *)
  16. (* RX data interrupts *)
  17. RxDataInterrupts = {PsUartMin.XUARTPS_IXR_TOUT , PsUartMin.XUARTPS_IXR_RXFULL , PsUartMin.XUARTPS_IXR_RXOVR};
  18. (* RX error interrupts *)
  19. RxErrorInterrupts = {PsUartMin.XUARTPS_IXR_PARITY , PsUartMin.XUARTPS_IXR_FRAMING , PsUartMin.XUARTPS_IXR_OVER};
  20. RxInterrupts = RxDataInterrupts + RxErrorInterrupts;
  21. TYPE
  22. UartId* = PsUartMin.UartId;
  23. ClockFrequency* = PsUartMin.ClockFrequency;
  24. UartController* = POINTER TO RECORD
  25. id-: UartId; (** UART controller ID *)
  26. regs-: PsUartMin.UartRegisters; (** controller registers *)
  27. inputClock-: ClockFrequency; (** controller input clock in Hz *)
  28. bps-, data-, parity-, stop-: LONGINT; (** current parameter values *)
  29. open-: BOOLEAN; (** TRUE if the controller is open *)
  30. rxBuf: POINTER TO ARRAY OF CHAR; (* receive (RX) circular buffer *)
  31. rxBufRdPos, rxBufWrPos: SIZE; (* RX buffer read and write positions *)
  32. errors: SET;
  33. END;
  34. VAR
  35. uarts: ARRAY 2 OF UartController;
  36. (* Disable all UART interrupts *)
  37. PROCEDURE DisableInterrupts(regs: PsUartMin.UartRegisters);
  38. BEGIN
  39. regs.idr := PsUartMin.XUARTPS_IXR_MASK;
  40. END DisableInterrupts;
  41. PROCEDURE IntrHandler(param: ANY);
  42. VAR
  43. uart: UartController;
  44. intrStatus: SET;
  45. BEGIN
  46. uart := param(UartController);
  47. intrStatus := uart.regs.imr * uart.regs.isr;
  48. uart.regs.isr := intrStatus; (* clear the interrupt *)
  49. IF intrStatus * RxInterrupts # {} THEN
  50. IntrHandlerRx(uart,intrStatus);
  51. END;
  52. END IntrHandler;
  53. PROCEDURE IntrHandlerRx(uart: UartController; intrStatus: SET);
  54. VAR
  55. bufWrPos: SIZE;
  56. BEGIN
  57. IF intrStatus * RxErrorInterrupts # {} THEN
  58. IF PsUartMin.XUARTPS_IXR_OVER IN intrStatus THEN
  59. INCL(uart.errors,OverrunError);
  60. Trace.String("---rx overrun(1)---: intrStatus="); Trace.Set(intrStatus); Trace.Ln;
  61. RETURN;
  62. END;
  63. END;
  64. bufWrPos := uart.rxBufWrPos;
  65. WHILE ~(PsUartMin.XUARTPS_SR_RXEMPTY IN uart.regs.sr) DO
  66. uart.rxBuf[bufWrPos] := CHR(uart.regs.fifo);
  67. INC(bufWrPos);
  68. IF bufWrPos = LEN(uart.rxBuf) THEN
  69. bufWrPos := 0;
  70. END;
  71. IF bufWrPos = uart.rxBufRdPos THEN
  72. INCL(uart.errors,OverrunError);
  73. Trace.String("---rx overrun(2)---: intrStatus="); Trace.Set(intrStatus); Trace.Ln;
  74. RETURN;
  75. END;
  76. END;
  77. uart.rxBufWrPos := bufWrPos;
  78. END IntrHandlerRx;
  79. (*
  80. Returns TRUE if a cyclic buffer is full
  81. *)
  82. PROCEDURE BufIsFull(bufWrPos, bufRdPos, bufSize: SIZE): BOOLEAN;
  83. BEGIN
  84. IF bufWrPos # (bufSize-1) THEN
  85. RETURN bufRdPos = (bufWrPos+1);
  86. ELSE
  87. RETURN bufRdPos = 0;
  88. END;
  89. END BufIsFull;
  90. (**
  91. Install a UART controller present in the system
  92. uart: ID (0-based index) of the UART controller to install
  93. base: controller base address
  94. inputClock: controller input clock in Hz
  95. res: returned error code, 0 in case of success
  96. *)
  97. PROCEDURE Install* (uart: UartId; base: ADDRESS; inputClock: ClockFrequency; VAR res: WORD);
  98. VAR ctl: UartController;
  99. BEGIN
  100. PsUartMin.Install(uart, base, inputClock, res);
  101. IF res # 0 THEN RETURN; END;
  102. NEW(ctl);
  103. uarts[uart] := ctl;
  104. ctl.id := uart;
  105. ctl.regs := PsUartMin.GetUart(uart);
  106. ctl.inputClock := inputClock;
  107. ctl.open := FALSE;
  108. ctl.bps := PsUartMin.DefaultBPS;
  109. ctl.data := PsUartMin.DefaultDataBits;
  110. ctl.parity := PsUartMin.DefaultParity;
  111. ctl.stop := PsUartMin.DefaultStop;
  112. NEW(ctl.rxBuf,DefaultRxBufSize);
  113. ASSERT(PsUartInterrupts.InstallInterruptHandler(uart,IntrHandler,ctl));
  114. END Install;
  115. (**
  116. Get UART controller with a given ID
  117. uart: UART controller ID
  118. Returns NIL in case if no controller with given ID has been installed
  119. *)
  120. PROCEDURE GetUart*(uart: UartId): UartController;
  121. BEGIN
  122. IF (uart >= 0) & (uart < LEN(uarts)) THEN
  123. RETURN uarts[uart];
  124. ELSE RETURN NIL;
  125. END;
  126. END GetUart;
  127. (**
  128. Open a UART controller
  129. uart: UART controller
  130. bps: baudrate
  131. data: number of data bits
  132. parity: parity control
  133. stop: number of stop bits
  134. res: returned error code, 0 in case of success
  135. *)
  136. PROCEDURE Open*(uart: UartController; bps, data, parity, stop: LONGINT; VAR res: WORD);
  137. VAR n: SIZE;
  138. BEGIN
  139. IF uart.open THEN res := PsUartMin.PortInUse; RETURN; END;
  140. PsUartMin.Reset(uart.regs);
  141. IF ~PsUartMin.SetBps(uart.regs, bps, res) OR
  142. ~PsUartMin.SetDataBits(uart.regs, data, res) OR
  143. ~PsUartMin.SetParity(uart.regs, parity, res) OR
  144. ~PsUartMin.SetStopBits(uart.regs, stop, res) THEN RETURN;
  145. END;
  146. uart.bps := bps;
  147. uart.data := data;
  148. uart.parity := parity;
  149. uart.stop := stop;
  150. uart.rxBufWrPos := 0;
  151. uart.rxBufRdPos := 0;
  152. (* configure receive timeout to be as close as possible to ReceiveTimeoutInUs *)
  153. n := ENTIER((ReceiveTimeoutInUs*REAL(bps)+1000000) / 4000000 + 0.5);
  154. n := MAX(1,MIN(255,n-1));
  155. uart.regs.rxtout := n;
  156. uart.regs.cr := uart.regs.cr + {PsUartMin.XUARTPS_CR_TORST}; (* restart receive timeout counter *)
  157. uart.regs.rxwm := 32; (* RX FIFO triggering threshold *)
  158. uart.regs.ier := RxInterrupts;
  159. PsUartMin.Enable(uart.regs,TRUE);
  160. res := 0;
  161. uart.open := TRUE;
  162. END Open;
  163. (**
  164. Close a UART controller
  165. uart: UART controller
  166. *)
  167. PROCEDURE Close*(uart: UartController);
  168. BEGIN
  169. IF uart.open THEN
  170. uart.open := FALSE;
  171. DisableInterrupts(uart.regs);
  172. PsUartMin.Enable(uart.regs,FALSE);
  173. END;
  174. END Close;
  175. PROCEDURE OccupiedBufSpace(bufWrPos, bufRdPos, bufSize: SIZE): SIZE;
  176. VAR n: SIZE;
  177. BEGIN
  178. n := bufWrPos - bufRdPos;
  179. IF n >= 0 THEN
  180. RETURN n;
  181. ELSE
  182. RETURN n+bufSize;
  183. END;
  184. END OccupiedBufSpace;
  185. (* Returns the amount of available free space in a cyclic buffer *)
  186. PROCEDURE AvailableBufSpace(bufWrPos, bufRdPos, bufSize: SIZE): SIZE;
  187. VAR n: SIZE;
  188. BEGIN
  189. n := bufWrPos - bufRdPos;
  190. IF n >= 0 THEN
  191. RETURN bufSize-1-n;
  192. ELSE
  193. RETURN -n-1;
  194. END;
  195. END AvailableBufSpace;
  196. (**
  197. Returns number of bytes available in the receive buffer of a UART controller
  198. uart: UART controller
  199. res: error code, 0 in case of success
  200. *)
  201. PROCEDURE Available*(uart: UartController): SIZE;
  202. BEGIN
  203. RETURN OccupiedBufSpace(uart.rxBufWrPos,uart.rxBufRdPos,LEN(uart.rxBuf));
  204. END Available;
  205. (**
  206. Send a single character to the UART
  207. ch: character to send
  208. propagate: TRUE for flushing the TX FIFO buffer
  209. res: error code, 0 in case of success
  210. *)
  211. PROCEDURE SendChar*(uart: UartController; ch: CHAR; propagate: BOOLEAN; onBusy: PsUartMin.BusyLoopCallback; VAR res: WORD);
  212. BEGIN
  213. PsUartMin.SendChar(uart.regs,ch,propagate,onBusy,res);
  214. END SendChar;
  215. (**
  216. Send data to the UART
  217. *)
  218. PROCEDURE Send*(uart: UartController; CONST buf: ARRAY OF CHAR; offs, len: LONGINT; propagate: BOOLEAN; onBusy: PsUartMin.BusyLoopCallback; VAR res: WORD);
  219. BEGIN
  220. WHILE uart.open & (len > 0) DO
  221. IF ~(PsUartMin.XUARTPS_SR_TNFUL IN uart.regs.sr) THEN
  222. uart.regs.fifo := ORD(buf[offs]);
  223. INC(offs); DEC(len);
  224. ELSIF (onBusy # NIL) & ~onBusy(res) THEN
  225. RETURN;
  226. END;
  227. END;
  228. IF propagate THEN (* flush the FIFO *)
  229. WHILE uart.open & ~(PsUartMin.XUARTPS_SR_TXEMPTY IN uart.regs.sr) DO
  230. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  231. END;
  232. END;
  233. IF uart.open THEN
  234. res := PsUartMin.Ok;
  235. ELSE
  236. res := PsUartMin.Closed;
  237. END;
  238. END Send;
  239. (**
  240. Receive a single character from UART
  241. res: error code, 0 in case of success
  242. Remarks: blocks until a character is available
  243. *)
  244. PROCEDURE ReceiveChar*(uart: UartController; onBusy: PsUartMin.BusyLoopCallback; VAR res: WORD): CHAR;
  245. VAR
  246. buf: ARRAY 1 OF CHAR;
  247. len: LONGINT;
  248. BEGIN
  249. Receive(uart,buf,0,1,1,len,onBusy,res);
  250. RETURN buf[0];
  251. END ReceiveChar;
  252. (**
  253. Receive data from the UART
  254. *)
  255. PROCEDURE Receive*(uart: UartController; VAR buf: ARRAY OF CHAR; offs, size, min: LONGINT; VAR len: LONGINT; onBusy: PsUartMin.BusyLoopCallback; VAR res: WORD);
  256. VAR
  257. bufRdPos, bufWrPos, n: SIZE;
  258. BEGIN
  259. IF ~uart.open THEN res := PsUartMin.Closed; RETURN; END;
  260. res := 0;
  261. len := 0;
  262. IF size = 0 THEN RETURN; END;
  263. min := MIN(size,min);
  264. WHILE uart.open & (size > 0) DO
  265. bufRdPos := uart.rxBufRdPos;
  266. bufWrPos := uart.rxBufWrPos;
  267. n := OccupiedBufSpace(bufWrPos,bufRdPos,LEN(uart.rxBuf));
  268. IF n # 0 THEN
  269. n := MIN(n,size);
  270. DEC(size,n); INC(len,n);
  271. IF min > 0 THEN DEC(min,n); END;
  272. (*!
  273. Make sure the receive buffer content
  274. corresponds to the state of uart.rxBufWrPos
  275. *)
  276. CODE
  277. DMB
  278. END;
  279. WHILE n > 0 DO
  280. buf[offs] := uart.rxBuf[bufRdPos];
  281. INC(bufRdPos);
  282. IF bufRdPos = LEN(uart.rxBuf) THEN
  283. bufRdPos := 0;
  284. END;
  285. INC(offs); DEC(n);
  286. END;
  287. uart.rxBufRdPos := bufRdPos;
  288. ELSIF min > 0 THEN
  289. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  290. ELSE
  291. RETURN;
  292. END;
  293. END;
  294. END Receive;
  295. PROCEDURE PrintRegisters(regs: PsUartMin.UartRegisters);
  296. BEGIN
  297. Trace.String("cr("); Trace.Hex(ADDRESSOF(regs.cr),-8); Trace.String("): "); Trace.Set(regs.cr); Trace.Ln;
  298. Trace.String("mr("); Trace.Hex(ADDRESSOF(regs.mr),-8); Trace.String("): "); Trace.Set(regs.mr); Trace.Ln;
  299. Trace.String("ier("); Trace.Hex(ADDRESSOF(regs.ier),-8); Trace.String("): write only"); Trace.Ln;
  300. Trace.String("idr("); Trace.Hex(ADDRESSOF(regs.idr),-8); Trace.String("): write only"); Trace.Ln;
  301. Trace.String("imr("); Trace.Hex(ADDRESSOF(regs.imr),-8); Trace.String("): "); Trace.Set(regs.imr); Trace.Ln;
  302. Trace.String("isr("); Trace.Hex(ADDRESSOF(regs.isr),-8); Trace.String("): "); Trace.Set(regs.isr); Trace.Ln;
  303. Trace.String("baudgen("); Trace.Hex(ADDRESSOF(regs.baudgen),-8); Trace.String("): "); Trace.Int(regs.baudgen,0); Trace.Ln;
  304. Trace.String("rxtout("); Trace.Hex(ADDRESSOF(regs.rxtout),-8); Trace.String("): "); Trace.Int(regs.rxtout,0); Trace.Ln;
  305. Trace.String("rxwm("); Trace.Hex(ADDRESSOF(regs.rxwm),-8); Trace.String("): "); Trace.Int(regs.rxwm,0); Trace.Ln;
  306. Trace.String("modemcr("); Trace.Hex(ADDRESSOF(regs.modemcr),-8); Trace.String("): "); Trace.Set(regs.modemcr); Trace.Ln;
  307. Trace.String("modemsr("); Trace.Hex(ADDRESSOF(regs.modemsr),-8); Trace.String("): "); Trace.Set(regs.modemsr); Trace.Ln;
  308. Trace.String("sr("); Trace.Hex(ADDRESSOF(regs.sr),-8); Trace.String("): "); Trace.Set(regs.sr); Trace.Ln;
  309. Trace.String("fifo("); Trace.Hex(ADDRESSOF(regs.fifo),-8); Trace.String("): --- "); Trace.Ln;
  310. Trace.String("bauddiv("); Trace.Hex(ADDRESSOF(regs.bauddiv),-8); Trace.String("): "); Trace.Int(regs.bauddiv,0); Trace.Ln;
  311. Trace.String("flowdel("); Trace.Hex(ADDRESSOF(regs.flowdel),-8); Trace.String("): "); Trace.Int(regs.flowdel,0); Trace.Ln;
  312. Trace.String("txwm("); Trace.Hex(ADDRESSOF(regs.txwm),-8); Trace.String("): "); Trace.Int(regs.txwm,0); Trace.Ln;
  313. END PrintRegisters;
  314. PROCEDURE Show*;
  315. BEGIN
  316. IF uarts[0] # NIL THEN
  317. Trace.StringLn("PS UART0:");
  318. PrintRegisters(uarts[0].regs);
  319. Trace.String("rxBufRdPos="); Trace.Int(uarts[0].rxBufRdPos,0); Trace.Ln;
  320. Trace.String("rxBufWrPos="); Trace.Int(uarts[0].rxBufWrPos,0); Trace.Ln;
  321. Trace.Ln;
  322. END;
  323. IF uarts[1] # NIL THEN
  324. Trace.StringLn("PS UART1:");
  325. PrintRegisters(uarts[1].regs);
  326. Trace.String("rxBufRdPos="); Trace.Int(uarts[1].rxBufRdPos,0); Trace.Ln;
  327. Trace.String("rxBufWrPos="); Trace.Int(uarts[1].rxBufWrPos,0); Trace.Ln;
  328. Trace.Ln;
  329. END;
  330. END Show;
  331. END PsUart.