| /* |
| * Copyright (c) 2017, NXP Semiconductors, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * o Redistributions of source code must retain the above copyright notice, this list |
| * of conditions and the following disclaimer. |
| * |
| * o Redistributions in binary form must reproduce the above copyright notice, this |
| * list of conditions and the following disclaimer in the documentation and/or |
| * other materials provided with the distribution. |
| * |
| * o Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived from this |
| * software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "fsl_csi.h" |
| |
| /******************************************************************************* |
| * Definitions |
| ******************************************************************************/ |
| |
| /* Two frame buffer loaded to CSI register at most. */ |
| #define CSI_MAX_ACTIVE_FRAME_NUM 2 |
| |
| /******************************************************************************* |
| * Prototypes |
| ******************************************************************************/ |
| /*! |
| * @brief Get the instance from the base address |
| * |
| * @param base CSI peripheral base address |
| * |
| * @return The CSI module instance |
| */ |
| static uint32_t CSI_GetInstance(CSI_Type *base); |
| |
| /*! |
| * @brief Get the delta value of two index in queue. |
| * |
| * @param startIdx Start index. |
| * @param endIdx End index. |
| * |
| * @return The delta between startIdx and endIdx in queue. |
| */ |
| static uint32_t CSI_TransferGetQueueDelta(uint32_t startIdx, uint32_t endIdx); |
| |
| /*! |
| * @brief Increase a index value in queue. |
| * |
| * This function increases the index value in the queue, if the index is out of |
| * the queue range, it is reset to 0. |
| * |
| * @param idx The index value to increase. |
| * |
| * @return The index value after increase. |
| */ |
| static uint32_t CSI_TransferIncreaseQueueIdx(uint32_t idx); |
| |
| /*! |
| * @brief Get the empty frame buffer count in queue. |
| * |
| * @param base CSI peripheral base address |
| * @param handle Pointer to CSI driver handle. |
| * |
| * @return Number of the empty frame buffer count in queue. |
| */ |
| static uint32_t CSI_TransferGetEmptyBufferCount(CSI_Type *base, csi_handle_t *handle); |
| |
| /*! |
| * @brief Load one empty frame buffer in queue to CSI module. |
| * |
| * Load one empty frame in queue to CSI module, this function could only be called |
| * when there is empty frame buffer in queue. |
| * |
| * @param base CSI peripheral base address |
| * @param handle Pointer to CSI driver handle. |
| */ |
| static void CSI_TransferLoadBufferToDevice(CSI_Type *base, csi_handle_t *handle); |
| |
| /* Typedef for interrupt handler. */ |
| typedef void (*csi_isr_t)(CSI_Type *base, csi_handle_t *handle); |
| |
| /******************************************************************************* |
| * Variables |
| ******************************************************************************/ |
| /*! @brief Pointers to CSI bases for each instance. */ |
| static CSI_Type *const s_csiBases[] = CSI_BASE_PTRS; |
| |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| /*! @brief Pointers to CSI clocks for each CSI submodule. */ |
| static const clock_ip_name_t s_csiClocks[] = CSI_CLOCKS; |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| |
| /* Array for the CSI driver handle. */ |
| static csi_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)]; |
| |
| /* Array of CSI IRQ number. */ |
| static const IRQn_Type s_csiIRQ[] = CSI_IRQS; |
| |
| /* CSI ISR for transactional APIs. */ |
| static csi_isr_t s_csiIsr; |
| |
| /******************************************************************************* |
| * Code |
| ******************************************************************************/ |
| static uint32_t CSI_GetInstance(CSI_Type *base) |
| { |
| uint32_t instance; |
| |
| /* Find the instance index from base address mappings. */ |
| for (instance = 0; instance < ARRAY_SIZE(s_csiBases); instance++) |
| { |
| if (s_csiBases[instance] == base) |
| { |
| break; |
| } |
| } |
| |
| assert(instance < ARRAY_SIZE(s_csiBases)); |
| |
| return instance; |
| } |
| |
| static uint32_t CSI_TransferGetQueueDelta(uint32_t startIdx, uint32_t endIdx) |
| { |
| if (endIdx >= startIdx) |
| { |
| return endIdx - startIdx; |
| } |
| else |
| { |
| return startIdx + CSI_DRIVER_ACTUAL_QUEUE_SIZE - endIdx; |
| } |
| } |
| |
| static uint32_t CSI_TransferIncreaseQueueIdx(uint32_t idx) |
| { |
| uint32_t ret; |
| |
| /* |
| * Here not use the method: |
| * ret = (idx+1) % CSI_DRIVER_ACTUAL_QUEUE_SIZE; |
| * |
| * Because the mod function might be slow. |
| */ |
| |
| ret = idx + 1; |
| |
| if (ret >= CSI_DRIVER_ACTUAL_QUEUE_SIZE) |
| { |
| ret = 0; |
| } |
| |
| return ret; |
| } |
| |
| static uint32_t CSI_TransferGetEmptyBufferCount(CSI_Type *base, csi_handle_t *handle) |
| { |
| return CSI_TransferGetQueueDelta(handle->queueDrvReadIdx, handle->queueUserWriteIdx); |
| } |
| |
| static void CSI_TransferLoadBufferToDevice(CSI_Type *base, csi_handle_t *handle) |
| { |
| /* Load the frame buffer address to CSI register. */ |
| CSI_SetRxBufferAddr(base, handle->nextBufferIdx, handle->frameBufferQueue[handle->queueDrvReadIdx]); |
| |
| handle->queueDrvReadIdx = CSI_TransferIncreaseQueueIdx(handle->queueDrvReadIdx); |
| handle->activeBufferNum++; |
| |
| /* There are two CSI buffers, so could use XOR to get the next index. */ |
| handle->nextBufferIdx ^= 1U; |
| } |
| |
| status_t CSI_Init(CSI_Type *base, const csi_config_t *config) |
| { |
| assert(config); |
| uint32_t reg; |
| uint32_t imgWidth_Bytes; |
| |
| imgWidth_Bytes = config->width * config->bytesPerPixel; |
| |
| /* The image width and frame buffer pitch should be multiple of 8-bytes. */ |
| if ((imgWidth_Bytes & 0x07) | ((uint32_t)config->linePitch_Bytes & 0x07)) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| uint32_t instance = CSI_GetInstance(base); |
| CLOCK_EnableClock(s_csiClocks[instance]); |
| #endif |
| |
| CSI_Reset(base); |
| |
| /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */ |
| reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CSICR1_FCC_MASK; |
| |
| if (config->useExtVsync) |
| { |
| reg |= CSI_CSICR1_EXT_VSYNC_MASK; |
| } |
| |
| base->CSICR1 = reg; |
| |
| /* |
| * Generally, CSIIMAG_PARA[IMAGE_WIDTH] indicates how many data bus cycles per line. |
| * One special case is when receiving 24-bit pixels through 8-bit data bus, and |
| * CSICR3[ZERO_PACK_EN] is enabled, in this case, the CSIIMAG_PARA[IMAGE_WIDTH] |
| * should be set to the pixel number per line. |
| * |
| * Currently the CSI driver only support 8-bit data bus, so generally the |
| * CSIIMAG_PARA[IMAGE_WIDTH] is bytes number per line. When the CSICR3[ZERO_PACK_EN] |
| * is enabled, CSIIMAG_PARA[IMAGE_WIDTH] is pixel number per line. |
| * |
| * NOTE: The CSIIMAG_PARA[IMAGE_WIDTH] setting code should be updated if the |
| * driver is upgraded to support other data bus width. |
| */ |
| if (4U == config->bytesPerPixel) |
| { |
| /* Enable zero pack. */ |
| base->CSICR3 |= CSI_CSICR3_ZERO_PACK_EN_MASK; |
| /* Image parameter. */ |
| base->CSIIMAG_PARA = ((uint32_t)(config->width) << CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) | |
| ((uint32_t)(config->height) << CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT); |
| } |
| else |
| { |
| /* Image parameter. */ |
| base->CSIIMAG_PARA = ((uint32_t)(imgWidth_Bytes) << CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) | |
| ((uint32_t)(config->height) << CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT); |
| } |
| |
| /* The CSI frame buffer bus is 8-byte width. */ |
| base->CSIFBUF_PARA = (uint32_t)((config->linePitch_Bytes - imgWidth_Bytes) / 8U) |
| << CSI_CSIFBUF_PARA_FBUF_STRIDE_SHIFT; |
| |
| /* Enable auto ECC. */ |
| base->CSICR3 |= CSI_CSICR3_ECC_AUTO_EN_MASK; |
| |
| /* |
| * For better performance. |
| * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte, |
| * choose the best burst size based on bytes per line. |
| */ |
| if (!(imgWidth_Bytes % (8 * 16))) |
| { |
| base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(3U); |
| base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((2U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); |
| } |
| else if (!(imgWidth_Bytes % (8 * 8))) |
| { |
| base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(2U); |
| base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((1U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); |
| } |
| else |
| { |
| base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(1U); |
| base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((0U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); |
| } |
| |
| CSI_ReflashFifoDma(base, kCSI_RxFifo); |
| |
| return kStatus_Success; |
| } |
| |
| void CSI_Deinit(CSI_Type *base) |
| { |
| /* Disable transfer first. */ |
| CSI_Stop(base); |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| uint32_t instance = CSI_GetInstance(base); |
| CLOCK_DisableClock(s_csiClocks[instance]); |
| #endif |
| } |
| |
| void CSI_Reset(CSI_Type *base) |
| { |
| uint32_t csisr; |
| |
| /* Disable transfer first. */ |
| CSI_Stop(base); |
| |
| /* Disable DMA request. */ |
| base->CSICR3 = 0U; |
| |
| /* Reset the fame count. */ |
| base->CSICR3 |= CSI_CSICR3_FRMCNT_RST_MASK; |
| while (base->CSICR3 & CSI_CSICR3_FRMCNT_RST_MASK) |
| { |
| } |
| |
| /* Clear the RX FIFO. */ |
| CSI_ClearFifo(base, kCSI_AllFifo); |
| |
| /* Reflash DMA. */ |
| CSI_ReflashFifoDma(base, kCSI_AllFifo); |
| |
| /* Clear the status. */ |
| csisr = base->CSISR; |
| base->CSISR = csisr; |
| |
| /* Set the control registers to default value. */ |
| base->CSICR1 = CSI_CSICR1_HSYNC_POL_MASK | CSI_CSICR1_EXT_VSYNC_MASK; |
| base->CSICR2 = 0U; |
| base->CSICR3 = 0U; |
| #if defined(CSI_CSICR18_CSI_LCDIF_BUFFER_LINES) |
| base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU) | CSI_CSICR18_CSI_LCDIF_BUFFER_LINES(0x02U); |
| #else |
| base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU); |
| #endif |
| base->CSIFBUF_PARA = 0U; |
| base->CSIIMAG_PARA = 0U; |
| } |
| |
| void CSI_GetDefaultConfig(csi_config_t *config) |
| { |
| assert(config); |
| |
| config->width = 320U; |
| config->height = 240U; |
| config->polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge; |
| config->bytesPerPixel = 2U; |
| config->linePitch_Bytes = 320U * 2U; |
| config->workMode = kCSI_GatedClockMode; |
| config->dataBus = kCSI_DataBus8Bit; |
| config->useExtVsync = true; |
| } |
| |
| void CSI_SetRxBufferAddr(CSI_Type *base, uint8_t index, uint32_t addr) |
| { |
| if (index) |
| { |
| base->CSIDMASA_FB2 = addr; |
| } |
| else |
| { |
| base->CSIDMASA_FB1 = addr; |
| } |
| } |
| |
| void CSI_ClearFifo(CSI_Type *base, csi_fifo_t fifo) |
| { |
| uint32_t cr1; |
| uint32_t mask = 0U; |
| |
| /* The FIFO could only be cleared when CSICR1[FCC] = 0, so first clear the FCC. */ |
| cr1 = base->CSICR1; |
| base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK); |
| |
| if ((uint32_t)fifo & (uint32_t)kCSI_RxFifo) |
| { |
| mask |= CSI_CSICR1_CLR_RXFIFO_MASK; |
| } |
| |
| if ((uint32_t)fifo & (uint32_t)kCSI_StatFifo) |
| { |
| mask |= CSI_CSICR1_CLR_STATFIFO_MASK; |
| } |
| |
| base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK) | mask; |
| |
| /* Wait clear completed. */ |
| while (base->CSICR1 & mask) |
| { |
| } |
| |
| /* Recover the FCC. */ |
| base->CSICR1 = cr1; |
| } |
| |
| void CSI_ReflashFifoDma(CSI_Type *base, csi_fifo_t fifo) |
| { |
| uint32_t cr3 = 0U; |
| |
| if ((uint32_t)fifo & (uint32_t)kCSI_RxFifo) |
| { |
| cr3 |= CSI_CSICR3_DMA_REFLASH_RFF_MASK; |
| } |
| |
| if ((uint32_t)fifo & (uint32_t)kCSI_StatFifo) |
| { |
| cr3 |= CSI_CSICR3_DMA_REFLASH_SFF_MASK; |
| } |
| |
| base->CSICR3 |= cr3; |
| |
| /* Wait clear completed. */ |
| while (base->CSICR3 & cr3) |
| { |
| } |
| } |
| |
| void CSI_EnableFifoDmaRequest(CSI_Type *base, csi_fifo_t fifo, bool enable) |
| { |
| uint32_t cr3 = 0U; |
| |
| if ((uint32_t)fifo & (uint32_t)kCSI_RxFifo) |
| { |
| cr3 |= CSI_CSICR3_DMA_REQ_EN_RFF_MASK; |
| } |
| |
| if ((uint32_t)fifo & (uint32_t)kCSI_StatFifo) |
| { |
| cr3 |= CSI_CSICR3_DMA_REQ_EN_SFF_MASK; |
| } |
| |
| if (enable) |
| { |
| base->CSICR3 |= cr3; |
| } |
| else |
| { |
| base->CSICR3 &= ~cr3; |
| } |
| } |
| |
| void CSI_EnableInterrupts(CSI_Type *base, uint32_t mask) |
| { |
| base->CSICR1 |= (mask & CSI_CSICR1_INT_EN_MASK); |
| base->CSICR3 |= (mask & CSI_CSICR3_INT_EN_MASK); |
| base->CSICR18 |= ((mask & CSI_CSICR18_INT_EN_MASK) >> 6U); |
| } |
| |
| void CSI_DisableInterrupts(CSI_Type *base, uint32_t mask) |
| { |
| base->CSICR1 &= ~(mask & CSI_CSICR1_INT_EN_MASK); |
| base->CSICR3 &= ~(mask & CSI_CSICR3_INT_EN_MASK); |
| base->CSICR18 &= ~((mask & CSI_CSICR18_INT_EN_MASK) >> 6U); |
| } |
| |
| status_t CSI_TransferCreateHandle(CSI_Type *base, |
| csi_handle_t *handle, |
| csi_transfer_callback_t callback, |
| void *userData) |
| { |
| assert(handle); |
| uint32_t instance; |
| |
| memset(handle, 0, sizeof(*handle)); |
| |
| /* Set the callback and user data. */ |
| handle->callback = callback; |
| handle->userData = userData; |
| |
| /* Get instance from peripheral base address. */ |
| instance = CSI_GetInstance(base); |
| |
| /* Save the handle in global variables to support the double weak mechanism. */ |
| s_csiHandle[instance] = handle; |
| |
| s_csiIsr = CSI_TransferHandleIRQ; |
| |
| /* Enable interrupt. */ |
| EnableIRQ(s_csiIRQ[instance]); |
| |
| return kStatus_Success; |
| } |
| |
| status_t CSI_TransferStart(CSI_Type *base, csi_handle_t *handle) |
| { |
| assert(handle); |
| |
| uint32_t emptyBufferCount; |
| |
| emptyBufferCount = CSI_TransferGetEmptyBufferCount(base, handle); |
| |
| if (emptyBufferCount < 2U) |
| { |
| return kStatus_CSI_NoEmptyBuffer; |
| } |
| |
| handle->nextBufferIdx = 0U; |
| handle->activeBufferNum = 0U; |
| |
| /* Write to memory from second completed frame. */ |
| base->CSICR18 = (base->CSICR18 & ~CSI_CSICR18_MASK_OPTION_MASK) | CSI_CSICR18_MASK_OPTION(2); |
| |
| /* Load the frame buffer to CSI register, there are at least two empty buffers. */ |
| CSI_TransferLoadBufferToDevice(base, handle); |
| CSI_TransferLoadBufferToDevice(base, handle); |
| |
| /* After reflash DMA, the CSI saves frame to frame buffer 0. */ |
| CSI_ReflashFifoDma(base, kCSI_RxFifo); |
| |
| handle->transferStarted = true; |
| handle->transferOnGoing = true; |
| |
| CSI_EnableInterrupts(base, kCSI_RxBuffer1DmaDoneInterruptEnable | kCSI_RxBuffer0DmaDoneInterruptEnable); |
| |
| CSI_Start(base); |
| |
| return kStatus_Success; |
| } |
| |
| status_t CSI_TransferStop(CSI_Type *base, csi_handle_t *handle) |
| { |
| assert(handle); |
| |
| CSI_Stop(base); |
| CSI_DisableInterrupts(base, kCSI_RxBuffer1DmaDoneInterruptEnable | kCSI_RxBuffer0DmaDoneInterruptEnable); |
| |
| handle->transferStarted = false; |
| handle->transferOnGoing = false; |
| |
| /* Stoped, reset the state flags. */ |
| handle->queueDrvReadIdx = handle->queueDrvWriteIdx; |
| handle->activeBufferNum = 0U; |
| |
| return kStatus_Success; |
| } |
| |
| status_t CSI_TransferSubmitEmptyBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t frameBuffer) |
| { |
| uint32_t csicr1; |
| |
| if (CSI_DRIVER_QUEUE_SIZE == CSI_TransferGetQueueDelta(handle->queueUserReadIdx, handle->queueUserWriteIdx)) |
| { |
| return kStatus_CSI_QueueFull; |
| } |
| |
| /* Disable the interrupt to protect the index information in handle. */ |
| csicr1 = base->CSICR1; |
| |
| base->CSICR1 = (csicr1 & ~(CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK | CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK)); |
| |
| /* Save the empty frame buffer address to queue. */ |
| handle->frameBufferQueue[handle->queueUserWriteIdx] = frameBuffer; |
| handle->queueUserWriteIdx = CSI_TransferIncreaseQueueIdx(handle->queueUserWriteIdx); |
| |
| base->CSICR1 = csicr1; |
| |
| if (handle->transferStarted) |
| { |
| /* |
| * If user has started transfer using @ref CSI_TransferStart, and the CSI is |
| * stopped due to no empty frame buffer in queue, then start the CSI. |
| */ |
| if ((!handle->transferOnGoing) && (CSI_TransferGetEmptyBufferCount(base, handle) >= 2U)) |
| { |
| handle->transferOnGoing = true; |
| handle->nextBufferIdx = 0U; |
| |
| /* Load the frame buffers to CSI module. */ |
| CSI_TransferLoadBufferToDevice(base, handle); |
| CSI_TransferLoadBufferToDevice(base, handle); |
| CSI_ReflashFifoDma(base, kCSI_RxFifo); |
| CSI_Start(base); |
| } |
| } |
| |
| return kStatus_Success; |
| } |
| |
| status_t CSI_TransferGetFullBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t *frameBuffer) |
| { |
| uint32_t csicr1; |
| |
| /* No full frame buffer. */ |
| if (handle->queueUserReadIdx == handle->queueDrvWriteIdx) |
| { |
| return kStatus_CSI_NoFullBuffer; |
| } |
| |
| /* Disable the interrupt to protect the index information in handle. */ |
| csicr1 = base->CSICR1; |
| |
| base->CSICR1 = (csicr1 & ~(CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK | CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK)); |
| |
| *frameBuffer = handle->frameBufferQueue[handle->queueUserReadIdx]; |
| |
| handle->queueUserReadIdx = CSI_TransferIncreaseQueueIdx(handle->queueUserReadIdx); |
| |
| base->CSICR1 = csicr1; |
| |
| return kStatus_Success; |
| } |
| |
| void CSI_TransferHandleIRQ(CSI_Type *base, csi_handle_t *handle) |
| { |
| uint32_t queueDrvWriteIdx; |
| uint32_t csisr = base->CSISR; |
| |
| /* Clear the error flags. */ |
| base->CSISR = csisr; |
| |
| /* |
| * If both frame buffer 0 and frame buffer 1 flags assert, driver does not |
| * know which frame buffer ready just now, so reset the CSI transfer to |
| * start from frame buffer 0. |
| */ |
| if ((csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) == |
| (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) |
| { |
| CSI_Stop(base); |
| |
| /* Reset the active buffers. */ |
| if (1 <= handle->activeBufferNum) |
| { |
| queueDrvWriteIdx = handle->queueDrvWriteIdx; |
| |
| base->CSIDMASA_FB1 = handle->frameBufferQueue[queueDrvWriteIdx]; |
| |
| if (2U == handle->activeBufferNum) |
| { |
| queueDrvWriteIdx = CSI_TransferIncreaseQueueIdx(queueDrvWriteIdx); |
| base->CSIDMASA_FB2 = handle->frameBufferQueue[queueDrvWriteIdx]; |
| handle->nextBufferIdx = 0U; |
| } |
| else |
| { |
| handle->nextBufferIdx = 1U; |
| } |
| } |
| CSI_ReflashFifoDma(base, kCSI_RxFifo); |
| CSI_Start(base); |
| } |
| else if (csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) |
| { |
| handle->queueDrvWriteIdx = CSI_TransferIncreaseQueueIdx(handle->queueDrvWriteIdx); |
| |
| handle->activeBufferNum--; |
| |
| if (handle->callback) |
| { |
| handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData); |
| } |
| |
| /* No frame buffer to save incoming data, then stop the CSI module. */ |
| if (!(handle->activeBufferNum)) |
| { |
| CSI_Stop(base); |
| handle->transferOnGoing = false; |
| } |
| else |
| { |
| if (CSI_TransferGetEmptyBufferCount(base, handle)) |
| { |
| CSI_TransferLoadBufferToDevice(base, handle); |
| } |
| } |
| } |
| else |
| { |
| } |
| } |
| |
| #if defined(CSI) |
| void CSI_DriverIRQHandler(void) |
| { |
| s_csiIsr(CSI, s_csiHandle[0]); |
| /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping |
| exception return operation might vector to incorrect interrupt */ |
| #if defined __CORTEX_M && (__CORTEX_M == 4U) |
| __DSB(); |
| #endif |
| } |
| #endif |
| |
| #if defined(CSI0) |
| void CSI0_DriverIRQHandler(void) |
| { |
| s_csiIsr(CSI, s_csiHandle[0]); |
| /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping |
| exception return operation might vector to incorrect interrupt */ |
| #if defined __CORTEX_M && (__CORTEX_M == 4U) |
| __DSB(); |
| #endif |
| } |
| #endif |