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