PageRenderTime 27ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/modules/px4iofirmware/serial.c

https://gitlab.com/victorl/PX4Firmware
C | 358 lines | 205 code | 70 blank | 83 comment | 23 complexity | f074778f2cb87aa2b9b4113285479740 MD5 | raw file
  1. /****************************************************************************
  2. *
  3. * Copyright (C) 2012,2013 PX4 Development Team. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in
  13. * the documentation and/or other materials provided with the
  14. * distribution.
  15. * 3. Neither the name PX4 nor the names of its contributors may be
  16. * used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  29. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. ****************************************************************************/
  33. /**
  34. * @file serial.c
  35. *
  36. * Serial communication for the PX4IO module.
  37. */
  38. #include <stdint.h>
  39. #include <unistd.h>
  40. #include <termios.h>
  41. #include <fcntl.h>
  42. #include <string.h>
  43. #include <nuttx/arch.h>
  44. #include <arch/board/board.h>
  45. /* XXX might be able to prune these */
  46. #include <chip.h>
  47. #include <up_internal.h>
  48. #include <up_arch.h>
  49. #include <stm32.h>
  50. #include <systemlib/perf_counter.h>
  51. //#define DEBUG
  52. #include "px4io.h"
  53. static perf_counter_t pc_txns;
  54. static perf_counter_t pc_errors;
  55. static perf_counter_t pc_ore;
  56. static perf_counter_t pc_fe;
  57. static perf_counter_t pc_ne;
  58. static perf_counter_t pc_idle;
  59. static perf_counter_t pc_badidle;
  60. static perf_counter_t pc_regerr;
  61. static perf_counter_t pc_crcerr;
  62. static void rx_handle_packet(void);
  63. static void rx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg);
  64. static DMA_HANDLE tx_dma;
  65. static DMA_HANDLE rx_dma;
  66. static int serial_interrupt(int irq, void *context);
  67. static void dma_reset(void);
  68. static struct IOPacket dma_packet;
  69. /* serial register accessors */
  70. #define REG(_x) (*(volatile uint32_t *)(PX4FMU_SERIAL_BASE + _x))
  71. #define rSR REG(STM32_USART_SR_OFFSET)
  72. #define rDR REG(STM32_USART_DR_OFFSET)
  73. #define rBRR REG(STM32_USART_BRR_OFFSET)
  74. #define rCR1 REG(STM32_USART_CR1_OFFSET)
  75. #define rCR2 REG(STM32_USART_CR2_OFFSET)
  76. #define rCR3 REG(STM32_USART_CR3_OFFSET)
  77. #define rGTPR REG(STM32_USART_GTPR_OFFSET)
  78. void
  79. interface_init(void)
  80. {
  81. pc_txns = perf_alloc(PC_ELAPSED, "txns");
  82. pc_errors = perf_alloc(PC_COUNT, "errors");
  83. pc_ore = perf_alloc(PC_COUNT, "overrun");
  84. pc_fe = perf_alloc(PC_COUNT, "framing");
  85. pc_ne = perf_alloc(PC_COUNT, "noise");
  86. pc_idle = perf_alloc(PC_COUNT, "idle");
  87. pc_badidle = perf_alloc(PC_COUNT, "badidle");
  88. pc_regerr = perf_alloc(PC_COUNT, "regerr");
  89. pc_crcerr = perf_alloc(PC_COUNT, "crcerr");
  90. /* allocate DMA */
  91. tx_dma = stm32_dmachannel(PX4FMU_SERIAL_TX_DMA);
  92. rx_dma = stm32_dmachannel(PX4FMU_SERIAL_RX_DMA);
  93. /* configure pins for serial use */
  94. stm32_configgpio(PX4FMU_SERIAL_TX_GPIO);
  95. stm32_configgpio(PX4FMU_SERIAL_RX_GPIO);
  96. /* reset and configure the UART */
  97. rCR1 = 0;
  98. rCR2 = 0;
  99. rCR3 = 0;
  100. /* clear status/errors */
  101. (void)rSR;
  102. (void)rDR;
  103. /* configure line speed */
  104. uint32_t usartdiv32 = PX4FMU_SERIAL_CLOCK / (PX4FMU_SERIAL_BITRATE / 2);
  105. uint32_t mantissa = usartdiv32 >> 5;
  106. uint32_t fraction = (usartdiv32 - (mantissa << 5) + 1) >> 1;
  107. rBRR = (mantissa << USART_BRR_MANT_SHIFT) | (fraction << USART_BRR_FRAC_SHIFT);
  108. /* connect our interrupt */
  109. irq_attach(PX4FMU_SERIAL_VECTOR, serial_interrupt);
  110. up_enable_irq(PX4FMU_SERIAL_VECTOR);
  111. /* enable UART and error/idle interrupts */
  112. rCR3 = USART_CR3_EIE;
  113. rCR1 = USART_CR1_RE | USART_CR1_TE | USART_CR1_UE | USART_CR1_IDLEIE;
  114. #if 0 /* keep this for signal integrity testing */
  115. for (;;) {
  116. while (!(rSR & USART_SR_TXE))
  117. ;
  118. rDR = 0xfa;
  119. while (!(rSR & USART_SR_TXE))
  120. ;
  121. rDR = 0xa0;
  122. }
  123. #endif
  124. /* configure RX DMA and return to listening state */
  125. dma_reset();
  126. debug("serial init");
  127. }
  128. static void
  129. rx_handle_packet(void)
  130. {
  131. /* check packet CRC */
  132. uint8_t crc = dma_packet.crc;
  133. dma_packet.crc = 0;
  134. if (crc != crc_packet(&dma_packet)) {
  135. perf_count(pc_crcerr);
  136. /* send a CRC error reply */
  137. dma_packet.count_code = PKT_CODE_CORRUPT;
  138. dma_packet.page = 0xff;
  139. dma_packet.offset = 0xff;
  140. return;
  141. }
  142. if (PKT_CODE(dma_packet) == PKT_CODE_WRITE) {
  143. /* it's a blind write - pass it on */
  144. if (registers_set(dma_packet.page, dma_packet.offset, &dma_packet.regs[0], PKT_COUNT(dma_packet))) {
  145. perf_count(pc_regerr);
  146. dma_packet.count_code = PKT_CODE_ERROR;
  147. } else {
  148. dma_packet.count_code = PKT_CODE_SUCCESS;
  149. }
  150. return;
  151. }
  152. if (PKT_CODE(dma_packet) == PKT_CODE_READ) {
  153. /* it's a read - get register pointer for reply */
  154. unsigned count;
  155. uint16_t *registers;
  156. if (registers_get(dma_packet.page, dma_packet.offset, &registers, &count) < 0) {
  157. perf_count(pc_regerr);
  158. dma_packet.count_code = PKT_CODE_ERROR;
  159. } else {
  160. /* constrain reply to requested size */
  161. if (count > PKT_MAX_REGS) {
  162. count = PKT_MAX_REGS;
  163. }
  164. if (count > PKT_COUNT(dma_packet)) {
  165. count = PKT_COUNT(dma_packet);
  166. }
  167. /* copy reply registers into DMA buffer */
  168. memcpy((void *)&dma_packet.regs[0], registers, count * 2);
  169. dma_packet.count_code = count | PKT_CODE_SUCCESS;
  170. }
  171. return;
  172. }
  173. /* send a bad-packet error reply */
  174. dma_packet.count_code = PKT_CODE_CORRUPT;
  175. dma_packet.page = 0xff;
  176. dma_packet.offset = 0xfe;
  177. }
  178. static void
  179. rx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg)
  180. {
  181. /*
  182. * We are here because DMA completed, or UART reception stopped and
  183. * we think we have a packet in the buffer.
  184. */
  185. perf_begin(pc_txns);
  186. /* disable UART DMA */
  187. rCR3 &= ~(USART_CR3_DMAT | USART_CR3_DMAR);
  188. /* handle the received packet */
  189. rx_handle_packet();
  190. /* re-set DMA for reception first, so we are ready to receive before we start sending */
  191. dma_reset();
  192. /* send the reply to the just-processed request */
  193. dma_packet.crc = 0;
  194. dma_packet.crc = crc_packet(&dma_packet);
  195. stm32_dmasetup(
  196. tx_dma,
  197. (uint32_t)&rDR,
  198. (uint32_t)&dma_packet,
  199. PKT_SIZE(dma_packet),
  200. DMA_CCR_DIR |
  201. DMA_CCR_MINC |
  202. DMA_CCR_PSIZE_8BITS |
  203. DMA_CCR_MSIZE_8BITS);
  204. stm32_dmastart(tx_dma, NULL, NULL, false);
  205. rCR3 |= USART_CR3_DMAT;
  206. perf_end(pc_txns);
  207. }
  208. static int
  209. serial_interrupt(int irq, void *context)
  210. {
  211. static bool abort_on_idle = false;
  212. uint32_t sr = rSR; /* get UART status register */
  213. (void)rDR; /* required to clear any of the interrupt status that brought us here */
  214. if (sr & (USART_SR_ORE | /* overrun error - packet was too big for DMA or DMA was too slow */
  215. USART_SR_NE | /* noise error - we have lost a byte due to noise */
  216. USART_SR_FE)) { /* framing error - start/stop bit lost or line break */
  217. perf_count(pc_errors);
  218. if (sr & USART_SR_ORE) {
  219. perf_count(pc_ore);
  220. }
  221. if (sr & USART_SR_NE) {
  222. perf_count(pc_ne);
  223. }
  224. if (sr & USART_SR_FE) {
  225. perf_count(pc_fe);
  226. }
  227. /* send a line break - this will abort transmission/reception on the other end */
  228. rCR1 |= USART_CR1_SBK;
  229. /* when the line goes idle, abort rather than look at the packet */
  230. abort_on_idle = true;
  231. }
  232. if (sr & USART_SR_IDLE) {
  233. /*
  234. * If we saw an error, don't bother looking at the packet - it should have
  235. * been aborted by the sender and will definitely be bad. Get the DMA reconfigured
  236. * ready for their retry.
  237. */
  238. if (abort_on_idle) {
  239. abort_on_idle = false;
  240. dma_reset();
  241. return 0;
  242. }
  243. /*
  244. * The sender has stopped sending - this is probably the end of a packet.
  245. * Check the received length against the length in the header to see if
  246. * we have something that looks like a packet.
  247. */
  248. unsigned length = sizeof(dma_packet) - stm32_dmaresidual(rx_dma);
  249. if ((length < 1) || (length < PKT_SIZE(dma_packet))) {
  250. /* it was too short - possibly truncated */
  251. perf_count(pc_badidle);
  252. dma_reset();
  253. return 0;
  254. }
  255. /*
  256. * Looks like we received a packet. Stop the DMA and go process the
  257. * packet.
  258. */
  259. perf_count(pc_idle);
  260. stm32_dmastop(rx_dma);
  261. rx_dma_callback(rx_dma, DMA_STATUS_TCIF, NULL);
  262. }
  263. return 0;
  264. }
  265. static void
  266. dma_reset(void)
  267. {
  268. rCR3 &= ~(USART_CR3_DMAT | USART_CR3_DMAR);
  269. (void)rSR;
  270. (void)rDR;
  271. (void)rDR;
  272. /* kill any pending DMA */
  273. stm32_dmastop(tx_dma);
  274. stm32_dmastop(rx_dma);
  275. /* reset the RX side */
  276. stm32_dmasetup(
  277. rx_dma,
  278. (uint32_t)&rDR,
  279. (uint32_t)&dma_packet,
  280. sizeof(dma_packet),
  281. DMA_CCR_MINC |
  282. DMA_CCR_PSIZE_8BITS |
  283. DMA_CCR_MSIZE_8BITS |
  284. DMA_CCR_PRIVERYHI);
  285. /* start receive DMA ready for the next packet */
  286. stm32_dmastart(rx_dma, rx_dma_callback, NULL, false);
  287. rCR3 |= USART_CR3_DMAR;
  288. }