1 /*
2 * Copyright (c) 2022 OpenLuat & AirM2M
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of
5 * this software and associated documentation files (the "Software"), to deal in
6 * the Software without restriction, including without limitation the rights to
7 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 * the Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #include "user.h"
23 #define DCMI_BUF_SIZE (1280)
24 #define DCMI_RXBUF_BAND (2)
25 typedef struct
26 {
27 PV_Union uBuf[DCMI_RXBUF_BAND];
28 CBFuncEx_t CB;
29 void *pUserData;
30 uint32_t BufLen;
31 uint8_t RxDMASn;
32
33 }DCMI_CtrlStruct;
34
35 static DCMI_CtrlStruct prvDCMI;
36 static int32_t prvDCMI_DMADone(void *pData, void *pParam);
prvDCMI_DummyCB(void * pData,void * pParam)37 static int32_t prvDCMI_DummyCB(void *pData, void *pParam)
38 {
39 return -1;
40 }
prvDCMI_IrqHandler(int32_t Line,void * pData)41 static void prvDCMI_IrqHandler(int32_t Line, void *pData)
42 {
43 uint32_t SR = DCMI->RISR;
44
45 DCMI->ICR = 0xff;
46 if (SR & DCMI_IER_VSYNC_IE)
47 {
48 prvDCMI.RxDMASn = (prvDCMI.RxDMASn + 1)%DCMI_RXBUF_BAND;
49 DMA_ClearStreamFlag(DCMI_RX_DMA_STREAM);
50 DMA_ForceStartStream(DCMI_RX_DMA_STREAM, prvDCMI.uBuf[prvDCMI.RxDMASn].pu32, prvDCMI.BufLen, prvDCMI_DMADone, NULL, 1);
51 prvDCMI.CB(NULL, prvDCMI.pUserData);
52 }
53 }
54
prvDCMI_DMADone(void * pData,void * pParam)55 static int32_t prvDCMI_DMADone(void *pData, void *pParam)
56 {
57 uint8_t LastRxDMASn;
58 Buffer_Struct RxBuf;
59 LastRxDMASn = prvDCMI.RxDMASn;
60 prvDCMI.RxDMASn = (prvDCMI.RxDMASn + 1)%DCMI_RXBUF_BAND;
61 DMA_ClearStreamFlag(DCMI_RX_DMA_STREAM);
62 DMA_ForceStartStream(DCMI_RX_DMA_STREAM, prvDCMI.uBuf[prvDCMI.RxDMASn].pu32, prvDCMI.BufLen, prvDCMI_DMADone, NULL, 1);
63 Buffer_StaticInit(&RxBuf, prvDCMI.uBuf[LastRxDMASn].pu32, prvDCMI.BufLen);
64 prvDCMI.CB(&RxBuf, prvDCMI.pUserData);
65 return 0;
66 }
67
DCMI_Setup(uint8_t VsyncLevel,uint8_t HsyncLevel,uint8_t PclkPOL,uint8_t DataBit,uint32_t FrameRate)68 void DCMI_Setup(uint8_t VsyncLevel, uint8_t HsyncLevel, uint8_t PclkPOL, uint8_t DataBit, uint32_t FrameRate)
69 {
70 uint32_t Ctrl = (1 << 29);
71 Ctrl |= VsyncLevel?DCMI_CR_VSPOL:0;
72 Ctrl |= HsyncLevel?DCMI_CR_HSPOL:0;
73 Ctrl |= PclkPOL?DCMI_CR_PCKPOL:0;
74 Ctrl |= ((DataBit - 8) >> 1) << 10;
75 Ctrl |= (FrameRate & 0x03 ) << 8;
76 SYSCTRL->DBG_CR |= DCMI_FROM_OUT;
77 DCMI->CR = Ctrl | (1 << 21);
78 DCMI->IER = DCMI_IER_VSYNC_IE|DCMI_IER_OVF_IE|DCMI_IER_ERR_IE;
79 DCMI->ICR = 0xff;
80 ISR_OnOff(DCMI_IRQn, 0);
81 ISR_SetHandler(DCMI_IRQn, prvDCMI_IrqHandler, NULL);
82 #ifdef __BUILD_OS__
83 ISR_SetPriority(DCMI_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 2);
84 #else
85 ISR_SetPriority(DCMI_IRQn, 5);
86 #endif
87 DMA_InitTypeDef DMA_InitStruct;
88 DMA_BaseConfig(&DMA_InitStruct);
89 DMA_InitStruct.DMA_Peripheral = SYSCTRL_PHER_CTRL_DMA_CHx_IF_DCMI_TX;
90 DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&DCMI->DR;
91 DMA_InitStruct.DMA_MemoryDataSize = DMA_DataSize_Word;
92 DMA_InitStruct.DMA_PeripheralDataSize = DMA_DataSize_Word;
93 DMA_InitStruct.DMA_Priority = DMA_Priority_1;
94 DMA_ConfigStream(DCMI_RX_DMA_STREAM, &DMA_InitStruct);
95 if (!prvDCMI.CB)
96 {
97 prvDCMI.CB = prvDCMI_DummyCB;
98 }
99 }
100
DCMI_SetCallback(CBFuncEx_t CB,void * pData)101 void DCMI_SetCallback(CBFuncEx_t CB, void *pData)
102 {
103 if (CB)
104 {
105 prvDCMI.CB = CB;
106 }
107 else
108 {
109 prvDCMI.CB = prvDCMI_DummyCB;
110 }
111 prvDCMI.pUserData = pData;
112 }
113
DCMI_SetCROPConfig(uint8_t OnOff,uint32_t VStart,uint32_t HStart,uint32_t VLen,uint32_t HLen)114 void DCMI_SetCROPConfig(uint8_t OnOff, uint32_t VStart, uint32_t HStart, uint32_t VLen, uint32_t HLen)
115 {
116 if (OnOff)
117 {
118 /* Sets the CROP window coordinates */
119 DCMI->CWSTRTR = (VStart << 16)|HStart;
120
121 /* Sets the CROP window size */
122 DCMI->CWSIZER = (VLen << 16)|HLen;
123 DCMI->CR |= DCMI_CR_CROP;
124 }
125 else
126 {
127 DCMI->CR &= ~DCMI_CR_CROP;
128 }
129 }
130 /**
131 * @brief 摄像头捕获开关
132 *
133 * @param OnOff 0: 关 1: 开
134 */
DCMI_CaptureSwitch(uint8_t OnOff,uint32_t BufLen,uint32_t ImageW,uint32_t ImageH,uint8_t DataByte,uint32_t * OutH)135 void DCMI_CaptureSwitch(uint8_t OnOff, uint32_t BufLen, uint32_t ImageW, uint32_t ImageH, uint8_t DataByte, uint32_t *OutH)
136 {
137 uint32_t i;
138 uint32_t WDataLen, HLen;
139 if (OnOff)
140 {
141 if (DCMI->CR & DCMI_CR_CAPTURE) return;
142 if (!BufLen)
143 {
144 WDataLen = (ImageW * DataByte) >> 2;
145 if (ImageH > 100)
146 {
147 if (!(ImageH % 10))
148 {
149 HLen = ImageH / 10;
150 }
151 else
152 {
153 HLen = ImageH >> 1;
154 }
155 }
156 else
157 {
158 HLen = ImageH >> 1;
159 }
160 while( (WDataLen * HLen) > 2048)
161 {
162 HLen >>= 1;
163 }
164 BufLen = WDataLen * HLen;
165 DBG("buf %u, H %u", BufLen, HLen);
166 *OutH = HLen;
167 }
168 for(i = 0; i < DCMI_RXBUF_BAND; i++)
169 {
170 prvDCMI.uBuf[i].pu32 = OS_Malloc(BufLen * sizeof(uint32_t));
171 }
172 prvDCMI.RxDMASn = 0;
173 prvDCMI.BufLen = BufLen;
174 DMA_ClearStreamFlag(DCMI_RX_DMA_STREAM);
175 DMA_ForceStartStream(DCMI_RX_DMA_STREAM, prvDCMI.uBuf[0].pu32, prvDCMI.BufLen, prvDCMI_DMADone, NULL, 1);
176 DCMI->ICR = 0x1f;
177 ISR_OnOff(DCMI_IRQn, 1);
178 DCMI->CR |= DCMI_CR_CAPTURE|DCMI_CR_ENABLE;
179 }
180 else
181 {
182 DMA_StopStream(DCMI_RX_DMA_STREAM);
183 DCMI->CR &= ~(DCMI_CR_CAPTURE|DCMI_CR_ENABLE|DCMI_CR_CM);
184 DCMI->CR |= (1 << 21);
185 ISR_OnOff(DCMI_IRQn, 0);
186 DCMI->ICR = 0x1f;
187 ISR_Clear(DCMI_IRQn);
188 for(i = 0; i < DCMI_RXBUF_BAND; i++)
189 {
190 if (prvDCMI.uBuf[i].pu32)
191 {
192 OS_Free(prvDCMI.uBuf[i].pu32);
193 prvDCMI.uBuf[i].pu32 = 0;
194 }
195 }
196 }
197 }
198
199