Nicolas Borla / Mbed OS BBR_1Ebene
Committer:
borlanic
Date:
Mon May 14 11:29:06 2018 +0000
Revision:
0:fbdae7e6d805
BBR

Who changed what in which revision?

UserRevisionLine numberNew contents of line
borlanic 0:fbdae7e6d805 1 /*
borlanic 0:fbdae7e6d805 2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
borlanic 0:fbdae7e6d805 3 * Copyright 2016-2017 NXP
borlanic 0:fbdae7e6d805 4 *
borlanic 0:fbdae7e6d805 5 * Redistribution and use in source and binary forms, with or without modification,
borlanic 0:fbdae7e6d805 6 * are permitted provided that the following conditions are met:
borlanic 0:fbdae7e6d805 7 *
borlanic 0:fbdae7e6d805 8 * o Redistributions of source code must retain the above copyright notice, this list
borlanic 0:fbdae7e6d805 9 * of conditions and the following disclaimer.
borlanic 0:fbdae7e6d805 10 *
borlanic 0:fbdae7e6d805 11 * o Redistributions in binary form must reproduce the above copyright notice, this
borlanic 0:fbdae7e6d805 12 * list of conditions and the following disclaimer in the documentation and/or
borlanic 0:fbdae7e6d805 13 * other materials provided with the distribution.
borlanic 0:fbdae7e6d805 14 *
borlanic 0:fbdae7e6d805 15 * o Neither the name of the copyright holder nor the names of its
borlanic 0:fbdae7e6d805 16 * contributors may be used to endorse or promote products derived from this
borlanic 0:fbdae7e6d805 17 * software without specific prior written permission.
borlanic 0:fbdae7e6d805 18 *
borlanic 0:fbdae7e6d805 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
borlanic 0:fbdae7e6d805 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
borlanic 0:fbdae7e6d805 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
borlanic 0:fbdae7e6d805 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
borlanic 0:fbdae7e6d805 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
borlanic 0:fbdae7e6d805 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
borlanic 0:fbdae7e6d805 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
borlanic 0:fbdae7e6d805 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
borlanic 0:fbdae7e6d805 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
borlanic 0:fbdae7e6d805 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
borlanic 0:fbdae7e6d805 29 */
borlanic 0:fbdae7e6d805 30
borlanic 0:fbdae7e6d805 31 #include "fsl_lpi2c_edma.h"
borlanic 0:fbdae7e6d805 32 #include <stdlib.h>
borlanic 0:fbdae7e6d805 33 #include <string.h>
borlanic 0:fbdae7e6d805 34
borlanic 0:fbdae7e6d805 35 /*******************************************************************************
borlanic 0:fbdae7e6d805 36 * Definitions
borlanic 0:fbdae7e6d805 37 ******************************************************************************/
borlanic 0:fbdae7e6d805 38
borlanic 0:fbdae7e6d805 39 /* @brief Mask to align an address to 32 bytes. */
borlanic 0:fbdae7e6d805 40 #define ALIGN_32_MASK (0x1fU)
borlanic 0:fbdae7e6d805 41
borlanic 0:fbdae7e6d805 42 /*! @brief Common sets of flags used by the driver. */
borlanic 0:fbdae7e6d805 43 enum _lpi2c_flag_constants
borlanic 0:fbdae7e6d805 44 {
borlanic 0:fbdae7e6d805 45 /*! All flags which are cleared by the driver upon starting a transfer. */
borlanic 0:fbdae7e6d805 46 kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag |
borlanic 0:fbdae7e6d805 47 kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag |
borlanic 0:fbdae7e6d805 48 kLPI2C_MasterDataMatchFlag,
borlanic 0:fbdae7e6d805 49
borlanic 0:fbdae7e6d805 50 /*! IRQ sources enabled by the non-blocking transactional API. */
borlanic 0:fbdae7e6d805 51 kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag |
borlanic 0:fbdae7e6d805 52 kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag |
borlanic 0:fbdae7e6d805 53 kLPI2C_MasterFifoErrFlag,
borlanic 0:fbdae7e6d805 54
borlanic 0:fbdae7e6d805 55 /*! Errors to check for. */
borlanic 0:fbdae7e6d805 56 kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag |
borlanic 0:fbdae7e6d805 57 kLPI2C_MasterPinLowTimeoutFlag,
borlanic 0:fbdae7e6d805 58
borlanic 0:fbdae7e6d805 59 /*! All flags which are cleared by the driver upon starting a transfer. */
borlanic 0:fbdae7e6d805 60 kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag |
borlanic 0:fbdae7e6d805 61 kLPI2C_SlaveFifoErrFlag,
borlanic 0:fbdae7e6d805 62
borlanic 0:fbdae7e6d805 63 /*! IRQ sources enabled by the non-blocking transactional API. */
borlanic 0:fbdae7e6d805 64 kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag |
borlanic 0:fbdae7e6d805 65 kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag |
borlanic 0:fbdae7e6d805 66 kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag,
borlanic 0:fbdae7e6d805 67
borlanic 0:fbdae7e6d805 68 /*! Errors to check for. */
borlanic 0:fbdae7e6d805 69 kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag,
borlanic 0:fbdae7e6d805 70 };
borlanic 0:fbdae7e6d805 71
borlanic 0:fbdae7e6d805 72 /* ! @brief LPI2C master fifo commands. */
borlanic 0:fbdae7e6d805 73 enum _lpi2c_master_fifo_cmd
borlanic 0:fbdae7e6d805 74 {
borlanic 0:fbdae7e6d805 75 kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
borlanic 0:fbdae7e6d805 76 kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
borlanic 0:fbdae7e6d805 77 kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
borlanic 0:fbdae7e6d805 78 kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
borlanic 0:fbdae7e6d805 79 };
borlanic 0:fbdae7e6d805 80
borlanic 0:fbdae7e6d805 81 /*! @brief States for the state machine used by transactional APIs. */
borlanic 0:fbdae7e6d805 82 enum _lpi2c_transfer_states
borlanic 0:fbdae7e6d805 83 {
borlanic 0:fbdae7e6d805 84 kIdleState = 0,
borlanic 0:fbdae7e6d805 85 kSendCommandState,
borlanic 0:fbdae7e6d805 86 kIssueReadCommandState,
borlanic 0:fbdae7e6d805 87 kTransferDataState,
borlanic 0:fbdae7e6d805 88 kStopState,
borlanic 0:fbdae7e6d805 89 kWaitForCompletionState,
borlanic 0:fbdae7e6d805 90 };
borlanic 0:fbdae7e6d805 91
borlanic 0:fbdae7e6d805 92 /*! @brief Typedef for interrupt handler. */
borlanic 0:fbdae7e6d805 93 typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
borlanic 0:fbdae7e6d805 94
borlanic 0:fbdae7e6d805 95 /*******************************************************************************
borlanic 0:fbdae7e6d805 96 * Prototypes
borlanic 0:fbdae7e6d805 97 ******************************************************************************/
borlanic 0:fbdae7e6d805 98
borlanic 0:fbdae7e6d805 99 /* Defined in fsl_lpi2c.c. */
borlanic 0:fbdae7e6d805 100 extern status_t LPI2C_CheckForBusyBus(LPI2C_Type *base);
borlanic 0:fbdae7e6d805 101
borlanic 0:fbdae7e6d805 102 /* Defined in fsl_lpi2c.c. */
borlanic 0:fbdae7e6d805 103 extern status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status);
borlanic 0:fbdae7e6d805 104
borlanic 0:fbdae7e6d805 105 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
borlanic 0:fbdae7e6d805 106
borlanic 0:fbdae7e6d805 107 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
borlanic 0:fbdae7e6d805 108
borlanic 0:fbdae7e6d805 109 /*******************************************************************************
borlanic 0:fbdae7e6d805 110 * Code
borlanic 0:fbdae7e6d805 111 ******************************************************************************/
borlanic 0:fbdae7e6d805 112
borlanic 0:fbdae7e6d805 113 void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
borlanic 0:fbdae7e6d805 114 lpi2c_master_edma_handle_t *handle,
borlanic 0:fbdae7e6d805 115 edma_handle_t *rxDmaHandle,
borlanic 0:fbdae7e6d805 116 edma_handle_t *txDmaHandle,
borlanic 0:fbdae7e6d805 117 lpi2c_master_edma_transfer_callback_t callback,
borlanic 0:fbdae7e6d805 118 void *userData)
borlanic 0:fbdae7e6d805 119 {
borlanic 0:fbdae7e6d805 120 assert(handle);
borlanic 0:fbdae7e6d805 121 assert(rxDmaHandle);
borlanic 0:fbdae7e6d805 122 assert(txDmaHandle);
borlanic 0:fbdae7e6d805 123
borlanic 0:fbdae7e6d805 124 /* Clear out the handle. */
borlanic 0:fbdae7e6d805 125 memset(handle, 0, sizeof(*handle));
borlanic 0:fbdae7e6d805 126
borlanic 0:fbdae7e6d805 127 /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
borlanic 0:fbdae7e6d805 128 /* in order to make the transfer API code simpler. */
borlanic 0:fbdae7e6d805 129 handle->base = base;
borlanic 0:fbdae7e6d805 130 handle->completionCallback = callback;
borlanic 0:fbdae7e6d805 131 handle->userData = userData;
borlanic 0:fbdae7e6d805 132 handle->rx = rxDmaHandle;
borlanic 0:fbdae7e6d805 133 handle->tx = FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) ? txDmaHandle : rxDmaHandle;
borlanic 0:fbdae7e6d805 134
borlanic 0:fbdae7e6d805 135 /* Set DMA channel completion callbacks. */
borlanic 0:fbdae7e6d805 136 EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
borlanic 0:fbdae7e6d805 137 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 138 {
borlanic 0:fbdae7e6d805 139 EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
borlanic 0:fbdae7e6d805 140 }
borlanic 0:fbdae7e6d805 141 }
borlanic 0:fbdae7e6d805 142
borlanic 0:fbdae7e6d805 143 /*!
borlanic 0:fbdae7e6d805 144 * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
borlanic 0:fbdae7e6d805 145 * @param handle Master DMA driver handle.
borlanic 0:fbdae7e6d805 146 * @return Number of command words.
borlanic 0:fbdae7e6d805 147 */
borlanic 0:fbdae7e6d805 148 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
borlanic 0:fbdae7e6d805 149 {
borlanic 0:fbdae7e6d805 150 lpi2c_master_transfer_t *xfer = &handle->transfer;
borlanic 0:fbdae7e6d805 151 uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
borlanic 0:fbdae7e6d805 152 uint32_t cmdCount = 0;
borlanic 0:fbdae7e6d805 153
borlanic 0:fbdae7e6d805 154 /* Handle no start option. */
borlanic 0:fbdae7e6d805 155 if (xfer->flags & kLPI2C_TransferNoStartFlag)
borlanic 0:fbdae7e6d805 156 {
borlanic 0:fbdae7e6d805 157 if (xfer->direction == kLPI2C_Read)
borlanic 0:fbdae7e6d805 158 {
borlanic 0:fbdae7e6d805 159 /* Need to issue read command first. */
borlanic 0:fbdae7e6d805 160 cmd[cmdCount++] = kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1);
borlanic 0:fbdae7e6d805 161 }
borlanic 0:fbdae7e6d805 162 }
borlanic 0:fbdae7e6d805 163 else
borlanic 0:fbdae7e6d805 164 {
borlanic 0:fbdae7e6d805 165 /*
borlanic 0:fbdae7e6d805 166 * Initial direction depends on whether a subaddress was provided, and of course the actual
borlanic 0:fbdae7e6d805 167 * data transfer direction.
borlanic 0:fbdae7e6d805 168 */
borlanic 0:fbdae7e6d805 169 lpi2c_direction_t direction = xfer->subaddressSize ? kLPI2C_Write : xfer->direction;
borlanic 0:fbdae7e6d805 170
borlanic 0:fbdae7e6d805 171 /* Start command. */
borlanic 0:fbdae7e6d805 172 cmd[cmdCount++] =
borlanic 0:fbdae7e6d805 173 (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
borlanic 0:fbdae7e6d805 174
borlanic 0:fbdae7e6d805 175 /* Subaddress, MSB first. */
borlanic 0:fbdae7e6d805 176 if (xfer->subaddressSize)
borlanic 0:fbdae7e6d805 177 {
borlanic 0:fbdae7e6d805 178 uint32_t subaddressRemaining = xfer->subaddressSize;
borlanic 0:fbdae7e6d805 179 while (subaddressRemaining--)
borlanic 0:fbdae7e6d805 180 {
borlanic 0:fbdae7e6d805 181 uint8_t subaddressByte = (xfer->subaddress >> (8 * subaddressRemaining)) & 0xff;
borlanic 0:fbdae7e6d805 182 cmd[cmdCount++] = subaddressByte;
borlanic 0:fbdae7e6d805 183 }
borlanic 0:fbdae7e6d805 184 }
borlanic 0:fbdae7e6d805 185
borlanic 0:fbdae7e6d805 186 /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
borlanic 0:fbdae7e6d805 187 if ((xfer->dataSize) && (xfer->direction == kLPI2C_Read))
borlanic 0:fbdae7e6d805 188 {
borlanic 0:fbdae7e6d805 189 /* Need to send repeated start if switching directions to read. */
borlanic 0:fbdae7e6d805 190 if (direction == kLPI2C_Write)
borlanic 0:fbdae7e6d805 191 {
borlanic 0:fbdae7e6d805 192 cmd[cmdCount++] = (uint16_t)kStartCmd |
borlanic 0:fbdae7e6d805 193 (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
borlanic 0:fbdae7e6d805 194 }
borlanic 0:fbdae7e6d805 195
borlanic 0:fbdae7e6d805 196 /* Read command. */
borlanic 0:fbdae7e6d805 197 cmd[cmdCount++] = kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1);
borlanic 0:fbdae7e6d805 198 }
borlanic 0:fbdae7e6d805 199 }
borlanic 0:fbdae7e6d805 200
borlanic 0:fbdae7e6d805 201 return cmdCount;
borlanic 0:fbdae7e6d805 202 }
borlanic 0:fbdae7e6d805 203
borlanic 0:fbdae7e6d805 204 status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
borlanic 0:fbdae7e6d805 205 lpi2c_master_edma_handle_t *handle,
borlanic 0:fbdae7e6d805 206 lpi2c_master_transfer_t *transfer)
borlanic 0:fbdae7e6d805 207 {
borlanic 0:fbdae7e6d805 208 status_t result;
borlanic 0:fbdae7e6d805 209
borlanic 0:fbdae7e6d805 210 assert(handle);
borlanic 0:fbdae7e6d805 211 assert(transfer);
borlanic 0:fbdae7e6d805 212 assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
borlanic 0:fbdae7e6d805 213
borlanic 0:fbdae7e6d805 214 /* Return busy if another transaction is in progress. */
borlanic 0:fbdae7e6d805 215 if (handle->isBusy)
borlanic 0:fbdae7e6d805 216 {
borlanic 0:fbdae7e6d805 217 return kStatus_LPI2C_Busy;
borlanic 0:fbdae7e6d805 218 }
borlanic 0:fbdae7e6d805 219
borlanic 0:fbdae7e6d805 220 /* Return an error if the bus is already in use not by us. */
borlanic 0:fbdae7e6d805 221 result = LPI2C_CheckForBusyBus(base);
borlanic 0:fbdae7e6d805 222 if (result)
borlanic 0:fbdae7e6d805 223 {
borlanic 0:fbdae7e6d805 224 return result;
borlanic 0:fbdae7e6d805 225 }
borlanic 0:fbdae7e6d805 226
borlanic 0:fbdae7e6d805 227 /* We're now busy. */
borlanic 0:fbdae7e6d805 228 handle->isBusy = true;
borlanic 0:fbdae7e6d805 229
borlanic 0:fbdae7e6d805 230 /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
borlanic 0:fbdae7e6d805 231 LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags);
borlanic 0:fbdae7e6d805 232 LPI2C_MasterEnableDMA(base, false, false);
borlanic 0:fbdae7e6d805 233
borlanic 0:fbdae7e6d805 234 /* Clear all flags. */
borlanic 0:fbdae7e6d805 235 LPI2C_MasterClearStatusFlags(base, kMasterClearFlags);
borlanic 0:fbdae7e6d805 236
borlanic 0:fbdae7e6d805 237 /* Save transfer into handle. */
borlanic 0:fbdae7e6d805 238 handle->transfer = *transfer;
borlanic 0:fbdae7e6d805 239
borlanic 0:fbdae7e6d805 240 /* Generate commands to send. */
borlanic 0:fbdae7e6d805 241 uint32_t commandCount = LPI2C_GenerateCommands(handle);
borlanic 0:fbdae7e6d805 242
borlanic 0:fbdae7e6d805 243 /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
borlanic 0:fbdae7e6d805 244 if ((!commandCount) && (transfer->dataSize == 0))
borlanic 0:fbdae7e6d805 245 {
borlanic 0:fbdae7e6d805 246 if (handle->completionCallback)
borlanic 0:fbdae7e6d805 247 {
borlanic 0:fbdae7e6d805 248 handle->completionCallback(base, handle, kStatus_Success, handle->userData);
borlanic 0:fbdae7e6d805 249 }
borlanic 0:fbdae7e6d805 250 return kStatus_Success;
borlanic 0:fbdae7e6d805 251 }
borlanic 0:fbdae7e6d805 252
borlanic 0:fbdae7e6d805 253 /* Reset DMA channels. */
borlanic 0:fbdae7e6d805 254 EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
borlanic 0:fbdae7e6d805 255 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 256 {
borlanic 0:fbdae7e6d805 257 EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
borlanic 0:fbdae7e6d805 258 }
borlanic 0:fbdae7e6d805 259
borlanic 0:fbdae7e6d805 260 /* Get a 32-byte aligned TCD pointer. */
borlanic 0:fbdae7e6d805 261 edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
borlanic 0:fbdae7e6d805 262
borlanic 0:fbdae7e6d805 263 bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize);
borlanic 0:fbdae7e6d805 264 bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize);
borlanic 0:fbdae7e6d805 265
borlanic 0:fbdae7e6d805 266 edma_transfer_config_t transferConfig;
borlanic 0:fbdae7e6d805 267 edma_tcd_t *linkTcd = NULL;
borlanic 0:fbdae7e6d805 268
borlanic 0:fbdae7e6d805 269 /* Set up data transmit. */
borlanic 0:fbdae7e6d805 270 if (hasSendData)
borlanic 0:fbdae7e6d805 271 {
borlanic 0:fbdae7e6d805 272 transferConfig.srcAddr = (uint32_t)transfer->data;
borlanic 0:fbdae7e6d805 273 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
borlanic 0:fbdae7e6d805 274 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
borlanic 0:fbdae7e6d805 275 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
borlanic 0:fbdae7e6d805 276 transferConfig.srcOffset = sizeof(uint8_t);
borlanic 0:fbdae7e6d805 277 transferConfig.destOffset = 0;
borlanic 0:fbdae7e6d805 278 transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
borlanic 0:fbdae7e6d805 279 transferConfig.majorLoopCounts = transfer->dataSize;
borlanic 0:fbdae7e6d805 280
borlanic 0:fbdae7e6d805 281 /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
borlanic 0:fbdae7e6d805 282 handle->nbytes = transferConfig.minorLoopBytes;
borlanic 0:fbdae7e6d805 283
borlanic 0:fbdae7e6d805 284 if (commandCount)
borlanic 0:fbdae7e6d805 285 {
borlanic 0:fbdae7e6d805 286 /* Create a software TCD, which will be chained after the commands. */
borlanic 0:fbdae7e6d805 287 EDMA_TcdReset(tcd);
borlanic 0:fbdae7e6d805 288 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
borlanic 0:fbdae7e6d805 289 EDMA_TcdEnableInterrupts(tcd, kEDMA_MajorInterruptEnable);
borlanic 0:fbdae7e6d805 290 linkTcd = tcd;
borlanic 0:fbdae7e6d805 291 }
borlanic 0:fbdae7e6d805 292 else
borlanic 0:fbdae7e6d805 293 {
borlanic 0:fbdae7e6d805 294 /* User is only transmitting data with no required commands, so this transfer can stand alone. */
borlanic 0:fbdae7e6d805 295 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
borlanic 0:fbdae7e6d805 296 EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, kEDMA_MajorInterruptEnable);
borlanic 0:fbdae7e6d805 297 }
borlanic 0:fbdae7e6d805 298 }
borlanic 0:fbdae7e6d805 299 else if (hasReceiveData)
borlanic 0:fbdae7e6d805 300 {
borlanic 0:fbdae7e6d805 301 /* Set up data receive. */
borlanic 0:fbdae7e6d805 302 transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
borlanic 0:fbdae7e6d805 303 transferConfig.destAddr = (uint32_t)transfer->data;
borlanic 0:fbdae7e6d805 304 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
borlanic 0:fbdae7e6d805 305 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
borlanic 0:fbdae7e6d805 306 transferConfig.srcOffset = 0;
borlanic 0:fbdae7e6d805 307 transferConfig.destOffset = sizeof(uint8_t);
borlanic 0:fbdae7e6d805 308 transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
borlanic 0:fbdae7e6d805 309 transferConfig.majorLoopCounts = transfer->dataSize;
borlanic 0:fbdae7e6d805 310
borlanic 0:fbdae7e6d805 311 /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
borlanic 0:fbdae7e6d805 312 handle->nbytes = transferConfig.minorLoopBytes;
borlanic 0:fbdae7e6d805 313
borlanic 0:fbdae7e6d805 314 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) || (!commandCount))
borlanic 0:fbdae7e6d805 315 {
borlanic 0:fbdae7e6d805 316 /* We can put this receive transfer on its own DMA channel. */
borlanic 0:fbdae7e6d805 317 EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
borlanic 0:fbdae7e6d805 318 EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, kEDMA_MajorInterruptEnable);
borlanic 0:fbdae7e6d805 319 }
borlanic 0:fbdae7e6d805 320 else
borlanic 0:fbdae7e6d805 321 {
borlanic 0:fbdae7e6d805 322 /* For shared rx/tx DMA requests when there are commands, create a software TCD which will be */
borlanic 0:fbdae7e6d805 323 /* chained onto the commands transfer, notice that in this situation assume tx/rx uses same channel */
borlanic 0:fbdae7e6d805 324 EDMA_TcdReset(tcd);
borlanic 0:fbdae7e6d805 325 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
borlanic 0:fbdae7e6d805 326 EDMA_TcdEnableInterrupts(tcd, kEDMA_MajorInterruptEnable);
borlanic 0:fbdae7e6d805 327 linkTcd = tcd;
borlanic 0:fbdae7e6d805 328 }
borlanic 0:fbdae7e6d805 329 }
borlanic 0:fbdae7e6d805 330 else
borlanic 0:fbdae7e6d805 331 {
borlanic 0:fbdae7e6d805 332 /* No data to send */
borlanic 0:fbdae7e6d805 333 }
borlanic 0:fbdae7e6d805 334
borlanic 0:fbdae7e6d805 335 /* Set up commands transfer. */
borlanic 0:fbdae7e6d805 336 if (commandCount)
borlanic 0:fbdae7e6d805 337 {
borlanic 0:fbdae7e6d805 338 transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
borlanic 0:fbdae7e6d805 339 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
borlanic 0:fbdae7e6d805 340 transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
borlanic 0:fbdae7e6d805 341 transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
borlanic 0:fbdae7e6d805 342 transferConfig.srcOffset = sizeof(uint16_t);
borlanic 0:fbdae7e6d805 343 transferConfig.destOffset = 0;
borlanic 0:fbdae7e6d805 344 transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
borlanic 0:fbdae7e6d805 345 transferConfig.majorLoopCounts = commandCount;
borlanic 0:fbdae7e6d805 346
borlanic 0:fbdae7e6d805 347 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
borlanic 0:fbdae7e6d805 348 }
borlanic 0:fbdae7e6d805 349
borlanic 0:fbdae7e6d805 350 /* Start DMA transfer. */
borlanic 0:fbdae7e6d805 351 if (hasReceiveData || !FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 352 {
borlanic 0:fbdae7e6d805 353 EDMA_StartTransfer(handle->rx);
borlanic 0:fbdae7e6d805 354 }
borlanic 0:fbdae7e6d805 355
borlanic 0:fbdae7e6d805 356 if (hasReceiveData && !FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 357 {
borlanic 0:fbdae7e6d805 358 EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, kEDMA_MajorInterruptEnable);
borlanic 0:fbdae7e6d805 359 }
borlanic 0:fbdae7e6d805 360
borlanic 0:fbdae7e6d805 361 if ((hasSendData || commandCount) && FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 362 {
borlanic 0:fbdae7e6d805 363 EDMA_StartTransfer(handle->tx);
borlanic 0:fbdae7e6d805 364 }
borlanic 0:fbdae7e6d805 365
borlanic 0:fbdae7e6d805 366 /* Enable DMA in both directions. This actually kicks of the transfer. */
borlanic 0:fbdae7e6d805 367 LPI2C_MasterEnableDMA(base, true, true);
borlanic 0:fbdae7e6d805 368
borlanic 0:fbdae7e6d805 369 return result;
borlanic 0:fbdae7e6d805 370 }
borlanic 0:fbdae7e6d805 371
borlanic 0:fbdae7e6d805 372 status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
borlanic 0:fbdae7e6d805 373 {
borlanic 0:fbdae7e6d805 374 assert(handle);
borlanic 0:fbdae7e6d805 375
borlanic 0:fbdae7e6d805 376 if (!count)
borlanic 0:fbdae7e6d805 377 {
borlanic 0:fbdae7e6d805 378 return kStatus_InvalidArgument;
borlanic 0:fbdae7e6d805 379 }
borlanic 0:fbdae7e6d805 380
borlanic 0:fbdae7e6d805 381 /* Catch when there is not an active transfer. */
borlanic 0:fbdae7e6d805 382 if (!handle->isBusy)
borlanic 0:fbdae7e6d805 383 {
borlanic 0:fbdae7e6d805 384 *count = 0;
borlanic 0:fbdae7e6d805 385 return kStatus_NoTransferInProgress;
borlanic 0:fbdae7e6d805 386 }
borlanic 0:fbdae7e6d805 387
borlanic 0:fbdae7e6d805 388 uint32_t remaining = handle->transfer.dataSize;
borlanic 0:fbdae7e6d805 389
borlanic 0:fbdae7e6d805 390 /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
borlanic 0:fbdae7e6d805 391 /* we do nothing and return the number of transferred bytes as zero. */
borlanic 0:fbdae7e6d805 392 if (EDMA_GetNextTCDAddress(handle->tx) == 0)
borlanic 0:fbdae7e6d805 393 {
borlanic 0:fbdae7e6d805 394 if (handle->transfer.direction == kLPI2C_Write)
borlanic 0:fbdae7e6d805 395 {
borlanic 0:fbdae7e6d805 396 remaining =
borlanic 0:fbdae7e6d805 397 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
borlanic 0:fbdae7e6d805 398 }
borlanic 0:fbdae7e6d805 399 else
borlanic 0:fbdae7e6d805 400 {
borlanic 0:fbdae7e6d805 401 remaining =
borlanic 0:fbdae7e6d805 402 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
borlanic 0:fbdae7e6d805 403 }
borlanic 0:fbdae7e6d805 404 }
borlanic 0:fbdae7e6d805 405
borlanic 0:fbdae7e6d805 406 *count = handle->transfer.dataSize - remaining;
borlanic 0:fbdae7e6d805 407
borlanic 0:fbdae7e6d805 408 return kStatus_Success;
borlanic 0:fbdae7e6d805 409 }
borlanic 0:fbdae7e6d805 410
borlanic 0:fbdae7e6d805 411 status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
borlanic 0:fbdae7e6d805 412 {
borlanic 0:fbdae7e6d805 413 /* Catch when there is not an active transfer. */
borlanic 0:fbdae7e6d805 414 if (!handle->isBusy)
borlanic 0:fbdae7e6d805 415 {
borlanic 0:fbdae7e6d805 416 return kStatus_LPI2C_Idle;
borlanic 0:fbdae7e6d805 417 }
borlanic 0:fbdae7e6d805 418
borlanic 0:fbdae7e6d805 419 /* Terminate DMA transfers. */
borlanic 0:fbdae7e6d805 420 EDMA_AbortTransfer(handle->rx);
borlanic 0:fbdae7e6d805 421 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 422 {
borlanic 0:fbdae7e6d805 423 EDMA_AbortTransfer(handle->tx);
borlanic 0:fbdae7e6d805 424 }
borlanic 0:fbdae7e6d805 425
borlanic 0:fbdae7e6d805 426 /* Reset fifos. */
borlanic 0:fbdae7e6d805 427 base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
borlanic 0:fbdae7e6d805 428
borlanic 0:fbdae7e6d805 429 /* Send a stop command to finalize the transfer. */
borlanic 0:fbdae7e6d805 430 base->MTDR = kStopCmd;
borlanic 0:fbdae7e6d805 431
borlanic 0:fbdae7e6d805 432 /* Reset handle. */
borlanic 0:fbdae7e6d805 433 handle->isBusy = false;
borlanic 0:fbdae7e6d805 434
borlanic 0:fbdae7e6d805 435 return kStatus_Success;
borlanic 0:fbdae7e6d805 436 }
borlanic 0:fbdae7e6d805 437
borlanic 0:fbdae7e6d805 438 /*!
borlanic 0:fbdae7e6d805 439 * @brief DMA completion callback.
borlanic 0:fbdae7e6d805 440 * @param dmaHandle DMA channel handle for the channel that completed.
borlanic 0:fbdae7e6d805 441 * @param userData User data associated with the channel handle. For this callback, the user data is the
borlanic 0:fbdae7e6d805 442 * LPI2C DMA driver handle.
borlanic 0:fbdae7e6d805 443 * @param isTransferDone Whether the DMA transfer has completed.
borlanic 0:fbdae7e6d805 444 * @param tcds Number of TCDs that completed.
borlanic 0:fbdae7e6d805 445 */
borlanic 0:fbdae7e6d805 446 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
borlanic 0:fbdae7e6d805 447 {
borlanic 0:fbdae7e6d805 448 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
borlanic 0:fbdae7e6d805 449 bool hasReceiveData = (handle->transfer.direction == kLPI2C_Read) && (handle->transfer.dataSize);
borlanic 0:fbdae7e6d805 450 if (hasReceiveData && !FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base))
borlanic 0:fbdae7e6d805 451 {
borlanic 0:fbdae7e6d805 452 if (EDMA_GetNextTCDAddress(handle->tx) != 0)
borlanic 0:fbdae7e6d805 453 {
borlanic 0:fbdae7e6d805 454 LPI2C_MasterEnableDMA(handle->base, false, true);
borlanic 0:fbdae7e6d805 455 }
borlanic 0:fbdae7e6d805 456 }
borlanic 0:fbdae7e6d805 457
borlanic 0:fbdae7e6d805 458 if (!handle)
borlanic 0:fbdae7e6d805 459 {
borlanic 0:fbdae7e6d805 460 return;
borlanic 0:fbdae7e6d805 461 }
borlanic 0:fbdae7e6d805 462
borlanic 0:fbdae7e6d805 463 /* Check for errors. */
borlanic 0:fbdae7e6d805 464 status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
borlanic 0:fbdae7e6d805 465
borlanic 0:fbdae7e6d805 466 /* Done with this transaction. */
borlanic 0:fbdae7e6d805 467 handle->isBusy = false;
borlanic 0:fbdae7e6d805 468
borlanic 0:fbdae7e6d805 469 if (!(handle->transfer.flags & kLPI2C_TransferNoStopFlag))
borlanic 0:fbdae7e6d805 470 {
borlanic 0:fbdae7e6d805 471 /* Send a stop command to finalize the transfer. */
borlanic 0:fbdae7e6d805 472 handle->base->MTDR = kStopCmd;
borlanic 0:fbdae7e6d805 473 }
borlanic 0:fbdae7e6d805 474
borlanic 0:fbdae7e6d805 475 /* Invoke callback. */
borlanic 0:fbdae7e6d805 476 if (handle->completionCallback)
borlanic 0:fbdae7e6d805 477 {
borlanic 0:fbdae7e6d805 478 handle->completionCallback(handle->base, handle, result, handle->userData);
borlanic 0:fbdae7e6d805 479 }
borlanic 0:fbdae7e6d805 480 }