USART module reference

Header :
#include <usart.h>
Makefile :
MODULES+=usart

Description

An USART (Universal Synchronous/Asynchronous Receiver/Transmitter) is a peripheral used to send and receive data to/from another device using a standard and very simple serial communication scheme. This interface is sometimes abusively called "Serial" (even though SPI, I2C and USB are also serial protocols) or RS-232 (which is the older computer standard which used the same encoding scheme but with different voltage levels). In this protocol, there is no "master" or "slave" : the communication is symetrical, each device has a transmitter (Tx) and a receiver (Rx), and one device's transmitter sends data to the other device's receiver. If the communication is only required in one direction, the other line can be left unconnected. For more information and see how this interface compares to other protocols such as I2C and SPI, take a look at the Communication buses tutorial.

The most common use cases are :

  • Exchanging data with a computer using a "serial-to-USB adapter" (such as the infamous FTDI FT232) : this was the standard way to connect a microcontroller to a computer before microcontrollers had USB support; nowdays, it is usually better to use USB.
  • Setting up a simple communication between two microcontrollers, even of very different kind, because USART is usually the most well supported interface (and it is simpler than I2C or SPI).
  • Some kind of devices, especially GPS and GSM chipset, commonly have a USART interface.

Synchronous vs Asynchronous

A communication line is called "synchronous" when a clock signal is transfered along the data, or "asynchronous" otherwise. Synchronous protocols are somewhat easier to use and more reliable because the sender and the receiver are, as the name implies, synchronized; however, this requires another dedicated wire to carry the clock signal. With asynchronous protocols, the two devices must be correctly configured with the same clock setting in order to understand each other.

The USART protocol in general can be used either in synchronous or asynchronous mode, but in fact, the vast majority of devices do not have a clock line and therefore only work in asynchronous mode. Currently, this is the only mode supported by the driver. This is why the S is sometimes dropped from the name, and the peripheral (or, by extension, the protocol) is simply called UART.

API

void enable(Port port, unsigned long baudrate, bool hardwareFlowControl=false, CharLength charLength=CharLength::CHAR8, Parity parity=Parity::NONE, StopBit stopBit=StopBit::STOP1)
void disable()
void enableInterrupt(Port port, void (*handler)(), Interrupt interrupt)
int available(Port port)
bool contains(Port port, char byte)
char peek(Port port)

Hacking

Code

Header

  1. #ifndef _USART_H_
  2. #define _USART_H_
  3.  
  4. #include <stdint.h>
  5. #include "gpio.h"
  6.  
  7. // Universal Synchronous Asynchronous Receiver Transmitter
  8. // This module allows the chip to communicate on an RS232 link
  9. // (also sometimes called Serial port)
  10. namespace USART {
  11.  
  12. // Peripheral memory space base addresses
  13. const uint32_t USART_BASE = 0x40024000;
  14. const uint32_t USART_REG_SIZE = 0x4000;
  15.  
  16. // Register offsets
  17. const uint32_t OFFSET_CR = 0x00;
  18. const uint32_t OFFSET_MR = 0x04;
  19. const uint32_t OFFSET_IER = 0x08;
  20. const uint32_t OFFSET_IDR = 0x0C;
  21. const uint32_t OFFSET_IMR = 0x10;
  22. const uint32_t OFFSET_CSR = 0x14;
  23. const uint32_t OFFSET_RHR = 0x18;
  24. const uint32_t OFFSET_THR = 0x1C;
  25. const uint32_t OFFSET_BRGR = 0x20;
  26. const uint32_t OFFSET_RTOR = 0x24;
  27. const uint32_t OFFSET_TTGR = 0x28;
  28. const uint32_t OFFSET_FIDI = 0x40;
  29. const uint32_t OFFSET_NER = 0x44;
  30. const uint32_t OFFSET_IFR = 0x4C;
  31. const uint32_t OFFSET_MAN = 0x50;
  32. const uint32_t OFFSET_LINMR = 0x54;
  33. const uint32_t OFFSET_LINIR = 0x58;
  34. const uint32_t OFFSET_LINBR = 0x5C;
  35. const uint32_t OFFSET_WPMR = 0xE4;
  36. const uint32_t OFFSET_WPSR = 0xE8;
  37. const uint32_t OFFSET_VERSION = 0xFC;
  38.  
  39. // Subregisters
  40. const uint32_t CR_RSTRX = 2;
  41. const uint32_t CR_RSTTX = 3;
  42. const uint32_t CR_RXEN = 4;
  43. const uint32_t CR_RXDIS = 5;
  44. const uint32_t CR_TXEN = 6;
  45. const uint32_t CR_TXDIS = 7;
  46. const uint32_t CR_RSTSTA = 8;
  47. const uint32_t MR_MODE = 0;
  48. const uint32_t MR_CHRL = 6;
  49. const uint32_t MR_PAR = 9;
  50. const uint32_t MR_NBSTOP = 12;
  51. const uint32_t MR_MODE9 = 17;
  52. const uint32_t BRGR_CD = 0;
  53. const uint32_t BRGR_FP = 16;
  54. const uint32_t CSR_RXRDY = 0;
  55. const uint32_t CSR_TXRDY = 1;
  56. const uint32_t CSR_RXBRK = 2;
  57. const uint32_t CSR_OVRE = 5;
  58. const uint32_t CSR_PARE = 7;
  59. const uint32_t CSR_TXEMPTY = 9;
  60. const uint32_t IER_RXRDY = 0;
  61.  
  62. // Constants
  63. const uint32_t WPMR_KEY = 0x555341 << 8;
  64. const uint32_t WPMR_ENABLE = 1;
  65. const uint32_t WPMR_DISABLE = 0;
  66. const uint32_t MODE_NORMAL = 0b0000;
  67. const uint32_t MODE_HARDWARE_HANDSHAKE = 0b0010;
  68.  
  69. const int N_PORTS = 4;
  70. enum class Port {
  71. USART0,
  72. USART1,
  73. USART2,
  74. USART3
  75. };
  76.  
  77. const uint8_t BIN = 2;
  78. const uint8_t DEC = 10;
  79. const uint8_t HEX = 16;
  80.  
  81. // Port configuration : character length (default 8)
  82. // Value refers to MR.CHRL and MR.MODE9
  83. enum class CharLength {
  84. CHAR5 = 0b000,
  85. CHAR6 = 0b001,
  86. CHAR7 = 0b010,
  87. CHAR8 = 0b011,
  88. CHAR9 = 0b100
  89. };
  90.  
  91. // Port configuration : parity type (default NONE)
  92. // Value refers to MR.PAR
  93. enum class Parity {
  94. EVEN = 0b000,
  95. ODD = 0b001,
  96. SPACE = 0b010, // Parity forced to 0
  97. MARK = 0b011, // Parity forced to 1
  98. NONE = 0b100,
  99. };
  100.  
  101. // Port configuration : length of stop bit (default 1)
  102. // Value refers to MR.NBSTOP
  103. enum class StopBit {
  104. STOP1 = 0b00,
  105. STOP15 = 0b01, // length 1.5 bit
  106. STOP2 = 0b10
  107. };
  108.  
  109. const int N_INTERRUPTS = 4;
  110. enum class Interrupt {
  111. BYTE_RECEIVED,
  112. TRANSMIT_READY,
  113. OVERFLOW,
  114. PARITY_ERROR
  115. };
  116.  
  117. enum class PinFunction {
  118. RX,
  119. TX,
  120. RTS,
  121. CTS
  122. };
  123.  
  124. const int BUFFER_SIZE = 2048;
  125.  
  126.  
  127. // Error codes
  128. const Error::Code ERR_BAUDRATE_OUT_OF_RANGE = 0x0001;
  129.  
  130.  
  131. // Module API
  132. void enable(Port port, unsigned long baudrate, bool hardwareFlowControl=false, CharLength charLength=CharLength::CHAR8, Parity parity=Parity::NONE, StopBit stopBit=StopBit::STOP1);
  133. void disable(Port port);
  134. void enableInterrupt(Port port, void (*handler)(), Interrupt interrupt);
  135. int available(Port port);
  136. bool contains(Port port, char byte);
  137. char peek(Port port);
  138. bool peek(Port port, const char* test, int size);
  139. char read(Port port);
  140. int read(Port port, char* buffer, int size, bool readUntil=false, char end=0x00);
  141. int readUntil(Port port, char* buffer, int size, char end);
  142. unsigned long readInt(Port port, int nBytes, bool wait=true);
  143. int write(Port port, const char* buffer, int size=-1, bool async=false);
  144. int write(Port port, char byte, bool async=false);
  145. int write(Port port, int number, uint8_t base, bool async=false);
  146. int write(Port port, bool boolean, bool async=false);
  147. int writeLine(Port port, const char* buffer, int size=-1, bool async=false);
  148. int writeLine(Port port, char byte, bool async=false);
  149. int writeLine(Port port, int number, uint8_t base, bool async=false);
  150. int writeLine(Port port, bool boolean, bool async=false);
  151. bool isWriteFinished(Port port);
  152. void waitWriteFinished(Port port);
  153. void waitReadFinished(Port port, unsigned long timeout=100);
  154. void flush(Port port);
  155. void setPin(Port port, PinFunction function, GPIO::Pin pin);
  156.  
  157. }
  158.  
  159.  
  160. #endif

Module

  1. #include "usart.h"
  2. #include "core.h"
  3. #include "gpio.h"
  4. #include "pm.h"
  5. #include "dma.h"
  6.  
  7. namespace USART {
  8.  
  9. // Internal functions
  10. void rxBufferFullHandler();
  11.  
  12. // Clocks
  13. const int PM_CLK[] = {PM::CLK_USART0, PM::CLK_USART1, PM::CLK_USART2, PM::CLK_USART3};
  14.  
  15. // Interrupt handlers
  16. extern uint8_t INTERRUPT_PRIORITY;
  17. uint32_t _interruptHandlers[N_PORTS][N_INTERRUPTS];
  18. const int _interruptBits[N_INTERRUPTS] = {CSR_RXRDY, CSR_TXRDY, CSR_OVRE, CSR_PARE};
  19. void interruptHandlerWrapper();
  20.  
  21. // Package-dependant, defined in pins_sam4l_XX.cpp
  22. // Can be modified using setPin()
  23. extern struct GPIO::Pin PINS_RX[];
  24. extern struct GPIO::Pin PINS_TX[];
  25. extern struct GPIO::Pin PINS_CTS[];
  26. extern struct GPIO::Pin PINS_RTS[];
  27.  
  28. // Ports
  29. struct USART {
  30. unsigned long baudrate;
  31. bool hardwareFlowControl;
  32. CharLength charLength;
  33. Parity parity;
  34. StopBit stopBit;
  35. uint8_t rxBuffer[BUFFER_SIZE];
  36. uint8_t txBuffer[BUFFER_SIZE];
  37. int rxBufferCursorR;
  38. int rxBufferCursorW;
  39. int txBufferCursor;
  40. int rxDMAChannel = -1;
  41. int txDMAChannel = -1;
  42. };
  43. struct USART _ports[N_PORTS];
  44.  
  45. int _rxDMAChannelsToPorts[DMA::N_CHANNELS_MAX];
  46.  
  47. bool _portsEnabled[N_PORTS] = {false, false, false, false};
  48.  
  49.  
  50. void enable(Port port, unsigned long baudrate, bool hardwareFlowControl, CharLength charLength, Parity parity, StopBit stopBit) {
  51. const uint32_t REG_BASE = USART_BASE + static_cast<int>(port) * USART_REG_SIZE;
  52. struct USART* p = &(_ports[static_cast<int>(port)]);
  53.  
  54. // Port configuration
  55. p->hardwareFlowControl = hardwareFlowControl;
  56. p->charLength = charLength;
  57. p->parity = parity;
  58. p->stopBit = stopBit;
  59.  
  60. // Initialize the buffers
  61. for (int i = 0; i < BUFFER_SIZE; i++) {
  62. p->rxBuffer[i] = 0;
  63. p->txBuffer[i] = 0;
  64. }
  65. p->rxBufferCursorR = 0;
  66. p->rxBufferCursorW = 0;
  67. p->txBufferCursor = 0;
  68.  
  69. // Set the pins in peripheral mode
  70. GPIO::enablePeripheral(PINS_RX[static_cast<int>(port)]);
  71. GPIO::enablePeripheral(PINS_TX[static_cast<int>(port)]);
  72. if (hardwareFlowControl) {
  73. GPIO::enablePeripheral(PINS_RTS[static_cast<int>(port)]);
  74. GPIO::enablePeripheral(PINS_CTS[static_cast<int>(port)]);
  75. }
  76.  
  77. // Enable the clock
  78. PM::enablePeripheralClock(PM_CLK[static_cast<int>(port)]);
  79.  
  80. // WPMR (Write Protect Mode Register) : disable the Write Protect
  81. (*(volatile uint32_t*)(REG_BASE + OFFSET_WPMR)) = WPMR_KEY | WPMR_DISABLE;
  82.  
  83. // MR (Mode Register) : set the USART configuration
  84. (*(volatile uint32_t*)(REG_BASE + OFFSET_MR))
  85. = (hardwareFlowControl ? MODE_HARDWARE_HANDSHAKE : MODE_NORMAL) << MR_MODE // Hardware flow control
  86. | (static_cast<int>(charLength) & 0b11) << MR_CHRL // Character length <= 8
  87. | (static_cast<int>(charLength) >> 2) << MR_MODE9 // Character length == 9
  88. | static_cast<int>(parity) << MR_PAR // Parity
  89. | static_cast<int>(stopBit) << MR_NBSTOP; // Length of stop bit
  90.  
  91. // BRGR (Baud Rate Generator Register) : configure the baudrate generator
  92. // Cf datasheet 24.6.4 : baudrate = mainclock / (16 * CD), with FP to fine-tune by steps of 1/8
  93. p->baudrate = baudrate;
  94. const unsigned long clk = PM::getModuleClockFrequency(PM_CLK[static_cast<int>(port)]);
  95. const uint64_t cd100 = 100 * clk / 16 / baudrate; // cd100 = cd * 100
  96. const uint32_t cd = cd100 / 100;
  97. const uint64_t fp100 = (cd100 % 100) * 8;
  98. uint8_t fp = fp100 / 100;
  99. if (fp100 - fp * 100 >= 50) {
  100. fp++; // Round
  101. }
  102. if (cd == 0 || cd > 0xFFFF) {
  103. Error::happened(Error::Module::USART, ERR_BAUDRATE_OUT_OF_RANGE, Error::Severity::CRITICAL);
  104. return;
  105. }
  106. (*(volatile uint32_t*)(REG_BASE + OFFSET_BRGR))
  107. = cd << BRGR_CD
  108. | fp << BRGR_FP;
  109.  
  110. // CR (Control Register) : enable RX and TX
  111. (*(volatile uint32_t*)(REG_BASE + OFFSET_CR))
  112. = 1 << CR_RXEN
  113. | 1 << CR_TXEN;
  114.  
  115. // WPMR (Write Protect Mode Register) : re-enable the Write Protect
  116. (*(volatile uint32_t*)(REG_BASE + OFFSET_WPMR)) = WPMR_KEY | WPMR_ENABLE;
  117.  
  118. // Set up the DMA channels and related interrupts
  119. p->rxDMAChannel = DMA::setupChannel(p->rxDMAChannel, static_cast<DMA::Device>(static_cast<int>(DMA::Device::USART0_RX) + static_cast<int>(port)), DMA::Size::BYTE);
  120. p->txDMAChannel = DMA::setupChannel(p->txDMAChannel, static_cast<DMA::Device>(static_cast<int>(DMA::Device::USART0_TX) + static_cast<int>(port)), DMA::Size::BYTE);
  121. _rxDMAChannelsToPorts[p->rxDMAChannel] = static_cast<int>(port);
  122. DMA::startChannel(p->rxDMAChannel, (uint32_t)(p->rxBuffer), BUFFER_SIZE);
  123. //DMA::reloadChannel(p->rxDMAChannel, (uint32_t)(p->rxBuffer), BUFFER_SIZE);
  124. DMA::enableInterrupt(p->rxDMAChannel, &rxBufferFullHandler, DMA::Interrupt::TRANSFER_FINISHED);
  125.  
  126. _portsEnabled[static_cast<int>(port)] = true;
  127. }
  128.  
  129. void disable(Port port) {
  130. // Don't do anything if this port is not enabled
  131. if (!_portsEnabled[static_cast<int>(port)]) {
  132. return;
  133. }
  134. _portsEnabled[static_cast<int>(port)] = false;
  135.  
  136. const uint32_t REG_BASE = USART_BASE + static_cast<int>(port) * USART_REG_SIZE;
  137. struct USART* p = &(_ports[static_cast<int>(port)]);
  138.  
  139. // Disable the DMA channels
  140. DMA::stopChannel(p->rxDMAChannel);
  141. DMA::stopChannel(p->txDMAChannel);
  142.  
  143. // WPMR (Write Protect Mode Register) : disable the Write Protect
  144. (*(volatile uint32_t*)(REG_BASE + OFFSET_WPMR)) = WPMR_KEY | WPMR_DISABLE;
  145.  
  146. // CR (Control Register) : disable RX and TX
  147. (*(volatile uint32_t*)(REG_BASE + OFFSET_CR))
  148. = 1 << CR_RXDIS
  149. | 1 << CR_TXDIS;
  150.  
  151. // WPMR (Write Protect Mode Register) : re-enable the Write Protect
  152. (*(volatile uint32_t*)(REG_BASE + OFFSET_WPMR)) = WPMR_KEY | WPMR_ENABLE;
  153.  
  154. // Disable the clock
  155. PM::disablePeripheralClock(PM_CLK[static_cast<int>(port)]);
  156.  
  157. // Free the pins
  158. GPIO::disablePeripheral(PINS_RX[static_cast<int>(port)]);
  159. GPIO::disablePeripheral(PINS_TX[static_cast<int>(port)]);
  160. if (p->hardwareFlowControl) {
  161. GPIO::disablePeripheral(PINS_RTS[static_cast<int>(port)]);
  162. GPIO::disablePeripheral(PINS_CTS[static_cast<int>(port)]);
  163. }
  164. }
  165.  
  166. void enableInterrupt(Port port, void (*handler)(), Interrupt interrupt) {
  167. const uint32_t REG_BASE = USART_BASE + static_cast<int>(port) * USART_REG_SIZE;
  168.  
  169. // Save the user handler
  170. _interruptHandlers[static_cast<int>(port)][static_cast<int>(interrupt)] = (uint32_t)handler;
  171.  
  172. // IER (Interrupt Enable Register) : enable the requested interrupt
  173. (*(volatile uint32_t*)(REG_BASE + OFFSET_IER))
  174. = 1 << IER_RXRDY;
  175.  
  176. // Enable the interrupt in the NVIC
  177. Core::Interrupt interruptChannel = static_cast<Core::Interrupt>(static_cast<int>(Core::Interrupt::USART0) + static_cast<int>(port));
  178. Core::setInterruptHandler(interruptChannel, interruptHandlerWrapper);
  179. Core::enableInterrupt(interruptChannel, INTERRUPT_PRIORITY);
  180. }
  181.  
  182. void interruptHandlerWrapper() {
  183. // Get the port number through the current interrupt number
  184. int port = static_cast<int>(Core::currentInterrupt()) - static_cast<int>(Core::Interrupt::USART0);
  185. const uint32_t REG_BASE = USART_BASE + port * USART_REG_SIZE;
  186.  
  187. // Call the user handler of every interrupt that is enabled and pending
  188. for (int i = 0; i < N_INTERRUPTS; i++) {
  189. if ((*(volatile uint32_t*)(REG_BASE + OFFSET_IMR)) & (1 << _interruptBits[i]) // Interrupt is enabled
  190. && (*(volatile uint32_t*)(REG_BASE + OFFSET_CSR)) & (1 << _interruptBits[i])) { // Interrupt is pending
  191. void (*handler)() = (void (*)())_interruptHandlers[port][i];
  192. if (handler != nullptr) {
  193. handler();
  194. }
  195. }
  196. }
  197.  
  198. // Clear the interrupts
  199. (*(volatile uint32_t*)(REG_BASE + OFFSET_CR))
  200. = 1 << CR_RSTSTA; // Reset status bits
  201. }
  202.  
  203. void rxBufferFullHandler() {
  204. // Get the port that provoqued this interrupt
  205. int channel = static_cast<int>(Core::currentInterrupt()) - static_cast<int>(Core::Interrupt::DMA0);
  206. int portNumber = _rxDMAChannelsToPorts[channel];
  207. struct USART* p = &(_ports[portNumber]);
  208.  
  209. // Reload the DMA channel
  210. int length = 0;
  211. int cur = p->rxBufferCursorW;
  212. if (p->rxBufferCursorR == p->rxBufferCursorW) {
  213. // Buffer is full, the DMA channel will be disabled
  214. // If hardware flow control is enabled this will pause the transfer by raising RTS,
  215. // otherwise if more data arrives it will trigger an overflow
  216. length = 0;
  217.  
  218. } else if (p->rxBufferCursorR > p->rxBufferCursorW) {
  219. // Reload until the cursor
  220. length = p->rxBufferCursorR - p->rxBufferCursorW;
  221. p->rxBufferCursorW = p->rxBufferCursorR;
  222.  
  223. } else { // p->rxBufferCursorR < p->rxBufferCursorW
  224. // Reload until the end of the linear buffer
  225. length = BUFFER_SIZE - p->rxBufferCursorW;
  226. p->rxBufferCursorW = 0;
  227. }
  228.  
  229. if (length == 0) {
  230. DMA::stopChannel(p->rxDMAChannel);
  231. } else {
  232. DMA::reloadChannel(p->rxDMAChannel, (uint32_t)(p->rxBuffer + cur), length);
  233. }
  234. }
  235.  
  236. int available(Port port) {
  237. struct USART* p = &(_ports[static_cast<int>(port)]);
  238.  
  239. // Get the position of the second cursors from the DMA
  240. int cursor2 = p->rxBufferCursorW - DMA::getCounter(p->rxDMAChannel);
  241.  
  242. // Get the position of the last char inserted into the buffer by DMA
  243. int length = cursor2 - p->rxBufferCursorR;
  244. if (length == 0) {
  245. // The buffer is either complety empty or complety full
  246. if (DMA::getCounter(p->rxDMAChannel) == 0) {
  247. // Complety full
  248. return BUFFER_SIZE;
  249. } else {
  250. // Complety empty
  251. return 0;
  252. }
  253. } else if (length > 0) {
  254. return length;
  255. } else {
  256. return BUFFER_SIZE + length; // length is negative here
  257. }
  258. }
  259.  
  260. bool contains(Port port, char byte) {
  261. struct USART* p = &(_ports[static_cast<int>(port)]);
  262.  
  263. // Check if the received buffer contains the specified byte
  264. int avail = available(port);
  265. for (int i = 0; i < avail; i++) {
  266. if (p->rxBuffer[(p->rxBufferCursorR + i) % BUFFER_SIZE] == byte) {
  267. return true;
  268. }
  269. }
  270. return false;
  271. }
  272.  
  273. char peek(Port port) {
  274. struct USART* p = &(_ports[static_cast<int>(port)]);
  275.  
  276. if (available(port) > 0) {
  277. // Return the next char in the port's RX buffer
  278. return p->rxBuffer[p->rxBufferCursorR];
  279. } else {
  280. return 0;
  281. }
  282. }
  283.  
  284. bool peek(Port port, const char* test, int size) {
  285. struct USART* p = &(_ports[static_cast<int>(port)]);
  286.  
  287. if (available(port) >= size) {
  288. // Check whether the /size/ next chars in the buffer are equal to test
  289. for (int i = 0; i < size; i++) {
  290. if (p->rxBuffer[(p->rxBufferCursorR + i) % BUFFER_SIZE] != test[i]) {
  291. return false;
  292. }
  293. }
  294. return true;
  295. } else {
  296. return false;
  297. }
  298. }
  299.  
  300. // Read one byte
  301. char read(Port port) {
  302. struct USART* p = &(_ports[static_cast<int>(port)]);
  303.  
  304. if (available(port) > 0) {
  305. // Read the next char in the port's Rx buffer
  306. char c = p->rxBuffer[p->rxBufferCursorR];
  307.  
  308. // Increment the cursor
  309. p->rxBufferCursorR++;
  310. if (p->rxBufferCursorR == BUFFER_SIZE) {
  311. p->rxBufferCursorR = 0;
  312. }
  313.  
  314. // If the Rx DMA channel was stopped because the buffer was full,
  315. // there is now room available, so it can be restarted
  316. if (!DMA::isEnabled(p->rxDMAChannel)) {
  317. int cur = p->rxBufferCursorW;
  318. p->rxBufferCursorW++;
  319. if (p->rxBufferCursorW == BUFFER_SIZE) {
  320. p->rxBufferCursorW = 0;
  321. }
  322. DMA::startChannel(p->rxDMAChannel, (uint32_t)(p->rxBuffer + cur), 1);
  323. }
  324. // Return the character that was read
  325. return c;
  326.  
  327. } else {
  328. return 0;
  329. }
  330. }
  331.  
  332. // Read up to /size/ bytes
  333. // If buffer is nullptr, the bytes are simply poped from the buffer
  334. int read(Port port, char* buffer, int size, bool readUntil, char end) {
  335. struct USART* p = &(_ports[static_cast<int>(port)]);
  336.  
  337. int avail = available(port);
  338. int n = 0;
  339. for (int i = 0; i < size && i < avail; i++) {
  340. // Copy the next char from the port's Rx buffer to the user buffer
  341. char c = p->rxBuffer[p->rxBufferCursorR];
  342. if (buffer != nullptr) {
  343. buffer[i] = c;
  344. }
  345.  
  346. // Keep track of the number of bytes written
  347. n++;
  348.  
  349. // Increment the cursor
  350. p->rxBufferCursorR++;
  351. if (p->rxBufferCursorR == BUFFER_SIZE) {
  352. p->rxBufferCursorR = 0;
  353. }
  354. // If the "read until" mode is selected, exit the loop if the selected byte is found
  355. if (readUntil && c == end) {
  356. break;
  357. }
  358. }
  359.  
  360. // If the Rx DMA channel was stopped because the buffer was full,
  361. // there is now room available, so it can be restarted
  362. if (!DMA::isEnabled(p->rxDMAChannel)) {
  363. int cur = p->rxBufferCursorW;
  364. int length = 0;
  365. if (p->rxBufferCursorR > p->rxBufferCursorW) {
  366. length = p->rxBufferCursorR - p->rxBufferCursorW;
  367. } else {
  368. length = BUFFER_SIZE - p->rxBufferCursorW;
  369. }
  370. p->rxBufferCursorW += length;
  371. if (p->rxBufferCursorW >= BUFFER_SIZE) {
  372. p->rxBufferCursorW -= BUFFER_SIZE;
  373. }
  374. DMA::startChannel(p->rxDMAChannel, (uint32_t)(p->rxBuffer + cur), length);
  375. }
  376.  
  377. return n;
  378. }
  379.  
  380. // Read up to n bytes until the specified byte is found
  381. int readUntil(Port port, char* buffer, int size, char end) {
  382. return read(port, buffer, size, true, end);
  383. }
  384.  
  385. // Read an int on n bytes (LSByte first, max n = 8 bytes)
  386. // and return it as an unsigned long
  387. unsigned long readInt(Port port, int nBytes, bool wait) {
  388. if (nBytes > 8) {
  389. nBytes = 8;
  390. }
  391.  
  392. if (wait) {
  393. while (available(port) < nBytes);
  394. }
  395.  
  396. unsigned long result = 0;
  397. for (int i = 0; i < nBytes; i++) {
  398. uint8_t c = read(port);
  399. result |= c << (i * 8);
  400. }
  401. return result;
  402. }
  403.  
  404. int write(Port port, const char* buffer, int size, bool async) {
  405. struct USART* p = &(_ports[static_cast<int>(port)]);
  406.  
  407. // Wait until any previous write is finished
  408. waitWriteFinished(port);
  409.  
  410. // If size is not specified, write at most BUFFER_SIZE characters
  411. int n = size;
  412. if (n < 0 || n > BUFFER_SIZE) {
  413. n = BUFFER_SIZE;
  414. }
  415.  
  416. // Copy the user buffer into the Tx buffer
  417. for (int i = 0; i < n; i++) {
  418. // If size is not specified, stops at the end of the string
  419. if (size < 0 && buffer[i] == 0) {
  420. n = i;
  421. break;
  422. }
  423. p->txBuffer[i] = buffer[i];
  424. }
  425.  
  426. // Start the DMA
  427. DMA::startChannel(p->txDMAChannel, (uint32_t)(p->txBuffer), n);
  428.  
  429. // In synchronous mode, wait until this transfer is finished
  430. if (!async) {
  431. waitWriteFinished(port);
  432. }
  433.  
  434. // Return the number of bytes written
  435. return n;
  436. }
  437.  
  438. int write(Port port, char byte, bool async) {
  439. struct USART* p = &(_ports[static_cast<int>(port)]);
  440.  
  441. // Wait until any previous write is finished
  442. waitWriteFinished(port);
  443. // Write a single byte
  444. p->txBuffer[0] = byte;
  445. DMA::startChannel(p->txDMAChannel, (uint32_t)(p->txBuffer), 1);
  446.  
  447. // In synchronous mode, wait until this transfer is finished
  448. if (!async) {
  449. waitWriteFinished(port);
  450. }
  451.  
  452. return 1;
  453. }
  454.  
  455. int write(Port port, int number, uint8_t base, bool async) {
  456. // Write a human-readable number in the given base
  457. const int bufferSize = 32; // Enough to write a 32-bits word in binary
  458. char buffer[bufferSize];
  459. int cursor = 0;
  460. if (base < 2) {
  461. return 0;
  462. }
  463.  
  464. // Special case : number = 0
  465. if (number == 0) {
  466. return write(port, '0');
  467. }
  468.  
  469. // Minus sign
  470. if (number < 0) {
  471. buffer[cursor] = '-';
  472. cursor++;
  473. number = -number;
  474. }
  475.  
  476. // Compute the number in reverse
  477. int start = cursor;
  478. for (; cursor < bufferSize && number > 0; cursor++) {
  479. char c = number % base;
  480. if (c < 10) {
  481. c += '0';
  482. } else {
  483. c += 'A' - 10;
  484. }
  485. buffer[cursor] = c;
  486. number = number / base;
  487. }
  488.  
  489. // Reverse the result
  490. for (int i = 0; i < (cursor - start) / 2; i++) {
  491. char c = buffer[start + i];
  492. buffer[start + i] = buffer[cursor - i - 1];
  493. buffer[cursor - i - 1] = c;
  494. }
  495.  
  496. buffer[cursor] = 0;
  497. cursor++;
  498. return write(port, buffer, cursor, async);
  499. }
  500.  
  501. int write(Port port, bool boolean, bool async) {
  502. // Write a boolean value
  503. if (boolean) {
  504. return write(port, "true", 4, async);
  505. } else {
  506. return write(port, "false", 5, async);
  507. }
  508. }
  509.  
  510. int writeLine(Port port, const char* buffer, int size, bool async) {
  511. int written = write(port, buffer, size, async);
  512. written += write(port, "\r\n", 2, async);
  513. return written;
  514. }
  515.  
  516. int writeLine(Port port, char byte, bool async) {
  517. int written = write(port, byte, async);
  518. written += write(port, "\r\n", 2, async);
  519. return written;
  520. }
  521.  
  522. int writeLine(Port port, int number, uint8_t base, bool async) {
  523. int written = write(port, number, base, async);
  524. written += write(port, "\r\n", 2, async);
  525. return written;
  526. }
  527.  
  528. int writeLine(Port port, bool boolean, bool async) {
  529. int written = write(port, boolean, async);
  530. written += write(port, "\r\n", 2, async);
  531. return written;
  532. }
  533.  
  534. void flush(Port port) {
  535. struct USART* p = &(_ports[static_cast<int>(port)]);
  536.  
  537. // Stop the Rx channel
  538. DMA::stopChannel(p->rxDMAChannel);
  539.  
  540. // Empty the reception buffer
  541. p->rxBufferCursorR = 0;
  542. p->rxBufferCursorW = 0;
  543.  
  544. // Start the channel again
  545. DMA::startChannel(p->rxDMAChannel, (uint32_t)(p->rxBuffer), BUFFER_SIZE);
  546. }
  547.  
  548. bool isWriteFinished(Port port) {
  549. const uint32_t REG_BASE = USART_BASE + static_cast<int>(port) * USART_REG_SIZE;
  550. struct USART* p = &(_ports[static_cast<int>(port)]);
  551.  
  552. // Check if the DMA has finished the transfer and if the Tx buffer is empty
  553. return DMA::isFinished(p->txDMAChannel) && (*(volatile uint32_t*)(REG_BASE + OFFSET_CSR)) & (1 << CSR_TXEMPTY);
  554. }
  555.  
  556. void waitWriteFinished(Port port) {
  557. // Wait for the transfer to finish
  558. while (!isWriteFinished(port));
  559. }
  560.  
  561. void waitReadFinished(Port port, unsigned long timeout) {
  562. // Wait until no more bytes is received
  563. struct USART* p = &(_ports[static_cast<int>(port)]);
  564. unsigned long tStart = Core::time();
  565. int n = available(port);
  566. while (n == 0) {
  567. n = available(port);
  568. if (timeout > 0 && Core::time() - tStart > timeout) {
  569. return;
  570. }
  571. }
  572. unsigned long byteDuration = 1000000UL / p->baudrate * 8; // in us
  573. while (1) {
  574. Core::waitMicroseconds(5 * byteDuration); // Wait for 5 times the duration of a byte
  575. int n2 = available(port);
  576. if (n2 == n) {
  577. // No byte received during the delay, the transfer looks finished
  578. return;
  579. }
  580. n = n2;
  581. }
  582. }
  583.  
  584. void setPin(Port port, PinFunction function, GPIO::Pin pin) {
  585. switch (function) {
  586. case PinFunction::RX:
  587. PINS_RX[static_cast<int>(port)] = pin;
  588. break;
  589.  
  590. case PinFunction::TX:
  591. PINS_TX[static_cast<int>(port)] = pin;
  592. break;
  593.  
  594. case PinFunction::RTS:
  595. PINS_RTS[static_cast<int>(port)] = pin;
  596. break;
  597.  
  598. case PinFunction::CTS:
  599. PINS_CTS[static_cast<int>(port)] = pin;
  600. break;
  601. }
  602. }
  603.  
  604. }