raspiuart.pp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. {
  2. Copyright (c) 1998-2022 by the Free Pascal development team
  3. Raspberry Pi 3/4 UART0 support
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {$IFNDEF FPC_DOTTEDUNITS}
  18. unit raspiuart;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. {-
  21. The Raspberry Pi 3 and 4 use an ARM PL011 UART, but requires
  22. some configuration of the clock via the GPIO before you
  23. can set the baud rate of the UART and to connect the GPIO
  24. pins for TX/RX
  25. -}
  26. interface
  27. procedure UARTInit(BaseAddr: DWord); public name 'UARTInit';
  28. procedure UARTPuts(BaseAddr: DWord; C: AnsiChar);
  29. function UARTGet(BaseAddr: DWord): AnsiChar;
  30. procedure UARTFlush(BaseAddr: DWord);
  31. implementation
  32. {$IFDEF FPC_DOTTEDUNITS}
  33. uses
  34. EmbeddedApi.mailbox, EmbeddedApi.mmio, EmbeddedApi.gpio;
  35. {$ELSE FPC_DOTTEDUNITS}
  36. uses
  37. mailbox, mmio, gpio;
  38. {$ENDIF FPC_DOTTEDUNITS}
  39. const
  40. { UART offsets from PeripheralBase }
  41. UART0_DR = $00201000;
  42. UART0_FR = $00201018;
  43. UART0_IBRD = $00201024;
  44. UART0_FBRD = $00201028;
  45. UART0_LCRH = $0020102C;
  46. UART0_CR = $00201030;
  47. UART0_IMSC = $00201038;
  48. UART0_ICR = $00201044;
  49. procedure SetClockRate(BaseAddr: DWord);
  50. begin
  51. MBox[0] := 9*4;
  52. MBox[1] := MBOX_REQUEST;
  53. MBox[2] := MBOX_TAG_SETCLKRATE;
  54. MBox[3] := 12;
  55. MBox[4] := 8;
  56. MBox[5] := 2;
  57. MBox[6] := 4000000; { 4 Mhz }
  58. MBox[7] := 0; { Clear turbo flag }
  59. MBox[8] := MBOX_TAG_LAST;
  60. MailboxCall(BaseAddr, MBOX_CH_PROP);
  61. end;
  62. procedure UARTInit(BaseAddr: DWord); public name 'UARTInit';
  63. var
  64. ra: DWord;
  65. begin
  66. { Turn off the UART first }
  67. PUT32(BaseAddr + UART0_CR, 0);
  68. SetClockRate(BaseAddr);
  69. { map UART0 to GPIO pins }
  70. ra := GET32(GPFSEL1);
  71. ra := ra AND (not (7 shl 12));
  72. ra := ra OR (4 shl 12);
  73. PUT32(GPFSEL1, ra);
  74. PUT32(GPPUD, 0);
  75. DUMMY(150);
  76. { Enable pins 14 and 15 }
  77. ra := ((1 shl 14) or (1 shl 15));
  78. PUT32(GPPUDCLK0, ra);
  79. DUMMY(150);
  80. { Flush GPIO setup }
  81. PUT32(GPPUDCLK0, 0);
  82. { Clear interrupts }
  83. PUT32(BaseAddr + UART0_ICR, $7FF);
  84. { 115200 baud }
  85. PUT32(BaseAddr + UART0_IBRD, 2);
  86. PUT32(BaseAddr + UART0_FBRD, $B);
  87. { 8n1, enable FIFO }
  88. PUT32(BaseAddr + UART0_LCRH, ($7 shl 4));
  89. { Enable rx and tx }
  90. PUT32(BaseAddr + UART0_CR, $301);
  91. end;
  92. procedure UARTPuts(BaseAddr: DWord; C: AnsiChar);
  93. begin
  94. while True do
  95. begin
  96. DUMMY(1);
  97. if (GET32(BaseAddr + UART0_FR) and $20) = 0 then break;
  98. end;
  99. PUT32(BaseAddr + UART0_DR, DWord(C));
  100. end;
  101. function UARTGet(BaseAddr: DWord): AnsiChar;
  102. begin
  103. while True do
  104. begin
  105. DUMMY(1);
  106. if (GET32(BaseAddr + UART0_FR) and $10) = 0 then break;
  107. end;
  108. UARTGet := AnsiChar(GET32(BaseAddr + UART0_DR));
  109. end;
  110. procedure UARTFlush(BaseAddr: DWord);
  111. begin
  112. PUT32(BaseAddr + UART0_LCRH, (1 shl 4));
  113. end;
  114. end.