/* * Copyright (c) 2022 OpenLuat & AirM2M * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "user.h" #define DCMI_BUF_SIZE (1280) #define DCMI_RXBUF_BAND (2) typedef struct { PV_Union uBuf[DCMI_RXBUF_BAND]; CBFuncEx_t CB; void *pUserData; uint32_t BufLen; uint8_t RxDMASn; uint8_t IsFirstVsync; }DCMI_CtrlStruct; static DCMI_CtrlStruct prvDCMI; static int32_t prvDCMI_DMADone(void *pData, void *pParam); static int32_t prvDCMI_DummyCB(void *pData, void *pParam) { return -1; } static void prvDCMI_IrqHandler(int32_t Line, void *pData) { uint32_t SR = DCMI->RISR; DCMI->ICR = 0xff; if (SR & DCMI_IER_VSYNC_IE) { prvDCMI.RxDMASn = (prvDCMI.RxDMASn + 1)%DCMI_RXBUF_BAND; DMA_ClearStreamFlag(DCMI_RX_DMA_STREAM); DMA_ForceStartStream(DCMI_RX_DMA_STREAM, prvDCMI.uBuf[prvDCMI.RxDMASn].pu32, prvDCMI.BufLen, prvDCMI_DMADone, NULL, 1); if (prvDCMI.IsFirstVsync) { prvDCMI.IsFirstVsync = 0; } prvDCMI.CB(NULL, prvDCMI.pUserData); } } static int32_t prvDCMI_DMADone(void *pData, void *pParam) { uint8_t LastRxDMASn; Buffer_Struct RxBuf; LastRxDMASn = prvDCMI.RxDMASn; prvDCMI.RxDMASn = (prvDCMI.RxDMASn + 1)%DCMI_RXBUF_BAND; DMA_ClearStreamFlag(DCMI_RX_DMA_STREAM); DMA_ForceStartStream(DCMI_RX_DMA_STREAM, prvDCMI.uBuf[prvDCMI.RxDMASn].pu32, prvDCMI.BufLen, prvDCMI_DMADone, NULL, 1); Buffer_StaticInit(&RxBuf, prvDCMI.uBuf[LastRxDMASn].pu32, prvDCMI.BufLen); if (!prvDCMI.IsFirstVsync) { prvDCMI.CB(&RxBuf, prvDCMI.pUserData); } return 0; } void DCMI_Setup(uint8_t VsyncLevel, uint8_t HsyncLevel, uint8_t PclkPOL, uint8_t DataBit, uint32_t FrameRate) { uint32_t Ctrl = (1 << 29); Ctrl |= VsyncLevel?DCMI_CR_VSPOL:0; Ctrl |= HsyncLevel?DCMI_CR_HSPOL:0; Ctrl |= PclkPOL?DCMI_CR_PCKPOL:0; Ctrl |= ((DataBit - 8) >> 1) << 10; Ctrl |= (FrameRate & 0x03 ) << 8; SYSCTRL->DBG_CR |= DCMI_FROM_OUT; DCMI->CR = Ctrl | (1 << 21); DCMI->IER = DCMI_IER_VSYNC_IE|DCMI_IER_OVF_IE|DCMI_IER_ERR_IE; DCMI->ICR = 0xff; ISR_OnOff(DCMI_IRQn, 0); ISR_SetHandler(DCMI_IRQn, prvDCMI_IrqHandler, NULL); #ifdef __BUILD_OS__ ISR_SetPriority(DCMI_IRQn, IRQ_LOWEST_PRIORITY - 2); #else ISR_SetPriority(DCMI_IRQn, 5); #endif DMA_InitTypeDef DMA_InitStruct; DMA_BaseConfig(&DMA_InitStruct); DMA_InitStruct.DMA_Peripheral = SYSCTRL_PHER_CTRL_DMA_CHx_IF_DCMI_TX; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&DCMI->DR; DMA_InitStruct.DMA_MemoryDataSize = DMA_DataSize_Word; DMA_InitStruct.DMA_PeripheralDataSize = DMA_DataSize_Word; DMA_InitStruct.DMA_Priority = DMA_Priority_1; DMA_ConfigStream(DCMI_RX_DMA_STREAM, &DMA_InitStruct); if (!prvDCMI.CB) { prvDCMI.CB = prvDCMI_DummyCB; } } void DCMI_SetCallback(CBFuncEx_t CB, void *pData) { if (CB) { prvDCMI.CB = CB; } else { prvDCMI.CB = prvDCMI_DummyCB; } prvDCMI.pUserData = pData; } void DCMI_SetCROPConfig(uint8_t OnOff, uint32_t VStart, uint32_t HStart, uint32_t VLen, uint32_t HLen) { if (OnOff) { /* Sets the CROP window coordinates */ DCMI->CWSTRTR = (VStart << 16)|HStart; /* Sets the CROP window size */ DCMI->CWSIZER = (VLen << 16)|HLen; DCMI->CR |= DCMI_CR_CROP; } else { DCMI->CR &= ~DCMI_CR_CROP; } } /** * @brief 摄像头捕获开关 * * @param OnOff 0: 关 1: 开 */ void DCMI_CaptureSwitch(uint8_t OnOff, uint32_t BufLen, uint32_t ImageW, uint32_t ImageH, uint8_t DataByte, uint32_t *OutH) { uint32_t i; uint32_t WDataLen, HLen; if (OnOff) { PM_SetHardwareRunFlag(PM_HW_DCMI_0, 1); if (DCMI->CR & DCMI_CR_CAPTURE) return; prvDCMI.IsFirstVsync = 1; if (!BufLen) { WDataLen = (ImageW * DataByte) >> 2; // if (ImageH > 100) // { // if (!(ImageH % 10)) // { // HLen = ImageH / 10; // } // else // { // HLen = ImageH >> 1; // } // } // else // { // HLen = ImageH >> 1; // } HLen = 8; while( (WDataLen * HLen) > 4000) { HLen >>= 1; } BufLen = WDataLen * HLen; // DBG("buf %u, H %u", BufLen, HLen); *OutH = HLen; } for(i = 0; i < DCMI_RXBUF_BAND; i++) { prvDCMI.uBuf[i].pu32 = OS_Malloc(BufLen * sizeof(uint32_t)); } prvDCMI.RxDMASn = 0; prvDCMI.BufLen = BufLen; DMA_ClearStreamFlag(DCMI_RX_DMA_STREAM); DMA_ForceStartStream(DCMI_RX_DMA_STREAM, prvDCMI.uBuf[0].pu32, prvDCMI.BufLen, prvDCMI_DMADone, NULL, 1); DCMI->ICR = 0x1f; ISR_OnOff(DCMI_IRQn, 1); DCMI->CR |= DCMI_CR_CAPTURE|DCMI_CR_ENABLE; } else { DMA_StopStream(DCMI_RX_DMA_STREAM); DCMI->CR &= ~(DCMI_CR_CAPTURE|DCMI_CR_ENABLE|DCMI_CR_CM); DCMI->CR |= (1 << 21); ISR_OnOff(DCMI_IRQn, 0); DCMI->ICR = 0x1f; ISR_Clear(DCMI_IRQn); for(i = 0; i < DCMI_RXBUF_BAND; i++) { if (prvDCMI.uBuf[i].pu32) { OS_Free(prvDCMI.uBuf[i].pu32); prvDCMI.uBuf[i].pu32 = 0; } } PM_SetHardwareRunFlag(PM_HW_DCMI_0, 0); } }