rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
hal_uart_lld.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file hal_uart_lld.c
19 * @brief KINETIS UART subsystem low level driver source.
20 * @author andreika <prometheus.pcb@gmail.com>
21 *
22 * @addtogroup UART
23 * @{
24 */
25
26#include "hal.h"
27#include "fsl_dmamux.h"
28
29#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__)
30
31/*===========================================================================*/
32/* Driver local definitions. */
33/*===========================================================================*/
34
35/*===========================================================================*/
36/* Driver exported variables. */
37/*===========================================================================*/
38
39/**
40 * @brief UART1 driver identifier.
41 */
42#if (KINETIS_UART_USE_UART1 == TRUE) || defined(__DOXYGEN__)
44#endif
45#if (KINETIS_UART_USE_UART2 == TRUE) || defined(__DOXYGEN__)
47#endif
48#if (KINETIS_UART_USE_UART3 == TRUE) || defined(__DOXYGEN__)
50#endif
51
52/*===========================================================================*/
53/* Driver local variables and types. */
54/*===========================================================================*/
55
56/*===========================================================================*/
57/* Driver local functions. */
58/*===========================================================================*/
59
60/**
61 * @brief Puts the receiver in the UART_RX_IDLE state.
62 *
63 * @param[in] uartp pointer to the @p UARTDriver object
64 */
66}
67
68/*===========================================================================*/
69/* Driver interrupt handlers. */
70/*===========================================================================*/
71
72void uart_lld_callback(LPUART_Type *base, void *handle, status_t status, void *userData) {
73 UARTDriver *uartp = (UARTDriver *)userData;
74#ifdef UART_USE_RING_BUFFER
75 // FSL LPUART lib can call this callback from anywhere, that's not good! :(
76 if (!port_is_isr_context()) {
77 // we cannot just call _uart_rx_complete_isr_code() without failing on osalSysLockFromISR(),
78 // so we have to trigger an IRQ interrupt to wake-up the thread after osalThreadSuspendTimeoutS()
79 // (See uartReceiveTimeout())
80 // We use 'LPUART_STAT_RXINV_MASK' just because it's unused flag
81 // and we can pass the status into the IRQ handler.
82 // todo: this is a hack! :( is there a better way?
83 base->STAT |= LPUART_STAT_RXINV_MASK;
84 NVIC_SetPendingIRQ(uartp->pendingRxIrq);
85 return;
86 }
87
88#endif /* UART_USE_RING_BUFFER */
89
90 // this is a common part for both interrupt-ring mode and DMA mode
91 switch (status) {
93 _uart_tx1_isr_code(uartp);
94 break;
96 _uart_rx_complete_isr_code(uartp);
97 break;
100 _uart_rx_error_isr_code(uartp, UART_OVERRUN_ERROR);
101 break;
103 _uart_rx_error_isr_code(uartp, UART_FRAMING_ERROR);
104 break;
106 _uart_rx_error_isr_code(uartp, UART_PARITY_ERROR);
107 break;
109 _uart_rx_error_isr_code(uartp, UART_NOISE_ERROR);
110 break;
111 }
112}
113
114/*===========================================================================*/
115/* Driver exported functions. */
116/*===========================================================================*/
117
118/**
119 * @brief Low level UART driver initialization.
120 *
121 * @notapi
122 */
123void uart_lld_init(void) {
124
125#if KINETIS_UART_USE_UART1 == TRUE
126 /* Driver initialization.*/
127 uartObjectInit(&UARTD1);
128#endif
129
130#if KINETIS_UART_USE_UART2 == TRUE
131 /* Driver initialization.*/
132 uartObjectInit(&UARTD2);
133#endif
134
135#if KINETIS_UART_USE_UART3 == TRUE
136 /* Driver initialization.*/
137 uartObjectInit(&UARTD3);
138#endif
139}
140
141/**
142 * @brief Configures and activates the UART peripheral.
143 *
144 * @param[in] uartp pointer to the @p UARTDriver object
145 *
146 * @notapi
147 */
149
150 if (uartp->state == UART_STOP) {
151 lpuart_config_t lpuartConfig;
152 LPUART_GetDefaultConfig(&lpuartConfig);
153 lpuartConfig.enableTx = true;
154 lpuartConfig.enableRx = true;
155 lpuartConfig.baudRate_Bps = uartp->config->speed;
156 lpuartConfig.parityMode = (uartp->config->cr1 & USART_CR1_PCE) ?
157 ((uartp->config->cr1 & USART_CR1_PS) ? kLPUART_ParityOdd : kLPUART_ParityEven) :
159 lpuartConfig.dataBitsCount = kLPUART_EightDataBits; // todo: check for USART_CR1_M?
160 lpuartConfig.stopBitCount = (uartp->config->cr2 & USART_CR2_STOP2_BITS) ? kLPUART_TwoStopBit : kLPUART_OneStopBit;
161#ifdef UART_USE_RING_BUFFER
162 lpuartConfig.txFifoWatermark = 0;
163 lpuartConfig.rxFifoWatermark = 1;
164#endif /* UART_USE_RING_BUFFER */
165
166 dma_request_source_t reqRx, reqTx;
167 uint32_t dmaStreamRx, dmaStreamTx;
168
169#if KINETIS_UART_USE_UART1 == TRUE
170 if (&UARTD1 == uartp) {
171 uartp->lpuart = LPUART0;
172 reqRx = kDmaRequestMux0LPUART0Rx;
173 reqTx = kDmaRequestMux0LPUART0Tx;
174 dmaStreamRx = KINETIS_DMA_STREAM_UART0_RX;
175 dmaStreamTx = KINETIS_DMA_STREAM_UART0_TX;
176 nvicEnableVector(LPUART0_TX_IRQn, KINETIS_UART0_IRQ_PRIORITY);
177 nvicEnableVector(LPUART0_RX_IRQn, KINETIS_UART0_IRQ_PRIORITY);
178 uartp->pendingRxIrq = LPUART0_RX_IRQn;
179 }
180#endif
181#if KINETIS_UART_USE_UART2 == TRUE
182 if (&UARTD2 == uartp) {
183 uartp->lpuart = LPUART1;
184 reqRx = kDmaRequestMux0LPUART1Rx;
185 reqTx = kDmaRequestMux0LPUART1Tx;
186 dmaStreamRx = KINETIS_DMA_STREAM_UART1_RX;
187 dmaStreamTx = KINETIS_DMA_STREAM_UART1_TX;
188 nvicEnableVector(LPUART1_TX_IRQn, KINETIS_UART1_IRQ_PRIORITY);
189 nvicEnableVector(LPUART1_RX_IRQn, KINETIS_UART1_IRQ_PRIORITY);
190 uartp->pendingRxIrq = LPUART1_RX_IRQn;
191 }
192#endif
193#if KINETIS_UART_USE_UART3 == TRUE
194 if (&UARTD3 == uartp) {
195 uartp->lpuart = LPUART2;
196 reqRx = kDmaRequestMux0LPUART2Rx;
197 reqTx = kDmaRequestMux0LPUART2Tx;
198 dmaStreamRx = KINETIS_DMA_STREAM_UART2_RX;
199 dmaStreamTx = KINETIS_DMA_STREAM_UART2_TX;
200 nvicEnableVector(LPUART2_TX_IRQn, KINETIS_UART2_IRQ_PRIORITY);
201 nvicEnableVector(LPUART2_RX_IRQn, KINETIS_UART2_IRQ_PRIORITY);
202 uartp->pendingRxIrq = LPUART2_RX_IRQn;
203 }
204#endif
205 // Enable UART
206 status_t status = LPUART_Init(uartp->lpuart, &lpuartConfig, KINETIS_UART_FREQUENCY);
207 if (status == kStatus_LPUART_BaudrateNotSupport) {
208 // the only reason we could fail is wrong 'baudRate_Bps'. So let's give it a second chance...
209 static const int defaultBaudRate = 115200;
210 lpuartConfig.baudRate_Bps = defaultBaudRate;
211 status = LPUART_Init(uartp->lpuart, &lpuartConfig, KINETIS_UART_FREQUENCY);
212 assert (status == kStatus_Success);
213 }
214
215 //LPUART_EnableInterrupts(uartp->lpuart, kLPUART_IdleLineInterruptEnable);
216
217 // Enable DMA
218 nvicEnableVector(DMA0_IRQn + dmaStreamRx, KINETIS_UART_DMA_IRQ_PRIORITY);
219 nvicEnableVector(DMA0_IRQn + dmaStreamTx, KINETIS_UART_DMA_IRQ_PRIORITY);
220
221 EDMA_CreateHandle(&uartp->lpuartRxEdmaHandle, DMA0, dmaStreamRx);
222 EDMA_CreateHandle(&uartp->lpuartTxEdmaHandle, DMA0, dmaStreamTx);
223
224 DMAMUX_SetSource(DMAMUX, dmaStreamRx, reqRx);
225 DMAMUX_EnableChannel(DMAMUX, dmaStreamRx);
226
227 DMAMUX_SetSource(DMAMUX, dmaStreamTx, reqTx);
228 DMAMUX_EnableChannel(DMAMUX, dmaStreamTx);
229
231 uartp, &uartp->lpuartTxEdmaHandle, &uartp->lpuartRxEdmaHandle);
232
233 // This is needed not only for the Ring-buffer mode, but also for the EDMA mode - for UART error handling!
235
236#ifdef UART_USE_RING_BUFFER
237 LPUART_TransferStartRingBuffer(uartp->lpuart, &uartp->rxHandle, uartp->rxRingBuffer, KINETIS_UART_RX_RING_BUFFER_SIZE);
238#endif
239 }
240
241 uartp->rxstate = UART_RX_IDLE;
242 uartp->txstate = UART_TX_IDLE;
243}
244
245/**
246 * @brief Deactivates the UART peripheral.
247 *
248 * @param[in] uartp pointer to the @p UARTDriver object
249 *
250 * @notapi
251 */
253
254 if (uartp->state == UART_READY) {
255 /* Resets the peripheral.*/
256
257 /* Disables the peripheral.*/
258#if KINETIS_UART_USE_UART1 == TRUE
259 if (&UARTD1 == uartp) {
260 nvicDisableVector(LPUART0_TX_IRQn);
261 nvicDisableVector(LPUART0_RX_IRQn);
262 DMAMUX_DisableChannel(DMAMUX, KINETIS_DMA_STREAM_UART0_RX);
263 DMAMUX_DisableChannel(DMAMUX, KINETIS_DMA_STREAM_UART0_TX);
264 LPUART_Deinit(LPUART0);
265 }
266#endif
267#if KINETIS_UART_USE_UART2 == TRUE
268 if (&UARTD2 == uartp) {
269 nvicDisableVector(LPUART1_TX_IRQn);
270 nvicDisableVector(LPUART1_RX_IRQn);
271 DMAMUX_DisableChannel(DMAMUX, KINETIS_DMA_STREAM_UART1_RX);
272 DMAMUX_DisableChannel(DMAMUX, KINETIS_DMA_STREAM_UART1_TX);
273 LPUART_Deinit(LPUART1);
274 }
275#endif
276#if KINETIS_UART_USE_UART3 == TRUE
277 if (&UARTD3 == uartp) {
278 nvicDisableVector(LPUART2_TX_IRQn);
279 nvicDisableVector(LPUART2_RX_IRQn);
280 DMAMUX_DisableChannel(DMAMUX, KINETIS_DMA_STREAM_UART2_RX);
281 DMAMUX_DisableChannel(DMAMUX, KINETIS_DMA_STREAM_UART2_TX);
282 LPUART_Deinit(LPUART2);
283 }
284#endif
285 }
286}
287
288/**
289 * @brief Starts a transmission on the UART peripheral.
290 * @note The buffers are organized as uint8_t arrays for data sizes below
291 * or equal to 8 bits else it is organized as uint16_t arrays.
292 *
293 * @param[in] uartp pointer to the @p UARTDriver object
294 * @param[in] n number of data frames to send
295 * @param[in] txbuf the pointer to the transmit buffer
296 *
297 * @notapi
298 */
299void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
300
302 xfer.data = (uint8_t *)txbuf;
303 xfer.dataSize = n;
304
305 /*status_t status = */LPUART_SendEDMA(uartp->lpuart, &uartp->dmaHandle, &xfer);
306 // todo: check status
307}
308
309/**
310 * @brief Stops any ongoing transmission.
311 * @note Stopping a transmission also suppresses the transmission callbacks.
312 *
313 * @param[in] uartp pointer to the @p UARTDriver object
314 *
315 * @return The number of data frames not transmitted by the
316 * stopped transmit operation.
317 *
318 * @notapi
319 */
321
323
324 return 0;
325}
326
327/**
328 * @brief Starts a receive operation on the UART peripheral.
329 * @note The buffers are organized as uint8_t arrays for data sizes below
330 * or equal to 8 bits else it is organized as uint16_t arrays.
331 *
332 * @param[in] uartp pointer to the @p UARTDriver object
333 * @param[in] n number of data frames to send
334 * @param[out] rxbuf the pointer to the receive buffer
335 *
336 * @notapi
337 */
338void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
340 xfer.data = (uint8_t *)rxbuf;
341 xfer.dataSize = n;
342
343#ifdef UART_USE_RING_BUFFER
344 size_t receivedBytes = 0U;
345 /*status_t status = */LPUART_TransferReceiveNonBlocking(uartp->lpuart, &uartp->rxHandle, &xfer, &receivedBytes);
346 // todo: check receivedBytes?
347#else
348 /*status_t status = */LPUART_ReceiveEDMA(uartp->lpuart, &uartp->dmaHandle, &xfer);
349 // This is needed for UART error handling
351#endif /* UART_USE_RING_BUFFER */
352 // todo: check status
353}
354
355/**
356 * @brief Stops any ongoing receive operation.
357 * @note Stopping a receive operation also suppresses the receive callbacks.
358 *
359 * @param[in] uartp pointer to the @p UARTDriver object
360 *
361 * @return The number of data frames not received by the
362 * stopped receive operation.
363 *
364 * @notapi
365 */
367
368 uint32_t numReceived = 0;
369#ifdef UART_USE_RING_BUFFER
371 {
372 return 0;
373 }
374
376
377 return uartp->rxHandle.rxDataSizeAll - (size_t)numReceived;
378#else
379 // let's do it before LPUART_TransferGetReceiveCountEDMA()?
380 LPUART_EnableRxDMA(uartp->lpuart, false);
381
383 //numReceived = uartp->dmaHandle.rxDataSizeAll;
384 return 0;
385 }
386
388
389 return uartp->dmaHandle.rxDataSizeAll - (size_t)numReceived;
390#endif /* UART_USE_RING_BUFFER */
391}
392
393#endif /* HAL_USE_UART == TRUE */
394
395void uart_lld_blocking_send(UARTDriver *uartp, size_t n, const void *txbuf) {
396 LPUART_WriteBlocking(uartp->lpuart, txbuf, n);
397}
398
399/** @} */
void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf)
Starts a transmission on the UART peripheral.
void uart_lld_blocking_send(UARTDriver *uartp, size_t n, const void *txbuf)
void uart_lld_start(UARTDriver *uartp)
Configures and activates the UART peripheral.
UARTDriver UARTD2
UARTDriver UARTD1
UART1 driver identifier.
void uart_lld_init(void)
Low level UART driver initialization.
static void uart_enter_rx_idle_loop(UARTDriver *uartp)
Puts the receiver in the UART_RX_IDLE state.
UARTDriver UARTD3
size_t uart_lld_stop_send(UARTDriver *uartp)
Stops any ongoing transmission.
void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf)
Starts a receive operation on the UART peripheral.
size_t uart_lld_stop_receive(UARTDriver *uartp)
Stops any ongoing receive operation.
void uart_lld_stop(UARTDriver *uartp)
Deactivates the UART peripheral.
void uart_lld_callback(LPUART_Type *base, void *handle, status_t status, void *userData)
static void DMAMUX_DisableChannel(DMAMUX_Type *base, uint32_t channel)
Disables the DMAMUX channel.
Definition fsl_dmamux.h:92
static void DMAMUX_SetSource(DMAMUX_Type *base, uint32_t channel, uint32_t source)
Configures the DMAMUX channel source.
Definition fsl_dmamux.h:106
static void DMAMUX_EnableChannel(DMAMUX_Type *base, uint32_t channel)
Enables the DMAMUX channel.
Definition fsl_dmamux.h:76
void EDMA_CreateHandle(edma_handle_t *handle, DMA_Type *base, uint32_t channel)
Creates the eDMA handle.
Definition fsl_edma.c:757
int32_t status_t
Type used for all status and error return values.
Definition fsl_common.h:169
@ kStatus_Success
Definition fsl_common.h:159
@ kStatus_NoTransferInProgress
Definition fsl_common.h:165
uint8_t rxFifoWatermark
Definition fsl_lpuart.h:200
void LPUART_TransferCreateHandle(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_callback_t callback, void *userData)
Initializes the LPUART handle.
Definition fsl_lpuart.c:942
uint8_t txFifoWatermark
Definition fsl_lpuart.h:199
status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz)
Initializes an LPUART instance with the user configuration structure and the peripheral clock.
Definition fsl_lpuart.c:239
void LPUART_Deinit(LPUART_Type *base)
Deinitializes a LPUART instance.
Definition fsl_lpuart.c:455
lpuart_parity_mode_t parityMode
Definition fsl_lpuart.h:192
void LPUART_TransferAbortReceive(LPUART_Type *base, lpuart_handle_t *handle)
Aborts the interrupt-driven data receiving.
void LPUART_TransferStartRingBuffer(LPUART_Type *base, lpuart_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
Sets up the RX ring buffer.
void(* lpuart_transfer_callback_t)(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData)
LPUART transfer callback function.
Definition fsl_lpuart.h:225
status_t LPUART_TransferReceiveNonBlocking(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_t *xfer, size_t *receivedBytes)
Receives a buffer of data using the interrupt method.
lpuart_stop_bit_count_t stopBitCount
Definition fsl_lpuart.h:196
void LPUART_GetDefaultConfig(lpuart_config_t *config)
Gets the default configuration structure.
Definition fsl_lpuart.c:519
void LPUART_EnableInterrupts(LPUART_Type *base, uint32_t mask)
Enables LPUART interrupts according to a provided mask.
Definition fsl_lpuart.c:662
status_t LPUART_TransferGetReceiveCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count)
Gets the number of bytes that have been received.
void LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
Writes to the transmitter register using a blocking method.
Definition fsl_lpuart.c:832
static void LPUART_EnableRxDMA(LPUART_Type *base, bool enable)
Enables or disables the LPUART receiver DMA.
Definition fsl_lpuart.h:510
size_t rxDataSizeAll
Definition fsl_lpuart.h:235
uint32_t baudRate_Bps
Definition fsl_lpuart.h:191
lpuart_data_bits_t dataBitsCount
Definition fsl_lpuart.h:193
@ kLPUART_RxDataRegFullInterruptEnable
Definition fsl_lpuart.h:126
@ kLPUART_RxOverrunInterruptEnable
Definition fsl_lpuart.h:128
@ kLPUART_ParityDisabled
Definition fsl_lpuart.h:53
@ kLPUART_ParityEven
Definition fsl_lpuart.h:54
@ kLPUART_ParityOdd
Definition fsl_lpuart.h:55
@ kLPUART_EightDataBits
Definition fsl_lpuart.h:61
@ kStatus_LPUART_RxIdle
Definition fsl_lpuart.h:34
@ kStatus_LPUART_TxIdle
Definition fsl_lpuart.h:33
@ kStatus_LPUART_FramingError
Definition fsl_lpuart.h:43
@ kStatus_LPUART_RxRingBufferOverrun
Definition fsl_lpuart.h:39
@ kStatus_LPUART_NoiseError
Definition fsl_lpuart.h:42
@ kStatus_LPUART_BaudrateNotSupport
Definition fsl_lpuart.h:45
@ kStatus_LPUART_ParityError
Definition fsl_lpuart.h:44
@ kStatus_LPUART_RxHardwareOverrun
Definition fsl_lpuart.h:41
@ kLPUART_OneStopBit
Definition fsl_lpuart.h:70
@ kLPUART_TwoStopBit
Definition fsl_lpuart.h:71
status_t LPUART_SendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
Sends data using eDMA.
status_t LPUART_TransferGetReceiveCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
Gets the number of received bytes.
void LPUART_TransferAbortSendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
Aborts the sent data using eDMA.
void LPUART_TransferCreateHandleEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_edma_transfer_callback_t callback, void *userData, edma_handle_t *txEdmaHandle, edma_handle_t *rxEdmaHandle)
Initializes the LPUART handle which is used in transactional functions.
void(* lpuart_edma_transfer_callback_t)(LPUART_Type *base, lpuart_edma_handle_t *handle, status_t status, void *userData)
LPUART transfer callback function.
status_t LPUART_ReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
Receives data using eDMA.
void LPUART_TransferAbortReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
Aborts the received data using eDMA.
LPUART configuration structure.
Definition fsl_lpuart.h:190
LPUART transfer structure.
Definition fsl_lpuart.h:216
uint16_t cr1
Initialization value for the CR1 register.
uint16_t cr2
Initialization value for the CR2 register.
uint32_t speed
Bit rate.
Structure representing an UART driver.
lpuart_edma_handle_t dmaHandle
LPUART common eDMA channel handle.
edma_handle_t lpuartRxEdmaHandle
eDMA transfer handles.
uartrxstate_t rxstate
Receiver state.
int pendingRxIrq
Used to trigger the IRQ from our software handler. See uart_lld_callback() and UART_USE_RING_BUFFER.
lpuart_handle_t rxHandle
Used for the RingBuffer mode or to handle UART errors in EDMA mode.
const UARTConfig * config
Current configuration data.
uartstate_t state
Driver state.
UART_DRIVER_EXT_FIELDS LPUART_Type * lpuart
Pointer to the USART registers block.
uint8_t rxRingBuffer[KINETIS_UART_RX_RING_BUFFER_SIZE]
uarttxstate_t txstate
Transmitter state.
edma_handle_t lpuartTxEdmaHandle