Frank's Random Wanderings

STM32F2xx Digital Camera Interface (DCMI)

I’m using the STM32F2xx DCMI port to receive data from an CMOS image sensor. There aren’t too many Cortex-M3 or M4 parts which have this ability natively; the STM32F2xx is a rare breed. It’s a very nice feature. Along the way I’ve learnt a few things about the DCMI port, some of which are documented, some of which are not.

DCMI Interrupt Only At Frame End

There’s no way to get a DCMI interrupt at the start of a frame. If you need that, route the image sensor’s frame sync pin to a processor GPIO pin, and generate a GPIO interrupt on the rising or falling edge as appropriate.

Data Count Register

One of the things you notice once you start trying to use the DCMI port is that it doesn’t have a simple “data count” register. The way the DCMI port works, is it receives data from an external source and puts it into a small FIFO, which then gets fed to the STM32F2xx DMA controller. For some data types you know exactly how much data you’re going to receive; for other types (particularly jpeg data) you have no idea. But you always need to know how much you have received, and with the DCMI there’s no easy way to know. It’s a surprisingly difficult problem to solve, particularly when you start inserting other things into your image data buffers (like image file headers and the like). When I queried ST tech support about this, they suggested setting things up so an interrupt was generated every time a byte was received. Can you imagine 4 million interrupts a second?

I ended up writing some code to count with the help of the DMA controller. The DMA doesn’t have a “data count up” register either, however it does have a “data count down” register, the NDTR. It gets tricky when you’re using the double-buffer or circular-buffer modes of the DMA controller, because the NDTR register is automatically reloaded by hardware. But with enough puzzling, thinking, head-scratching and experimenting it can be done. Although it’s only accurate to multiples of 4 bytes – see the “zero padding” discussion below.

Ideally I’d like to see ST add a simple “data count” register to the DCMI port, but I’m guessing it probably won’t happen for these parts.

Zero Padding

Talking about JPEG mode, there’s a nasty little “gotcha” in the DCMI port that the documentation does mention in the “JPEG Format” section, but I’ll re-iterate it here. It very much ties in to the lack of a data count register mentioned earlier.

If the amount of data received in a frame is not a multiple of 4 bytes, the DCMI will pad out the end of the frame to a multiple of 4 bytes by inserting zeros. For example, if your frame is 1001 bytes long, you’ll receive from the DCMI port 1004 bytes, consisting of 1001 bytes of “real” data, followed by 3 bytes of zeros.

And therein lies the rub. If you (a) don’t know how many bytes you’re expecting to receive, and (b) don’t know how many bytes were actually received by the DCMI port because it doesn’t have a data count register, then how do you know whether those 3 bytes at the end are padding zeros, or “real data” zeros? In short, you don’t know, there’s no way to tell. You need to consider this, and decide whether or not it might be a problem in your application.

Strangely enough, the DCMI documentation only mentions this zero padding for the JPEG mode, however I would assume (and it’s only an assumption – not confirmed with ST) that this zero padding would occur in the other capture modes as well.

Control Signals Polarity

The documentation is remarkably confusing on this point. If a control signal (eg vsync) is active-high, what DCMI setting is required for that? It’s a bit too difficult to explain, so here’s a repost of a code snippet I posted on the STM32F forum for exactly that question.

Hopefully this will help. As a bonus this code snippet shows how to enable the DCMI JPEG mode.

Unexpected “Frame Skipping” in Continuous Mode

The STM32F2xx DCMI control register DCMI_CR contains a couple of bits called FCRC to select which frames are grabbed. Clearing the bits means “grab all frames”, which is how I use the port.

However, I’ve found that despite this, the DCMI can appear to “skip frames”. Take a look at the following two oscilloscope captures. The top trace is a GPIO pin toggled at the start of the DCMI interrupt service routine. The middle trace is the image sensor frame sync pin, and the bottom trace is the image sensor clock pin. As you can plainly see, the first screenshot shows the DCMI triggering on every frame (as expected), where the second screenshot shows the DCMI triggering on every second frame (as you’d certainly not expect).

DCMI Capture All Frames

DCMI Skipping Frames

The difference between these two is a DCMI FIFO overflow. In the case of the first screenshot, the DMA controller is always taking the received data from the DCMI, so the DCMI internal FIFO never overflows. In the second case, the DMA is being turned off halfway through the frame, every second frame. This causes the STM32F2xx DCMI port FIFO to overflow and generate a DCMI error, badly enough to prevent it from generating an “end of frame” interrupt at the end of that frame. However it resets itself at the start of the next frame, which allows it to capture and complete the next frame normally. Then for the subsequent frame the DMA is turned off partway through and the cycle repeats itself.

This was rather unexpected. It seemed like a good idea, turning off the DMA controller once the necessary data was received to save on internal bus bandwidth. However it appears the DCMI peripheral doesn’t like this idea so much, because it doesn’t generate IT_FRAME interrupts properly when this happens. I have not yet had this DCMI behavior confirmed by ST, however it is clear and repeatable on my hardware. I will update this post if I receive any information from ST.

Depending upon the application, losing the IT_FRAME interrupt at the end of a corrupted or overflow frame may, or may not, be a problem. One way to work around this (ahem) “undocumented feature” is to also route the frame sync signal to a GPIO pin, and have the GPIO pin generate an interrupt at the end of each frame. That way you’re guaranteed a GPIO interrupt at the completion of every frame, even if you don’t receive the DCMI IT_FRAME interrupt.

STM32F2xx DCMI Overflow

In my working with the DCMI port I’ve found some other DCMI-overflow related behavior that’s worth mentioning, even though I can’t explain it entirely clearly.

In the second screenshot above, we see IT_FRAME interrupts being missed due to a periodic DCMI overflow, which in turn is caused by software turning off the DCMI’s DMA controller.

The DCMI port can generate an overflow interrupt, called IT_OVR. I tried enabling this interrupt, to see if I would get this interrupt for those frames which are missing the IT_FRAME interrupt. Turning on the IT_OVR interrupt (by setting the OVR_IE bit in the DCMI_IER register) was actually a bit of a disaster – I no longer received any IT_FRAME interrupts at all, and the DCMI port stopped receiving data. It effectively killed the system.

The behavior I saw was this. With both the FRAME and OVR interrupts enabled, initially (after powerup) the DCMI port worked fine, receiving data and passing it to the DMA. After 20 or 30 frames of data I triggered an overflow by momentarily turning off the DMA controller. This resulted in the IT_ OVR interrupt occuring and no IT_FRAME interrupt taking place. I expected this state of affairs to be brief. In fact what happened was the IT_OVR interrupt triggered continuously after that point, and the IT_FRAME never triggered again. Nothing I could dream up would clear the OVR overflow error – it always error’ed again on the next frame, and the next, etc. Even turning off the DCMI port and re-enabling it didn’t cure the problem. It took a reset of the STM32F2xx to have the DCMI port working normally again. This behavior happened even if the OVR interrupt service routine did nothing at all – not even clear the interrupt. Somehow, enabling that OVR interrupt causes the DCMI to behave differently than leaving that interrupt disabled.

I can’t rule out that there was something I was doing wrong, or strange. But for identical incoming DCMI data, if I didn’t enable the OVR interrupt, the DCMI port would recover from an overflow. But if I did enable the OVR interrupt, once an overflow occurred, the DCMI port appeared broken forever. Very strange.

For this reason, obviously, I don’t enable the OVR overflow interrupt – I simply pretend it doesn’t exist.

Other testing I performed, reading the status of the overflow bit in the DCMI port, indicated that the port seems to be tolerant of a certain amount of overflow. Either that or it’s a bit quick to set the flag. I found that even during normal DCMI operation, with the port receiving data and everything apparently going perfectly, the OVR bit could become set. But the DCMI port seemed to ignore it and just continue. I never saw any data corruption or missed data despite the bit being set. Of course forcing a “real” overflow, by momentarily disabling the DMA controller, would also set the OVR flag and in addition would usually cause the IT_FRAME for that particular frame to be skipped. But the subsequent frame would be OK again.

Long story short: don’t enable the overflow interrupt. And if you do, test it (by generating some overflows) very carefully to ensure you don’t end up in some apparently unrecoverable state.

That’s it for the DCMI – the next post will talk about the STM32F2xx SDIO SD Card interface.

31 thoughts on “STM32F2xx Digital Camera Interface (DCMI)

  1. Sukanya

    woah.. cool.. we are stuck with the problem that I mentioned since the last 2 weeks.. Unable to find out what could be the error since we have done our best possible corrections based on our study about dma..We get the data as 0 every time even though the image is getting captured! can you please send the complete code if you don’t mind to sukanyasurendrapai@gmail.com ??? so that we can cross check what might have possibly gone wrong…

  2. frank Post author

    I can tell you how I did it, but it’ll be different for every application and data type. I set aside 2 areas of RAM, call them buffers A and B. Then the DCMI DMA would be putting image data into buffer A. At the same time the SD Card DMA would be reading data from buffer B. Then flip – the DCMI DMA will be filling buffer B while the SD card DMA will be emptying buffer A. Then flip again. Etc. At the completion of each DMA transfer you get an interrupt so its easy to keep track of who’s doing what. That’s the general concept – exactly what you need to do for your application is up to you.

  3. Sukanya

    Hello.
    Please tell how did you use 2 DMAs? I mean Did you disable one and then used the other or enabled both the DMAs at the same time?? We are having problem in reading the data of the image captured by DCMI which ought to be stored in sd card after accessing the data. Please do help….

  4. Ranjan Hebbar

    yes, my doubt is how exactly did you extract the data from DMA and send through USART..?? I mean how did you access the stored data from first DMA to send through another….

  5. frank Post author

    It’s data from an image sensor, so it’ll fill the internal RAM of the processor pretty quick (unless you only take a single photo, at low resolution). Anyway, I had 2 DMAs running. One to get the data from the image sensor into internal RAM. And the second reading the data from RAM to send it out to an SD card.

  6. Ranjan Hebbar

    how did you store the image captured data in DMA?? After storing how do you access the stored data from DMA????

  7. frank Post author

    No, I haven’t. Although it’s been a while since I worked on that project, I did always get the data (unless of course the DMA stopped, but that was a different issue.)

  8. Gideon

    When I try to capture a jpeg from an OV5640 with the STM32F429, the first byte is missing. Have you seen anything like this?

  9. frank Post author

    It’s been a little while since I last used the part. But from what I recall, I think you’re right, you need to select either the rising or falling edge.

  10. Indiana

    Hi,
    Found your webpage searching for STM32F429 DCMI on google. Great content BTW, thanks for sharing your findings.
    I am having a little trouble using the DCMI port in a way that it wasn’t intended to! I’m trying to interface a CCD circuit using the DCMI, but if I understand the STM documentation, data can only be read in on either the rising or falling edge of the clock. Unfortunately the ADC’s writes the 16 bit data over the 8 bit bus on both the rising and falling edges. Am I correct in my understanding or can the DCMI be configured to read on both the rising and falling edges of the clock.
    Thanks for your help!

  11. AlVal

    About the data in JPEG, which are complemented with zeros …
    The fact that according to the specification of JPEG, Data may be equal to zero, were present only in conjunction “0xFF00” – and nothing else (“0xFF” accompanying “0x00” is a prefix, and how the data is ignored).
    Thus easy to distinguish significant 00 in the file (always in front of him is “0xFF”), and in ones’s complement of DCMI operations (in front of him there is no add-on “0xFF”)

  12. Trepidacious

    I’ve just been looking through the STM32F4 datasheet, and although the vsync/hsync values ARE backwards from what you might expect (e.g. HSPOL 1 should mean that data is valid when HSYNC is high), the reason for this IS actually more or less explained by this:

    “The HSYNC/VSYNC signals act like blanking signals since all the data received during HSYNC/VSYNC active periods are ignored.”

    So if HSYNC is “active” when it is 1, that means that “blanking” is active, and data is discarded. So it’s not so much that the HSPOL and VSPOL are backwards, more that the datasheet considers things in terms of which data is blanked, NOT which data is captured – that’s what makes it seem backwards… Presumably they should have called the signals HBLANK and VBLANK instead, but never mind 😉

  13. Trepidacious

    Minor update – I think I answered some of my own question on the DMA FIFO – slowing the pixel clock down from 33.6MHz to 8MHz removes the FIFO overruns. I still don’t know whether the data at 33.6MHz is valid despite the FIFO overruns, but it seems like it might be.

  14. Trepidacious

    Thanks for the very useful information, it’s great to have some of the weird issues set out clearly so I can avoid them! I did have a few questions (apologies for the lengthy post!):

    I noticed you said that there aren’t many Cortex MCUs with a camera input port – do you know of any apart from the STM32F2/4 lines? I can’t find anything else with a usable port (or that comes close to the price/performance ratio, even if that seems to be at the cost of some weird behaviour and patchy STM example code!)

    I was also wondering whether you had mentioned the OVR interrupt thing to STM? I noticed you got something back from them in the end on the odd DMA2 behaviour, it might be very useful to get the official line on what is up with OVR. I was trying to work out a bulletproof way to detect when there might be something wrong with a received frame (non-compressed), and the best I can come up with is to assume that if I use the DCMI snapshot mode to trigger just one frame, and the exact right amount of data makes it through the DMA, the frame is definitely good. If this doesn’t happen within a wall-clock timeout, the frame may be (almost certainly is) bad, and so I can ignore any data received and start another frame. I’m not one hundred percent certain though that just receiving the right amount of data implies that the data is all good. I do think this is likely, since the data sheet says that a DCMI fifo overflow will cause the frame to abort.

    Finally, I’ve had some odd behaviour with DMA interrupts transferring from the DCMI, where I get valid TCIF interrupts as expected, but also some additional DMA FIFO interrupts – have you seen anything like this? I assume that because the frame doesn’t abort (and I don’t see OVR interrupts), that the DCMI FIFO has not overflowed, but it seems a little bit worrying that the DMA FIFO is apparently overrunning! However I’m still confused about the DMA interrupts, I seem to get them even when I only enable TCIF interrupts, which seems very odd.

  15. frank Post author

    Post your question over at the STM32 forums – you’re far more likely to get help with your board over there.

  16. Nakul

    I am using the stm3240g eval board. I tried to get images in the Jpeg mode. but instead of getting 320×240 I am getting very low resolutions. I store the picture on the sd card and view the image on my laptop. Haven’t introduced any file system. so i use the HxD hex reader and RGB565 Converter. INitially I had used that converter for rgb565 images from the same board and on trying it worked for jpeg images also. but instead of 320×240 I get around 160×80. any ideas?

  17. Michael

    Fantastic info. I’ve been toying with cameras here and there, now I am eager to try using an STM32 and the DCMI port. Will no doubt be back with questions. 😀

  18. frank Post author

    Yes, you can use a DMA controller or simple code (read then write). Of course what you do with the data is a whole other story and completely up to you.

  19. John Chichvarin

    Good evening. Got a question here, If it is posible to redirect the data flow from dcmi to Sd-card some way?
    or use it as a buffer? thanks in advance.

  20. frank Post author

    I don’t have any magic solutions – the pin mappings on these parts can get tricky, and for some packages certain functions may only be available on one pin. Which is the case here. You might want to think about using a small knife to, very carefully, cut those problem traces. Alternatively, if you have access to it, use a hot air desoldering station to remove the chips (like the CS43L22) that might cause a conflict. If you haven’t done so already, posting your question over at the STM32F4Discovery forum might also be an idea. Good luck!

  21. swenson

    Do you know if DCMI be used on the STM32F4Discovery board? It appears that there are pin conflicts that make it impossible.

    PA4 – DCMI_HSYNC conflicts with CS43L22 – LRCK/AN1x
    PA6 – DCMI_PIXCLK conflicts with LIS302DL – SDO
    PB6 – DCMI_D5 conflicts with CS43L22 – SCL
    PC7 – DCM!_D1 conflicts with CS43L22 – MCLK

    The STM3240G-EVAL board appears to use the H and I pins to avoid these conflicts.

    Any comments or suggestions? Thanks.

  22. frank Post author

    A lot of CMOS sensors are compatible with the DCMI. The DCMI is a pretty flexible port. You’ll need to read the documentation (datasheets etc) for both the DCMI and the sensor you’re interested in to confirm they’re compatible with each other. There’s no avoiding the reading – you’ll need to do it (in great detail) to program the DCMI and image sensor anyway. I looked at the product brief for the OV7670 and at first glance, it looks like it might be ok – I didn’t see any immediate obvious problem. Take a look at some of ST’s reference designs, for example the STM3240G-EVAL board, for sample schematics on how to connect up an image sensor.

  23. nikitas

    “I’m using the STM32F2xx DCMI port to receive data from an CMOS image sensor.”

    What kind of cameras are compatible with dcmi? and how i can find them, I cant seem to find any info!
    Is the OV7670 VGA Camera Module compatible?

  24. frank Post author

    If you’re already building for the F1xx parts then there’s nothing you need to do from a compiler point of view to support the F2x parts. They’re both Cortex-M3 parts and that’s all the compiler needs to know about. It’s entirely possible your makefile doesn’t need to change at all. You may want to include the F2x versions of whatever files you might be using from the ST standard library, but that’s nothing more than a simple rename. If you’re afraid of touching a makefile, there’s no substitute for learning. Most makefiles are fairly simple things – the main thing to watch out for is the use of the TAB character. Google will find you any number of makefile tutorials. Good luck!

  25. Sergarro

    Thanks a lot frank for the information!!
    I have used Yagarto + Eclipse to program and debug STM32F1xx series (OLIMEX USB-TINY-H as debugger). However, I use to start my projects from some example (i.e. from Yagarto´s web) reason why the modifications over the makefile are minimal.
    Unfortunately, I could not find any example to use the STM32F207 with Yagarto and I don´t have solid knowledges to build from scratch my own makefile. In resume, could you include in some post any details about how to define the makefile to compile and link the code, or maybe, could you attached some example project?

    Again, thanks a lot frank!!!

  26. frank Post author

    You’re right – simple but not trivial!

    I’m a fan of the GNU toolchain. So for the compiler / linker / etc I’ve been flipping between Yagarto and Sourcery G++ Lite. Right now I’m using Yagarto, but not long ago I was using G++, and to be honest I haven’t noticed much if any real difference between the two. For an IDE I’ve been using Programmers Notepad. This is the point where everyone can start yelling “Programmers Notepad isn’t a real IDE!”. That may be true, but it’s real enough to me, and it gets the job done. It’s easy enough to call a makefile from the Tools menu, and it has plenty of nice editing features. Eclipse is more full-featured and apparently it even has a makefile generator; perhaps at some point I’ll give Eclipse a go. Programming of the STMs is done using a ST-Link.

  27. Sergarro

    Hi Frank,
    Just I simple but not trivial question 🙂
    Wich IDE are you using to compile and debug your nice projects?
    Thanks a lot!!!

Leave a Reply

Your email address will not be published. Required fields are marked *