_hal_uart_dma.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /**************************************************************************************************
  2. Filename: _hal_uart_dma.c
  3. Revised: $Date: 2010-04-01 18:14:33 -0700 (Thu, 01 Apr 2010) $
  4. Revision: $Revision: 22068 $
  5. Description: This file contains the interface to the H/W UART driver by DMA.
  6. Copyright 2006-2010 Texas Instruments Incorporated. All rights reserved.
  7. IMPORTANT: Your use of this Software is limited to those specific rights
  8. granted under the terms of a software license agreement between the user
  9. who downloaded the software, his/her employer (which must be your employer)
  10. and Texas Instruments Incorporated (the "License"). You may not use this
  11. Software unless you agree to abide by the terms of the License. The License
  12. limits your use, and you acknowledge, that the Software may not be modified,
  13. copied or distributed unless embedded on a Texas Instruments microcontroller
  14. or used solely and exclusively in conjunction with a Texas Instruments radio
  15. frequency transceiver, which is integrated into your product. Other than for
  16. the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  17. works of, modify, distribute, perform, display or sell this Software and/or
  18. its documentation for any purpose.
  19. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  20. PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  21. INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  22. NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  23. TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  24. NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  25. LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  26. INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  27. OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  28. OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  29. (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
  30. Should you have any questions regarding your right to use this Software,
  31. contact Texas Instruments Incorporated at www.TI.com.
  32. **************************************************************************************************/
  33. /*********************************************************************
  34. * INCLUDES
  35. */
  36. #include "hal_types.h"
  37. #include "hal_assert.h"
  38. #include "hal_board.h"
  39. #include "hal_defs.h"
  40. #include "hal_dma.h"
  41. #include "hal_mcu.h"
  42. #include "hal_uart.h"
  43. #if defined MT_TASK
  44. #include "mt_uart.h"
  45. #endif
  46. #include "osal.h"
  47. /*********************************************************************
  48. * MACROS
  49. */
  50. //#define HAL_UART_ASSERT(expr) HAL_ASSERT((expr))
  51. #define HAL_UART_ASSERT(expr)
  52. #if defined HAL_BOARD_CC2430EB || defined HAL_BOARD_CC2430DB || defined HAL_BOARD_CC2430BB
  53. #define HAL_UART_DMA_NEW_RX_BYTE(IDX) (DMA_PAD == LO_UINT16(dmaCfg.rxBuf[(IDX)]))
  54. #define HAL_UART_DMA_GET_RX_BYTE(IDX) (HI_UINT16(dmaCfg.rxBuf[(IDX)]))
  55. #define HAL_UART_DMA_CLR_RX_BYTE(IDX) (dmaCfg.rxBuf[(IDX)] = BUILD_UINT16((DMA_PAD ^ 0xFF), 0))
  56. #else
  57. #define HAL_UART_DMA_NEW_RX_BYTE(IDX) (DMA_PAD == HI_UINT16(dmaCfg.rxBuf[(IDX)]))
  58. #define HAL_UART_DMA_GET_RX_BYTE(IDX) (LO_UINT16(dmaCfg.rxBuf[(IDX)]))
  59. #define HAL_UART_DMA_CLR_RX_BYTE(IDX) (dmaCfg.rxBuf[(IDX)] = BUILD_UINT16(0, (DMA_PAD ^ 0xFF)))
  60. #endif
  61. /*********************************************************************
  62. * CONSTANTS
  63. */
  64. // UxCSR - USART Control and Status Register.
  65. #define CSR_MODE 0x80
  66. #define CSR_RE 0x40
  67. #define CSR_SLAVE 0x20
  68. #define CSR_FE 0x10
  69. #define CSR_ERR 0x08
  70. #define CSR_RX_BYTE 0x04
  71. #define CSR_TX_BYTE 0x02
  72. #define CSR_ACTIVE 0x01
  73. // UxUCR - USART UART Control Register.
  74. #define UCR_FLUSH 0x80
  75. #define UCR_FLOW 0x40
  76. #define UCR_D9 0x20
  77. #define UCR_BIT9 0x10
  78. #define UCR_PARITY 0x08
  79. #define UCR_SPB 0x04
  80. #define UCR_STOP 0x02
  81. #define UCR_START 0x01
  82. #define UTX0IE 0x04
  83. #define UTX1IE 0x08
  84. #define P2DIR_PRIPO 0xC0
  85. // Incompatible redefinitions result with more than one UART driver sub-module.
  86. #undef PxOUT
  87. #undef PxDIR
  88. #undef PxSEL
  89. #undef UxCSR
  90. #undef UxUCR
  91. #undef UxDBUF
  92. #undef UxBAUD
  93. #undef UxGCR
  94. #undef URXxIE
  95. #undef URXxIF
  96. #undef UTXxIE
  97. #undef UTXxIF
  98. #undef HAL_UART_PERCFG_BIT
  99. #undef HAL_UART_Px_RTS
  100. #undef HAL_UART_Px_CTS
  101. #undef HAL_UART_Px_RX_TX
  102. #if (HAL_UART_DMA == 1)
  103. #define PxOUT P0
  104. #define PxIN P0
  105. #define PxDIR P0DIR
  106. #define PxSEL P0SEL
  107. #define UxCSR U0CSR
  108. #define UxUCR U0UCR
  109. #define UxDBUF U0DBUF
  110. #define UxBAUD U0BAUD
  111. #define UxGCR U0GCR
  112. #define URXxIE URX0IE
  113. #define URXxIF URX0IF
  114. #define UTXxIE UTX0IE
  115. #define UTXxIF UTX0IF
  116. #else
  117. #define PxOUT P1
  118. #define PxIN P1
  119. #define PxDIR P1DIR
  120. #define PxSEL P1SEL
  121. #define UxCSR U1CSR
  122. #define UxUCR U1UCR
  123. #define UxDBUF U1DBUF
  124. #define UxBAUD U1BAUD
  125. #define UxGCR U1GCR
  126. #define URXxIE URX1IE
  127. #define URXxIF URX1IF
  128. #define UTXxIE UTX1IE
  129. #define UTXxIF UTX1IF
  130. #endif
  131. #if (HAL_UART_DMA == 1)
  132. #define HAL_UART_PERCFG_BIT 0x01 // USART0 on P0, Alt-1; so clear this bit.
  133. #define HAL_UART_Px_RX_TX 0x0C // Peripheral I/O Select for Rx/Tx.
  134. #define HAL_UART_Px_RTS 0x20 // Peripheral I/O Select for RTS.
  135. #define HAL_UART_Px_CTS 0x10 // Peripheral I/O Select for CTS.
  136. #else
  137. #define HAL_UART_PERCFG_BIT 0x02 // USART1 on P1, Alt-2; so set this bit.
  138. #define HAL_UART_Px_RTS 0x20 // Peripheral I/O Select for RTS.
  139. #define HAL_UART_Px_CTS 0x10 // Peripheral I/O Select for CTS.
  140. #define HAL_UART_Px_RX_TX 0xC0 // Peripheral I/O Select for Rx/Tx.
  141. #endif
  142. // The timeout tick is at 32-kHz, so multiply msecs by 33.
  143. #define HAL_UART_MSECS_TO_TICKS 33
  144. #if defined MT_TASK
  145. #define HAL_UART_DMA_TX_MAX MT_UART_DEFAULT_MAX_TX_BUFF
  146. #define HAL_UART_DMA_RX_MAX MT_UART_DEFAULT_MAX_RX_BUFF
  147. #define HAL_UART_DMA_HIGH MT_UART_DEFAULT_THRESHOLD
  148. #define HAL_UART_DMA_IDLE (MT_UART_DEFAULT_IDLE_TIMEOUT * HAL_UART_MSECS_TO_TICKS)
  149. #else
  150. #if !defined HAL_UART_DMA_RX_MAX
  151. #define HAL_UART_DMA_RX_MAX 256
  152. #endif
  153. #if !defined HAL_UART_DMA_TX_MAX
  154. #define HAL_UART_DMA_TX_MAX HAL_UART_DMA_RX_MAX
  155. #endif
  156. #if !defined HAL_UART_DMA_HIGH
  157. #define HAL_UART_DMA_HIGH (HAL_UART_DMA_RX_MAX / 2 - 16)
  158. #endif
  159. #if !defined HAL_UART_DMA_IDLE
  160. #define HAL_UART_DMA_IDLE (1 * HAL_UART_MSECS_TO_TICKS)
  161. #endif
  162. #endif
  163. #if !defined HAL_UART_DMA_FULL
  164. #define HAL_UART_DMA_FULL (HAL_UART_DMA_RX_MAX - 16)
  165. #endif
  166. #if defined HAL_BOARD_CC2430EB || defined HAL_BOARD_CC2430DB || defined HAL_BOARD_CC2430BB
  167. #define HAL_DMA_U0DBUF 0xDFC1
  168. #define HAL_DMA_U1DBUF 0xDFF9
  169. #else /* CC2530 */
  170. #define HAL_DMA_U0DBUF 0x70C1
  171. #define HAL_DMA_U1DBUF 0x70F9
  172. #endif
  173. #if (HAL_UART_DMA == 1)
  174. #define DMATRIG_RX HAL_DMA_TRIG_URX0
  175. #define DMATRIG_TX HAL_DMA_TRIG_UTX0
  176. #define DMA_UDBUF HAL_DMA_U0DBUF
  177. #define DMA_PAD U0BAUD
  178. #else
  179. #define DMATRIG_RX HAL_DMA_TRIG_URX1
  180. #define DMATRIG_TX HAL_DMA_TRIG_UTX1
  181. #define DMA_UDBUF HAL_DMA_U1DBUF
  182. #define DMA_PAD U1BAUD
  183. #endif
  184. /*********************************************************************
  185. * TYPEDEFS
  186. */
  187. #if HAL_UART_DMA_RX_MAX <= 256
  188. typedef uint8 rxIdx_t;
  189. #else
  190. typedef uint16 rxIdx_t;
  191. #endif
  192. #if HAL_UART_DMA_TX_MAX <= 256
  193. typedef uint8 txIdx_t;
  194. #else
  195. typedef uint16 txIdx_t;
  196. #endif
  197. typedef struct
  198. {
  199. uint16 rxBuf[HAL_UART_DMA_RX_MAX];
  200. rxIdx_t rxHead;
  201. rxIdx_t rxTail;
  202. uint8 rxTick;
  203. uint8 rxShdw;
  204. uint8 txBuf[2][HAL_UART_DMA_TX_MAX];
  205. txIdx_t txIdx[2];
  206. volatile uint8 txSel;
  207. uint8 txMT;
  208. uint8 txTick; // 1-character time in 32kHz ticks according to baud rate,
  209. // to be used in calculating time lapse since DMA ISR
  210. // to allow delay margin before start firing DMA, so that
  211. // DMA does not overwrite UART DBUF of previous packet
  212. volatile uint8 txShdw; // Sleep Timer LSB shadow.
  213. volatile uint8 txShdwValid; // TX shadow value is valid
  214. uint8 txDMAPending; // UART TX DMA is pending
  215. halUARTCBack_t uartCB;
  216. } uartDMACfg_t;
  217. /*********************************************************************
  218. * GLOBAL VARIABLES
  219. */
  220. /*********************************************************************
  221. * GLOBAL FUNCTIONS
  222. */
  223. void HalUARTIsrDMA(void);
  224. /*********************************************************************
  225. * LOCAL VARIABLES
  226. */
  227. static uartDMACfg_t dmaCfg;
  228. /*********************************************************************
  229. * LOCAL FUNCTIONS
  230. */
  231. static rxIdx_t findTail(void);
  232. // Invoked by functions in hal_uart.c when this file is included.
  233. static void HalUARTInitDMA(void);
  234. static void HalUARTOpenDMA(halUARTCfg_t *config);
  235. static uint16 HalUARTReadDMA(uint8 *buf, uint16 len);
  236. static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len);
  237. static void HalUARTPollDMA(void);
  238. static uint16 HalUARTRxAvailDMA(void);
  239. static void HalUARTSuspendDMA(void);
  240. static void HalUARTResumeDMA(void);
  241. /*****************************************************************************
  242. * @fn findTail
  243. *
  244. * @brief Find the rxBuf index where the DMA RX engine is working.
  245. *
  246. * @param None.
  247. *
  248. * @return Index of tail of rxBuf.
  249. *****************************************************************************/
  250. static rxIdx_t findTail(void)
  251. {
  252. rxIdx_t idx = dmaCfg.rxHead;
  253. do
  254. {
  255. if (!HAL_UART_DMA_NEW_RX_BYTE(idx))
  256. {
  257. break;
  258. }
  259. #if HAL_UART_DMA_RX_MAX == 256
  260. idx++;
  261. #else
  262. if (++idx >= HAL_UART_DMA_RX_MAX)
  263. {
  264. idx = 0;
  265. }
  266. #endif
  267. } while (idx != dmaCfg.rxHead);
  268. return idx;
  269. }
  270. /******************************************************************************
  271. * @fn HalUARTInitDMA
  272. *
  273. * @brief Initialize the UART
  274. *
  275. * @param none
  276. *
  277. * @return none
  278. *****************************************************************************/
  279. static void HalUARTInitDMA(void)
  280. {
  281. halDMADesc_t *ch;
  282. P2DIR &= ~P2DIR_PRIPO;
  283. P2DIR |= HAL_UART_PRIPO;
  284. #if (HAL_UART_DMA == 1)
  285. PERCFG &= ~HAL_UART_PERCFG_BIT; // Set UART0 I/O to Alt. 1 location on P0.
  286. #else
  287. PERCFG |= HAL_UART_PERCFG_BIT; // Set UART1 I/O to Alt. 2 location on P1.
  288. #endif
  289. PxSEL |= HAL_UART_Px_RX_TX; // Enable Tx and Rx on P1.
  290. ADCCFG &= ~HAL_UART_Px_RX_TX; // Make sure ADC doesnt use this.
  291. UxCSR = CSR_MODE; // Mode is UART Mode.
  292. UxUCR = UCR_FLUSH; // Flush it.
  293. // Setup Tx by DMA.
  294. ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );
  295. // The start address of the destination.
  296. HAL_DMA_SET_DEST( ch, DMA_UDBUF );
  297. // Using the length field to determine how many bytes to transfer.
  298. HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );
  299. // One byte is transferred each time.
  300. HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE );
  301. // The bytes are transferred 1-by-1 on Tx Complete trigger.
  302. HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
  303. HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX );
  304. // The source address is incremented by 1 byte after each transfer.
  305. HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 );
  306. // The destination address is constant - the Tx Data Buffer.
  307. HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 );
  308. // The DMA Tx done is serviced by ISR in order to maintain full thruput.
  309. HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_ENABLE );
  310. // Xfer all 8 bits of a byte xfer.
  311. HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );
  312. // DMA has highest priority for memory access.
  313. HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );
  314. // Setup Rx by DMA.
  315. ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );
  316. // The start address of the source.
  317. HAL_DMA_SET_SOURCE( ch, DMA_UDBUF );
  318. // Using the length field to determine how many bytes to transfer.
  319. HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );
  320. /* The trick is to cfg DMA to xfer 2 bytes for every 1 byte of Rx.
  321. * The byte after the Rx Data Buffer is the Baud Cfg Register,
  322. * which always has a known value. So init Rx buffer to inverse of that
  323. * known value. DMA word xfer will flip the bytes, so every valid Rx byte
  324. * in the Rx buffer will be preceded by a DMA_PAD char equal to the
  325. * Baud Cfg Register value.
  326. */
  327. HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_WORD );
  328. // The bytes are transferred 1-by-1 on Rx Complete trigger.
  329. HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE_REPEATED );
  330. HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_RX );
  331. // The source address is constant - the Rx Data Buffer.
  332. HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_0 );
  333. // The destination address is incremented by 1 word after each transfer.
  334. HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_1 );
  335. HAL_DMA_SET_DEST( ch, dmaCfg.rxBuf );
  336. HAL_DMA_SET_LEN( ch, HAL_UART_DMA_RX_MAX );
  337. // The DMA is to be polled and shall not issue an IRQ upon completion.
  338. HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );
  339. // Xfer all 8 bits of a byte xfer.
  340. HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );
  341. // DMA has highest priority for memory access.
  342. HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );
  343. }
  344. /******************************************************************************
  345. * @fn HalUARTOpenDMA
  346. *
  347. * @brief Open a port according tp the configuration specified by parameter.
  348. *
  349. * @param config - contains configuration information
  350. *
  351. * @return none
  352. *****************************************************************************/
  353. static void HalUARTOpenDMA(halUARTCfg_t *config)
  354. {
  355. dmaCfg.uartCB = config->callBackFunc;
  356. // Only supporting subset of baudrate for code size - other is possible.
  357. HAL_UART_ASSERT((config->baudRate == HAL_UART_BR_9600) ||
  358. (config->baudRate == HAL_UART_BR_19200) ||
  359. (config->baudRate == HAL_UART_BR_38400) ||
  360. (config->baudRate == HAL_UART_BR_57600) ||
  361. (config->baudRate == HAL_UART_BR_115200));
  362. if (config->baudRate == HAL_UART_BR_57600 ||
  363. config->baudRate == HAL_UART_BR_115200)
  364. {
  365. UxBAUD = 216;
  366. }
  367. else
  368. {
  369. UxBAUD = 59;
  370. }
  371. switch (config->baudRate)
  372. {
  373. case HAL_UART_BR_9600:
  374. UxGCR = 8;
  375. dmaCfg.txTick = 35; // (32768Hz / (9600bps / 10 bits))
  376. // 10 bits include start and stop bits.
  377. break;
  378. case HAL_UART_BR_19200:
  379. UxGCR = 9;
  380. dmaCfg.txTick = 18;
  381. break;
  382. case HAL_UART_BR_38400:
  383. UxGCR = 10;
  384. dmaCfg.txTick = 9;
  385. break;
  386. case HAL_UART_BR_57600:
  387. UxGCR = 10;
  388. dmaCfg.txTick = 6;
  389. break;
  390. default:
  391. // HAL_UART_BR_115200
  392. UxGCR = 11;
  393. dmaCfg.txTick = 3;
  394. break;
  395. }
  396. // 8 bits/char; no parity; 1 stop bit; stop bit hi.
  397. if (config->flowControl)
  398. {
  399. UxUCR = UCR_FLOW | UCR_STOP;
  400. PxSEL |= HAL_UART_Px_CTS;
  401. // DMA Rx is always on (self-resetting). So flow must be controlled by the S/W polling the Rx
  402. // buffer level. Start by allowing flow.
  403. PxOUT &= ~HAL_UART_Px_RTS;
  404. PxDIR |= HAL_UART_Px_RTS;
  405. }
  406. else
  407. {
  408. UxUCR = UCR_STOP;
  409. }
  410. dmaCfg.rxBuf[0] = *(volatile uint8 *)DMA_UDBUF; // Clear the DMA Rx trigger.
  411. HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_RX);
  412. HAL_DMA_ARM_CH(HAL_DMA_CH_RX);
  413. osal_memset(dmaCfg.rxBuf, (DMA_PAD ^ 0xFF), HAL_UART_DMA_RX_MAX*2);
  414. UxCSR |= CSR_RE;
  415. // Initialize that TX DMA is not pending
  416. dmaCfg.txDMAPending = FALSE;
  417. dmaCfg.txShdwValid = FALSE;
  418. }
  419. /*****************************************************************************
  420. * @fn HalUARTReadDMA
  421. *
  422. * @brief Read a buffer from the UART
  423. *
  424. * @param buf - valid data buffer at least 'len' bytes in size
  425. * len - max length number of bytes to copy to 'buf'
  426. *
  427. * @return length of buffer that was read
  428. *****************************************************************************/
  429. static uint16 HalUARTReadDMA(uint8 *buf, uint16 len)
  430. {
  431. uint16 cnt;
  432. for (cnt = 0; cnt < len; cnt++)
  433. {
  434. if (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))
  435. {
  436. break;
  437. }
  438. *buf++ = HAL_UART_DMA_GET_RX_BYTE(dmaCfg.rxHead);
  439. HAL_UART_DMA_CLR_RX_BYTE(dmaCfg.rxHead);
  440. #if HAL_UART_DMA_RX_MAX == 256
  441. (dmaCfg.rxHead)++;
  442. #else
  443. if (++(dmaCfg.rxHead) >= HAL_UART_DMA_RX_MAX)
  444. {
  445. dmaCfg.rxHead = 0;
  446. }
  447. #endif
  448. }
  449. PxOUT &= ~HAL_UART_Px_RTS; // Re-enable the flow on any read.
  450. return cnt;
  451. }
  452. /******************************************************************************
  453. * @fn HalUARTWriteDMA
  454. *
  455. * @brief Write a buffer to the UART.
  456. *
  457. * @param buf - pointer to the buffer that will be written, not freed
  458. * len - length of
  459. *
  460. * @return length of the buffer that was sent
  461. *****************************************************************************/
  462. static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len)
  463. {
  464. uint16 cnt;
  465. halIntState_t his;
  466. uint8 txSel;
  467. txIdx_t txIdx;
  468. // Enforce all or none.
  469. if ((len + dmaCfg.txIdx[dmaCfg.txSel]) > HAL_UART_DMA_TX_MAX)
  470. {
  471. return 0;
  472. }
  473. HAL_ENTER_CRITICAL_SECTION(his);
  474. txSel = dmaCfg.txSel;
  475. txIdx = dmaCfg.txIdx[txSel];
  476. HAL_EXIT_CRITICAL_SECTION(his);
  477. for (cnt = 0; cnt < len; cnt++)
  478. {
  479. dmaCfg.txBuf[txSel][txIdx++] = buf[cnt];
  480. }
  481. HAL_ENTER_CRITICAL_SECTION(his);
  482. if (txSel != dmaCfg.txSel)
  483. {
  484. HAL_EXIT_CRITICAL_SECTION(his);
  485. txSel = dmaCfg.txSel;
  486. txIdx = dmaCfg.txIdx[txSel];
  487. for (cnt = 0; cnt < len; cnt++)
  488. {
  489. dmaCfg.txBuf[txSel][txIdx++] = buf[cnt];
  490. }
  491. HAL_ENTER_CRITICAL_SECTION(his);
  492. }
  493. dmaCfg.txIdx[txSel] = txIdx;
  494. if (dmaCfg.txIdx[(txSel ^ 1)] == 0)
  495. {
  496. // TX DMA is expected to be fired
  497. dmaCfg.txDMAPending = TRUE;
  498. }
  499. HAL_EXIT_CRITICAL_SECTION(his);
  500. return cnt;
  501. }
  502. /******************************************************************************
  503. * @fn HalUARTPollDMA
  504. *
  505. * @brief Poll a USART module implemented by DMA.
  506. *
  507. * @param none
  508. *
  509. * @return none
  510. *****************************************************************************/
  511. static void HalUARTPollDMA(void)
  512. {
  513. uint16 cnt = 0;
  514. uint8 evt = 0;
  515. if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))
  516. {
  517. rxIdx_t tail = findTail();
  518. // If the DMA has transferred in more Rx bytes, reset the Rx idle timer.
  519. if (dmaCfg.rxTail != tail)
  520. {
  521. dmaCfg.rxTail = tail;
  522. // Re-sync the shadow on any 1st byte(s) received.
  523. if (dmaCfg.rxTick == 0)
  524. {
  525. dmaCfg.rxShdw = ST0;
  526. }
  527. dmaCfg.rxTick = HAL_UART_DMA_IDLE;
  528. }
  529. else if (dmaCfg.rxTick)
  530. {
  531. // Use the LSB of the sleep timer (ST0 must be read first anyway).
  532. uint8 decr = ST0 - dmaCfg.rxShdw;
  533. if (dmaCfg.rxTick > decr)
  534. {
  535. dmaCfg.rxTick -= decr;
  536. dmaCfg.rxShdw = ST0;
  537. }
  538. else
  539. {
  540. dmaCfg.rxTick = 0;
  541. }
  542. }
  543. cnt = HalUARTRxAvailDMA();
  544. }
  545. else
  546. {
  547. dmaCfg.rxTick = 0;
  548. }
  549. if (cnt >= HAL_UART_DMA_FULL)
  550. {
  551. evt = HAL_UART_RX_FULL;
  552. }
  553. else if (cnt >= HAL_UART_DMA_HIGH)
  554. {
  555. evt = HAL_UART_RX_ABOUT_FULL;
  556. PxOUT |= HAL_UART_Px_RTS; // Disable Rx flow.
  557. }
  558. else if (cnt && !dmaCfg.rxTick)
  559. {
  560. evt = HAL_UART_RX_TIMEOUT;
  561. }
  562. if (dmaCfg.txMT)
  563. {
  564. dmaCfg.txMT = FALSE;
  565. evt |= HAL_UART_TX_EMPTY;
  566. }
  567. if (dmaCfg.txShdwValid)
  568. {
  569. uint8 decr = ST0;
  570. decr -= dmaCfg.txShdw;
  571. if (decr > dmaCfg.txTick)
  572. {
  573. // No protection for txShdwValid is required
  574. // because while the shadow was valid, DMA ISR cannot be triggered
  575. // to cause concurrent access to this variable.
  576. dmaCfg.txShdwValid = FALSE;
  577. }
  578. }
  579. if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid)
  580. {
  581. // UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR
  582. // to know that DBUF can be overwritten
  583. halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX);
  584. halIntState_t intState;
  585. // Clear the DMA pending flag
  586. dmaCfg.txDMAPending = FALSE;
  587. HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]);
  588. HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]);
  589. dmaCfg.txSel ^= 1;
  590. HAL_ENTER_CRITICAL_SECTION(intState);
  591. HAL_DMA_ARM_CH(HAL_DMA_CH_TX);
  592. do
  593. {
  594. asm("NOP");
  595. } while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX));
  596. HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX);
  597. HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX);
  598. HAL_EXIT_CRITICAL_SECTION(intState);
  599. }
  600. else
  601. {
  602. halIntState_t his;
  603. HAL_ENTER_CRITICAL_SECTION(his);
  604. if ((dmaCfg.txIdx[dmaCfg.txSel] != 0) && !HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)
  605. && !HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX))
  606. {
  607. HAL_EXIT_CRITICAL_SECTION(his);
  608. HalUARTIsrDMA();
  609. }
  610. else
  611. {
  612. HAL_EXIT_CRITICAL_SECTION(his);
  613. }
  614. }
  615. if (evt && (dmaCfg.uartCB != NULL))
  616. {
  617. dmaCfg.uartCB(HAL_UART_DMA-1, evt);
  618. }
  619. }
  620. /**************************************************************************************************
  621. * @fn HalUARTRxAvailDMA()
  622. *
  623. * @brief Calculate Rx Buffer length - the number of bytes in the buffer.
  624. *
  625. * @param none
  626. *
  627. * @return length of current Rx Buffer
  628. **************************************************************************************************/
  629. static uint16 HalUARTRxAvailDMA(void)
  630. {
  631. uint16 cnt = 0;
  632. if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))
  633. {
  634. uint16 idx;
  635. for (idx = 0; idx < HAL_UART_DMA_RX_MAX; idx++)
  636. {
  637. if (HAL_UART_DMA_NEW_RX_BYTE(idx))
  638. {
  639. cnt++;
  640. }
  641. }
  642. }
  643. return cnt;
  644. }
  645. /******************************************************************************
  646. * @fn HalUARTSuspendDMA
  647. *
  648. * @brief Suspend UART hardware before entering PM mode 1, 2 or 3.
  649. *
  650. * @param None
  651. *
  652. * @return None
  653. *****************************************************************************/
  654. static void HalUARTSuspendDMA( void )
  655. {
  656. PxOUT |= HAL_UART_Px_RTS; // Disable Rx flow.
  657. UxCSR &= ~CSR_RE;
  658. P0IEN |= HAL_UART_Px_CTS; // Enable the CTS ISR.
  659. }
  660. /******************************************************************************
  661. * @fn HalUARTResumeDMA
  662. *
  663. * @brief Resume UART hardware after exiting PM mode 1, 2 or 3.
  664. *
  665. * @param None
  666. *
  667. * @return None
  668. *****************************************************************************/
  669. static void HalUARTResumeDMA( void )
  670. {
  671. P0IEN &= ~HAL_UART_Px_CTS; // Disable the CTS ISR.
  672. UxUCR |= UCR_FLUSH;
  673. UxCSR |= CSR_RE;
  674. PxOUT &= ~HAL_UART_Px_RTS; // Re-enable Rx flow.
  675. }
  676. /******************************************************************************
  677. * @fn HalUARTIsrDMA
  678. *
  679. * @brief Handle the Tx done DMA ISR.
  680. *
  681. * @param none
  682. *
  683. * @return none
  684. *****************************************************************************/
  685. void HalUARTIsrDMA(void);
  686. void HalUARTIsrDMA(void)
  687. {
  688. HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX);
  689. // Indicate that the other buffer is free now.
  690. dmaCfg.txIdx[(dmaCfg.txSel ^ 1)] = 0;
  691. dmaCfg.txMT = TRUE;
  692. // Set TX shadow
  693. dmaCfg.txShdw = ST0;
  694. dmaCfg.txShdwValid = TRUE;
  695. // If there is more Tx data ready to go, re-start the DMA immediately on it.
  696. if (dmaCfg.txIdx[dmaCfg.txSel])
  697. {
  698. // UART TX DMA is expected to be fired
  699. dmaCfg.txDMAPending = TRUE;
  700. }
  701. }
  702. /******************************************************************************
  703. ******************************************************************************/