Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:00

0001 /*
0002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2022 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_lpuart_edma.h"
0010 
0011 /*******************************************************************************
0012  * Definitions
0013  ******************************************************************************/
0014 
0015 /* Component ID definition, used by tools. */
0016 #ifndef FSL_COMPONENT_ID
0017 #define FSL_COMPONENT_ID "platform.drivers.lpuart_edma"
0018 #endif
0019 
0020 /*<! Structure definition for lpuart_edma_private_handle_t. The structure is private. */
0021 typedef struct _lpuart_edma_private_handle
0022 {
0023     LPUART_Type *base;
0024     lpuart_edma_handle_t *handle;
0025 } lpuart_edma_private_handle_t;
0026 
0027 /* LPUART EDMA transfer handle. */
0028 enum
0029 {
0030     kLPUART_TxIdle, /* TX idle. */
0031     kLPUART_TxBusy, /* TX busy. */
0032     kLPUART_RxIdle, /* RX idle. */
0033     kLPUART_RxBusy  /* RX busy. */
0034 };
0035 
0036 /*******************************************************************************
0037  * Variables
0038  ******************************************************************************/
0039 
0040 /* Array of LPUART handle. */
0041 #if (defined(LPUART12))
0042 #define LPUART_HANDLE_ARRAY_SIZE 13
0043 #else /* LPUART12 */
0044 #if (defined(LPUART11))
0045 #define LPUART_HANDLE_ARRAY_SIZE 12
0046 #else /* LPUART11 */
0047 #if (defined(LPUART10))
0048 #define LPUART_HANDLE_ARRAY_SIZE 11
0049 #else /* LPUART10 */
0050 #if (defined(LPUART9))
0051 #define LPUART_HANDLE_ARRAY_SIZE 10
0052 #else /* LPUART9 */
0053 #if (defined(LPUART8))
0054 #define LPUART_HANDLE_ARRAY_SIZE 9
0055 #else /* LPUART8 */
0056 #if (defined(LPUART7))
0057 #define LPUART_HANDLE_ARRAY_SIZE 8
0058 #else /* LPUART7 */
0059 #if (defined(LPUART6))
0060 #define LPUART_HANDLE_ARRAY_SIZE 7
0061 #else /* LPUART6 */
0062 #if (defined(LPUART5))
0063 #define LPUART_HANDLE_ARRAY_SIZE 6
0064 #else /* LPUART5 */
0065 #if (defined(LPUART4))
0066 #define LPUART_HANDLE_ARRAY_SIZE 5
0067 #else /* LPUART4 */
0068 #if (defined(LPUART3))
0069 #define LPUART_HANDLE_ARRAY_SIZE 4
0070 #else /* LPUART3 */
0071 #if (defined(LPUART2))
0072 #define LPUART_HANDLE_ARRAY_SIZE 3
0073 #else /* LPUART2 */
0074 #if (defined(LPUART1))
0075 #define LPUART_HANDLE_ARRAY_SIZE 2
0076 #else /* LPUART1 */
0077 #if (defined(LPUART0))
0078 #define LPUART_HANDLE_ARRAY_SIZE 1
0079 #else /* LPUART0 */
0080 #define LPUART_HANDLE_ARRAY_SIZE FSL_FEATURE_SOC_LPUART_COUNT
0081 #endif /* LPUART 0 */
0082 #endif /* LPUART 1 */
0083 #endif /* LPUART 2 */
0084 #endif /* LPUART 3 */
0085 #endif /* LPUART 4 */
0086 #endif /* LPUART 5 */
0087 #endif /* LPUART 6 */
0088 #endif /* LPUART 7 */
0089 #endif /* LPUART 8 */
0090 #endif /* LPUART 9 */
0091 #endif /* LPUART 10 */
0092 #endif /* LPUART 11 */
0093 #endif /* LPUART 12 */
0094 
0095 /*<! Private handle only used for internally. */
0096 static lpuart_edma_private_handle_t s_lpuartEdmaPrivateHandle[LPUART_HANDLE_ARRAY_SIZE];
0097 
0098 /*******************************************************************************
0099  * Prototypes
0100  ******************************************************************************/
0101 
0102 /*!
0103  * @brief LPUART EDMA send finished callback function.
0104  *
0105  * This function is called when LPUART EDMA send finished. It disables the LPUART
0106  * TX EDMA request and sends @ref kStatus_LPUART_TxIdle to LPUART callback.
0107  *
0108  * @param handle The EDMA handle.
0109  * @param param Callback function parameter.
0110  */
0111 static void LPUART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
0112 
0113 /*!
0114  * @brief LPUART EDMA receive finished callback function.
0115  *
0116  * This function is called when LPUART EDMA receive finished. It disables the LPUART
0117  * RX EDMA request and sends @ref kStatus_LPUART_RxIdle to LPUART callback.
0118  *
0119  * @param handle The EDMA handle.
0120  * @param param Callback function parameter.
0121  */
0122 static void LPUART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
0123 
0124 /*******************************************************************************
0125  * Code
0126  ******************************************************************************/
0127 
0128 static void LPUART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
0129 {
0130     assert(NULL != param);
0131 
0132     lpuart_edma_private_handle_t *lpuartPrivateHandle = (lpuart_edma_private_handle_t *)param;
0133 
0134     /* Avoid the warning for unused variables. */
0135     handle = handle;
0136     tcds   = tcds;
0137 
0138     if (transferDone)
0139     {
0140         /* Disable LPUART TX EDMA. */
0141         LPUART_EnableTxDMA(lpuartPrivateHandle->base, false);
0142 
0143         /* Stop transfer. */
0144         EDMA_AbortTransfer(handle);
0145 
0146         /* Enable tx complete interrupt */
0147         LPUART_EnableInterrupts(lpuartPrivateHandle->base, (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
0148     }
0149 }
0150 
0151 static void LPUART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
0152 {
0153     assert(NULL != param);
0154 
0155     lpuart_edma_private_handle_t *lpuartPrivateHandle = (lpuart_edma_private_handle_t *)param;
0156 
0157     /* Avoid warning for unused parameters. */
0158     handle = handle;
0159     tcds   = tcds;
0160 
0161     if (transferDone)
0162     {
0163         /* Disable transfer. */
0164         LPUART_TransferAbortReceiveEDMA(lpuartPrivateHandle->base, lpuartPrivateHandle->handle);
0165 
0166         if (NULL != lpuartPrivateHandle->handle->callback)
0167         {
0168             lpuartPrivateHandle->handle->callback(lpuartPrivateHandle->base, lpuartPrivateHandle->handle,
0169                                                   kStatus_LPUART_RxIdle, lpuartPrivateHandle->handle->userData);
0170         }
0171     }
0172 }
0173 
0174 /*!
0175  * brief Initializes the LPUART handle which is used in transactional functions.
0176  *
0177  * note This function disables all LPUART interrupts.
0178  *
0179  * param base LPUART peripheral base address.
0180  * param handle Pointer to lpuart_edma_handle_t structure.
0181  * param callback Callback function.
0182  * param userData User data.
0183  * param txEdmaHandle User requested DMA handle for TX DMA transfer.
0184  * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
0185  */
0186 void LPUART_TransferCreateHandleEDMA(LPUART_Type *base,
0187                                      lpuart_edma_handle_t *handle,
0188                                      lpuart_edma_transfer_callback_t callback,
0189                                      void *userData,
0190                                      edma_handle_t *txEdmaHandle,
0191                                      edma_handle_t *rxEdmaHandle)
0192 {
0193     assert(NULL != handle);
0194 
0195     uint32_t instance = LPUART_GetInstance(base);
0196 
0197     s_lpuartEdmaPrivateHandle[instance].base   = base;
0198     s_lpuartEdmaPrivateHandle[instance].handle = handle;
0199 
0200     (void)memset(handle, 0, sizeof(*handle));
0201 
0202     handle->rxState = (uint8_t)kLPUART_RxIdle;
0203     handle->txState = (uint8_t)kLPUART_TxIdle;
0204 
0205     handle->rxEdmaHandle = rxEdmaHandle;
0206     handle->txEdmaHandle = txEdmaHandle;
0207 
0208     handle->callback = callback;
0209     handle->userData = userData;
0210 
0211 #if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
0212     /* Note:
0213        Take care of the RX FIFO, EDMA request only assert when received bytes
0214        equal or more than RX water mark, there is potential issue if RX water
0215        mark larger than 1.
0216        For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
0217        5 bytes are received. the last byte will be saved in FIFO but not trigger
0218        EDMA transfer because the water mark is 2.
0219      */
0220     if (NULL != rxEdmaHandle)
0221     {
0222         base->WATER &= (~LPUART_WATER_RXWATER_MASK);
0223     }
0224 #endif
0225 
0226     /* Save the handle in global variables to support the double weak mechanism. */
0227     s_lpuartHandle[instance] = handle;
0228     /* Set LPUART_TransferEdmaHandleIRQ as DMA IRQ handler */
0229     s_lpuartIsr[instance] = LPUART_TransferEdmaHandleIRQ;
0230     /* Disable all LPUART internal interrupts */
0231     LPUART_DisableInterrupts(base, (uint32_t)kLPUART_AllInterruptEnable);
0232     /* Enable interrupt in NVIC. */
0233 #if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
0234     (void)EnableIRQ(s_lpuartTxIRQ[instance]);
0235 #else
0236     (void)EnableIRQ(s_lpuartIRQ[instance]);
0237 #endif
0238 
0239     /* Configure TX. */
0240     if (NULL != txEdmaHandle)
0241     {
0242         EDMA_SetCallback(handle->txEdmaHandle, LPUART_SendEDMACallback, &s_lpuartEdmaPrivateHandle[instance]);
0243     }
0244 
0245     /* Configure RX. */
0246     if (NULL != rxEdmaHandle)
0247     {
0248         EDMA_SetCallback(handle->rxEdmaHandle, LPUART_ReceiveEDMACallback, &s_lpuartEdmaPrivateHandle[instance]);
0249     }
0250 }
0251 
0252 /*!
0253  * brief Sends data using eDMA.
0254  *
0255  * This function sends data using eDMA. This is a non-blocking function, which returns
0256  * right away. When all data is sent, the send callback function is called.
0257  *
0258  * param base LPUART peripheral base address.
0259  * param handle LPUART handle pointer.
0260  * param xfer LPUART eDMA transfer structure. See #lpuart_transfer_t.
0261  * retval kStatus_Success if succeed, others failed.
0262  * retval kStatus_LPUART_TxBusy Previous transfer on going.
0263  * retval kStatus_InvalidArgument Invalid argument.
0264  */
0265 status_t LPUART_SendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
0266 {
0267     assert(NULL != handle);
0268     assert(NULL != handle->txEdmaHandle);
0269     assert(NULL != xfer);
0270     assert(NULL != xfer->data);
0271     assert(0U != xfer->dataSize);
0272 
0273     edma_transfer_config_t xferConfig;
0274     status_t status;
0275 
0276     /* If previous TX not finished. */
0277     if ((uint8_t)kLPUART_TxBusy == handle->txState)
0278     {
0279         status = kStatus_LPUART_TxBusy;
0280     }
0281     else
0282     {
0283         handle->txState       = (uint8_t)kLPUART_TxBusy;
0284         handle->txDataSizeAll = xfer->dataSize;
0285 
0286         /* Prepare transfer. */
0287         EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
0288                              (void *)(uint32_t *)LPUART_GetDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
0289                              xfer->dataSize, kEDMA_MemoryToPeripheral);
0290 
0291         /* Store the initially configured eDMA minor byte transfer count into the LPUART handle */
0292         handle->nbytes = (uint8_t)sizeof(uint8_t);
0293 
0294         /* Submit transfer. */
0295         if (kStatus_Success !=
0296             EDMA_SubmitTransfer(handle->txEdmaHandle, (const edma_transfer_config_t *)(uint32_t)&xferConfig))
0297         {
0298             return kStatus_Fail;
0299         }
0300         EDMA_StartTransfer(handle->txEdmaHandle);
0301 
0302         /* Enable LPUART TX EDMA. */
0303         LPUART_EnableTxDMA(base, true);
0304 
0305         status = kStatus_Success;
0306     }
0307 
0308     return status;
0309 }
0310 
0311 /*!
0312  * brief Receives data using eDMA.
0313  *
0314  * This function receives data using eDMA. This is non-blocking function, which returns
0315  * right away. When all data is received, the receive callback function is called.
0316  *
0317  * param base LPUART peripheral base address.
0318  * param handle Pointer to lpuart_edma_handle_t structure.
0319  * param xfer LPUART eDMA transfer structure, see #lpuart_transfer_t.
0320  * retval kStatus_Success if succeed, others fail.
0321  * retval kStatus_LPUART_RxBusy Previous transfer ongoing.
0322  * retval kStatus_InvalidArgument Invalid argument.
0323  */
0324 status_t LPUART_ReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
0325 {
0326     assert(NULL != handle);
0327     assert(NULL != handle->rxEdmaHandle);
0328     assert(NULL != xfer);
0329     assert(NULL != xfer->data);
0330     assert(0U != xfer->dataSize);
0331 
0332     edma_transfer_config_t xferConfig;
0333     status_t status;
0334 
0335     /* If previous RX not finished. */
0336     if ((uint8_t)kLPUART_RxBusy == handle->rxState)
0337     {
0338         status = kStatus_LPUART_RxBusy;
0339     }
0340     else
0341     {
0342         handle->rxState       = (uint8_t)kLPUART_RxBusy;
0343         handle->rxDataSizeAll = xfer->dataSize;
0344 
0345         /* Prepare transfer. */
0346         EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)LPUART_GetDataRegisterAddress(base), sizeof(uint8_t),
0347                              xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
0348 
0349         /* Store the initially configured eDMA minor byte transfer count into the LPUART handle */
0350         handle->nbytes = (uint8_t)sizeof(uint8_t);
0351 
0352         /* Submit transfer. */
0353         if (kStatus_Success !=
0354             EDMA_SubmitTransfer(handle->rxEdmaHandle, (const edma_transfer_config_t *)(uint32_t)&xferConfig))
0355         {
0356             return kStatus_Fail;
0357         }
0358         EDMA_StartTransfer(handle->rxEdmaHandle);
0359 
0360         /* Enable LPUART RX EDMA. */
0361         LPUART_EnableRxDMA(base, true);
0362 
0363         status = kStatus_Success;
0364     }
0365 
0366     return status;
0367 }
0368 
0369 /*!
0370  * brief Aborts the sent data using eDMA.
0371  *
0372  * This function aborts the sent data using eDMA.
0373  *
0374  * param base LPUART peripheral base address.
0375  * param handle Pointer to lpuart_edma_handle_t structure.
0376  */
0377 void LPUART_TransferAbortSendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
0378 {
0379     assert(NULL != handle);
0380     assert(NULL != handle->txEdmaHandle);
0381 
0382     /* Disable LPUART TX EDMA. */
0383     LPUART_EnableTxDMA(base, false);
0384 
0385     /* Stop transfer. */
0386     EDMA_AbortTransfer(handle->txEdmaHandle);
0387 
0388     handle->txState = (uint8_t)kLPUART_TxIdle;
0389 }
0390 
0391 /*!
0392  * brief Aborts the received data using eDMA.
0393  *
0394  * This function aborts the received data using eDMA.
0395  *
0396  * param base LPUART peripheral base address.
0397  * param handle Pointer to lpuart_edma_handle_t structure.
0398  */
0399 void LPUART_TransferAbortReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
0400 {
0401     assert(NULL != handle);
0402     assert(NULL != handle->rxEdmaHandle);
0403 
0404     /* Disable LPUART RX EDMA. */
0405     LPUART_EnableRxDMA(base, false);
0406 
0407     /* Stop transfer. */
0408     EDMA_AbortTransfer(handle->rxEdmaHandle);
0409 
0410     handle->rxState = (uint8_t)kLPUART_RxIdle;
0411 }
0412 
0413 /*!
0414  * brief Gets the number of received bytes.
0415  *
0416  * This function gets the number of received bytes.
0417  *
0418  * param base LPUART peripheral base address.
0419  * param handle LPUART handle pointer.
0420  * param count Receive bytes count.
0421  * retval kStatus_NoTransferInProgress No receive in progress.
0422  * retval kStatus_InvalidArgument Parameter is invalid.
0423  * retval kStatus_Success Get successfully through the parameter \p count;
0424  */
0425 status_t LPUART_TransferGetReceiveCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
0426 {
0427     assert(NULL != handle);
0428     assert(NULL != handle->rxEdmaHandle);
0429     assert(NULL != count);
0430 
0431     if ((uint8_t)kLPUART_RxIdle == handle->rxState)
0432     {
0433         return kStatus_NoTransferInProgress;
0434     }
0435 
0436     *count = handle->rxDataSizeAll -
0437              ((uint32_t)handle->nbytes *
0438               EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel));
0439 
0440     return kStatus_Success;
0441 }
0442 
0443 /*!
0444  * brief Gets the number of bytes written to the LPUART TX register.
0445  *
0446  * This function gets the number of bytes written to the LPUART TX
0447  * register by DMA.
0448  *
0449  * param base LPUART peripheral base address.
0450  * param handle LPUART handle pointer.
0451  * param count Send bytes count.
0452  * retval kStatus_NoTransferInProgress No send in progress.
0453  * retval kStatus_InvalidArgument Parameter is invalid.
0454  * retval kStatus_Success Get successfully through the parameter \p count;
0455  */
0456 status_t LPUART_TransferGetSendCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
0457 {
0458     assert(NULL != handle);
0459     assert(NULL != handle->txEdmaHandle);
0460     assert(NULL != count);
0461 
0462     if ((uint8_t)kLPUART_TxIdle == handle->txState)
0463     {
0464         return kStatus_NoTransferInProgress;
0465     }
0466 
0467     *count = handle->txDataSizeAll -
0468              ((uint32_t)handle->nbytes *
0469               EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel));
0470 
0471     return kStatus_Success;
0472 }
0473 
0474 /*!
0475  * brief LPUART eDMA IRQ handle function.
0476  *
0477  * This function handles the LPUART tx complete IRQ request and invoke user callback.
0478  * It is not set to static so that it can be used in user application.
0479  * note This function is used as default IRQ handler by double weak mechanism.
0480  * If user's specific IRQ handler is implemented, make sure this function is invoked in the handler.
0481  *
0482  * param base LPUART peripheral base address.
0483  * param lpuartEdmaHandle LPUART handle pointer.
0484  */
0485 void LPUART_TransferEdmaHandleIRQ(LPUART_Type *base, void *lpuartEdmaHandle)
0486 {
0487     assert(lpuartEdmaHandle != NULL);
0488 
0489     if (((uint32_t)kLPUART_TransmissionCompleteFlag & LPUART_GetStatusFlags(base)) != 0U)
0490     {
0491         lpuart_edma_handle_t *handle = (lpuart_edma_handle_t *)lpuartEdmaHandle;
0492 
0493         /* Disable tx complete interrupt */
0494         LPUART_DisableInterrupts(base, (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
0495 
0496         handle->txState = (uint8_t)kLPUART_TxIdle;
0497 
0498         if (handle->callback != NULL)
0499         {
0500             handle->callback(base, handle, kStatus_LPUART_TxIdle, handle->userData);
0501         }
0502     }
0503 }