cyhal_uart.c 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. /*******************************************************************************
  2. * File Name: cyhal_uart.c
  3. *
  4. * Description:
  5. * Provides a high level interface for interacting with the Infineon UART. This is
  6. * a wrapper around the lower level PDL API.
  7. *
  8. ********************************************************************************
  9. * \copyright
  10. * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
  11. * an affiliate of Cypress Semiconductor Corporation
  12. *
  13. * SPDX-License-Identifier: Apache-2.0
  14. *
  15. * Licensed under the Apache License, Version 2.0 (the "License");
  16. * you may not use this file except in compliance with the License.
  17. * You may obtain a copy of the License at
  18. *
  19. * http://www.apache.org/licenses/LICENSE-2.0
  20. *
  21. * Unless required by applicable law or agreed to in writing, software
  22. * distributed under the License is distributed on an "AS IS" BASIS,
  23. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  24. * See the License for the specific language governing permissions and
  25. * limitations under the License.
  26. *******************************************************************************/
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include "cyhal_uart.h"
  30. #include "cyhal_scb_common.h"
  31. #include "cyhal_gpio.h"
  32. #include "cyhal_system_impl.h"
  33. #include "cyhal_hwmgr.h"
  34. #include "cyhal_syspm.h"
  35. #include "cyhal_clock.h"
  36. #include "cyhal_interconnect.h"
  37. #include "cyhal_irq_impl.h"
  38. #if (CYHAL_DRIVER_AVAILABLE_UART)
  39. #if defined(__cplusplus)
  40. extern "C"
  41. {
  42. #endif
  43. #define _CYHAL_UART_OVERSAMPLE 12UL
  44. #define _CYHAL_UART_OVERSAMPLE_MIN 8UL
  45. #define _CYHAL_UART_OVERSAMPLE_MAX 16UL
  46. /* Default UART configuration */
  47. static const cy_stc_scb_uart_config_t _cyhal_uart_default_config = {
  48. .uartMode = CY_SCB_UART_STANDARD,
  49. .enableMutliProcessorMode = false,
  50. .smartCardRetryOnNack = false,
  51. .irdaInvertRx = false,
  52. .irdaEnableLowPowerReceiver = false,
  53. .oversample = _CYHAL_UART_OVERSAMPLE,
  54. .enableMsbFirst = false,
  55. .dataWidth = 8UL,
  56. .parity = CY_SCB_UART_PARITY_NONE,
  57. .stopBits = CY_SCB_UART_STOP_BITS_1,
  58. .enableInputFilter = false,
  59. .breakWidth = 11UL,
  60. .dropOnFrameError = false,
  61. .dropOnParityError = false,
  62. .receiverAddress = 0x0UL,
  63. .receiverAddressMask = 0x0UL,
  64. .acceptAddrInFifo = false,
  65. .enableCts = false,
  66. .ctsPolarity = CY_SCB_UART_ACTIVE_LOW,
  67. #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1D)
  68. .rtsRxFifoLevel = 20UL,
  69. #elif defined(COMPONENT_CAT2)
  70. .rtsRxFifoLevel = 3UL,
  71. #endif
  72. .rtsPolarity = CY_SCB_UART_ACTIVE_LOW,
  73. .rxFifoTriggerLevel = 0UL, /* Level triggers when at least one element is in FIFO */
  74. .rxFifoIntEnableMask = 0x0UL,
  75. .txFifoTriggerLevel = (CY_SCB_FIFO_SIZE/2 - 1), /* Level triggers when half-fifo is half empty */
  76. .txFifoIntEnableMask = 0x0UL
  77. };
  78. /* The PDL clears the IRQ status during Cy_SCB_UART_Interrupt which prevents _cyhal_scb_get_irq_obj()
  79. * from working properly in _cyhal_uart_cb_wrapper on devices with muxed IRQs, because they can't tell
  80. * at that point which system IRQ caused the CPU IRQ. So we need to save this value at the beginning of the
  81. * IRQ handler when we are able to determine what it is */
  82. static volatile cyhal_uart_t* _cyhal_uart_irq_obj = NULL;
  83. #if defined (COMPONENT_CAT5)
  84. static void _cyhal_uart_irq_handler(_cyhal_system_irq_t irqn)
  85. #else
  86. static void _cyhal_uart_irq_handler(void)
  87. #endif
  88. {
  89. /* Save the old value and store it aftewards in case we get into a nested IRQ situation */
  90. /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
  91. * just might change where the original pointer points */
  92. cyhal_uart_t* old_irq_obj = (cyhal_uart_t*)_cyhal_uart_irq_obj;
  93. #if defined (COMPONENT_CAT5)
  94. _cyhal_uart_irq_obj = (cyhal_uart_t*) _cyhal_scb_get_irq_obj(irqn);
  95. #else
  96. _cyhal_uart_irq_obj = (cyhal_uart_t*) _cyhal_scb_get_irq_obj();
  97. #endif
  98. if (NULL == _cyhal_uart_irq_obj)
  99. {
  100. return; /* The interrupt object is not valid */
  101. }
  102. cyhal_uart_t* obj = (cyhal_uart_t*)_cyhal_uart_irq_obj;
  103. /* Cy_SCB_UART_Interrupt() manipulates the interrupt masks. Save a copy to work around it. */
  104. uint32_t txMasked = Cy_SCB_GetTxInterruptStatusMasked(obj->base);
  105. uint32_t rxMasked = Cy_SCB_GetRxInterruptStatusMasked(obj->base);
  106. /* SCB high-level API interrupt handler. Must be called as high-level API is used in the HAL */
  107. Cy_SCB_UART_Interrupt(obj->base, &(obj->context));
  108. /* Custom handling for TX overflow (cannot occur using HAL API but can occur if user makes custom modifications)
  109. Note: This is partially handled in Cy_SCB_UART_Interrupt()
  110. but it only takes care of NACK and ARB_LOST errors. */
  111. if (0UL != (CY_SCB_UART_TX_OVERFLOW & txMasked))
  112. {
  113. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_OVERFLOW);
  114. if (NULL != obj->context.cbEvents)
  115. {
  116. obj->context.cbEvents(CY_SCB_UART_TRANSMIT_ERR_EVENT);
  117. }
  118. }
  119. /* Custom handling for TX underflow (cannot occur using HAL API but can occur if user makes custom modifications)
  120. Note: This is partially handled in Cy_SCB_UART_Interrupt()
  121. but it only takes care of NACK and ARB_LOST errors. */
  122. if (0UL != (CY_SCB_UART_TX_UNDERFLOW & txMasked))
  123. {
  124. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_UNDERFLOW);
  125. if (NULL != obj->context.cbEvents)
  126. {
  127. obj->context.cbEvents(CY_SCB_UART_TRANSMIT_ERR_EVENT);
  128. }
  129. }
  130. /* Custom handling for TX FIFO trigger.
  131. Note: This is partially handled in Cy_SCB_UART_Interrupt()
  132. when processing CY_SCB_TX_INTR_LEVEL. Do not clear the interrupt. */
  133. if (0UL != (CY_SCB_UART_TX_TRIGGER & txMasked))
  134. {
  135. if (NULL != obj->context.cbEvents)
  136. {
  137. // Need to shift by 1 due to to existing logic in _cyhal_utils_convert_flags()
  138. obj->context.cbEvents(CYHAL_UART_IRQ_TX_FIFO >> 1u);
  139. }
  140. }
  141. /* Manually clear the tx done interrupt and re-enable the interrupt mask */
  142. if (0UL != (CY_SCB_UART_TX_DONE & txMasked))
  143. {
  144. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_DONE);
  145. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | CY_SCB_UART_TX_DONE);
  146. }
  147. /* Custom handling for RX underflow (cannot occur using HAL API but can occur if user makes custom modifications)
  148. Note: This is partially handled in Cy_SCB_UART_Interrupt()
  149. which takes care of overflow, frame and parity errors. */
  150. if (0UL != (CY_SCB_RX_INTR_UNDERFLOW & rxMasked))
  151. {
  152. Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_RX_INTR_UNDERFLOW);
  153. if (NULL != obj->context.cbEvents)
  154. {
  155. obj->context.cbEvents(CY_SCB_UART_RECEIVE_ERR_EVENT);
  156. }
  157. }
  158. /* Custom handling for RX FIFO trigger
  159. Note: This is partially handled in Cy_SCB_UART_Interrupt()
  160. when processing CY_SCB_RX_INTR_LEVEL. Do not clear the interrupt. */
  161. if (0UL != (CY_SCB_UART_RX_TRIGGER & rxMasked))
  162. {
  163. if (NULL != obj->context.cbEvents)
  164. {
  165. // Need to shift by 1 due to to existing logic in _cyhal_utils_convert_flags()
  166. obj->context.cbEvents(CYHAL_UART_IRQ_RX_FIFO >> 1u);
  167. }
  168. }
  169. _cyhal_uart_irq_obj = old_irq_obj;
  170. }
  171. #if defined (COMPONENT_CAT5)
  172. static void _cyhal_uart0_irq_handler(void)
  173. {
  174. _cyhal_uart_irq_handler(scb_0_interrupt_IRQn);
  175. }
  176. static void _cyhal_uart1_irq_handler(void)
  177. {
  178. _cyhal_uart_irq_handler(scb_1_interrupt_IRQn);
  179. }
  180. static void _cyhal_uart2_irq_handler(void)
  181. {
  182. _cyhal_uart_irq_handler(scb_2_interrupt_IRQn);
  183. }
  184. static CY_SCB_IRQ_THREAD_CB_t _cyhal_irq_cb[3] = {_cyhal_uart0_irq_handler, _cyhal_uart1_irq_handler, _cyhal_uart2_irq_handler};
  185. #endif
  186. static void _cyhal_uart_cb_wrapper(uint32_t event)
  187. {
  188. static const uint32_t status_map[] =
  189. {
  190. /* The ordering here has to match group_scb_uart_macros_callback_events in the PDL since it uses
  191. the high-level APIs to perform the callback handling.
  192. Note: Remember that the values are shifted by 1. */
  193. (uint32_t)CYHAL_UART_IRQ_NONE, // 0: Default no IRQ
  194. (uint32_t)CYHAL_UART_IRQ_TX_TRANSMIT_IN_FIFO, // 1: CY_SCB_UART_TRANSMIT_IN_FIFO_EVENT
  195. (uint32_t)CYHAL_UART_IRQ_TX_DONE, // 2: CY_SCB_UART_TRANSMIT_DONE_EVENT
  196. (uint32_t)CYHAL_UART_IRQ_RX_DONE, // 3: CY_SCB_UART_RECEIVE_DONE_EVENT
  197. (uint32_t)CYHAL_UART_IRQ_RX_FULL, // 4: CY_SCB_UART_RB_FULL_EVENT
  198. (uint32_t)CYHAL_UART_IRQ_RX_ERROR, // 5: CY_SCB_UART_RECEIVE_ERR_EVENT
  199. (uint32_t)CYHAL_UART_IRQ_TX_ERROR, // 6: CY_SCB_UART_TRANSMIT_ERR_EVENT
  200. (uint32_t)CYHAL_UART_IRQ_RX_NOT_EMPTY, // 7: CY_SCB_UART_RECEIVE_NOT_EMTPY
  201. (uint32_t)CYHAL_UART_IRQ_TX_EMPTY, // 8: CY_SCB_UART_TRANSMIT_EMTPY
  202. // Custom events from HAL
  203. (uint32_t)CYHAL_UART_IRQ_TX_FIFO, // 9: CYHAL_UART_IRQ_TX_FIFO
  204. (uint32_t)CYHAL_UART_IRQ_RX_FIFO, // 10: CYHAL_UART_IRQ_RX_FIFO
  205. };
  206. uint32_t hal_event = _cyhal_utils_convert_flags(status_map, sizeof(status_map) / sizeof(uint32_t), event);
  207. /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
  208. * just might change where the original pointer points */
  209. cyhal_uart_t *obj = (cyhal_uart_t*)_cyhal_uart_irq_obj;
  210. cyhal_uart_event_t anded_events = (cyhal_uart_event_t)(obj->irq_cause & hal_event);
  211. if (anded_events)
  212. {
  213. cyhal_uart_event_callback_t callback = (cyhal_uart_event_callback_t) obj->callback_data.callback;
  214. callback(obj->callback_data.callback_arg, anded_events);
  215. }
  216. }
  217. static bool _cyhal_uart_pm_callback_instance(void *obj_ptr, cyhal_syspm_callback_state_t state, cy_en_syspm_callback_mode_t pdl_mode)
  218. {
  219. CY_UNUSED_PARAMETER(state);
  220. cyhal_uart_t *obj = (cyhal_uart_t*)obj_ptr;
  221. bool allow = false;
  222. // The output pins need to be set to high before going to deepsleep.
  223. // Otherwise the UART on the other side would see incoming data as '0'.
  224. GPIO_PRT_Type *txport = obj->pin_tx != NC ? CYHAL_GET_PORTADDR(obj->pin_tx) : NULL;
  225. GPIO_PRT_Type *rtsport = ((obj->pin_rts != NC) && obj->rts_enabled) ? CYHAL_GET_PORTADDR(obj->pin_rts) : NULL;
  226. uint8_t txpin = (uint8_t)CYHAL_GET_PIN(obj->pin_tx);
  227. uint8_t rtspin = (uint8_t)CYHAL_GET_PIN(obj->pin_rts);
  228. #if defined (COMPONENT_CAT5)
  229. CY_UNUSED_PARAMETER(txpin);
  230. CY_UNUSED_PARAMETER(rtspin);
  231. #endif
  232. switch (pdl_mode)
  233. {
  234. case CY_SYSPM_CHECK_READY:
  235. /* Check whether the High-level API is not busy executing the transmit
  236. * or receive operation.
  237. */
  238. if ((0UL == (CY_SCB_UART_TRANSMIT_ACTIVE & Cy_SCB_UART_GetTransmitStatus(obj->base, &(obj->context)))) &&
  239. (0UL == (CY_SCB_UART_RECEIVE_ACTIVE & Cy_SCB_UART_GetReceiveStatus (obj->base, &(obj->context)))))
  240. {
  241. /* If all data elements are transmitted from the TX FIFO and
  242. * shifter and the RX FIFO is empty: the UART is ready to enter
  243. * Deep Sleep mode.
  244. */
  245. if (Cy_SCB_UART_IsTxComplete(obj->base))
  246. {
  247. if (0UL == Cy_SCB_UART_GetNumInRxFifo(obj->base))
  248. {
  249. /* Disable the UART. The transmitter stops driving the
  250. * lines and the receiver stops receiving data until
  251. * the UART is enabled.
  252. * This happens when the device failed to enter Deep
  253. * Sleep or it is awaken from Deep Sleep mode.
  254. */
  255. if (NULL != txport)
  256. {
  257. obj->saved_tx_hsiom = Cy_GPIO_GetHSIOM(txport, txpin);
  258. Cy_GPIO_Set(txport, txpin);
  259. Cy_GPIO_SetHSIOM(txport, txpin, HSIOM_SEL_GPIO);
  260. }
  261. if (NULL != rtsport)
  262. {
  263. obj->saved_rts_hsiom = Cy_GPIO_GetHSIOM(rtsport, rtspin);
  264. Cy_GPIO_Set(rtsport, rtspin);
  265. Cy_GPIO_SetHSIOM(rtsport, rtspin, HSIOM_SEL_GPIO);
  266. }
  267. Cy_SCB_UART_Disable(obj->base, &(obj->context));
  268. allow = true;
  269. }
  270. }
  271. }
  272. break;
  273. case CY_SYSPM_CHECK_FAIL:
  274. case CY_SYSPM_AFTER_TRANSITION:
  275. allow = true;
  276. Cy_SCB_UART_Enable(obj->base);
  277. if (NULL != txport)
  278. {
  279. Cy_GPIO_SetHSIOM(txport, txpin, obj->saved_tx_hsiom);
  280. }
  281. if (NULL != rtsport)
  282. {
  283. Cy_GPIO_SetHSIOM(rtsport, rtspin, obj->saved_rts_hsiom);
  284. }
  285. break;
  286. case CY_SYSPM_BEFORE_TRANSITION:
  287. allow = true;
  288. break;
  289. #if defined(COMPONENT_CAT1B)
  290. case CY_SYSPM_AFTER_DS_WFI_TRANSITION:
  291. allow = true;
  292. break;
  293. #endif
  294. default:
  295. CY_ASSERT(false);
  296. break;
  297. }
  298. return allow;
  299. }
  300. static cy_en_scb_uart_parity_t _cyhal_uart_convert_parity(cyhal_uart_parity_t parity)
  301. {
  302. switch (parity)
  303. {
  304. case CYHAL_UART_PARITY_NONE:
  305. return CY_SCB_UART_PARITY_NONE;
  306. case CYHAL_UART_PARITY_EVEN:
  307. return CY_SCB_UART_PARITY_EVEN;
  308. case CYHAL_UART_PARITY_ODD:
  309. return CY_SCB_UART_PARITY_ODD;
  310. default:
  311. return CY_SCB_UART_PARITY_NONE;
  312. }
  313. }
  314. static cy_en_scb_uart_stop_bits_t _cyhal_uart_convert_stopbits(uint8_t stopbits)
  315. {
  316. switch (stopbits)
  317. {
  318. case 1:
  319. return CY_SCB_UART_STOP_BITS_1;
  320. case 2:
  321. return CY_SCB_UART_STOP_BITS_2;
  322. case 3:
  323. return CY_SCB_UART_STOP_BITS_3;
  324. case 4:
  325. return CY_SCB_UART_STOP_BITS_4;
  326. default:
  327. CY_ASSERT(false);
  328. return CY_SCB_UART_STOP_BITS_1;
  329. }
  330. }
  331. static uint32_t _cyhal_uart_actual_baud(const cyhal_resource_inst_t *resource, uint32_t divider, uint32_t oversample)
  332. {
  333. return _cyhal_utils_get_peripheral_clock_frequency(resource) / (divider * oversample);
  334. }
  335. static uint32_t _cyhal_uart_baud_perdif(uint32_t desired_baud, uint32_t actual_baud)
  336. {
  337. return (actual_baud > desired_baud)
  338. ? ((actual_baud * 100) - (desired_baud * 100)) / desired_baud
  339. : ((desired_baud * 100) - (actual_baud * 100)) / desired_baud;
  340. }
  341. static uint8_t _cyhal_uart_best_oversample(const cyhal_resource_inst_t *resource, uint32_t baudrate)
  342. {
  343. uint8_t best_oversample = _CYHAL_UART_OVERSAMPLE_MIN;
  344. uint8_t best_difference = 0xFF;
  345. for (uint8_t i = _CYHAL_UART_OVERSAMPLE_MIN; i < _CYHAL_UART_OVERSAMPLE_MAX + 1; i++)
  346. {
  347. uint32_t divider = _cyhal_utils_divider_value(resource, baudrate * i, 0);
  348. uint8_t difference = (uint8_t)_cyhal_uart_baud_perdif(baudrate, _cyhal_uart_actual_baud(resource, divider, i));
  349. if (difference < best_difference)
  350. {
  351. best_difference = difference;
  352. best_oversample = i;
  353. }
  354. }
  355. return best_oversample;
  356. }
  357. static cy_rslt_t _cyhal_uart_setup_resources(cyhal_uart_t *obj, cyhal_gpio_t tx, cyhal_gpio_t rx, cyhal_gpio_t cts,
  358. cyhal_gpio_t rts, const cyhal_clock_t *clk)
  359. {
  360. cy_rslt_t result;
  361. // Explicitly marked not allocated resources as invalid to prevent freeing them.
  362. obj->resource.type = CYHAL_RSC_INVALID;
  363. obj->is_clock_owned = false;
  364. obj->pin_rx = CYHAL_NC_PIN_VALUE;
  365. obj->pin_tx = CYHAL_NC_PIN_VALUE;
  366. obj->pin_cts = CYHAL_NC_PIN_VALUE;
  367. obj->pin_rts = CYHAL_NC_PIN_VALUE;
  368. // checking for invalid flow control pin combinations (corresponding pin required) and checking that at least TX or RX is specified (both cannot be NC)
  369. if ((NC == tx && NC != rts) || (NC == rx && NC != cts) || (NC == tx && NC == rx))
  370. {
  371. return CYHAL_UART_RSLT_ERR_INVALID_PIN;
  372. }
  373. uint32_t saved_intr_status = cyhal_system_critical_section_enter();
  374. // pins_blocks will contain bit representation of blocks, that are connected to specified pin
  375. // 1 block - 1 bit, so, for example, pin_blocks = 0x00000006 means that certain pin
  376. // can belong to next non-reserved blocks SCB2 and SCB1
  377. uint32_t pins_blocks = _CYHAL_SCB_AVAILABLE_BLOCKS_MASK;
  378. if (NC != tx)
  379. {
  380. pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(tx, cyhal_pin_map_scb_uart_tx);
  381. }
  382. if (NC != rx)
  383. {
  384. pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(rx, cyhal_pin_map_scb_uart_rx);
  385. }
  386. if (NC != cts)
  387. {
  388. pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(cts, cyhal_pin_map_scb_uart_cts);
  389. }
  390. if (NC != rts)
  391. {
  392. pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(rts, cyhal_pin_map_scb_uart_rts);
  393. }
  394. // One (or more) pin does not belong to any SCB instance or all corresponding SCB instances
  395. // are reserved
  396. if (0 == pins_blocks)
  397. {
  398. cyhal_system_critical_section_exit(saved_intr_status);
  399. return CYHAL_UART_RSLT_ERR_INVALID_PIN;
  400. }
  401. uint8_t found_block_idx = 0;
  402. while(((pins_blocks >> found_block_idx) & 0x1) == 0)
  403. {
  404. found_block_idx++;
  405. }
  406. cyhal_resource_inst_t uart_rsc = { CYHAL_RSC_SCB, found_block_idx, 0 };
  407. // Reserve the UART
  408. const cyhal_resource_pin_mapping_t *tx_map = _CYHAL_SCB_FIND_MAP_BLOCK(tx, cyhal_pin_map_scb_uart_tx, &uart_rsc);
  409. const cyhal_resource_pin_mapping_t *rx_map = _CYHAL_SCB_FIND_MAP_BLOCK(rx, cyhal_pin_map_scb_uart_rx, &uart_rsc);
  410. const cyhal_resource_pin_mapping_t *cts_map = _CYHAL_SCB_FIND_MAP_BLOCK(cts, cyhal_pin_map_scb_uart_cts, &uart_rsc);
  411. const cyhal_resource_pin_mapping_t *rts_map = _CYHAL_SCB_FIND_MAP_BLOCK(rts, cyhal_pin_map_scb_uart_rts, &uart_rsc);
  412. if ((NC != tx && NULL == tx_map) || (NC != rx && NULL == rx_map) || (NC != cts && NULL == cts_map) || (NC != rts && NULL == rts_map))
  413. {
  414. // Should never enter here, as _CYHAL_SCB_CHECK_AFFILIATION above garantee that all of these pin maps exist.
  415. CY_ASSERT(false);
  416. }
  417. result = cyhal_hwmgr_reserve(&uart_rsc);
  418. cyhal_system_critical_section_exit(saved_intr_status);
  419. if (CY_RSLT_SUCCESS != result)
  420. {
  421. return result;
  422. }
  423. obj->resource = uart_rsc;
  424. // reserve the TX pin
  425. if ((result == CY_RSLT_SUCCESS) && NC != tx)
  426. {
  427. result = _cyhal_utils_reserve_and_connect(tx_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_TX);
  428. if (result == CY_RSLT_SUCCESS)
  429. {
  430. obj->pin_tx = tx;
  431. }
  432. }
  433. //reseve the RX pin
  434. if ((result == CY_RSLT_SUCCESS) && NC != rx)
  435. {
  436. result = _cyhal_utils_reserve_and_connect(rx_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_RX);
  437. if (result == CY_RSLT_SUCCESS)
  438. {
  439. obj->pin_rx = rx;
  440. }
  441. }
  442. if ((result == CY_RSLT_SUCCESS) && (NULL != cts_map))
  443. {
  444. // reserve the CTS pin
  445. result = _cyhal_utils_reserve_and_connect(cts_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_CTS);
  446. if (result == CY_RSLT_SUCCESS)
  447. {
  448. obj->cts_enabled = true;
  449. obj->pin_cts = cts;
  450. }
  451. }
  452. if ((result == CY_RSLT_SUCCESS) && (NULL != rts_map))
  453. {
  454. // reserve the RTS pin
  455. result = _cyhal_utils_reserve_and_connect(rts_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_RTS);
  456. if (result == CY_RSLT_SUCCESS)
  457. {
  458. obj->rts_enabled = true;
  459. obj->pin_rts = rts;
  460. }
  461. }
  462. if (result == CY_RSLT_SUCCESS)
  463. {
  464. if (clk == NULL)
  465. {
  466. result = _cyhal_utils_allocate_clock(&(obj->clock), &obj->resource, CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
  467. obj->is_clock_owned = (CY_RSLT_SUCCESS == result);
  468. }
  469. else
  470. {
  471. obj->is_clock_owned = false;
  472. obj->clock = *clk;
  473. }
  474. }
  475. if (result == CY_RSLT_SUCCESS)
  476. {
  477. result = _cyhal_utils_peri_pclk_assign_divider(
  478. _cyhal_scb_get_clock_index(obj->resource.block_num), &(obj->clock));
  479. }
  480. return result;
  481. }
  482. static cy_rslt_t _cyhal_uart_init_hw(cyhal_uart_t *obj)
  483. {
  484. uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
  485. obj->base = _CYHAL_SCB_BASE_ADDRESSES[scb_arr_index];
  486. cy_rslt_t result = (cy_rslt_t) Cy_SCB_UART_Init(obj->base, &(obj->config), &(obj->context));
  487. if (CY_RSLT_SUCCESS == result)
  488. {
  489. obj->callback_data.callback = NULL;
  490. obj->callback_data.callback_arg = NULL;
  491. obj->irq_cause = CYHAL_UART_IRQ_NONE;
  492. #if defined (COMPONENT_CAT5)
  493. Cy_SCB_RegisterInterruptCallback(obj->base, _cyhal_irq_cb[_CYHAL_SCB_IRQ_N[scb_arr_index]]);
  494. Cy_SCB_EnableInterrupt(obj->base);
  495. #endif
  496. _cyhal_irq_register(_CYHAL_SCB_IRQ_N[scb_arr_index], CYHAL_ISR_PRIORITY_DEFAULT, (cy_israddress)_cyhal_uart_irq_handler);
  497. _cyhal_irq_enable(_CYHAL_SCB_IRQ_N[scb_arr_index]);
  498. _cyhal_scb_update_instance_data(obj->resource.block_num, (void*)obj, &_cyhal_uart_pm_callback_instance);
  499. Cy_SCB_UART_Enable(obj->base);
  500. }
  501. return result;
  502. }
  503. cy_rslt_t cyhal_uart_init(cyhal_uart_t *obj, cyhal_gpio_t tx, cyhal_gpio_t rx, cyhal_gpio_t cts, cyhal_gpio_t rts,
  504. const cyhal_clock_t *clk, const cyhal_uart_cfg_t *cfg)
  505. {
  506. CY_ASSERT(NULL != obj);
  507. memset(obj, 0, sizeof(cyhal_uart_t));
  508. obj->dc_configured = false;
  509. cy_rslt_t result = _cyhal_uart_setup_resources(obj, tx, rx, cts, rts, clk);
  510. if (CY_RSLT_SUCCESS == result)
  511. {
  512. obj->config = _cyhal_uart_default_config;
  513. obj->config.enableCts = obj->cts_enabled;
  514. if (cfg != NULL)
  515. {
  516. obj->config.dataWidth = cfg->data_bits;
  517. obj->config.stopBits = _cyhal_uart_convert_stopbits((uint8_t)cfg->stop_bits);
  518. obj->config.parity = _cyhal_uart_convert_parity(cfg->parity);
  519. }
  520. result = _cyhal_uart_init_hw(obj);
  521. }
  522. if (CY_RSLT_SUCCESS == result)
  523. {
  524. if ((cfg != NULL) && (cfg->rx_buffer != NULL))
  525. {
  526. cyhal_uart_config_software_buffer(obj, cfg->rx_buffer, cfg->rx_buffer_size);
  527. }
  528. if (obj->is_clock_owned)
  529. {
  530. result = cyhal_uart_set_baud(obj, CYHAL_UART_DEFAULT_BAUD, NULL);
  531. }
  532. }
  533. if (CY_RSLT_SUCCESS != result)
  534. {
  535. cyhal_uart_free(obj);
  536. }
  537. return result;
  538. }
  539. cy_rslt_t cyhal_uart_init_cfg(cyhal_uart_t *obj, const cyhal_uart_configurator_t *cfg)
  540. {
  541. CY_ASSERT(NULL != obj);
  542. CY_ASSERT(NULL != cfg);
  543. CY_ASSERT(NULL != cfg->config);
  544. memset(obj, 0, sizeof(cyhal_uart_t));
  545. obj->resource = *cfg->resource;
  546. obj->clock = *cfg->clock;
  547. obj->is_clock_owned = false;
  548. obj->pin_tx = cfg->gpios.pin_tx;
  549. obj->pin_rts = cfg->gpios.pin_rts;
  550. obj->pin_cts = cfg->gpios.pin_cts;
  551. obj->dc_configured = true;
  552. obj->cts_enabled = cfg->config->enableCts;
  553. obj->rts_enabled = (NC != cfg->gpios.pin_rts);
  554. obj->config = *cfg->config;
  555. return _cyhal_uart_init_hw(obj);
  556. }
  557. void cyhal_uart_free(cyhal_uart_t *obj)
  558. {
  559. CY_ASSERT(NULL != obj);
  560. if (NULL != obj->base)
  561. {
  562. Cy_SCB_UART_Disable(obj->base, &obj->context);
  563. Cy_SCB_UART_DeInit(obj->base);
  564. obj->base = NULL;
  565. }
  566. if (obj->resource.type != CYHAL_RSC_INVALID)
  567. {
  568. uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
  569. _cyhal_system_irq_t irqn = _CYHAL_SCB_IRQ_N[scb_arr_index];
  570. _cyhal_irq_free(irqn);
  571. _cyhal_scb_update_instance_data(obj->resource.block_num, NULL, NULL);
  572. if (false == obj->dc_configured)
  573. {
  574. cyhal_hwmgr_free(&(obj->resource));
  575. }
  576. obj->resource.type = CYHAL_RSC_INVALID;
  577. }
  578. if (false == obj->dc_configured)
  579. {
  580. _cyhal_utils_release_if_used(&(obj->pin_rx));
  581. _cyhal_utils_release_if_used(&(obj->pin_tx));
  582. _cyhal_utils_release_if_used(&(obj->pin_rts));
  583. _cyhal_utils_release_if_used(&(obj->pin_cts));
  584. if (obj->is_clock_owned)
  585. {
  586. cyhal_clock_free(&(obj->clock));
  587. }
  588. }
  589. }
  590. cy_rslt_t cyhal_uart_set_baud(cyhal_uart_t *obj, uint32_t baudrate, uint32_t *actualbaud)
  591. {
  592. cy_rslt_t status;
  593. if (obj->is_clock_owned)
  594. {
  595. uint8_t oversample_value;
  596. uint32_t calculated_baud;
  597. uint32_t divider;
  598. Cy_SCB_UART_Disable(obj->base, NULL);
  599. status = cyhal_clock_set_enabled(&(obj->clock), false, false);
  600. if(status != CY_RSLT_SUCCESS)
  601. {
  602. Cy_SCB_UART_Enable(obj->base);
  603. return status;
  604. }
  605. oversample_value = _cyhal_uart_best_oversample(&(obj->resource), baudrate);
  606. obj->config.oversample = oversample_value;
  607. divider = _cyhal_utils_divider_value(&(obj->resource), baudrate * oversample_value, 0);
  608. /* Set baud rate */
  609. #if defined (COMPONENT_CAT5)
  610. status = _cyhal_utils_peri_pclk_set_freq(0, &(obj->clock), baudrate, oversample_value);
  611. #else
  612. status = cyhal_clock_set_divider(&(obj->clock), divider);
  613. #endif
  614. if(status != CY_RSLT_SUCCESS)
  615. {
  616. cyhal_clock_set_enabled(&(obj->clock), true, false);
  617. Cy_SCB_UART_Enable(obj->base);
  618. return status;
  619. }
  620. calculated_baud = _cyhal_uart_actual_baud(&(obj->resource), divider, oversample_value);
  621. if (actualbaud != NULL)
  622. *actualbaud = calculated_baud;
  623. uint32_t baud_difference = _cyhal_uart_baud_perdif(baudrate, calculated_baud);
  624. if (baud_difference > CYHAL_UART_MAX_BAUD_PERCENT_DIFFERENCE)
  625. status = CY_RSLT_WRN_CSP_UART_BAUD_TOLERANCE;
  626. status = cyhal_clock_set_enabled(&(obj->clock), true, false);
  627. /* Configure the UART interface */
  628. #if (CY_IP_MXSCB_VERSION >= 2) || (CY_IP_MXS22SCB_VERSION >= 1)
  629. uint32_t mem_width = (obj->config.dataWidth <= CY_SCB_BYTE_WIDTH)
  630. #if defined(COMPONENT_CAT1)
  631. ? CY_SCB_MEM_WIDTH_BYTE : CY_SCB_MEM_WIDTH_HALFWORD;
  632. #elif defined(COMPONENT_CAT2)
  633. ? CY_SCB_CTRL_MEM_WIDTH_BYTE : CY_SCB_CTRL_MEM_WIDTH_HALFWORD;
  634. #endif
  635. SCB_CTRL(obj->base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, obj->config.acceptAddrInFifo) |
  636. _BOOL2FLD(SCB_CTRL_MEM_WIDTH, mem_width) |
  637. _VAL2FLD(SCB_CTRL_OVS, oversample_value - 1) |
  638. _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
  639. #else /* Older versions of the block */
  640. SCB_CTRL(obj->base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, obj->config.acceptAddrInFifo) |
  641. _BOOL2FLD(SCB_CTRL_BYTE_MODE, (obj->config.dataWidth <= CY_SCB_BYTE_WIDTH)) |
  642. _VAL2FLD(SCB_CTRL_OVS, oversample_value - 1) |
  643. _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
  644. #endif
  645. Cy_SCB_UART_Enable(obj->base);
  646. }
  647. else
  648. {
  649. /* Not able to make changes in user-provided clock */
  650. status = CYHAL_UART_RSLT_CLOCK_ERROR;
  651. }
  652. return status;
  653. }
  654. cy_rslt_t cyhal_uart_configure(cyhal_uart_t *obj, const cyhal_uart_cfg_t *cfg)
  655. {
  656. CY_ASSERT(NULL != obj);
  657. CY_ASSERT(NULL != cfg);
  658. Cy_SCB_UART_Disable(obj->base, NULL);
  659. obj->config.dataWidth = cfg->data_bits;
  660. obj->config.stopBits = _cyhal_uart_convert_stopbits((uint8_t)cfg->stop_bits);
  661. obj->config.parity = _cyhal_uart_convert_parity(cfg->parity);
  662. obj->config.enableCts = obj->cts_enabled;
  663. // Do not pass obj->context here because Cy_SCB_UART_Init will destroy it
  664. Cy_SCB_UART_Init(obj->base, &(obj->config), NULL);
  665. Cy_SCB_UART_Enable(obj->base);
  666. return CY_RSLT_SUCCESS;
  667. }
  668. cy_rslt_t cyhal_uart_getc(cyhal_uart_t *obj, uint8_t *value, uint32_t timeout)
  669. {
  670. if (_cyhal_scb_pm_transition_pending())
  671. return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
  672. uint32_t read_value = Cy_SCB_UART_Get(obj->base);
  673. uint32_t timeoutTicks = timeout;
  674. while (read_value == CY_SCB_UART_RX_NO_DATA)
  675. {
  676. if(timeout != 0UL)
  677. {
  678. if(timeoutTicks > 0UL)
  679. {
  680. Cy_SysLib_Delay(1);
  681. timeoutTicks--;
  682. }
  683. else
  684. {
  685. return CY_RSLT_ERR_CSP_UART_GETC_TIMEOUT;
  686. }
  687. }
  688. read_value = Cy_SCB_UART_Get(obj->base);
  689. }
  690. *value = (uint8_t)read_value;
  691. return CY_RSLT_SUCCESS;
  692. }
  693. cy_rslt_t cyhal_uart_putc(cyhal_uart_t *obj, uint32_t value)
  694. {
  695. if (_cyhal_scb_pm_transition_pending())
  696. return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
  697. uint32_t count = 0;
  698. while (count == 0)
  699. {
  700. count = Cy_SCB_UART_Put(obj->base, value);
  701. }
  702. return CY_RSLT_SUCCESS;
  703. }
  704. uint32_t cyhal_uart_readable(cyhal_uart_t *obj)
  705. {
  706. uint32_t number_available = Cy_SCB_UART_GetNumInRxFifo(obj->base);
  707. if(obj->context.rxRingBuf != NULL)
  708. {
  709. number_available += Cy_SCB_UART_GetNumInRingBuffer(obj->base, &(obj->context));
  710. }
  711. return number_available;
  712. }
  713. uint32_t cyhal_uart_writable(cyhal_uart_t *obj)
  714. {
  715. return Cy_SCB_GetFifoSize(obj->base) - Cy_SCB_GetNumInTxFifo(obj->base);
  716. }
  717. cy_rslt_t cyhal_uart_clear(cyhal_uart_t *obj)
  718. {
  719. Cy_SCB_UART_ClearRxFifo(obj->base);
  720. Cy_SCB_UART_ClearTxFifo(obj->base);
  721. if(obj->context.rxRingBuf != NULL)
  722. {
  723. Cy_SCB_UART_ClearRingBuffer(obj->base, &(obj->context));
  724. }
  725. return CY_RSLT_SUCCESS;
  726. }
  727. cy_rslt_t cyhal_uart_enable_flow_control(cyhal_uart_t *obj, bool enable_cts, bool enable_rts)
  728. {
  729. cy_rslt_t result = CY_RSLT_SUCCESS;
  730. if (obj->pin_cts != NC)
  731. {
  732. if (enable_cts && (false == obj->cts_enabled))
  733. {
  734. const cyhal_resource_pin_mapping_t *cts_map = _CYHAL_SCB_FIND_MAP_BLOCK(obj->pin_cts, cyhal_pin_map_scb_uart_cts, &obj->resource);
  735. if (false == obj->dc_configured)
  736. {
  737. result = _cyhal_utils_reserve_and_connect(cts_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_CTS);
  738. }
  739. else
  740. {
  741. result = cyhal_connect_pin(cts_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_CTS);
  742. }
  743. if (CY_RSLT_SUCCESS == result)
  744. {
  745. Cy_SCB_UART_EnableCts(obj->base);
  746. obj->cts_enabled = true;
  747. }
  748. }
  749. else if (!enable_cts)
  750. {
  751. if (false == obj->dc_configured)
  752. {
  753. _cyhal_utils_disconnect_and_free(obj->pin_cts);
  754. }
  755. else
  756. {
  757. result = cyhal_disconnect_pin(obj->pin_cts);
  758. }
  759. if (CY_RSLT_SUCCESS == result)
  760. {
  761. Cy_SCB_UART_DisableCts(obj->base);
  762. obj->cts_enabled = false;
  763. }
  764. }
  765. }
  766. if ((CY_RSLT_SUCCESS == result) && (obj->pin_rts != NC))
  767. {
  768. if (enable_rts && (false == obj->rts_enabled))
  769. {
  770. const cyhal_resource_pin_mapping_t *rts_map = _CYHAL_SCB_FIND_MAP_BLOCK(obj->pin_rts, cyhal_pin_map_scb_uart_rts, &obj->resource);
  771. if (false == obj->dc_configured)
  772. {
  773. result = _cyhal_utils_reserve_and_connect(rts_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_RTS);
  774. }
  775. else
  776. {
  777. result = cyhal_connect_pin(rts_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_UART_RTS);
  778. }
  779. obj->rts_enabled = (CY_RSLT_SUCCESS == result);
  780. }
  781. else if (!enable_rts)
  782. {
  783. if (false == obj->dc_configured)
  784. {
  785. _cyhal_utils_disconnect_and_free(obj->pin_rts);
  786. }
  787. else
  788. {
  789. result = cyhal_disconnect_pin(obj->pin_rts);
  790. }
  791. if (CY_RSLT_SUCCESS == result)
  792. {
  793. obj->rts_enabled = false;
  794. }
  795. }
  796. }
  797. return result;
  798. }
  799. cy_rslt_t cyhal_uart_write(cyhal_uart_t *obj, void *tx, size_t *tx_length)
  800. {
  801. if (_cyhal_scb_pm_transition_pending())
  802. return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
  803. *tx_length = Cy_SCB_UART_PutArray(obj->base, tx, *tx_length);
  804. return CY_RSLT_SUCCESS;
  805. }
  806. cy_rslt_t cyhal_uart_read(cyhal_uart_t *obj, void *rx, size_t *rx_length)
  807. {
  808. if (_cyhal_scb_pm_transition_pending())
  809. return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
  810. *rx_length = Cy_SCB_UART_GetArray(obj->base, rx, *rx_length);
  811. return CY_RSLT_SUCCESS;
  812. }
  813. cy_rslt_t cyhal_uart_write_async(cyhal_uart_t *obj, void *tx, size_t length)
  814. {
  815. if (_cyhal_scb_pm_transition_pending())
  816. return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
  817. return Cy_SCB_UART_Transmit(obj->base, tx, length, &(obj->context));
  818. }
  819. cy_rslt_t cyhal_uart_read_async(cyhal_uart_t *obj, void *rx, size_t length)
  820. {
  821. if (_cyhal_scb_pm_transition_pending())
  822. return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
  823. return Cy_SCB_UART_Receive(obj->base, rx, length, &(obj->context));
  824. }
  825. bool cyhal_uart_is_tx_active(cyhal_uart_t *obj)
  826. {
  827. return (0UL != (obj->context.txStatus & CY_SCB_UART_TRANSMIT_ACTIVE)) || !Cy_SCB_IsTxComplete(obj->base);
  828. }
  829. bool cyhal_uart_is_rx_active(cyhal_uart_t *obj)
  830. {
  831. return (0UL != (obj->context.rxStatus & CY_SCB_UART_RECEIVE_ACTIVE));
  832. }
  833. cy_rslt_t cyhal_uart_write_abort(cyhal_uart_t *obj)
  834. {
  835. Cy_SCB_UART_AbortTransmit(obj->base, &(obj->context));
  836. return CY_RSLT_SUCCESS;
  837. }
  838. cy_rslt_t cyhal_uart_read_abort(cyhal_uart_t *obj)
  839. {
  840. Cy_SCB_UART_AbortReceive(obj->base, &(obj->context));
  841. return CY_RSLT_SUCCESS;
  842. }
  843. void cyhal_uart_register_callback(cyhal_uart_t *obj, cyhal_uart_event_callback_t callback, void *callback_arg)
  844. {
  845. uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
  846. obj->callback_data.callback = (cy_israddress) callback;
  847. obj->callback_data.callback_arg = callback_arg;
  848. cyhal_system_critical_section_exit(savedIntrStatus);
  849. Cy_SCB_UART_RegisterCallback(obj->base, _cyhal_uart_cb_wrapper, &(obj->context));
  850. obj->irq_cause = CYHAL_UART_IRQ_NONE;
  851. }
  852. void cyhal_uart_enable_event(cyhal_uart_t *obj, cyhal_uart_event_t event, uint8_t intr_priority, bool enable)
  853. {
  854. uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
  855. _cyhal_irq_disable(_CYHAL_SCB_IRQ_N[scb_arr_index]);
  856. _cyhal_irq_clear_pending(_CYHAL_SCB_IRQ_N[scb_arr_index]);
  857. if (enable)
  858. {
  859. obj->irq_cause |= event;
  860. if (event & CYHAL_UART_IRQ_TX_EMPTY)
  861. {
  862. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_EMPTY);
  863. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | CY_SCB_UART_TX_EMPTY);
  864. }
  865. if (event & CYHAL_UART_IRQ_TX_DONE)
  866. {
  867. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_DONE);
  868. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | CY_SCB_UART_TX_DONE);
  869. }
  870. if (event & CYHAL_UART_IRQ_TX_ERROR)
  871. {
  872. // Omit underflow condition as the interrupt perpetually triggers
  873. //Standard mode only uses OVERFLOW irq
  874. if(obj->config.uartMode == CY_SCB_UART_STANDARD)
  875. {
  876. Cy_SCB_ClearTxInterrupt(obj->base, (CY_SCB_UART_TX_OVERFLOW | CY_SCB_UART_TRANSMIT_ERR));
  877. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | (CY_SCB_UART_TX_OVERFLOW | CY_SCB_UART_TRANSMIT_ERR));
  878. }
  879. //SMARTCARD mode uses OVERFLOW, NACK, and ARB_LOST irq's
  880. else if(obj->config.uartMode == CY_SCB_UART_SMARTCARD)
  881. {
  882. Cy_SCB_ClearTxInterrupt(obj->base, (CY_SCB_UART_TX_OVERFLOW | CY_SCB_TX_INTR_UART_NACK | CY_SCB_TX_INTR_UART_ARB_LOST | CY_SCB_UART_TRANSMIT_ERR));
  883. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | (CY_SCB_UART_TX_OVERFLOW | CY_SCB_TX_INTR_UART_NACK | CY_SCB_TX_INTR_UART_ARB_LOST | CY_SCB_UART_TRANSMIT_ERR));
  884. }
  885. //LIN Mode only uses OVERFLOW, ARB_LOST irq's
  886. else
  887. {
  888. Cy_SCB_ClearTxInterrupt(obj->base, (CY_SCB_UART_TX_OVERFLOW | CY_SCB_TX_INTR_UART_ARB_LOST | CY_SCB_UART_TRANSMIT_ERR));
  889. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | (CY_SCB_UART_TX_OVERFLOW | CY_SCB_TX_INTR_UART_ARB_LOST | CY_SCB_UART_TRANSMIT_ERR));
  890. }
  891. }
  892. if (event & CYHAL_UART_IRQ_TX_FIFO)
  893. {
  894. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_TRIGGER);
  895. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) | CY_SCB_UART_TX_TRIGGER);
  896. }
  897. if (event & CYHAL_UART_IRQ_RX_NOT_EMPTY)
  898. {
  899. Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_UART_RX_NOT_EMPTY);
  900. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) | CY_SCB_UART_RX_NOT_EMPTY);
  901. }
  902. if (event & CYHAL_UART_IRQ_RX_ERROR)
  903. {
  904. // Omit underflow condition as the interrupt perpetually triggers.
  905. Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_UART_RECEIVE_ERR);
  906. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) | CY_SCB_UART_RECEIVE_ERR);
  907. }
  908. if (event & CYHAL_UART_IRQ_RX_FIFO)
  909. {
  910. Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_UART_RX_TRIGGER);
  911. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) | CY_SCB_UART_RX_TRIGGER);
  912. }
  913. }
  914. else
  915. {
  916. obj->irq_cause &= ~event;
  917. if (event & CYHAL_UART_IRQ_TX_EMPTY)
  918. {
  919. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) & ~CY_SCB_UART_TX_EMPTY);
  920. }
  921. if (event & CYHAL_UART_IRQ_TX_DONE)
  922. {
  923. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) & ~CY_SCB_UART_TX_DONE);
  924. }
  925. if (event & CYHAL_UART_IRQ_TX_ERROR)
  926. {
  927. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) & ~(CY_SCB_UART_TX_OVERFLOW | CY_SCB_UART_TRANSMIT_ERR));
  928. }
  929. if (event & CYHAL_UART_IRQ_TX_FIFO)
  930. {
  931. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) & ~CY_SCB_UART_TX_TRIGGER);
  932. }
  933. if (event & CYHAL_UART_IRQ_RX_NOT_EMPTY)
  934. {
  935. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) & ~CY_SCB_UART_RX_NOT_EMPTY);
  936. }
  937. if (event & CYHAL_UART_IRQ_RX_ERROR)
  938. {
  939. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) & ~CY_SCB_UART_RECEIVE_ERR);
  940. }
  941. if (event & CYHAL_UART_IRQ_RX_FIFO)
  942. {
  943. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) & ~CY_SCB_UART_RX_TRIGGER);
  944. }
  945. }
  946. if (event & CYHAL_UART_IRQ_TX_TRANSMIT_IN_FIFO)
  947. {
  948. /* This is a software event only. It is only applicable for cyhal_uart_write_async() */
  949. }
  950. if (event & CYHAL_UART_IRQ_RX_FULL)
  951. {
  952. /* This is a software event only. It is only applicable when using rx software buffer */
  953. }
  954. if (event & CYHAL_UART_IRQ_RX_DONE)
  955. {
  956. /* This is a software event only. It is only applicable for cyhal_uart_read_async() */
  957. }
  958. if (event == CYHAL_UART_IRQ_NONE)
  959. {
  960. /* "No interrupt" is equivalent for both "enable" and "disable" */
  961. Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_RX_INTR_MASK);
  962. Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_TX_INTR_MASK);
  963. Cy_SCB_SetRxInterruptMask(obj->base, Cy_SCB_GetRxInterruptMask(obj->base) & ~CY_SCB_RX_INTR_MASK);
  964. Cy_SCB_SetTxInterruptMask(obj->base, Cy_SCB_GetTxInterruptMask(obj->base) & ~CY_SCB_TX_INTR_MASK);
  965. }
  966. _cyhal_irq_set_priority(_CYHAL_SCB_IRQ_N[scb_arr_index], intr_priority);
  967. _cyhal_irq_enable(_CYHAL_SCB_IRQ_N[scb_arr_index]);
  968. }
  969. cy_rslt_t cyhal_uart_set_fifo_level(cyhal_uart_t *obj, cyhal_uart_fifo_type_t type, uint16_t level)
  970. {
  971. return _cyhal_scb_set_fifo_level(obj->base, (cyhal_scb_fifo_type_t)type, level);
  972. }
  973. cy_rslt_t cyhal_uart_enable_output(cyhal_uart_t *obj, cyhal_uart_output_t output, cyhal_source_t *source)
  974. {
  975. return _cyhal_scb_enable_output(obj->resource, (cyhal_scb_output_t)output, source);
  976. }
  977. cy_rslt_t cyhal_uart_disable_output(cyhal_uart_t *obj, cyhal_uart_output_t output)
  978. {
  979. CY_UNUSED_PARAMETER(obj);
  980. return _cyhal_scb_disable_output((cyhal_scb_output_t)output);
  981. }
  982. cy_rslt_t cyhal_uart_config_software_buffer(cyhal_uart_t *obj, uint8_t *rx_buffer, uint32_t rx_buffer_size)
  983. {
  984. CY_ASSERT(NULL != obj);
  985. CY_ASSERT(NULL != rx_buffer);
  986. Cy_SCB_UART_StartRingBuffer(obj->base, rx_buffer, rx_buffer_size, &(obj->context));
  987. return CY_RSLT_SUCCESS;
  988. }
  989. #if defined(__cplusplus)
  990. }
  991. #endif
  992. #endif /* CYHAL_DRIVER_AVAILABLE_UART */