ARMEBS4  revision-26.06.2015
stm32_camera.c
Go to the documentation of this file.
1 /**
2  * \file heivs/stm32_camera.c
3  *
4  * \brief Camera interface for stm32 processors
5  * \author marc dot pignat at hevs dot ch
6  */
7 
8 #include "heivs/stm32_camera.h"
9 #include "stm32/stm32f4xx_rcc.h"
10 #include "stm32/stm32f4xx_dma.h"
11 #include "stm32/stm32f4xx_dcmi.h"
12 #include "stm32/stm32f4xx_misc.h"
13 #include "heivs/time.h"
14 
15 #define MAX_RETRY_COUNT 5
16 
17 struct dma_xfer_t
18 {
19  void *buffer_base;
20  uint32_t buffer_size;
21  uint32_t current_base;
22  uint32_t current_size;
23  uint32_t current_element_size;
24  const struct camera_t *cam;
25  void *(*next_handler)(const struct camera_t *cam);
26  void (*done_handler)(status_e status, const struct camera_t *cam);
27  uint32_t continuous;
28  uint32_t done;
29  uint32_t restart;
30  uint32_t dma_error;
31  uint32_t one_shot_running;
32  status_e one_shot_status;
33 };
34 
35 static struct dma_xfer_t xfer;
36 
37 static void xfer_update(volatile struct dma_xfer_t *xfer)
38 {
39  xfer->current_base += xfer->current_element_size;
40  xfer->current_size -= xfer->current_element_size;
41 }
42 
43 static status_e xfer_next(volatile struct dma_xfer_t *xfer)
44 {
45  uint32_t target = DMA_GetCurrentMemoryTarget(DMA2_Stream1);
46 
47  switch (target)
48  {
49  case 0:
50  target = DMA_Memory_1;
51  break;
52  case 1:
53  target = DMA_Memory_0;
54  break;
55  default:
56  return ERROR_BAD_STATE;
57  break;
58  }
59 
60  DMA_MemoryTargetConfig(DMA2_Stream1, xfer->current_base, target);
61 
62  xfer_update(xfer);
63 
64  return NO_ERROR;
65 }
66 
67 static uint32_t xfer_size(uint32_t size)
68 {
69  while (size > UINT16_MAX)
70  {
71  size /= 2;
72  }
73 
74  return size;
75 }
76 
77 static status_e xfer_setup(volatile struct dma_xfer_t *xfer)
78 {
79  const struct camera_t *cam = xfer->cam;
80 
81  xfer->current_base = (uint32_t)xfer->buffer_base;
82  xfer->current_size = camera_get_image_size(cam);
83  if (xfer->current_size > xfer->buffer_size)
84  {
85  return ERROR_TOO_BIG;
86  }
87  xfer->current_element_size = xfer_size(xfer->current_size);
88 
89  return NO_ERROR;
90 }
91 
92 static status_e xfer_start(volatile struct dma_xfer_t *xfer)
93 {
94  status_e status;
95  DMA_InitTypeDef config;
96 
97  DMA_DeInit(DMA2_Stream1);
98  DMA_ITConfig(DMA2_Stream1, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE | DMA_IT_FE, ENABLE);
99  status = xfer_setup(xfer);
100  if (status != NO_ERROR)
101  {
102  return status;
103  }
104 
105  config.DMA_Channel = DMA_Channel_1;
106  config.DMA_PeripheralBaseAddr = (uint32_t)&DCMI->DR;
107  config.DMA_Memory0BaseAddr = xfer->current_base;
108  config.DMA_DIR = DMA_DIR_PeripheralToMemory;
109  config.DMA_BufferSize = xfer->current_element_size/4;
110  config.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
111  config.DMA_MemoryInc = DMA_MemoryInc_Enable;
112  config.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
113  config.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
114  config.DMA_Mode = DMA_Mode_Normal;
115  config.DMA_Priority = DMA_Priority_VeryHigh;
116  config.DMA_FIFOMode = DMA_FIFOMode_Enable;
117  config.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
118  config.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
119  config.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
120 
121  if (xfer->current_size > UINT16_MAX)
122  {
123  config.DMA_Mode = DMA_Mode_Circular;
124  }
125 
126  /* DMA2 IRQ channel Configuration */
127  DMA_Init(DMA2_Stream1, &config);
128 
129  xfer_update(xfer);
130 
131  if (xfer->current_size > UINT16_MAX)
132  {
133  DMA_DoubleBufferModeConfig(DMA2_Stream1, xfer->current_base, DMA_Memory_0);
134  DMA_DoubleBufferModeCmd(DMA2_Stream1, ENABLE);
135  }
136 
137  DMA_Cmd(DMA2_Stream1, ENABLE);
138 
139  return NO_ERROR;
140 }
141 
142 /**
143  * @brief This function handles DMA2_Stream1 interrupt.
144  * @param None
145  * @retval None
146  */
147 static void Camera_DMA_IRQ_Handler(void)
148 {
149  /* FIFO Error interrupt */
150  if (DMA_GetFlagStatus(DMA2_Stream1, DMA_FLAG_FEIF1) != RESET)
151  {
152  /**
153  * DMA FIFO error is not necessary a problem because there is a fifo in
154  * the DCMI_DR, so let the DCMI_IRQ handle that problem.
155  */
156 
157  /* Clear the Interrupt flag */
158  DMA_ClearFlag(DMA2_Stream1, DMA_FLAG_FEIF1);
159  }
160 
161  /* Transfer error interrupt */
162  if (DMA_GetFlagStatus(DMA2_Stream1, DMA_FLAG_TEIF1) != RESET)
163  {
164  xfer.restart = 1;
165  xfer.dma_error++;
166 
167  DMA_ITConfig(DMA2_Stream1, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE | DMA_IT_FE, DISABLE);
168 
169  if (xfer.dma_error > MAX_RETRY_COUNT || xfer.one_shot_running)
170  {
171  xfer.done_handler(ERROR_DMA_UNDERRUN, xfer.cam);
172  xfer.dma_error = 0;
173  }
174 
175  xfer.one_shot_running = 0;
176 
177  /* Clear the Interrupt flag */
178  DMA_ClearFlag(DMA2_Stream1, DMA_FLAG_TEIF1 | DMA_FLAG_DMEIF1);
179  }
180 
181  /* Half Transfer complete interrupt */
182  if (DMA_GetFlagStatus(DMA2_Stream1, DMA_FLAG_HTIF1) != RESET)
183  {
184  if (!xfer.restart)
185  {
186  if (xfer.current_size)
187  {
188  xfer_next(&xfer);
189  }
190  else
191  {
192  xfer.done = 1;
193  xfer.buffer_base = NULL;
194  if (xfer.next_handler != NULL)
195  {
196  xfer.buffer_base = xfer.next_handler(xfer.cam);
197  }
198 
199  if (!(xfer.buffer_base == NULL))
200  {
201  xfer_setup(&xfer);
202  xfer_next(&xfer);
203  }
204  }
205  }
206 
207  /* Clear the Interrupt flag */
208  DMA_ClearFlag(DMA2_Stream1, DMA_FLAG_HTIF1);
209  }
210 
211  /* Transfer complete interrupt */
212  if (DMA_GetFlagStatus(DMA2_Stream1, DMA_FLAG_TCIF1) != RESET)
213  {
214  if (!xfer.restart)
215  {
216  if (xfer.done)
217  {
218  xfer.done = 0;
219  xfer.dma_error = 0;
220  if (xfer.done_handler)
221  {
222  xfer.done_handler(NO_ERROR, xfer.cam);
223  }
224  xfer.one_shot_running = 0;
225 
226  if (!xfer.continuous)
227  {
228  DMA_Cmd(DMA2_Stream1, DISABLE);
229  }
230  }
231  }
232 
233  /* Clear the Interrupt flag */
234  DMA_ClearFlag(DMA2_Stream1, DMA_FLAG_TCIF1);
235  }
236 }
237 
238 static void Camera_DCMI_IRQ_Handler(void)
239 {
240  uint32_t misr = DCMI->MISR;
241 
242  // Clear interrupts
243  DCMI->ICR = misr;
244 
245  // DCMI overflow (== not enough bandwidth from camera to RAM)
246  if (misr & DCMI_MISR_OVF_MIS)
247  {
248  xfer.restart = 0;
249  xfer_start(&xfer);
250  }
251 
252  // Restart needed because of bad alignment (a breakpoint will cause this)
253  if ((uint32_t)xfer.buffer_base+xfer.current_element_size != xfer.current_base)
254  {
255  if (xfer.continuous)
256  {
257  xfer_start(&xfer);
258  }
259  }
260 
261  // DMA error : restart
262  if (xfer.restart == 1)
263  {
264  xfer.restart++;
265  }
266  else if (xfer.restart == 2)
267  {
268  xfer.restart = 0;
269  xfer_start(&xfer);
270  }
271 }
272 
273 status_e camera_init(const struct camera_t *cam)
274 {
275  status_e status;
276 
277  /* Initialize DCMI used pins */
278  status = gpio_setup_list(cam->data_pins, cam->data_pins_count);
279  if (status != NO_ERROR)
280  {
281  return status;
282  }
283 
284  status = gpio_setup_list(cam->control_pins, cam->control_pins_count);
285  if (status != NO_ERROR)
286  {
287  return status;
288  }
289 
290  if (cam->mco_frequency != 0)
291  {
292  status = gpio_setup(&cam->mco_pin);
293  if (status != NO_ERROR)
294  {
295  return status;
296  }
297 
298  /**
299  * FIXME : use cam->mco_frequency to choose this frequency
300  *
301  * For now, use 8 MHz.
302  */
303  RCC_MCO1Config(RCC_MCO1Source_HSI, RCC_MCO1Div_2); /* MCO1 is 8 MHz */
304  }
305 
306  /* Enable DMCI clock and reset it */
307  RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);
308  RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_DCMI, ENABLE);
309  RCC_AHB2PeriphResetCmd(RCC_AHB2Periph_DCMI, DISABLE);
310 
311  DCMI->CR &= ~((uint32_t)DCMI_CR_CM | DCMI_CR_ESS | DCMI_CR_PCKPOL |
312  DCMI_CR_HSPOL | DCMI_CR_VSPOL | DCMI_CR_FCRC_0 |
313  DCMI_CR_FCRC_1 | DCMI_CR_EDM_0 | DCMI_CR_EDM_1);
314 
315  DCMI->CR = DCMI_CR_ENABLE;
316 
317  /* Configures the DMA2 to transfer Data from DCMI */
318  /* Enable DMA2 clock */
319  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
320 
321  NVIC_InitTypeDef NVIC_InitStructure;
322 
323  /* DMA2 IRQ channel Configuration */
324  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
325  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn ;
326  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;
327  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
328  NVIC_InitStructure.NVIC_Handler = Camera_DMA_IRQ_Handler;
329  NVIC_Init(&NVIC_InitStructure);
330 
331  /* DCMI IRQ Configuration */
332  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
333  NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn ;
334  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;
335  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
336  NVIC_InitStructure.NVIC_Handler = Camera_DCMI_IRQ_Handler;
337  NVIC_Init(&NVIC_InitStructure);
338 
339  return cam->funcs->init(cam);
340 }
341 
342 status_e camera_setup(const struct camera_t *cam, const struct camera_image_options_t *new_options)
343 {
344  status_e status;
345  uint32_t continuous_was = xfer.continuous;
346  void *(*next_was)(const struct camera_t *cam) = xfer.next_handler;
347  void (*done_was)(status_e status, const struct camera_t *cam) = xfer.done_handler;
348 
349 
350  if (continuous_was)
351  {
353  }
354 
355  *cam->image_options = *new_options;
356  if (cam->funcs->setup)
357  {
358  status = cam->funcs->setup(cam);
359  if (status != NO_ERROR)
360  {
361  return status;
362  }
363  }
364 
365  if (continuous_was)
366  {
367  camera_continuous_start(cam, next_was, done_was, xfer.buffer_size);
368  }
369 
370  return NO_ERROR;
371 }
372 
374 {
375  status_e status;
376  timeout_t timeout = time_set_timeout_ms(2000);
377 
378  DCMI->IER &= ~DCMI_IER_FRAME_IE;
379 
380  /* Wait end of frame */
381  while (! (DCMI->RISR & DCMI_RISR_FRAME_RIS))
382  {
383  if (time_elapsed(timeout))
384  {
385  break;
386  }
387  }
388 
389  DCMI->ICR = DCMI_ICR_FRAME_ISC;
390 
391  DCMI->CR &= ~DCMI_CR_CAPTURE;
392 
393  xfer.continuous = 0;
394  xfer.next_handler = NULL;
395  xfer.done_handler = NULL;
396 
397  if (cam->funcs->pause)
398  {
399  status = cam->funcs->pause(cam);
400  if (status != NO_ERROR)
401  {
402  return status;
403  }
404  }
405 
406  return NO_ERROR;
407 }
408 
409 status_e camera_continuous_start(const struct camera_t *cam, void *(*next_handler)(const struct camera_t *), void (*done_handler)(status_e status, const struct camera_t *), size_t size)
410 {
411  status_e status = NO_ERROR;
412 
413  if (!next_handler || !done_handler)
414  {
415  return ERROR_BAD_PARAM;
416  }
417 
418  if (cam->funcs->start)
419  {
420  status = cam->funcs->start(cam, 0);
421  if (status != NO_ERROR)
422  {
423  return status;
424  }
425  }
426 
427  memset(&xfer, 0x0, sizeof(xfer));
428 
429  xfer.cam = cam;
430  xfer.continuous = 1;
431  xfer.next_handler = next_handler;
432  xfer.done_handler = done_handler;
433  xfer.buffer_base = next_handler(cam);
434  xfer.buffer_size = size;
435  status = xfer_start(&xfer);
436  if (status != NO_ERROR)
437  {
438  return status;
439  }
440 
441  DCMI->CR &= ~DCMI_CR_CM;
442  DCMI->CR |= DCMI_CR_CAPTURE;
443  DCMI->IER = DCMI_IER_FRAME_IE | DCMI_IER_OVF_IE;
444 
445  return NO_ERROR;
446 }
447 
448 
449 static void default_done_handler(status_e status, const struct camera_t *cam)
450 {
451  (void)cam;
452  xfer.one_shot_status = status;
453 }
454 
456 {
457  timeout_t timeout = time_set_timeout_ms(1000);
458 
459  (void)cam;
460 
461  while (xfer.one_shot_running)
462  {
463  if (time_elapsed(timeout))
464  {
465  return ERROR_TIMEOUT;
466  }
467  }
468 
469  return xfer.one_shot_status;
470 }
471 
473 {
474  (void)cam;
475 
476  if (xfer.one_shot_running)
477  {
478  return ERROR_AGAIN;
479  }
480 
481  return xfer.one_shot_status;
482 }
483 
484 
485 status_e camera_one_shot_start(const struct camera_t *cam, void (*done_handler)(status_e, const struct camera_t *), void *dst, size_t size)
486 {
487  status_e status = NO_ERROR;
488 
489  if (cam->funcs->start)
490  {
491  status = cam->funcs->start(cam, 0);
492  if (status != NO_ERROR)
493  {
494  return status;
495  }
496  }
497 
498  memset(&xfer, 0x0, sizeof(xfer));
499 
500  xfer.cam = cam;
501  xfer.one_shot_running = 1;
502  xfer.next_handler = NULL;
503  if (!done_handler)
504  {
505  done_handler = default_done_handler;
506  }
507  xfer.done_handler = done_handler;
508  xfer.buffer_base = dst;
509  xfer.buffer_size = size;
510  status = xfer_start(&xfer);
511  if (status != NO_ERROR)
512  {
513  return status;
514  }
515 
516  DCMI->CR |= DCMI_CR_CM;
517  DCMI->CR |= DCMI_CR_CAPTURE;
518  DCMI->IER = DCMI_IER_FRAME_IE | DCMI_IER_OVF_IE;
519 
520  return NO_ERROR;
521 }
522 
523 static uint32_t noverify_camera_get_image_size(const struct camera_t *cam)
524 {
525  switch (cam->image_options->format)
526  {
527  case IMAGE_FORMAT_RGB565:
528  return cam->image_options->xres * cam->image_options->yres * 2;
529  break;
530 
531  default:
532  return 0;
533  }
534 }
535 
536 uint32_t camera_get_image_size(const struct camera_t *cam)
537 {
538  uint32_t size = noverify_camera_get_image_size(cam);
539 
540  return size;
541 }
This file contains all the functions prototypes for the RCC firmware library.
uint32_t DMA_MemoryInc
Definition: stm32f4xx_dma.h:70
No comment.
Definition: error.h:64
uint32_t DMA_Channel
Definition: stm32f4xx_dma.h:50
void(* done)(const void *)
Handler called at the end of Audio_DMA_Play.
Definition: audio_stm32.c:99
status_e camera_continuous_start(const struct camera_t *cam, void *(*next_handler)(const struct camera_t *), void(*done_handler)(status_e status, const struct camera_t *), size_t size)
Start continuous capture of camera images.
Definition: stm32_camera.c:409
DMA Init structure definition.
Definition: stm32f4xx_dma.h:48
uint8_t NVIC_IRQChannel
status_e camera_one_shot_status(const struct camera_t *cam)
Camera wait one shot status.
Definition: stm32_camera.c:472
simple time abstraction
Camera interface for stm32 processors.
uint32_t DMA_MemoryBurst
Definition: stm32f4xx_dma.h:95
void * memset(void *dest, int n, size_t n)
No comment.
Definition: error.h:74
uint32_t DMA_MemoryDataSize
Definition: stm32f4xx_dma.h:76
status_e camera_one_shot_wait(const struct camera_t *cam)
Camera wait one shot finished.
Definition: stm32_camera.c:455
uint8_t NVIC_IRQChannelSubPriority
uint32_t DMA_DIR
Definition: stm32f4xx_dma.h:59
status_e camera_one_shot_start(const struct camera_t *cam, void(*done_handler)(status_e, const struct camera_t *), void *dst, size_t size)
Camera take one shot.
Definition: stm32_camera.c:485
uint32_t DMA_PeripheralInc
Definition: stm32f4xx_dma.h:67
NVIC Init Structure definition.
static uint32_t time_elapsed(timeout_t timeout)
Is this time passed?
Definition: time.h:71
Function called at bad time.
Definition: error.h:67
uint32_t DMA_PeripheralDataSize
Definition: stm32f4xx_dma.h:73
uint32_t DMA_PeripheralBurst
status_e camera_init(const struct camera_t *cam)
Initialize camera.
Definition: stm32_camera.c:273
Parameter unsupported.
Definition: error.h:56
This file contains all the functions prototypes for the DMA firmware library.
uint32_t DMA_PeripheralBaseAddr
Definition: stm32f4xx_dma.h:53
uint32_t DMA_Memory0BaseAddr
Definition: stm32f4xx_dma.h:55
uint32_t DMA_FIFOThreshold
Definition: stm32f4xx_dma.h:92
FunctionalState NVIC_IRQChannelCmd
This file contains all the functions prototypes for the DCMI firmware library.
Retry later.
Definition: error.h:49
status_e camera_continuous_stop(const struct camera_t *cam)
Camera stop continous capture.
Definition: stm32_camera.c:373
uint8_t NVIC_IRQChannelPreemptionPriority
uint32_t DMA_FIFOMode
Definition: stm32f4xx_dma.h:87
Timeout structure.
Definition: time.h:34
status_e camera_setup(const struct camera_t *cam, const struct camera_image_options_t *new_options)
Camera setup.
Definition: stm32_camera.c:342
static void Camera_DMA_IRQ_Handler(void)
This function handles DMA2_Stream1 interrupt.
Definition: stm32_camera.c:147
timeout_t time_set_timeout_ms(uint32_t ms)
Set an obscure time at least ms milliseconds in the future.
Definition: time.c:15
uint32_t DMA_Mode
Definition: stm32f4xx_dma.h:79
uint32_t camera_get_image_size(const struct camera_t *cam)
Compute image byte size using current parameters.
Definition: stm32_camera.c:536
status_e gpio_setup_list(const struct gpio_t gpio[], size_t len)
Setup an array of gpio.
Definition: stm32_gpio.c:47
status_e gpio_setup(const struct gpio_t *gpio)
Setup a gpio.
Definition: stm32_gpio.c:9
uint32_t DMA_BufferSize
Definition: stm32f4xx_dma.h:63
status_e
Known errors.
Definition: error.h:21
uint32_t DMA_Priority
Definition: stm32f4xx_dma.h:84
Parameter too big.
Definition: error.h:73
No error.
Definition: error.h:28
Description of a DMA transfer.
Definition: audio_stm32.c:95