mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
targets/TARGET_Cypress/TARGET_PSOC6/serial_api.c@189:f392fc9709a3, 2019-02-20 (annotated)
- Committer:
- AnnaBridge
- Date:
- Wed Feb 20 22:31:08 2019 +0000
- Revision:
- 189:f392fc9709a3
- Parent:
- 188:bcfe06ba3d64
mbed library release version 165
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 188:bcfe06ba3d64 | 1 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 2 | * mbed Microcontroller Library |
AnnaBridge | 188:bcfe06ba3d64 | 3 | * Copyright (c) 2017-2018 Future Electronics |
AnnaBridge | 189:f392fc9709a3 | 4 | * Copyright (c) 2018-2019 Cypress Semiconductor Corporation |
AnnaBridge | 189:f392fc9709a3 | 5 | * SPDX-License-Identifier: Apache-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 6 | * |
AnnaBridge | 188:bcfe06ba3d64 | 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
AnnaBridge | 188:bcfe06ba3d64 | 8 | * you may not use this file except in compliance with the License. |
AnnaBridge | 188:bcfe06ba3d64 | 9 | * You may obtain a copy of the License at |
AnnaBridge | 188:bcfe06ba3d64 | 10 | * |
AnnaBridge | 188:bcfe06ba3d64 | 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 12 | * |
AnnaBridge | 188:bcfe06ba3d64 | 13 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 188:bcfe06ba3d64 | 14 | * distributed under the License is distributed on an "AS IS" BASIS, |
AnnaBridge | 188:bcfe06ba3d64 | 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 188:bcfe06ba3d64 | 16 | * See the License for the specific language governing permissions and |
AnnaBridge | 188:bcfe06ba3d64 | 17 | * limitations under the License. |
AnnaBridge | 188:bcfe06ba3d64 | 18 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 19 | |
AnnaBridge | 188:bcfe06ba3d64 | 20 | #if DEVICE_SERIAL |
AnnaBridge | 188:bcfe06ba3d64 | 21 | |
AnnaBridge | 188:bcfe06ba3d64 | 22 | #include <string.h> |
AnnaBridge | 188:bcfe06ba3d64 | 23 | |
AnnaBridge | 188:bcfe06ba3d64 | 24 | #include "cmsis.h" |
AnnaBridge | 188:bcfe06ba3d64 | 25 | #include "mbed_assert.h" |
AnnaBridge | 188:bcfe06ba3d64 | 26 | #include "mbed_error.h" |
AnnaBridge | 188:bcfe06ba3d64 | 27 | #include "PeripheralPins.h" |
AnnaBridge | 188:bcfe06ba3d64 | 28 | #include "pinmap.h" |
AnnaBridge | 188:bcfe06ba3d64 | 29 | #include "serial_api.h" |
AnnaBridge | 188:bcfe06ba3d64 | 30 | #include "psoc6_utils.h" |
AnnaBridge | 188:bcfe06ba3d64 | 31 | |
AnnaBridge | 189:f392fc9709a3 | 32 | #include "cy_sysclk.h" |
AnnaBridge | 189:f392fc9709a3 | 33 | #include "cy_gpio.h" |
AnnaBridge | 189:f392fc9709a3 | 34 | #include "cy_scb_uart.h" |
AnnaBridge | 189:f392fc9709a3 | 35 | #include "cy_sysint.h" |
AnnaBridge | 188:bcfe06ba3d64 | 36 | |
AnnaBridge | 188:bcfe06ba3d64 | 37 | #define UART_OVERSAMPLE 12 |
AnnaBridge | 188:bcfe06ba3d64 | 38 | #define UART_DEFAULT_BAUDRATE 115200 |
AnnaBridge | 188:bcfe06ba3d64 | 39 | #define NUM_SERIAL_PORTS 8 |
AnnaBridge | 188:bcfe06ba3d64 | 40 | #define SERIAL_DEFAULT_IRQ_PRIORITY 3 |
AnnaBridge | 188:bcfe06ba3d64 | 41 | |
AnnaBridge | 189:f392fc9709a3 | 42 | #define UART_RX_INTR_MASK (CY_SCB_UART_RX_TRIGGER | CY_SCB_UART_RX_OVERFLOW | \ |
AnnaBridge | 189:f392fc9709a3 | 43 | CY_SCB_UART_RX_ERR_FRAME | CY_SCB_UART_RX_ERR_PARITY) |
AnnaBridge | 189:f392fc9709a3 | 44 | |
AnnaBridge | 188:bcfe06ba3d64 | 45 | typedef struct serial_s serial_obj_t; |
AnnaBridge | 188:bcfe06ba3d64 | 46 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 47 | #define OBJ_P(in) (&(in->serial)) |
AnnaBridge | 188:bcfe06ba3d64 | 48 | #else |
AnnaBridge | 188:bcfe06ba3d64 | 49 | #define OBJ_P(in) (in) |
AnnaBridge | 188:bcfe06ba3d64 | 50 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 51 | |
AnnaBridge | 188:bcfe06ba3d64 | 52 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 53 | * NOTE: Cypress PDL high level API implementation of USART doe not |
AnnaBridge | 188:bcfe06ba3d64 | 54 | * align well with Mbed interface for interrupt-driven serial I/O. |
AnnaBridge | 188:bcfe06ba3d64 | 55 | * For this reason only low level PDL API is used here. |
AnnaBridge | 188:bcfe06ba3d64 | 56 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 57 | |
AnnaBridge | 189:f392fc9709a3 | 58 | /* Default UART configuration */ |
AnnaBridge | 188:bcfe06ba3d64 | 59 | static const cy_stc_scb_uart_config_t default_uart_config = { |
AnnaBridge | 188:bcfe06ba3d64 | 60 | .uartMode = CY_SCB_UART_STANDARD, |
AnnaBridge | 188:bcfe06ba3d64 | 61 | .enableMutliProcessorMode = false, |
AnnaBridge | 188:bcfe06ba3d64 | 62 | .smartCardRetryOnNack = false, |
AnnaBridge | 188:bcfe06ba3d64 | 63 | .irdaInvertRx = false, |
AnnaBridge | 188:bcfe06ba3d64 | 64 | .irdaEnableLowPowerReceiver = false, |
AnnaBridge | 188:bcfe06ba3d64 | 65 | |
AnnaBridge | 188:bcfe06ba3d64 | 66 | .oversample = UART_OVERSAMPLE, |
AnnaBridge | 188:bcfe06ba3d64 | 67 | |
AnnaBridge | 188:bcfe06ba3d64 | 68 | .enableMsbFirst = false, |
AnnaBridge | 188:bcfe06ba3d64 | 69 | .dataWidth = 8UL, |
AnnaBridge | 188:bcfe06ba3d64 | 70 | .parity = CY_SCB_UART_PARITY_NONE, |
AnnaBridge | 188:bcfe06ba3d64 | 71 | .stopBits = CY_SCB_UART_STOP_BITS_1, |
AnnaBridge | 188:bcfe06ba3d64 | 72 | .enableInputFilter = false, |
AnnaBridge | 188:bcfe06ba3d64 | 73 | .breakWidth = 11UL, |
AnnaBridge | 188:bcfe06ba3d64 | 74 | .dropOnFrameError = false, |
AnnaBridge | 188:bcfe06ba3d64 | 75 | .dropOnParityError = false, |
AnnaBridge | 188:bcfe06ba3d64 | 76 | |
AnnaBridge | 188:bcfe06ba3d64 | 77 | .receiverAddress = 0x0UL, |
AnnaBridge | 188:bcfe06ba3d64 | 78 | .receiverAddressMask = 0x0UL, |
AnnaBridge | 188:bcfe06ba3d64 | 79 | .acceptAddrInFifo = false, |
AnnaBridge | 188:bcfe06ba3d64 | 80 | |
AnnaBridge | 188:bcfe06ba3d64 | 81 | .enableCts = false, |
AnnaBridge | 188:bcfe06ba3d64 | 82 | .ctsPolarity = CY_SCB_UART_ACTIVE_LOW, |
AnnaBridge | 188:bcfe06ba3d64 | 83 | .rtsRxFifoLevel = 20UL, |
AnnaBridge | 188:bcfe06ba3d64 | 84 | .rtsPolarity = CY_SCB_UART_ACTIVE_LOW, |
AnnaBridge | 188:bcfe06ba3d64 | 85 | |
AnnaBridge | 189:f392fc9709a3 | 86 | .rxFifoTriggerLevel = 0UL, /* Level triggers when at least one element is in FIFO */ |
AnnaBridge | 188:bcfe06ba3d64 | 87 | .rxFifoIntEnableMask = 0x0UL, |
AnnaBridge | 188:bcfe06ba3d64 | 88 | |
AnnaBridge | 189:f392fc9709a3 | 89 | .txFifoTriggerLevel = 63UL, /* Level triggers when half-fifo is half empty */ |
AnnaBridge | 188:bcfe06ba3d64 | 90 | .txFifoIntEnableMask = 0x0UL |
AnnaBridge | 188:bcfe06ba3d64 | 91 | }; |
AnnaBridge | 188:bcfe06ba3d64 | 92 | |
AnnaBridge | 189:f392fc9709a3 | 93 | /* STDIO serial information */ |
AnnaBridge | 189:f392fc9709a3 | 94 | bool stdio_uart_inited = false; |
AnnaBridge | 188:bcfe06ba3d64 | 95 | serial_t stdio_uart; |
AnnaBridge | 188:bcfe06ba3d64 | 96 | |
AnnaBridge | 189:f392fc9709a3 | 97 | int bt_uart_inited = false; |
AnnaBridge | 189:f392fc9709a3 | 98 | serial_t bt_uart; |
AnnaBridge | 189:f392fc9709a3 | 99 | |
AnnaBridge | 188:bcfe06ba3d64 | 100 | typedef struct irq_info_s { |
AnnaBridge | 188:bcfe06ba3d64 | 101 | serial_obj_t *serial_obj; |
AnnaBridge | 188:bcfe06ba3d64 | 102 | uart_irq_handler handler; |
AnnaBridge | 188:bcfe06ba3d64 | 103 | uint32_t id_arg; |
AnnaBridge | 188:bcfe06ba3d64 | 104 | IRQn_Type irqn; |
AnnaBridge | 188:bcfe06ba3d64 | 105 | #if defined (TARGET_MCU_PSOC6_M0) |
AnnaBridge | 188:bcfe06ba3d64 | 106 | cy_en_intr_t cm0p_irq_src; |
AnnaBridge | 188:bcfe06ba3d64 | 107 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 108 | } irq_info_t; |
AnnaBridge | 188:bcfe06ba3d64 | 109 | |
AnnaBridge | 189:f392fc9709a3 | 110 | |
AnnaBridge | 189:f392fc9709a3 | 111 | /* Allocate interrupt information table */ |
AnnaBridge | 188:bcfe06ba3d64 | 112 | static irq_info_t irq_info[NUM_SERIAL_PORTS] = { |
AnnaBridge | 188:bcfe06ba3d64 | 113 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 114 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 115 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 116 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 117 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 118 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 119 | {NULL, NULL, 0, unconnected_IRQn}, |
AnnaBridge | 188:bcfe06ba3d64 | 120 | {NULL, NULL, 0, unconnected_IRQn} |
AnnaBridge | 188:bcfe06ba3d64 | 121 | }; |
AnnaBridge | 188:bcfe06ba3d64 | 122 | |
AnnaBridge | 188:bcfe06ba3d64 | 123 | |
AnnaBridge | 189:f392fc9709a3 | 124 | /** Routes interrupt to proper SCB block. |
AnnaBridge | 189:f392fc9709a3 | 125 | * |
AnnaBridge | 189:f392fc9709a3 | 126 | * @param serial_id The ID of serial object |
AnnaBridge | 189:f392fc9709a3 | 127 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 128 | static void serial_irq_dispatcher(uint32_t serial_id) |
AnnaBridge | 188:bcfe06ba3d64 | 129 | { |
AnnaBridge | 188:bcfe06ba3d64 | 130 | MBED_ASSERT(serial_id < NUM_SERIAL_PORTS); |
AnnaBridge | 189:f392fc9709a3 | 131 | |
AnnaBridge | 188:bcfe06ba3d64 | 132 | irq_info_t *info = &irq_info[serial_id]; |
AnnaBridge | 188:bcfe06ba3d64 | 133 | serial_obj_t *obj = info->serial_obj; |
AnnaBridge | 188:bcfe06ba3d64 | 134 | MBED_ASSERT(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 135 | |
AnnaBridge | 188:bcfe06ba3d64 | 136 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 137 | if (obj->async_handler) { |
AnnaBridge | 188:bcfe06ba3d64 | 138 | obj->async_handler(); |
AnnaBridge | 188:bcfe06ba3d64 | 139 | return; |
AnnaBridge | 188:bcfe06ba3d64 | 140 | } |
AnnaBridge | 188:bcfe06ba3d64 | 141 | #endif |
AnnaBridge | 189:f392fc9709a3 | 142 | |
AnnaBridge | 188:bcfe06ba3d64 | 143 | if (Cy_SCB_GetRxInterruptStatusMasked(obj->base) & CY_SCB_RX_INTR_NOT_EMPTY) { |
AnnaBridge | 188:bcfe06ba3d64 | 144 | info->handler(info->id_arg, RxIrq); |
AnnaBridge | 188:bcfe06ba3d64 | 145 | Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_RX_INTR_NOT_EMPTY); |
AnnaBridge | 188:bcfe06ba3d64 | 146 | } |
AnnaBridge | 188:bcfe06ba3d64 | 147 | |
AnnaBridge | 189:f392fc9709a3 | 148 | if (Cy_SCB_GetTxInterruptStatusMasked(obj->base) & CY_SCB_UART_TX_EMPTY) { |
AnnaBridge | 188:bcfe06ba3d64 | 149 | info->handler(info->id_arg, TxIrq); |
AnnaBridge | 189:f392fc9709a3 | 150 | Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_EMPTY); |
AnnaBridge | 188:bcfe06ba3d64 | 151 | } |
AnnaBridge | 188:bcfe06ba3d64 | 152 | } |
AnnaBridge | 188:bcfe06ba3d64 | 153 | |
AnnaBridge | 188:bcfe06ba3d64 | 154 | static void serial_irq_dispatcher_uart0(void) |
AnnaBridge | 188:bcfe06ba3d64 | 155 | { |
AnnaBridge | 188:bcfe06ba3d64 | 156 | serial_irq_dispatcher(0); |
AnnaBridge | 188:bcfe06ba3d64 | 157 | } |
AnnaBridge | 188:bcfe06ba3d64 | 158 | |
AnnaBridge | 188:bcfe06ba3d64 | 159 | static void serial_irq_dispatcher_uart1(void) |
AnnaBridge | 188:bcfe06ba3d64 | 160 | { |
AnnaBridge | 188:bcfe06ba3d64 | 161 | serial_irq_dispatcher(1); |
AnnaBridge | 188:bcfe06ba3d64 | 162 | } |
AnnaBridge | 188:bcfe06ba3d64 | 163 | |
AnnaBridge | 188:bcfe06ba3d64 | 164 | static void serial_irq_dispatcher_uart2(void) |
AnnaBridge | 188:bcfe06ba3d64 | 165 | { |
AnnaBridge | 188:bcfe06ba3d64 | 166 | serial_irq_dispatcher(2); |
AnnaBridge | 188:bcfe06ba3d64 | 167 | } |
AnnaBridge | 188:bcfe06ba3d64 | 168 | |
AnnaBridge | 188:bcfe06ba3d64 | 169 | static void serial_irq_dispatcher_uart3(void) |
AnnaBridge | 188:bcfe06ba3d64 | 170 | { |
AnnaBridge | 188:bcfe06ba3d64 | 171 | serial_irq_dispatcher(3); |
AnnaBridge | 188:bcfe06ba3d64 | 172 | } |
AnnaBridge | 188:bcfe06ba3d64 | 173 | |
AnnaBridge | 188:bcfe06ba3d64 | 174 | static void serial_irq_dispatcher_uart4(void) |
AnnaBridge | 188:bcfe06ba3d64 | 175 | { |
AnnaBridge | 188:bcfe06ba3d64 | 176 | serial_irq_dispatcher(4); |
AnnaBridge | 188:bcfe06ba3d64 | 177 | } |
AnnaBridge | 188:bcfe06ba3d64 | 178 | |
AnnaBridge | 188:bcfe06ba3d64 | 179 | static void serial_irq_dispatcher_uart5(void) |
AnnaBridge | 188:bcfe06ba3d64 | 180 | { |
AnnaBridge | 188:bcfe06ba3d64 | 181 | serial_irq_dispatcher(5); |
AnnaBridge | 188:bcfe06ba3d64 | 182 | } |
AnnaBridge | 188:bcfe06ba3d64 | 183 | |
AnnaBridge | 188:bcfe06ba3d64 | 184 | void serial_irq_dispatcher_uart6(void) |
AnnaBridge | 188:bcfe06ba3d64 | 185 | { |
AnnaBridge | 188:bcfe06ba3d64 | 186 | serial_irq_dispatcher(6); |
AnnaBridge | 188:bcfe06ba3d64 | 187 | } |
AnnaBridge | 188:bcfe06ba3d64 | 188 | |
AnnaBridge | 188:bcfe06ba3d64 | 189 | static void serial_irq_dispatcher_uart7(void) |
AnnaBridge | 188:bcfe06ba3d64 | 190 | { |
AnnaBridge | 188:bcfe06ba3d64 | 191 | serial_irq_dispatcher(7); |
AnnaBridge | 188:bcfe06ba3d64 | 192 | } |
AnnaBridge | 188:bcfe06ba3d64 | 193 | |
AnnaBridge | 189:f392fc9709a3 | 194 | /* Interrupts table */ |
AnnaBridge | 188:bcfe06ba3d64 | 195 | static void (*irq_dispatcher_table[])(void) = { |
AnnaBridge | 188:bcfe06ba3d64 | 196 | serial_irq_dispatcher_uart0, |
AnnaBridge | 188:bcfe06ba3d64 | 197 | serial_irq_dispatcher_uart1, |
AnnaBridge | 188:bcfe06ba3d64 | 198 | serial_irq_dispatcher_uart2, |
AnnaBridge | 188:bcfe06ba3d64 | 199 | serial_irq_dispatcher_uart3, |
AnnaBridge | 188:bcfe06ba3d64 | 200 | serial_irq_dispatcher_uart4, |
AnnaBridge | 188:bcfe06ba3d64 | 201 | serial_irq_dispatcher_uart5, |
AnnaBridge | 188:bcfe06ba3d64 | 202 | serial_irq_dispatcher_uart6, |
AnnaBridge | 188:bcfe06ba3d64 | 203 | serial_irq_dispatcher_uart7 |
AnnaBridge | 188:bcfe06ba3d64 | 204 | }; |
AnnaBridge | 188:bcfe06ba3d64 | 205 | |
AnnaBridge | 188:bcfe06ba3d64 | 206 | |
AnnaBridge | 188:bcfe06ba3d64 | 207 | static IRQn_Type serial_irq_allocate_channel(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 208 | { |
AnnaBridge | 188:bcfe06ba3d64 | 209 | #if defined (TARGET_MCU_PSOC6_M0) |
AnnaBridge | 188:bcfe06ba3d64 | 210 | irq_info[obj->serial_id].cm0p_irq_src = scb_0_interrupt_IRQn + obj->serial_id; |
AnnaBridge | 188:bcfe06ba3d64 | 211 | return cy_m0_nvic_allocate_channel(CY_SERIAL_IRQN_ID + obj->serial_id); |
AnnaBridge | 188:bcfe06ba3d64 | 212 | #else |
AnnaBridge | 188:bcfe06ba3d64 | 213 | return (IRQn_Type)(scb_0_interrupt_IRQn + obj->serial_id); |
AnnaBridge | 189:f392fc9709a3 | 214 | #endif /* (TARGET_MCU_PSOC6_M0) */ |
AnnaBridge | 188:bcfe06ba3d64 | 215 | } |
AnnaBridge | 188:bcfe06ba3d64 | 216 | |
AnnaBridge | 188:bcfe06ba3d64 | 217 | |
AnnaBridge | 188:bcfe06ba3d64 | 218 | static int serial_irq_setup_channel(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 219 | { |
AnnaBridge | 188:bcfe06ba3d64 | 220 | cy_stc_sysint_t irq_config; |
AnnaBridge | 188:bcfe06ba3d64 | 221 | irq_info_t *info = &irq_info[obj->serial_id]; |
AnnaBridge | 188:bcfe06ba3d64 | 222 | |
AnnaBridge | 188:bcfe06ba3d64 | 223 | if (info->irqn == unconnected_IRQn) { |
AnnaBridge | 188:bcfe06ba3d64 | 224 | IRQn_Type irqn = serial_irq_allocate_channel(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 225 | if (irqn < 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 226 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 227 | } |
AnnaBridge | 189:f392fc9709a3 | 228 | |
AnnaBridge | 189:f392fc9709a3 | 229 | /* Configure NVIC */ |
AnnaBridge | 188:bcfe06ba3d64 | 230 | irq_config.intrPriority = SERIAL_DEFAULT_IRQ_PRIORITY; |
AnnaBridge | 188:bcfe06ba3d64 | 231 | irq_config.intrSrc = irqn; |
AnnaBridge | 188:bcfe06ba3d64 | 232 | #if defined (TARGET_MCU_PSOC6_M0) |
AnnaBridge | 188:bcfe06ba3d64 | 233 | irq_config.cm0pSrc = info->cm0p_irq_src; |
AnnaBridge | 188:bcfe06ba3d64 | 234 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 235 | if (Cy_SysInt_Init(&irq_config, irq_dispatcher_table[obj->serial_id]) != CY_SYSINT_SUCCESS) { |
AnnaBridge | 189:f392fc9709a3 | 236 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 237 | } |
AnnaBridge | 188:bcfe06ba3d64 | 238 | |
AnnaBridge | 188:bcfe06ba3d64 | 239 | info->irqn = irqn; |
AnnaBridge | 188:bcfe06ba3d64 | 240 | info->serial_obj = obj; |
AnnaBridge | 188:bcfe06ba3d64 | 241 | } |
AnnaBridge | 189:f392fc9709a3 | 242 | |
AnnaBridge | 189:f392fc9709a3 | 243 | /* Enable interrupt after successful setup */ |
AnnaBridge | 189:f392fc9709a3 | 244 | NVIC_EnableIRQ(info->irqn); |
AnnaBridge | 189:f392fc9709a3 | 245 | |
AnnaBridge | 188:bcfe06ba3d64 | 246 | return 0; |
AnnaBridge | 188:bcfe06ba3d64 | 247 | } |
AnnaBridge | 188:bcfe06ba3d64 | 248 | |
AnnaBridge | 189:f392fc9709a3 | 249 | |
AnnaBridge | 189:f392fc9709a3 | 250 | /** Calculates fractional divider value. |
AnnaBridge | 189:f392fc9709a3 | 251 | * |
AnnaBridge | 189:f392fc9709a3 | 252 | * @param frequency The desired frequency of UART clock |
AnnaBridge | 189:f392fc9709a3 | 253 | * @param frac_bits The number of fractional bits in the divider |
AnnaBridge | 189:f392fc9709a3 | 254 | * @return The divider value |
AnnaBridge | 188:bcfe06ba3d64 | 255 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 256 | static uint32_t divider_value(uint32_t frequency, uint32_t frac_bits) |
AnnaBridge | 188:bcfe06ba3d64 | 257 | { |
AnnaBridge | 188:bcfe06ba3d64 | 258 | /* UARTs use peripheral clock */ |
AnnaBridge | 189:f392fc9709a3 | 259 | return ((cy_PeriClkFreqHz * (1 << frac_bits)) + (frequency / 2)) / frequency; |
AnnaBridge | 188:bcfe06ba3d64 | 260 | } |
AnnaBridge | 188:bcfe06ba3d64 | 261 | |
AnnaBridge | 189:f392fc9709a3 | 262 | |
AnnaBridge | 189:f392fc9709a3 | 263 | #define FRACT_DIV_INT(divider) (((divider) >> 5U) - 1U) |
AnnaBridge | 189:f392fc9709a3 | 264 | #define FRACT_DIV_FARCT(divider) ((divider) & 0x1FU) |
AnnaBridge | 189:f392fc9709a3 | 265 | |
AnnaBridge | 189:f392fc9709a3 | 266 | /** Finds clock divider, configures it and connects to SCB block. |
AnnaBridge | 189:f392fc9709a3 | 267 | * |
AnnaBridge | 189:f392fc9709a3 | 268 | * @param obj The serial object |
AnnaBridge | 189:f392fc9709a3 | 269 | * @param baudrate The desired UART baud rate |
AnnaBridge | 189:f392fc9709a3 | 270 | * @return CY_SYSCLK_SUCCESS if operation successful and CY_SYSCLK_BAD_PARAM otherwise |
AnnaBridge | 189:f392fc9709a3 | 271 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 272 | static cy_en_sysclk_status_t serial_init_clock(serial_obj_t *obj, uint32_t baudrate) |
AnnaBridge | 188:bcfe06ba3d64 | 273 | { |
AnnaBridge | 188:bcfe06ba3d64 | 274 | cy_en_sysclk_status_t status = CY_SYSCLK_BAD_PARAM; |
AnnaBridge | 188:bcfe06ba3d64 | 275 | |
AnnaBridge | 188:bcfe06ba3d64 | 276 | if (obj->div_num == CY_INVALID_DIVIDER) { |
AnnaBridge | 188:bcfe06ba3d64 | 277 | uint32_t divider_num = cy_clk_allocate_divider(CY_SYSCLK_DIV_16_5_BIT); |
AnnaBridge | 188:bcfe06ba3d64 | 278 | |
AnnaBridge | 188:bcfe06ba3d64 | 279 | if (divider_num < PERI_DIV_16_5_NR) { |
AnnaBridge | 189:f392fc9709a3 | 280 | /* Assign fractional divider */ |
AnnaBridge | 188:bcfe06ba3d64 | 281 | status = Cy_SysClk_PeriphAssignDivider(obj->clock, CY_SYSCLK_DIV_16_5_BIT, divider_num); |
AnnaBridge | 188:bcfe06ba3d64 | 282 | if (status == CY_SYSCLK_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 283 | obj->div_type = CY_SYSCLK_DIV_16_5_BIT; |
AnnaBridge | 189:f392fc9709a3 | 284 | obj->div_num = divider_num; |
AnnaBridge | 188:bcfe06ba3d64 | 285 | } |
AnnaBridge | 188:bcfe06ba3d64 | 286 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 287 | // Try 16-bit divider. |
AnnaBridge | 188:bcfe06ba3d64 | 288 | divider_num = cy_clk_allocate_divider(CY_SYSCLK_DIV_16_BIT); |
AnnaBridge | 188:bcfe06ba3d64 | 289 | if (divider_num < PERI_DIV_16_NR) { |
AnnaBridge | 189:f392fc9709a3 | 290 | /* Assign 16-bit divider */ |
AnnaBridge | 188:bcfe06ba3d64 | 291 | status = Cy_SysClk_PeriphAssignDivider(obj->clock, CY_SYSCLK_DIV_16_BIT, divider_num); |
AnnaBridge | 188:bcfe06ba3d64 | 292 | if (status == CY_SYSCLK_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 293 | obj->div_type = CY_SYSCLK_DIV_16_BIT; |
AnnaBridge | 189:f392fc9709a3 | 294 | obj->div_num = divider_num; |
AnnaBridge | 188:bcfe06ba3d64 | 295 | } |
AnnaBridge | 188:bcfe06ba3d64 | 296 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 297 | error("Serial: cannot assign clock divider."); |
AnnaBridge | 188:bcfe06ba3d64 | 298 | } |
AnnaBridge | 188:bcfe06ba3d64 | 299 | } |
AnnaBridge | 188:bcfe06ba3d64 | 300 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 301 | status = CY_SYSCLK_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 302 | } |
AnnaBridge | 188:bcfe06ba3d64 | 303 | |
AnnaBridge | 188:bcfe06ba3d64 | 304 | if (status == CY_SYSCLK_SUCCESS) { |
AnnaBridge | 189:f392fc9709a3 | 305 | Cy_SysClk_PeriphDisableDivider(obj->div_type, obj->div_num); |
AnnaBridge | 189:f392fc9709a3 | 306 | |
AnnaBridge | 188:bcfe06ba3d64 | 307 | /* Set baud rate */ |
AnnaBridge | 188:bcfe06ba3d64 | 308 | if (obj->div_type == CY_SYSCLK_DIV_16_5_BIT) { |
AnnaBridge | 189:f392fc9709a3 | 309 | /* Get fractional divider */ |
AnnaBridge | 189:f392fc9709a3 | 310 | uint32_t divider = divider_value(baudrate * UART_OVERSAMPLE, 5U); |
AnnaBridge | 189:f392fc9709a3 | 311 | |
AnnaBridge | 188:bcfe06ba3d64 | 312 | status = Cy_SysClk_PeriphSetFracDivider(CY_SYSCLK_DIV_16_5_BIT, |
AnnaBridge | 188:bcfe06ba3d64 | 313 | obj->div_num, |
AnnaBridge | 189:f392fc9709a3 | 314 | FRACT_DIV_INT(divider), |
AnnaBridge | 189:f392fc9709a3 | 315 | FRACT_DIV_FARCT(divider)); |
AnnaBridge | 189:f392fc9709a3 | 316 | } else { |
AnnaBridge | 189:f392fc9709a3 | 317 | /* Get integer divider */ |
AnnaBridge | 188:bcfe06ba3d64 | 318 | status = Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_16_BIT, |
AnnaBridge | 188:bcfe06ba3d64 | 319 | obj->div_num, |
AnnaBridge | 188:bcfe06ba3d64 | 320 | divider_value(baudrate * UART_OVERSAMPLE, 0)); |
AnnaBridge | 188:bcfe06ba3d64 | 321 | } |
AnnaBridge | 189:f392fc9709a3 | 322 | |
AnnaBridge | 189:f392fc9709a3 | 323 | Cy_SysClk_PeriphEnableDivider(obj->div_type, obj->div_num); |
AnnaBridge | 188:bcfe06ba3d64 | 324 | } |
AnnaBridge | 189:f392fc9709a3 | 325 | |
AnnaBridge | 188:bcfe06ba3d64 | 326 | return status; |
AnnaBridge | 188:bcfe06ba3d64 | 327 | } |
AnnaBridge | 188:bcfe06ba3d64 | 328 | |
AnnaBridge | 189:f392fc9709a3 | 329 | |
AnnaBridge | 189:f392fc9709a3 | 330 | /** Initializes i/o pins for UART tx/rx. |
AnnaBridge | 189:f392fc9709a3 | 331 | * |
AnnaBridge | 189:f392fc9709a3 | 332 | * @param obj The serial object |
AnnaBridge | 188:bcfe06ba3d64 | 333 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 334 | static void serial_init_pins(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 335 | { |
AnnaBridge | 189:f392fc9709a3 | 336 | if ((cy_reserve_io_pin(obj->pin_tx) || cy_reserve_io_pin(obj->pin_rx)) |
AnnaBridge | 189:f392fc9709a3 | 337 | && !obj->already_reserved) { |
AnnaBridge | 188:bcfe06ba3d64 | 338 | error("Serial TX/RX pin reservation conflict."); |
AnnaBridge | 188:bcfe06ba3d64 | 339 | } |
AnnaBridge | 189:f392fc9709a3 | 340 | |
AnnaBridge | 189:f392fc9709a3 | 341 | pin_function(obj->pin_tx, pinmap_function(obj->pin_tx, PinMap_UART_TX)); |
AnnaBridge | 189:f392fc9709a3 | 342 | pin_function(obj->pin_rx, pinmap_function(obj->pin_rx, PinMap_UART_RX)); |
AnnaBridge | 188:bcfe06ba3d64 | 343 | } |
AnnaBridge | 188:bcfe06ba3d64 | 344 | |
AnnaBridge | 189:f392fc9709a3 | 345 | |
AnnaBridge | 189:f392fc9709a3 | 346 | /** Initializes i/o pins for UART flow control |
AnnaBridge | 189:f392fc9709a3 | 347 | * |
AnnaBridge | 189:f392fc9709a3 | 348 | * @param obj The serial object |
AnnaBridge | 188:bcfe06ba3d64 | 349 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 350 | static void serial_init_flow_pins(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 351 | { |
AnnaBridge | 188:bcfe06ba3d64 | 352 | if (obj->pin_rts != NC) { |
AnnaBridge | 189:f392fc9709a3 | 353 | if ((0 != cy_reserve_io_pin(obj->pin_rts)) && !obj->already_reserved) { |
AnnaBridge | 188:bcfe06ba3d64 | 354 | error("Serial RTS pin reservation conflict."); |
AnnaBridge | 188:bcfe06ba3d64 | 355 | } |
AnnaBridge | 189:f392fc9709a3 | 356 | pin_function(obj->pin_rts, pinmap_function(obj->pin_rts, PinMap_UART_RTS)); |
AnnaBridge | 188:bcfe06ba3d64 | 357 | } |
AnnaBridge | 188:bcfe06ba3d64 | 358 | |
AnnaBridge | 188:bcfe06ba3d64 | 359 | if (obj->pin_cts != NC) { |
AnnaBridge | 189:f392fc9709a3 | 360 | if ((0 != cy_reserve_io_pin(obj->pin_cts)) && !obj->already_reserved) { |
AnnaBridge | 188:bcfe06ba3d64 | 361 | error("Serial CTS pin reservation conflict."); |
AnnaBridge | 188:bcfe06ba3d64 | 362 | } |
AnnaBridge | 189:f392fc9709a3 | 363 | pin_function(obj->pin_cts, pinmap_function(obj->pin_cts, PinMap_UART_CTS)); |
AnnaBridge | 188:bcfe06ba3d64 | 364 | } |
AnnaBridge | 188:bcfe06ba3d64 | 365 | } |
AnnaBridge | 188:bcfe06ba3d64 | 366 | |
AnnaBridge | 188:bcfe06ba3d64 | 367 | |
AnnaBridge | 189:f392fc9709a3 | 368 | /** Initializes and enables UART/SCB. |
AnnaBridge | 189:f392fc9709a3 | 369 | * |
AnnaBridge | 189:f392fc9709a3 | 370 | * @param obj The serial object |
AnnaBridge | 188:bcfe06ba3d64 | 371 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 372 | static void serial_init_peripheral(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 373 | { |
AnnaBridge | 188:bcfe06ba3d64 | 374 | cy_stc_scb_uart_config_t uart_config = default_uart_config; |
AnnaBridge | 188:bcfe06ba3d64 | 375 | |
AnnaBridge | 189:f392fc9709a3 | 376 | uart_config.dataWidth = obj->data_width; |
AnnaBridge | 189:f392fc9709a3 | 377 | uart_config.parity = obj->parity; |
AnnaBridge | 189:f392fc9709a3 | 378 | uart_config.stopBits = obj->stop_bits; |
AnnaBridge | 189:f392fc9709a3 | 379 | uart_config.enableCts = (obj->pin_cts != NC); |
AnnaBridge | 188:bcfe06ba3d64 | 380 | |
AnnaBridge | 188:bcfe06ba3d64 | 381 | Cy_SCB_UART_Init(obj->base, &uart_config, NULL); |
AnnaBridge | 188:bcfe06ba3d64 | 382 | Cy_SCB_UART_Enable(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 383 | } |
AnnaBridge | 188:bcfe06ba3d64 | 384 | |
AnnaBridge | 189:f392fc9709a3 | 385 | |
AnnaBridge | 189:f392fc9709a3 | 386 | #if DEVICE_SLEEP && DEVICE_LPTICKER && SERIAL_PM_CALLBACK_ENABLED |
AnnaBridge | 188:bcfe06ba3d64 | 387 | static cy_en_syspm_status_t serial_pm_callback(cy_stc_syspm_callback_params_t *params) |
AnnaBridge | 188:bcfe06ba3d64 | 388 | { |
AnnaBridge | 188:bcfe06ba3d64 | 389 | serial_obj_t *obj = (serial_obj_t *)params->context; |
AnnaBridge | 188:bcfe06ba3d64 | 390 | cy_en_syspm_status_t status = CY_SYSPM_FAIL; |
AnnaBridge | 188:bcfe06ba3d64 | 391 | |
AnnaBridge | 188:bcfe06ba3d64 | 392 | switch (params->mode) { |
AnnaBridge | 188:bcfe06ba3d64 | 393 | case CY_SYSPM_CHECK_READY: |
AnnaBridge | 188:bcfe06ba3d64 | 394 | /* If all data elements are transmitted from the TX FIFO and |
AnnaBridge | 188:bcfe06ba3d64 | 395 | * shifter and the RX FIFO is empty: the UART is ready to enter |
AnnaBridge | 188:bcfe06ba3d64 | 396 | * Deep Sleep mode. |
AnnaBridge | 188:bcfe06ba3d64 | 397 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 398 | if (Cy_SCB_UART_IsTxComplete(obj->base)) { |
AnnaBridge | 189:f392fc9709a3 | 399 | if (0 == Cy_SCB_UART_GetNumInRxFifo(obj->base)) { |
AnnaBridge | 188:bcfe06ba3d64 | 400 | /* Disable the UART. The transmitter stops driving the |
AnnaBridge | 188:bcfe06ba3d64 | 401 | * lines and the receiver stops receiving data until |
AnnaBridge | 188:bcfe06ba3d64 | 402 | * the UART is enabled. |
AnnaBridge | 188:bcfe06ba3d64 | 403 | * This happens when the device failed to enter Deep |
AnnaBridge | 188:bcfe06ba3d64 | 404 | * Sleep or it is awaken from Deep Sleep mode. |
AnnaBridge | 188:bcfe06ba3d64 | 405 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 406 | Cy_SCB_UART_Disable(obj->base, NULL); |
AnnaBridge | 188:bcfe06ba3d64 | 407 | status = CY_SYSPM_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 408 | } |
AnnaBridge | 188:bcfe06ba3d64 | 409 | } |
AnnaBridge | 188:bcfe06ba3d64 | 410 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 411 | |
AnnaBridge | 188:bcfe06ba3d64 | 412 | |
AnnaBridge | 188:bcfe06ba3d64 | 413 | case CY_SYSPM_CHECK_FAIL: |
AnnaBridge | 188:bcfe06ba3d64 | 414 | /* Enable the UART to operate */ |
AnnaBridge | 188:bcfe06ba3d64 | 415 | Cy_SCB_UART_Enable(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 416 | status = CY_SYSPM_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 417 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 418 | |
AnnaBridge | 188:bcfe06ba3d64 | 419 | case CY_SYSPM_BEFORE_TRANSITION: |
AnnaBridge | 188:bcfe06ba3d64 | 420 | status = CY_SYSPM_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 421 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 422 | |
AnnaBridge | 188:bcfe06ba3d64 | 423 | case CY_SYSPM_AFTER_TRANSITION: |
AnnaBridge | 188:bcfe06ba3d64 | 424 | /* Enable the UART to operate */ |
AnnaBridge | 188:bcfe06ba3d64 | 425 | Cy_SCB_UART_Enable(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 426 | status = CY_SYSPM_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 427 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 428 | |
AnnaBridge | 188:bcfe06ba3d64 | 429 | default: |
AnnaBridge | 188:bcfe06ba3d64 | 430 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 431 | } |
AnnaBridge | 189:f392fc9709a3 | 432 | |
AnnaBridge | 188:bcfe06ba3d64 | 433 | return status; |
AnnaBridge | 188:bcfe06ba3d64 | 434 | } |
AnnaBridge | 189:f392fc9709a3 | 435 | #endif /* (DEVICE_SLEEP && DEVICE_LPTICKER && SERIAL_PM_CALLBACK_ENABLED) */ |
AnnaBridge | 189:f392fc9709a3 | 436 | |
AnnaBridge | 188:bcfe06ba3d64 | 437 | |
AnnaBridge | 188:bcfe06ba3d64 | 438 | void serial_init(serial_t *obj_in, PinName tx, PinName rx) |
AnnaBridge | 188:bcfe06ba3d64 | 439 | { |
AnnaBridge | 188:bcfe06ba3d64 | 440 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 441 | bool is_stdio = (tx == CY_STDIO_UART_TX) || (rx == CY_STDIO_UART_RX); |
AnnaBridge | 189:f392fc9709a3 | 442 | #if !defined(TARGET_CY8CKIT_062_BLE) |
AnnaBridge | 189:f392fc9709a3 | 443 | bool is_bt = (tx == CY_BT_UART_TX) || (rx == CY_BT_UART_RX); |
AnnaBridge | 189:f392fc9709a3 | 444 | #else |
AnnaBridge | 189:f392fc9709a3 | 445 | bool is_bt = false; |
AnnaBridge | 189:f392fc9709a3 | 446 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 447 | |
AnnaBridge | 188:bcfe06ba3d64 | 448 | if (is_stdio && stdio_uart_inited) { |
AnnaBridge | 188:bcfe06ba3d64 | 449 | memcpy(obj_in, &stdio_uart, sizeof(serial_t)); |
AnnaBridge | 188:bcfe06ba3d64 | 450 | return; |
AnnaBridge | 189:f392fc9709a3 | 451 | } else if (is_bt && bt_uart_inited) { |
AnnaBridge | 189:f392fc9709a3 | 452 | memcpy(obj_in, &bt_uart, sizeof(serial_t)); |
AnnaBridge | 189:f392fc9709a3 | 453 | return; |
AnnaBridge | 189:f392fc9709a3 | 454 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 455 | uint32_t uart = pinmap_peripheral(tx, PinMap_UART_TX); |
AnnaBridge | 188:bcfe06ba3d64 | 456 | uart = pinmap_merge(uart, pinmap_peripheral(rx, PinMap_UART_RX)); |
AnnaBridge | 189:f392fc9709a3 | 457 | |
AnnaBridge | 188:bcfe06ba3d64 | 458 | if (uart != (uint32_t)NC) { |
AnnaBridge | 189:f392fc9709a3 | 459 | uint32_t serial_id = ((UARTName)uart - UART_0) / (UART_1 - UART_0); |
AnnaBridge | 189:f392fc9709a3 | 460 | |
AnnaBridge | 189:f392fc9709a3 | 461 | /* Initialize configuration */ |
AnnaBridge | 189:f392fc9709a3 | 462 | obj->base = (CySCB_Type *)uart; |
AnnaBridge | 189:f392fc9709a3 | 463 | obj->serial_id = serial_id; |
AnnaBridge | 189:f392fc9709a3 | 464 | obj->clock = CY_PIN_CLOCK(pinmap_function(tx, PinMap_UART_TX)); |
AnnaBridge | 189:f392fc9709a3 | 465 | obj->div_num = CY_INVALID_DIVIDER; |
AnnaBridge | 189:f392fc9709a3 | 466 | obj->already_reserved = (0 != cy_reserve_scb(obj->serial_id)); |
AnnaBridge | 189:f392fc9709a3 | 467 | |
AnnaBridge | 189:f392fc9709a3 | 468 | obj->pin_tx = tx; |
AnnaBridge | 189:f392fc9709a3 | 469 | obj->pin_rx = rx; |
AnnaBridge | 189:f392fc9709a3 | 470 | obj->pin_rts = NC; |
AnnaBridge | 189:f392fc9709a3 | 471 | obj->pin_cts = NC; |
AnnaBridge | 189:f392fc9709a3 | 472 | |
AnnaBridge | 188:bcfe06ba3d64 | 473 | obj->data_width = 8; |
AnnaBridge | 189:f392fc9709a3 | 474 | obj->stop_bits = CY_SCB_UART_STOP_BITS_1; |
AnnaBridge | 189:f392fc9709a3 | 475 | obj->parity = CY_SCB_UART_PARITY_NONE; |
AnnaBridge | 189:f392fc9709a3 | 476 | |
AnnaBridge | 189:f392fc9709a3 | 477 | /* Check if resource severed */ |
AnnaBridge | 189:f392fc9709a3 | 478 | if (obj->already_reserved) { |
AnnaBridge | 189:f392fc9709a3 | 479 | uint32_t map; |
AnnaBridge | 189:f392fc9709a3 | 480 | |
AnnaBridge | 189:f392fc9709a3 | 481 | /* SCB pins and clocks are connected */ |
AnnaBridge | 189:f392fc9709a3 | 482 | |
AnnaBridge | 189:f392fc9709a3 | 483 | /* Disable block and get it into the default state */ |
AnnaBridge | 189:f392fc9709a3 | 484 | Cy_SCB_UART_Disable(obj->base, NULL); |
AnnaBridge | 189:f392fc9709a3 | 485 | Cy_SCB_UART_DeInit(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 486 | |
AnnaBridge | 189:f392fc9709a3 | 487 | /* Get connected clock */ |
AnnaBridge | 189:f392fc9709a3 | 488 | map = Cy_SysClk_PeriphGetAssignedDivider(obj->clock); |
AnnaBridge | 189:f392fc9709a3 | 489 | obj->div_num = _FLD2VAL(CY_PERI_CLOCK_CTL_DIV_SEL, map); |
AnnaBridge | 189:f392fc9709a3 | 490 | obj->div_type = (cy_en_divider_types_t) _FLD2VAL(CY_PERI_CLOCK_CTL_TYPE_SEL, map); |
AnnaBridge | 189:f392fc9709a3 | 491 | } else { |
AnnaBridge | 189:f392fc9709a3 | 492 | #if DEVICE_SLEEP && DEVICE_LPTICKER && SERIAL_PM_CALLBACK_ENABLED |
AnnaBridge | 189:f392fc9709a3 | 493 | /* Register callback once */ |
AnnaBridge | 189:f392fc9709a3 | 494 | obj->pm_callback_handler.callback = serial_pm_callback; |
AnnaBridge | 189:f392fc9709a3 | 495 | obj->pm_callback_handler.type = CY_SYSPM_DEEPSLEEP; |
AnnaBridge | 189:f392fc9709a3 | 496 | obj->pm_callback_handler.skipMode = 0; |
AnnaBridge | 189:f392fc9709a3 | 497 | obj->pm_callback_handler.callbackParams = &obj->pm_callback_params; |
AnnaBridge | 189:f392fc9709a3 | 498 | obj->pm_callback_params.base = obj->base; |
AnnaBridge | 189:f392fc9709a3 | 499 | obj->pm_callback_params.context = obj; |
AnnaBridge | 189:f392fc9709a3 | 500 | |
AnnaBridge | 189:f392fc9709a3 | 501 | if (!Cy_SysPm_RegisterCallback(&obj->pm_callback_handler)) { |
AnnaBridge | 189:f392fc9709a3 | 502 | error("PM callback registration failed!"); |
AnnaBridge | 189:f392fc9709a3 | 503 | } |
AnnaBridge | 189:f392fc9709a3 | 504 | #endif /* (DEVICE_SLEEP && DEVICE_LPTICKER && SERIAL_PM_CALLBACK_ENABLED) */ |
AnnaBridge | 189:f392fc9709a3 | 505 | } |
AnnaBridge | 189:f392fc9709a3 | 506 | |
AnnaBridge | 189:f392fc9709a3 | 507 | /* Configure hardware resources */ |
AnnaBridge | 188:bcfe06ba3d64 | 508 | serial_init_clock(obj, UART_DEFAULT_BAUDRATE); |
AnnaBridge | 189:f392fc9709a3 | 509 | serial_init_pins(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 510 | serial_init_peripheral(obj); |
AnnaBridge | 189:f392fc9709a3 | 511 | |
AnnaBridge | 188:bcfe06ba3d64 | 512 | if (is_stdio) { |
AnnaBridge | 188:bcfe06ba3d64 | 513 | memcpy(&stdio_uart, obj_in, sizeof(serial_t)); |
AnnaBridge | 188:bcfe06ba3d64 | 514 | stdio_uart_inited = true; |
AnnaBridge | 189:f392fc9709a3 | 515 | } else if (is_bt) { |
AnnaBridge | 189:f392fc9709a3 | 516 | memcpy(&bt_uart, obj_in, sizeof(serial_t)); |
AnnaBridge | 189:f392fc9709a3 | 517 | bt_uart_inited = true; |
AnnaBridge | 188:bcfe06ba3d64 | 518 | } |
AnnaBridge | 188:bcfe06ba3d64 | 519 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 520 | error("Serial pinout mismatch. Requested pins Rx and Tx can't be used for the same Serial communication."); |
AnnaBridge | 188:bcfe06ba3d64 | 521 | } |
AnnaBridge | 188:bcfe06ba3d64 | 522 | } |
AnnaBridge | 188:bcfe06ba3d64 | 523 | } |
AnnaBridge | 188:bcfe06ba3d64 | 524 | |
AnnaBridge | 189:f392fc9709a3 | 525 | |
AnnaBridge | 189:f392fc9709a3 | 526 | void serial_free(serial_t *obj) |
AnnaBridge | 189:f392fc9709a3 | 527 | { |
AnnaBridge | 189:f392fc9709a3 | 528 | error("This function is not supported."); |
AnnaBridge | 189:f392fc9709a3 | 529 | } |
AnnaBridge | 189:f392fc9709a3 | 530 | |
AnnaBridge | 189:f392fc9709a3 | 531 | |
AnnaBridge | 188:bcfe06ba3d64 | 532 | void serial_baud(serial_t *obj_in, int baudrate) |
AnnaBridge | 188:bcfe06ba3d64 | 533 | { |
AnnaBridge | 188:bcfe06ba3d64 | 534 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 535 | |
AnnaBridge | 188:bcfe06ba3d64 | 536 | Cy_SCB_UART_Disable(obj->base, NULL); |
AnnaBridge | 188:bcfe06ba3d64 | 537 | serial_init_clock(obj, baudrate); |
AnnaBridge | 188:bcfe06ba3d64 | 538 | Cy_SCB_UART_Enable(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 539 | } |
AnnaBridge | 188:bcfe06ba3d64 | 540 | |
AnnaBridge | 189:f392fc9709a3 | 541 | |
AnnaBridge | 188:bcfe06ba3d64 | 542 | void serial_format(serial_t *obj_in, int data_bits, SerialParity parity, int stop_bits) |
AnnaBridge | 188:bcfe06ba3d64 | 543 | { |
AnnaBridge | 188:bcfe06ba3d64 | 544 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 545 | |
AnnaBridge | 188:bcfe06ba3d64 | 546 | if ((data_bits >= 5) && (data_bits <= 9)) { |
AnnaBridge | 188:bcfe06ba3d64 | 547 | obj->data_width = data_bits; |
AnnaBridge | 188:bcfe06ba3d64 | 548 | } |
AnnaBridge | 188:bcfe06ba3d64 | 549 | |
AnnaBridge | 188:bcfe06ba3d64 | 550 | switch (parity) { |
AnnaBridge | 188:bcfe06ba3d64 | 551 | case ParityNone: |
AnnaBridge | 188:bcfe06ba3d64 | 552 | obj->parity = CY_SCB_UART_PARITY_NONE; |
AnnaBridge | 188:bcfe06ba3d64 | 553 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 554 | case ParityOdd: |
AnnaBridge | 188:bcfe06ba3d64 | 555 | obj->parity = CY_SCB_UART_PARITY_ODD; |
AnnaBridge | 188:bcfe06ba3d64 | 556 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 557 | case ParityEven: |
AnnaBridge | 188:bcfe06ba3d64 | 558 | obj->parity = CY_SCB_UART_PARITY_EVEN; |
AnnaBridge | 188:bcfe06ba3d64 | 559 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 560 | case ParityForced1: |
AnnaBridge | 188:bcfe06ba3d64 | 561 | case ParityForced0: |
AnnaBridge | 189:f392fc9709a3 | 562 | error("Serial parity mode not supported!"); |
AnnaBridge | 188:bcfe06ba3d64 | 563 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 564 | } |
AnnaBridge | 188:bcfe06ba3d64 | 565 | |
AnnaBridge | 188:bcfe06ba3d64 | 566 | switch (stop_bits) { |
AnnaBridge | 188:bcfe06ba3d64 | 567 | case 1: |
AnnaBridge | 188:bcfe06ba3d64 | 568 | obj->stop_bits = CY_SCB_UART_STOP_BITS_1; |
AnnaBridge | 188:bcfe06ba3d64 | 569 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 570 | case 2: |
AnnaBridge | 188:bcfe06ba3d64 | 571 | obj->stop_bits = CY_SCB_UART_STOP_BITS_2; |
AnnaBridge | 188:bcfe06ba3d64 | 572 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 573 | case 3: |
AnnaBridge | 188:bcfe06ba3d64 | 574 | obj->stop_bits = CY_SCB_UART_STOP_BITS_3; |
AnnaBridge | 188:bcfe06ba3d64 | 575 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 576 | case 4: |
AnnaBridge | 188:bcfe06ba3d64 | 577 | obj->stop_bits = CY_SCB_UART_STOP_BITS_4; |
AnnaBridge | 188:bcfe06ba3d64 | 578 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 579 | } |
AnnaBridge | 188:bcfe06ba3d64 | 580 | |
AnnaBridge | 188:bcfe06ba3d64 | 581 | Cy_SCB_UART_Disable(obj->base, NULL); |
AnnaBridge | 188:bcfe06ba3d64 | 582 | serial_init_peripheral(obj); |
AnnaBridge | 189:f392fc9709a3 | 583 | /* SCB is enabled at the and of serial_init_peripheral() call */ |
AnnaBridge | 188:bcfe06ba3d64 | 584 | } |
AnnaBridge | 188:bcfe06ba3d64 | 585 | |
AnnaBridge | 189:f392fc9709a3 | 586 | |
AnnaBridge | 188:bcfe06ba3d64 | 587 | void serial_putc(serial_t *obj_in, int c) |
AnnaBridge | 188:bcfe06ba3d64 | 588 | { |
AnnaBridge | 188:bcfe06ba3d64 | 589 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 590 | |
AnnaBridge | 189:f392fc9709a3 | 591 | while (0 == serial_writable(obj_in)) { |
AnnaBridge | 189:f392fc9709a3 | 592 | /* There is an entry to be written */ |
AnnaBridge | 188:bcfe06ba3d64 | 593 | } |
AnnaBridge | 189:f392fc9709a3 | 594 | |
AnnaBridge | 189:f392fc9709a3 | 595 | Cy_SCB_WriteTxFifo(obj->base, (uint32_t) c); |
AnnaBridge | 188:bcfe06ba3d64 | 596 | } |
AnnaBridge | 188:bcfe06ba3d64 | 597 | |
AnnaBridge | 188:bcfe06ba3d64 | 598 | int serial_getc(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 599 | { |
AnnaBridge | 188:bcfe06ba3d64 | 600 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 601 | |
AnnaBridge | 189:f392fc9709a3 | 602 | while (0 == serial_readable(obj_in)) { |
AnnaBridge | 189:f392fc9709a3 | 603 | /* There is an item to be read */ |
AnnaBridge | 188:bcfe06ba3d64 | 604 | } |
AnnaBridge | 189:f392fc9709a3 | 605 | |
AnnaBridge | 188:bcfe06ba3d64 | 606 | return Cy_SCB_UART_Get(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 607 | } |
AnnaBridge | 188:bcfe06ba3d64 | 608 | |
AnnaBridge | 189:f392fc9709a3 | 609 | |
AnnaBridge | 188:bcfe06ba3d64 | 610 | int serial_readable(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 611 | { |
AnnaBridge | 188:bcfe06ba3d64 | 612 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 613 | return Cy_SCB_GetNumInRxFifo(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 614 | } |
AnnaBridge | 188:bcfe06ba3d64 | 615 | |
AnnaBridge | 189:f392fc9709a3 | 616 | |
AnnaBridge | 188:bcfe06ba3d64 | 617 | int serial_writable(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 618 | { |
AnnaBridge | 188:bcfe06ba3d64 | 619 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 620 | return (Cy_SCB_GetFifoSize(obj->base) != Cy_SCB_GetNumInTxFifo(obj->base)); |
AnnaBridge | 188:bcfe06ba3d64 | 621 | } |
AnnaBridge | 188:bcfe06ba3d64 | 622 | |
AnnaBridge | 189:f392fc9709a3 | 623 | |
AnnaBridge | 188:bcfe06ba3d64 | 624 | void serial_clear(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 625 | { |
AnnaBridge | 188:bcfe06ba3d64 | 626 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 627 | |
AnnaBridge | 189:f392fc9709a3 | 628 | /* The hardware FIFOs and statuses are cleared when SCB is disabled */ |
AnnaBridge | 188:bcfe06ba3d64 | 629 | Cy_SCB_UART_Disable(obj->base, NULL); |
AnnaBridge | 188:bcfe06ba3d64 | 630 | serial_init_peripheral(obj); |
AnnaBridge | 189:f392fc9709a3 | 631 | /* SCB is enabled at the and of serial_init_peripheral() call */ |
AnnaBridge | 188:bcfe06ba3d64 | 632 | } |
AnnaBridge | 188:bcfe06ba3d64 | 633 | |
AnnaBridge | 189:f392fc9709a3 | 634 | |
AnnaBridge | 188:bcfe06ba3d64 | 635 | void serial_break_set(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 636 | { |
AnnaBridge | 188:bcfe06ba3d64 | 637 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 638 | |
AnnaBridge | 188:bcfe06ba3d64 | 639 | /* Cypress SCB does not support transmitting break directly. |
AnnaBridge | 188:bcfe06ba3d64 | 640 | * We emulate functionality by switching TX pin to GPIO mode. |
AnnaBridge | 188:bcfe06ba3d64 | 641 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 642 | GPIO_PRT_Type *port_tx = Cy_GPIO_PortToAddr(CY_PORT(obj->pin_tx)); |
AnnaBridge | 188:bcfe06ba3d64 | 643 | Cy_GPIO_Pin_FastInit(port_tx, CY_PIN(obj->pin_tx), CY_GPIO_DM_STRONG_IN_OFF, 0, HSIOM_SEL_GPIO); |
AnnaBridge | 188:bcfe06ba3d64 | 644 | Cy_GPIO_Write(port_tx, CY_PIN(obj->pin_tx), 0); |
AnnaBridge | 188:bcfe06ba3d64 | 645 | } |
AnnaBridge | 188:bcfe06ba3d64 | 646 | |
AnnaBridge | 189:f392fc9709a3 | 647 | |
AnnaBridge | 188:bcfe06ba3d64 | 648 | void serial_break_clear(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 649 | { |
AnnaBridge | 188:bcfe06ba3d64 | 650 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 651 | |
AnnaBridge | 188:bcfe06ba3d64 | 652 | /* Connect TX pin back to SCB, see a comment in serial_break_set() above */ |
AnnaBridge | 188:bcfe06ba3d64 | 653 | GPIO_PRT_Type *port_tx = Cy_GPIO_PortToAddr(CY_PORT(obj->pin_tx)); |
AnnaBridge | 188:bcfe06ba3d64 | 654 | int tx_function = pinmap_function(obj->pin_tx, PinMap_UART_TX); |
AnnaBridge | 188:bcfe06ba3d64 | 655 | Cy_GPIO_Pin_FastInit(port_tx, CY_PIN(obj->pin_tx), CY_GPIO_DM_STRONG_IN_OFF, 0, CY_PIN_HSIOM(tx_function)); |
AnnaBridge | 188:bcfe06ba3d64 | 656 | } |
AnnaBridge | 188:bcfe06ba3d64 | 657 | |
AnnaBridge | 189:f392fc9709a3 | 658 | |
AnnaBridge | 189:f392fc9709a3 | 659 | void serial_pinout_tx(PinName tx) |
AnnaBridge | 189:f392fc9709a3 | 660 | { |
AnnaBridge | 189:f392fc9709a3 | 661 | error("This function is not supported."); |
AnnaBridge | 189:f392fc9709a3 | 662 | } |
AnnaBridge | 189:f392fc9709a3 | 663 | |
AnnaBridge | 189:f392fc9709a3 | 664 | |
AnnaBridge | 188:bcfe06ba3d64 | 665 | void serial_set_flow_control(serial_t *obj_in, FlowControl type, PinName rxflow, PinName txflow) |
AnnaBridge | 188:bcfe06ba3d64 | 666 | { |
AnnaBridge | 188:bcfe06ba3d64 | 667 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 668 | |
AnnaBridge | 189:f392fc9709a3 | 669 | /* Do not perform pins reservation second time for the same pins */ |
AnnaBridge | 189:f392fc9709a3 | 670 | if ((obj->pin_rts == rxflow) && (obj->pin_cts == txflow)) |
AnnaBridge | 189:f392fc9709a3 | 671 | return; |
AnnaBridge | 189:f392fc9709a3 | 672 | |
AnnaBridge | 188:bcfe06ba3d64 | 673 | Cy_SCB_UART_Disable(obj->base, NULL); |
AnnaBridge | 188:bcfe06ba3d64 | 674 | |
AnnaBridge | 188:bcfe06ba3d64 | 675 | switch (type) { |
AnnaBridge | 188:bcfe06ba3d64 | 676 | case FlowControlNone: |
AnnaBridge | 188:bcfe06ba3d64 | 677 | obj->pin_rts = NC; |
AnnaBridge | 188:bcfe06ba3d64 | 678 | obj->pin_cts = NC; |
AnnaBridge | 188:bcfe06ba3d64 | 679 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 680 | case FlowControlRTS: |
AnnaBridge | 188:bcfe06ba3d64 | 681 | obj->pin_rts = rxflow; |
AnnaBridge | 188:bcfe06ba3d64 | 682 | obj->pin_cts = NC; |
AnnaBridge | 188:bcfe06ba3d64 | 683 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 684 | case FlowControlCTS: |
AnnaBridge | 188:bcfe06ba3d64 | 685 | obj->pin_rts = NC; |
AnnaBridge | 188:bcfe06ba3d64 | 686 | obj->pin_cts = txflow; |
AnnaBridge | 188:bcfe06ba3d64 | 687 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 688 | case FlowControlRTSCTS: |
AnnaBridge | 188:bcfe06ba3d64 | 689 | obj->pin_rts = rxflow; |
AnnaBridge | 188:bcfe06ba3d64 | 690 | obj->pin_cts = txflow; |
AnnaBridge | 188:bcfe06ba3d64 | 691 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 692 | } |
AnnaBridge | 188:bcfe06ba3d64 | 693 | |
AnnaBridge | 189:f392fc9709a3 | 694 | serial_init_flow_pins(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 695 | serial_init_peripheral(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 696 | } |
AnnaBridge | 188:bcfe06ba3d64 | 697 | |
AnnaBridge | 189:f392fc9709a3 | 698 | |
AnnaBridge | 188:bcfe06ba3d64 | 699 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 700 | |
AnnaBridge | 188:bcfe06ba3d64 | 701 | void serial_irq_handler(serial_t *obj_in, uart_irq_handler handler, uint32_t id) |
AnnaBridge | 188:bcfe06ba3d64 | 702 | { |
AnnaBridge | 188:bcfe06ba3d64 | 703 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 704 | irq_info_t *info = &irq_info[obj->serial_id]; |
AnnaBridge | 188:bcfe06ba3d64 | 705 | |
AnnaBridge | 188:bcfe06ba3d64 | 706 | if (info->irqn != unconnected_IRQn) { |
AnnaBridge | 189:f392fc9709a3 | 707 | /* Seccessful serial_irq_setup_channel enables interrupt in NVIC */ |
AnnaBridge | 188:bcfe06ba3d64 | 708 | NVIC_DisableIRQ(info->irqn); |
AnnaBridge | 188:bcfe06ba3d64 | 709 | } |
AnnaBridge | 189:f392fc9709a3 | 710 | |
AnnaBridge | 188:bcfe06ba3d64 | 711 | info->handler = handler; |
AnnaBridge | 188:bcfe06ba3d64 | 712 | info->id_arg = id; |
AnnaBridge | 189:f392fc9709a3 | 713 | |
AnnaBridge | 189:f392fc9709a3 | 714 | if (0 != serial_irq_setup_channel(obj)) { |
AnnaBridge | 189:f392fc9709a3 | 715 | error("Interrupt setup failed."); |
AnnaBridge | 189:f392fc9709a3 | 716 | } |
AnnaBridge | 188:bcfe06ba3d64 | 717 | } |
AnnaBridge | 188:bcfe06ba3d64 | 718 | |
AnnaBridge | 189:f392fc9709a3 | 719 | |
AnnaBridge | 188:bcfe06ba3d64 | 720 | void serial_irq_set(serial_t *obj_in, SerialIrq irq, uint32_t enable) |
AnnaBridge | 188:bcfe06ba3d64 | 721 | { |
AnnaBridge | 188:bcfe06ba3d64 | 722 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 723 | |
AnnaBridge | 188:bcfe06ba3d64 | 724 | switch (irq) { |
AnnaBridge | 189:f392fc9709a3 | 725 | case RxIrq: /* RxIrq for receive (buffer is not empty) */ |
AnnaBridge | 189:f392fc9709a3 | 726 | Cy_SCB_SetRxInterruptMask(obj->base, (0 != enable) ? CY_SCB_RX_INTR_NOT_EMPTY : 0); |
AnnaBridge | 188:bcfe06ba3d64 | 727 | break; |
AnnaBridge | 189:f392fc9709a3 | 728 | |
AnnaBridge | 189:f392fc9709a3 | 729 | case TxIrq: /* TxIrq for transmit (buffer is empty) */ |
AnnaBridge | 189:f392fc9709a3 | 730 | Cy_SCB_SetTxInterruptMask(obj->base, (0 != enable) ? CY_SCB_UART_TX_EMPTY : 0); |
AnnaBridge | 188:bcfe06ba3d64 | 731 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 732 | } |
AnnaBridge | 188:bcfe06ba3d64 | 733 | } |
AnnaBridge | 188:bcfe06ba3d64 | 734 | |
AnnaBridge | 189:f392fc9709a3 | 735 | |
AnnaBridge | 189:f392fc9709a3 | 736 | int serial_tx_asynch(serial_t *obj_in, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint) |
AnnaBridge | 189:f392fc9709a3 | 737 | { |
AnnaBridge | 189:f392fc9709a3 | 738 | (void) tx_width; /* Deprecated argument */ |
AnnaBridge | 189:f392fc9709a3 | 739 | (void) hint; /* At the moment we do not support DMA transfers, so this parameter gets ignored. */ |
AnnaBridge | 189:f392fc9709a3 | 740 | |
AnnaBridge | 189:f392fc9709a3 | 741 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 742 | const uint8_t *p_buf = tx; |
AnnaBridge | 189:f392fc9709a3 | 743 | |
AnnaBridge | 189:f392fc9709a3 | 744 | if (obj->tx_pending || (tx_length == 0)) { |
AnnaBridge | 189:f392fc9709a3 | 745 | return 0; |
AnnaBridge | 189:f392fc9709a3 | 746 | } |
AnnaBridge | 189:f392fc9709a3 | 747 | |
AnnaBridge | 189:f392fc9709a3 | 748 | /* Configure interrupt handler */ |
AnnaBridge | 189:f392fc9709a3 | 749 | obj->async_handler = (cy_israddress)handler; |
AnnaBridge | 189:f392fc9709a3 | 750 | if (serial_irq_setup_channel(obj) < 0) { |
AnnaBridge | 189:f392fc9709a3 | 751 | return 0; |
AnnaBridge | 189:f392fc9709a3 | 752 | } |
AnnaBridge | 189:f392fc9709a3 | 753 | |
AnnaBridge | 189:f392fc9709a3 | 754 | /* Clear TX_DONE interrupt it might remain set from previous call */ |
AnnaBridge | 189:f392fc9709a3 | 755 | Cy_SCB_ClearTxInterrupt(obj->base, CY_SCB_UART_TX_DONE | CY_SCB_TX_INTR_LEVEL); |
AnnaBridge | 189:f392fc9709a3 | 756 | |
AnnaBridge | 189:f392fc9709a3 | 757 | /* Write as much as possible into the FIFO first */ |
AnnaBridge | 189:f392fc9709a3 | 758 | while ((tx_length > 0) && (0 != Cy_SCB_UART_Put(obj->base, *p_buf))) { |
AnnaBridge | 189:f392fc9709a3 | 759 | ++p_buf; |
AnnaBridge | 189:f392fc9709a3 | 760 | --tx_length; |
AnnaBridge | 189:f392fc9709a3 | 761 | } |
AnnaBridge | 189:f392fc9709a3 | 762 | |
AnnaBridge | 189:f392fc9709a3 | 763 | if (tx_length > 0) { |
AnnaBridge | 189:f392fc9709a3 | 764 | obj->tx_pending = true; |
AnnaBridge | 189:f392fc9709a3 | 765 | obj->tx_events = event; |
AnnaBridge | 189:f392fc9709a3 | 766 | obj_in->tx_buff.pos = 0; |
AnnaBridge | 189:f392fc9709a3 | 767 | obj_in->tx_buff.buffer = (void *)p_buf; |
AnnaBridge | 189:f392fc9709a3 | 768 | obj_in->tx_buff.length = tx_length; |
AnnaBridge | 189:f392fc9709a3 | 769 | |
AnnaBridge | 189:f392fc9709a3 | 770 | /* Enable LEVEL interrupt to complete transmission */ |
AnnaBridge | 189:f392fc9709a3 | 771 | Cy_SCB_SetTxInterruptMask(obj->base, CY_SCB_TX_INTR_LEVEL); |
AnnaBridge | 189:f392fc9709a3 | 772 | } else { |
AnnaBridge | 189:f392fc9709a3 | 773 | /* Enable DONE interrupt to signal completing of the transmission */ |
AnnaBridge | 189:f392fc9709a3 | 774 | Cy_SCB_SetTxInterruptMask(obj->base, CY_SCB_UART_TX_DONE); |
AnnaBridge | 189:f392fc9709a3 | 775 | } |
AnnaBridge | 189:f392fc9709a3 | 776 | |
AnnaBridge | 189:f392fc9709a3 | 777 | return tx_length; |
AnnaBridge | 189:f392fc9709a3 | 778 | } |
AnnaBridge | 189:f392fc9709a3 | 779 | |
AnnaBridge | 189:f392fc9709a3 | 780 | |
AnnaBridge | 189:f392fc9709a3 | 781 | void serial_rx_asynch(serial_t *obj_in, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint) |
AnnaBridge | 189:f392fc9709a3 | 782 | { |
AnnaBridge | 189:f392fc9709a3 | 783 | (void) rx_width; /* Deprecated argument */ |
AnnaBridge | 189:f392fc9709a3 | 784 | (void) hint; /* At the moment we do not support DMA transfers, so this parameter gets ignored. */ |
AnnaBridge | 189:f392fc9709a3 | 785 | |
AnnaBridge | 189:f392fc9709a3 | 786 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 787 | |
AnnaBridge | 189:f392fc9709a3 | 788 | if (obj->rx_pending || (rx_length == 0)) { |
AnnaBridge | 189:f392fc9709a3 | 789 | return; |
AnnaBridge | 189:f392fc9709a3 | 790 | } |
AnnaBridge | 189:f392fc9709a3 | 791 | |
AnnaBridge | 189:f392fc9709a3 | 792 | /* Configure interrupt handler */ |
AnnaBridge | 189:f392fc9709a3 | 793 | obj->async_handler = (cy_israddress)handler; |
AnnaBridge | 189:f392fc9709a3 | 794 | if (serial_irq_setup_channel(obj) < 0) { |
AnnaBridge | 189:f392fc9709a3 | 795 | return; |
AnnaBridge | 189:f392fc9709a3 | 796 | } |
AnnaBridge | 189:f392fc9709a3 | 797 | |
AnnaBridge | 189:f392fc9709a3 | 798 | obj->rx_pending = true; |
AnnaBridge | 189:f392fc9709a3 | 799 | obj->rx_events = event; |
AnnaBridge | 189:f392fc9709a3 | 800 | obj_in->char_match = char_match; |
AnnaBridge | 189:f392fc9709a3 | 801 | obj_in->char_found = false; |
AnnaBridge | 189:f392fc9709a3 | 802 | obj_in->rx_buff.pos = 0; |
AnnaBridge | 189:f392fc9709a3 | 803 | obj_in->rx_buff.buffer = rx; |
AnnaBridge | 189:f392fc9709a3 | 804 | obj_in->rx_buff.length = rx_length; |
AnnaBridge | 189:f392fc9709a3 | 805 | |
AnnaBridge | 189:f392fc9709a3 | 806 | /* Enable interrupts to start receiving */ |
AnnaBridge | 189:f392fc9709a3 | 807 | Cy_SCB_SetRxInterruptMask(obj->base, UART_RX_INTR_MASK); |
AnnaBridge | 189:f392fc9709a3 | 808 | } |
AnnaBridge | 189:f392fc9709a3 | 809 | |
AnnaBridge | 189:f392fc9709a3 | 810 | |
AnnaBridge | 189:f392fc9709a3 | 811 | uint8_t serial_tx_active(serial_t *obj) |
AnnaBridge | 189:f392fc9709a3 | 812 | { |
AnnaBridge | 189:f392fc9709a3 | 813 | return obj->serial.tx_pending; |
AnnaBridge | 189:f392fc9709a3 | 814 | } |
AnnaBridge | 189:f392fc9709a3 | 815 | |
AnnaBridge | 189:f392fc9709a3 | 816 | |
AnnaBridge | 189:f392fc9709a3 | 817 | uint8_t serial_rx_active(serial_t *obj) |
AnnaBridge | 189:f392fc9709a3 | 818 | { |
AnnaBridge | 189:f392fc9709a3 | 819 | return obj->serial.rx_pending; |
AnnaBridge | 189:f392fc9709a3 | 820 | } |
AnnaBridge | 189:f392fc9709a3 | 821 | |
AnnaBridge | 189:f392fc9709a3 | 822 | |
AnnaBridge | 189:f392fc9709a3 | 823 | /** Finishes TX asynchronous transfer: disable TX interrupts and clear |
AnnaBridge | 189:f392fc9709a3 | 824 | * pending state. |
AnnaBridge | 189:f392fc9709a3 | 825 | * |
AnnaBridge | 189:f392fc9709a3 | 826 | * @param obj The serial object |
AnnaBridge | 189:f392fc9709a3 | 827 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 828 | static void serial_finish_tx_asynch(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 829 | { |
AnnaBridge | 188:bcfe06ba3d64 | 830 | Cy_SCB_SetTxInterruptMask(obj->base, 0); |
AnnaBridge | 188:bcfe06ba3d64 | 831 | obj->tx_pending = false; |
AnnaBridge | 188:bcfe06ba3d64 | 832 | } |
AnnaBridge | 188:bcfe06ba3d64 | 833 | |
AnnaBridge | 189:f392fc9709a3 | 834 | |
AnnaBridge | 189:f392fc9709a3 | 835 | /** Finishes TX asynchronous transfer: disable TX interrupts and clear |
AnnaBridge | 189:f392fc9709a3 | 836 | * pending state. |
AnnaBridge | 189:f392fc9709a3 | 837 | * |
AnnaBridge | 189:f392fc9709a3 | 838 | * @param obj The serial object |
AnnaBridge | 189:f392fc9709a3 | 839 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 840 | static void serial_finish_rx_asynch(serial_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 841 | { |
AnnaBridge | 188:bcfe06ba3d64 | 842 | Cy_SCB_SetRxInterruptMask(obj->base, 0); |
AnnaBridge | 188:bcfe06ba3d64 | 843 | obj->rx_pending = false; |
AnnaBridge | 188:bcfe06ba3d64 | 844 | } |
AnnaBridge | 188:bcfe06ba3d64 | 845 | |
AnnaBridge | 188:bcfe06ba3d64 | 846 | |
AnnaBridge | 188:bcfe06ba3d64 | 847 | int serial_irq_handler_asynch(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 848 | { |
AnnaBridge | 188:bcfe06ba3d64 | 849 | uint32_t cur_events = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 850 | uint32_t tx_status; |
AnnaBridge | 188:bcfe06ba3d64 | 851 | uint32_t rx_status; |
AnnaBridge | 188:bcfe06ba3d64 | 852 | |
AnnaBridge | 188:bcfe06ba3d64 | 853 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 854 | |
AnnaBridge | 189:f392fc9709a3 | 855 | /* Interrupt cause is TX */ |
AnnaBridge | 189:f392fc9709a3 | 856 | if (0 != (CY_SCB_TX_INTR & Cy_SCB_GetInterruptCause(obj->base))) { |
AnnaBridge | 188:bcfe06ba3d64 | 857 | |
AnnaBridge | 189:f392fc9709a3 | 858 | /* Get interrupt sources and clear them */ |
AnnaBridge | 189:f392fc9709a3 | 859 | tx_status = Cy_SCB_GetTxInterruptStatusMasked(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 860 | Cy_SCB_ClearTxInterrupt(obj->base, tx_status); |
AnnaBridge | 188:bcfe06ba3d64 | 861 | |
AnnaBridge | 189:f392fc9709a3 | 862 | if (0 != (tx_status & CY_SCB_TX_INTR_LEVEL)) { |
AnnaBridge | 189:f392fc9709a3 | 863 | |
AnnaBridge | 189:f392fc9709a3 | 864 | /* Get current buffer position */ |
AnnaBridge | 189:f392fc9709a3 | 865 | uint8_t *ptr = obj_in->tx_buff.buffer; |
AnnaBridge | 189:f392fc9709a3 | 866 | ptr += obj_in->tx_buff.pos; |
AnnaBridge | 188:bcfe06ba3d64 | 867 | |
AnnaBridge | 189:f392fc9709a3 | 868 | /* FIFO has space available for more TX */ |
AnnaBridge | 189:f392fc9709a3 | 869 | while ((obj_in->tx_buff.pos < obj_in->tx_buff.length) && |
AnnaBridge | 189:f392fc9709a3 | 870 | (0 != Cy_SCB_UART_Put(obj->base, *ptr))) { |
AnnaBridge | 189:f392fc9709a3 | 871 | ++ptr; |
AnnaBridge | 189:f392fc9709a3 | 872 | ++(obj_in->tx_buff.pos); |
AnnaBridge | 189:f392fc9709a3 | 873 | } |
AnnaBridge | 189:f392fc9709a3 | 874 | |
AnnaBridge | 189:f392fc9709a3 | 875 | if (obj_in->tx_buff.pos == obj_in->tx_buff.length) { |
AnnaBridge | 189:f392fc9709a3 | 876 | /* No more bytes to follow; check to see if we need to signal completion */ |
AnnaBridge | 189:f392fc9709a3 | 877 | if (0 != (obj->tx_events & SERIAL_EVENT_TX_COMPLETE)) { |
AnnaBridge | 189:f392fc9709a3 | 878 | /* Disable TX_LEVEL and enable TX_DONE to get completion event */ |
AnnaBridge | 189:f392fc9709a3 | 879 | Cy_SCB_SetTxInterruptMask(obj->base, CY_SCB_UART_TX_DONE); |
AnnaBridge | 189:f392fc9709a3 | 880 | } else { |
AnnaBridge | 189:f392fc9709a3 | 881 | /* Nothing more to do, mark end of transmission */ |
AnnaBridge | 189:f392fc9709a3 | 882 | serial_finish_tx_asynch(obj); |
AnnaBridge | 189:f392fc9709a3 | 883 | } |
AnnaBridge | 189:f392fc9709a3 | 884 | } |
AnnaBridge | 188:bcfe06ba3d64 | 885 | } |
AnnaBridge | 189:f392fc9709a3 | 886 | |
AnnaBridge | 189:f392fc9709a3 | 887 | if (0 != (tx_status & CY_SCB_TX_INTR_UART_DONE)) { |
AnnaBridge | 189:f392fc9709a3 | 888 | /* Mark end of the transmission */ |
AnnaBridge | 189:f392fc9709a3 | 889 | serial_finish_tx_asynch(obj); |
AnnaBridge | 189:f392fc9709a3 | 890 | cur_events |= SERIAL_EVENT_TX_COMPLETE; |
AnnaBridge | 188:bcfe06ba3d64 | 891 | } |
AnnaBridge | 188:bcfe06ba3d64 | 892 | } |
AnnaBridge | 188:bcfe06ba3d64 | 893 | |
AnnaBridge | 189:f392fc9709a3 | 894 | /* Interrupt cause is RX */ |
AnnaBridge | 189:f392fc9709a3 | 895 | if (0 != (CY_SCB_RX_INTR & Cy_SCB_GetInterruptCause(obj->base))) { |
AnnaBridge | 188:bcfe06ba3d64 | 896 | |
AnnaBridge | 189:f392fc9709a3 | 897 | /* Get interrupt sources and clear them */ |
AnnaBridge | 189:f392fc9709a3 | 898 | rx_status = Cy_SCB_GetRxInterruptStatusMasked(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 899 | Cy_SCB_ClearRxInterrupt(obj->base, rx_status); |
AnnaBridge | 188:bcfe06ba3d64 | 900 | |
AnnaBridge | 189:f392fc9709a3 | 901 | if (0 != (rx_status & CY_SCB_RX_INTR_OVERFLOW)) { |
AnnaBridge | 189:f392fc9709a3 | 902 | cur_events |= SERIAL_EVENT_RX_OVERRUN_ERROR; |
AnnaBridge | 189:f392fc9709a3 | 903 | } |
AnnaBridge | 188:bcfe06ba3d64 | 904 | |
AnnaBridge | 189:f392fc9709a3 | 905 | if (0 != (rx_status & CY_SCB_RX_INTR_UART_FRAME_ERROR)) { |
AnnaBridge | 189:f392fc9709a3 | 906 | cur_events |= SERIAL_EVENT_RX_FRAMING_ERROR; |
AnnaBridge | 189:f392fc9709a3 | 907 | } |
AnnaBridge | 189:f392fc9709a3 | 908 | |
AnnaBridge | 189:f392fc9709a3 | 909 | if (0 != (rx_status & CY_SCB_RX_INTR_UART_PARITY_ERROR)) { |
AnnaBridge | 189:f392fc9709a3 | 910 | cur_events |= SERIAL_EVENT_RX_PARITY_ERROR; |
AnnaBridge | 189:f392fc9709a3 | 911 | } |
AnnaBridge | 189:f392fc9709a3 | 912 | |
AnnaBridge | 189:f392fc9709a3 | 913 | if (0 != (rx_status & CY_SCB_RX_INTR_LEVEL)) { |
AnnaBridge | 188:bcfe06ba3d64 | 914 | |
AnnaBridge | 189:f392fc9709a3 | 915 | /* Get current buffer position */ |
AnnaBridge | 189:f392fc9709a3 | 916 | uint8_t *ptr = obj_in->rx_buff.buffer; |
AnnaBridge | 189:f392fc9709a3 | 917 | ptr += obj_in->rx_buff.pos; |
AnnaBridge | 189:f392fc9709a3 | 918 | |
AnnaBridge | 189:f392fc9709a3 | 919 | /* Get data from the RX FIFO */ |
AnnaBridge | 189:f392fc9709a3 | 920 | while (obj_in->rx_buff.pos < obj_in->rx_buff.length) { |
AnnaBridge | 189:f392fc9709a3 | 921 | uint32_t c = Cy_SCB_UART_Get(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 922 | |
AnnaBridge | 189:f392fc9709a3 | 923 | if (c == CY_SCB_UART_RX_NO_DATA) { |
AnnaBridge | 189:f392fc9709a3 | 924 | break; |
AnnaBridge | 189:f392fc9709a3 | 925 | } |
AnnaBridge | 188:bcfe06ba3d64 | 926 | |
AnnaBridge | 189:f392fc9709a3 | 927 | *ptr++ = (uint8_t) c; |
AnnaBridge | 189:f392fc9709a3 | 928 | ++(obj_in->rx_buff.pos); |
AnnaBridge | 189:f392fc9709a3 | 929 | |
AnnaBridge | 189:f392fc9709a3 | 930 | /* Check for character match condition */ |
AnnaBridge | 189:f392fc9709a3 | 931 | if (obj_in->char_match != SERIAL_RESERVED_CHAR_MATCH) { |
AnnaBridge | 189:f392fc9709a3 | 932 | if (c == obj_in->char_match) { |
AnnaBridge | 189:f392fc9709a3 | 933 | obj_in->char_found = true; |
AnnaBridge | 189:f392fc9709a3 | 934 | cur_events |= SERIAL_EVENT_RX_CHARACTER_MATCH; |
AnnaBridge | 189:f392fc9709a3 | 935 | |
AnnaBridge | 189:f392fc9709a3 | 936 | /* Clamp RX buffer */ |
AnnaBridge | 189:f392fc9709a3 | 937 | obj_in->rx_buff.length = obj_in->rx_buff.pos; |
AnnaBridge | 189:f392fc9709a3 | 938 | break; |
AnnaBridge | 189:f392fc9709a3 | 939 | } |
AnnaBridge | 188:bcfe06ba3d64 | 940 | } |
AnnaBridge | 188:bcfe06ba3d64 | 941 | } |
AnnaBridge | 188:bcfe06ba3d64 | 942 | } |
AnnaBridge | 189:f392fc9709a3 | 943 | |
AnnaBridge | 189:f392fc9709a3 | 944 | if (obj_in->rx_buff.pos == obj_in->rx_buff.length) { |
AnnaBridge | 189:f392fc9709a3 | 945 | serial_finish_rx_asynch(obj); |
AnnaBridge | 189:f392fc9709a3 | 946 | cur_events |= SERIAL_EVENT_RX_COMPLETE; |
AnnaBridge | 189:f392fc9709a3 | 947 | } |
AnnaBridge | 188:bcfe06ba3d64 | 948 | } |
AnnaBridge | 188:bcfe06ba3d64 | 949 | |
AnnaBridge | 189:f392fc9709a3 | 950 | return (cur_events & (obj->tx_events | obj->rx_events)); |
AnnaBridge | 189:f392fc9709a3 | 951 | } |
AnnaBridge | 188:bcfe06ba3d64 | 952 | |
AnnaBridge | 188:bcfe06ba3d64 | 953 | |
AnnaBridge | 188:bcfe06ba3d64 | 954 | void serial_tx_abort_asynch(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 955 | { |
AnnaBridge | 188:bcfe06ba3d64 | 956 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 957 | |
AnnaBridge | 188:bcfe06ba3d64 | 958 | serial_finish_tx_asynch(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 959 | Cy_SCB_UART_ClearTxFifo(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 960 | } |
AnnaBridge | 188:bcfe06ba3d64 | 961 | |
AnnaBridge | 188:bcfe06ba3d64 | 962 | void serial_rx_abort_asynch(serial_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 963 | { |
AnnaBridge | 188:bcfe06ba3d64 | 964 | serial_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 965 | |
AnnaBridge | 188:bcfe06ba3d64 | 966 | serial_finish_rx_asynch(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 967 | Cy_SCB_UART_ClearRxFifo(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 968 | Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_UART_RX_INTR_MASK); |
AnnaBridge | 188:bcfe06ba3d64 | 969 | } |
AnnaBridge | 188:bcfe06ba3d64 | 970 | |
AnnaBridge | 189:f392fc9709a3 | 971 | #endif /* DEVICE_SERIAL_ASYNCH */ |
AnnaBridge | 188:bcfe06ba3d64 | 972 | |
AnnaBridge | 189:f392fc9709a3 | 973 | #endif /* DEVICE_SERIAL */ |