1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2020-07-27     thread-liu        the first version
9  */
10 
11 #include "board.h"
12 
13 #if defined(BSP_USING_DCMI)
14 
15 #include <drv_dcmi.h>
16 
17 #define DRV_DEBUG
18 #define LOG_TAG             "drv.dcmi"
19 #include <drv_log.h>
20 
21 struct stm32_dcmi
22 {
23     DCMI_HandleTypeDef DCMI_Handle;
24     struct rt_dcmi_device dev;
25 };
26 static struct stm32_dcmi rt_dcmi = {0};
27 
28 DMA_HandleTypeDef hdma_dcmi;
29 
rt_hw_dcmi_dma_init(void)30 static void rt_hw_dcmi_dma_init(void)
31 {
32     __HAL_RCC_DMA2_CLK_ENABLE();
33 
34     hdma_dcmi.Instance                 = DMA2_Stream1;
35     hdma_dcmi.Init.Request             = DMA_REQUEST_DCMI;
36     hdma_dcmi.Init.Direction           = DMA_PERIPH_TO_MEMORY;
37     hdma_dcmi.Init.PeriphInc           = DMA_PINC_DISABLE;
38     hdma_dcmi.Init.MemInc              = DMA_MINC_ENABLE;
39     hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
40     hdma_dcmi.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
41     hdma_dcmi.Init.Mode                = DMA_CIRCULAR;
42     hdma_dcmi.Init.Priority            = DMA_PRIORITY_HIGH;
43     hdma_dcmi.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
44     hdma_dcmi.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
45     hdma_dcmi.Init.MemBurst            = DMA_MBURST_SINGLE;
46     hdma_dcmi.Init.PeriphBurst         = DMA_PBURST_SINGLE;
47 
48     HAL_DMA_DeInit(&hdma_dcmi);
49     HAL_DMA_Init(&hdma_dcmi);
50 
51     __HAL_LINKDMA(&rt_dcmi.DCMI_Handle, DMA_Handle, hdma_dcmi);
52 
53     HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x00, 0x00);
54     HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);;
55 }
56 
rt_hw_dcmi_dma_config(rt_uint32_t dst_addr1,rt_uint32_t dst_addr2,rt_uint32_t len)57 void rt_hw_dcmi_dma_config(rt_uint32_t dst_addr1, rt_uint32_t dst_addr2, rt_uint32_t len)
58 {
59     __HAL_UNLOCK(&hdma_dcmi);
60 
61     HAL_DMAEx_MultiBufferStart(&hdma_dcmi, (rt_uint32_t)&DCMI->DR, dst_addr1, dst_addr2, len);
62 
63     __HAL_DMA_ENABLE_IT(&hdma_dcmi, DMA_IT_TC);
64 }
65 
rt_hw_dcmi_init(DCMI_HandleTypeDef * device)66 static rt_err_t rt_hw_dcmi_init(DCMI_HandleTypeDef *device)
67 {
68     RT_ASSERT(device != RT_NULL);
69 
70     device->Instance               = DCMI;
71     device->Init.SynchroMode       = DCMI_SYNCHRO_HARDWARE;
72     device->Init.PCKPolarity       = DCMI_PCKPOLARITY_RISING;
73     device->Init.VSPolarity        = DCMI_VSPOLARITY_LOW;
74     device->Init.HSPolarity        = DCMI_HSPOLARITY_LOW;
75     device->Init.CaptureRate       = DCMI_CR_ALL_FRAME;
76     device->Init.ExtendedDataMode  = DCMI_EXTEND_DATA_8B;
77     device->Init.JPEGMode          = DCMI_JPEG_ENABLE;
78     device->Init.ByteSelectMode    = DCMI_BSM_ALL;
79     device->Init.ByteSelectStart   = DCMI_OEBS_ODD;
80     device->Init.LineSelectMode    = DCMI_LSM_ALL;
81     device->Init.LineSelectStart   = DCMI_OELS_ODD;
82 
83     if (HAL_DCMI_Init(device) != HAL_OK)
84     {
85         LOG_E("dcmi init error!");
86         return -RT_ERROR;
87     }
88 
89     DCMI->IER = 0x0;
90 
91     __HAL_DCMI_ENABLE_IT(device, DCMI_IT_FRAME);
92     __HAL_DCMI_ENABLE(device);
93 
94     return RT_EOK;
95 }
96 
DCMI_IRQHandler(void)97 void DCMI_IRQHandler(void)
98 {
99     /* enter interrupt */
100     rt_interrupt_enter();
101 
102     HAL_DCMI_IRQHandler(&rt_dcmi.DCMI_Handle);
103 
104     /* leave interrupt */
105     rt_interrupt_leave();
106 }
107 
DCMI_Start(void)108 void DCMI_Start(void)
109 {
110     __HAL_DMA_ENABLE(&hdma_dcmi);
111     DCMI->CR |= DCMI_CR_CAPTURE;
112 }
113 
DCMI_Stop(void)114 void DCMI_Stop(void)
115 {
116     DCMI->CR &= ~(DCMI_CR_CAPTURE);
117     while (DCMI->CR & 0x01);
118     __HAL_DMA_DISABLE(&hdma_dcmi);
119 }
120 
121 /* Capture a frame of the image */
HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef * hdcmi)122 void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
123 {
124     extern void camera_frame_data_process(void);
125     /* enter interrupt */
126     rt_interrupt_enter();
127     /* move frame data to buffer */
128     camera_frame_data_process();
129 
130     __HAL_DCMI_ENABLE_IT(&rt_dcmi.DCMI_Handle, DCMI_IT_FRAME);
131 
132     /* leave interrupt */
133     rt_interrupt_leave();
134 }
135 
DMA2_Stream1_IRQHandler(void)136 void DMA2_Stream1_IRQHandler(void)
137 {
138     extern void camera_dma_data_process(void);
139     /* enter interrupt */
140     rt_interrupt_enter();
141 
142     if (__HAL_DMA_GET_FLAG(&hdma_dcmi, DMA_FLAG_TCIF1_5) != RESET)
143     {
144         __HAL_DMA_CLEAR_FLAG(&hdma_dcmi, DMA_FLAG_TCIF1_5);
145         /* move dma data to buffer */
146         camera_dma_data_process();
147     }
148 
149     /* leave interrupt */
150     rt_interrupt_leave();
151 }
152 
rt_dcmi_init(rt_device_t dev)153 static rt_err_t rt_dcmi_init(rt_device_t dev)
154 {
155     RT_ASSERT(dev != RT_NULL);
156     rt_err_t result = RT_EOK;
157 
158     result = rt_hw_dcmi_init(&rt_dcmi.DCMI_Handle);
159     if (result != RT_EOK)
160     {
161         return result;
162     }
163 
164     rt_hw_dcmi_dma_init();
165 
166     return result;
167 }
168 
rt_dcmi_open(rt_device_t dev,rt_uint16_t oflag)169 static rt_err_t rt_dcmi_open(rt_device_t dev, rt_uint16_t oflag)
170 {
171     RT_ASSERT(dev != RT_NULL);
172 
173     return RT_EOK;
174 }
175 
rt_dcmi_close(rt_device_t dev)176 static rt_err_t rt_dcmi_close(rt_device_t dev)
177 {
178     RT_ASSERT(dev != RT_NULL);
179 
180     return RT_EOK;
181 }
182 
rt_dcmi_control(rt_device_t dev,int cmd,void * args)183 static rt_err_t rt_dcmi_control(rt_device_t dev, int cmd, void *args)
184 {
185     RT_ASSERT(dev != RT_NULL);
186 
187     return RT_EOK;
188 }
189 
rt_dcmi_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)190 static rt_ssize_t rt_dcmi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
191 {
192     RT_ASSERT(dev != RT_NULL);
193 
194     return RT_EOK;
195 }
196 
rt_dcmi_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)197 static rt_ssize_t rt_dcmi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
198 {
199     RT_ASSERT(dev != RT_NULL);
200 
201     return RT_EOK;
202 }
203 
dcmi_init(void)204 int dcmi_init(void)
205 {
206     rt_dcmi.dev.parent.type      = RT_Device_Class_Miscellaneous;
207     rt_dcmi.dev.parent.init      = rt_dcmi_init;
208     rt_dcmi.dev.parent.open      = rt_dcmi_open;
209     rt_dcmi.dev.parent.close     = rt_dcmi_close;
210     rt_dcmi.dev.parent.read      = rt_dcmi_read;
211     rt_dcmi.dev.parent.write     = rt_dcmi_write;
212     rt_dcmi.dev.parent.control   = rt_dcmi_control;
213     rt_dcmi.dev.parent.user_data = RT_NULL;
214 
215     rt_device_register(&rt_dcmi.dev.parent, "dcmi", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
216 
217     LOG_I("dcmi init success!");
218 
219     return RT_EOK;
220 }
221 INIT_BOARD_EXPORT(dcmi_init);
222 
223 #endif
224