ArduCam have put together some really great products! The Arduino-based C libraries are extensive and easy to use. Being the Pico fans we are we decided to put together a basic camera driver for Raspberry Pi Pico - how hard could it be!?

Transcript

Hey, we're back in the factory except not actually in the factory, we're in the Makerverse studio because I'm joined by Liam today. We're going to talk about these little cameras. What can you tell us about the cameras Liam?

Okay, so these are the new ArduCam Mega cameras. They're made for microcontrollers and they run from SPI and yeah I've been cracking on a driver for these for about the past week. So ArduCam distribute these cameras with Arduino drivers, very nice Arduino drivers and you know they were kind of fanboys for the Raspberry Pi Pico and so all the examples for these cameras are running on Pico but on Arduino only. You have to be running C++ Arduino core which is super good enough right but we we've been putting a lot of work into MicroPython. Liam's working very diligently on getting a MicroPython driver working for these cameras and these are no joke. These are what are these like five megapixels? Yeah, five megapixels, range of different modes, very versatile cameras.

Cool, cameras have just kind of exploded with microcontrollers recently. What makes them hard and why are we going down this route?

So for the Raspberry Pi that uses the CSI connector and the base protocol for that is MIPI. They clock data out very fast at about 1.5 gigabits per second. That's pretty wild. Very fast, way too fast for a microcontroller. So yeah there's some other ones that have been running they use SPI and I2C but they're not as versatile as the Mega here. So this is kind of the first camera that's hit that uses just one protocol and has a nice range of features.

Right so this is using SPI right?

Yeah, just SPI. So it's SPI so it's kind of it's super good enough for low to medium resolution like up to about five megapixel.How long does it take to get a photo out of this thing? So the photo is just about instant. There's an IC on board that captures the photo, does some pre-processing into an RGB or a JPEG format and then we can read all of that off the SPI bus. That takes about three seconds for that read depending on the file size.

Okay so it takes three seconds to clock out a whole image. Whole 20 kilobyte photo. Well let's see a hardware demo. All right we've got it all plugged in wired up. We've got the main.py here that'll take the photo. So we'll run this. You can see that it started. All we have to do now is press the photo, press the button, we'll take a photo.

That's it? That's it. Now it's just clocking away all of those bytes into our Pico's flash. Right so it's buffering them over over SPI and this is about as fast as it'll go? Probably get a little bit faster. So this is using a single byte read though. It's a prototype. Oh we're only reading single bytes at a time. Right okay we can we can probably improve that. Reset the file system. Download our photo. Now we go.

Oh that's nice. That actually you know that looks pretty good. That's not bad. Really good especially through a microcontroller. I think we need to fix that ceiling tile.

For someone that's never done it before what does it take to write a driver at home? If someone wanted to go ahead and do this by themselves what are the steps? Because it's a pretty intimidating thing right? Very intimidating yeah. So I started out just by collecting all of my resources where I had to look through the rgcam documentation, through the data sheet that they provided, through their driver, just trying to understand the general flow. So I started trying to adapt all of that andThen it kind of got to the point where it's really hard to see what's happening. So opened up the Salier, got that software running and we were able to reverse engineer the protocol by having a look at the different SPI transfers. Yeah the transactions. Yeah transactions that's a word.

So what does that look like? We've opened up the C driver and these are always pretty intimidating to look at but big problems are just lots of small problems and when you're starting with a device like this you pretty much just want to get to the point where you're copying the same setup that an existing driver does.

So when you were putting this to MicroPython how did you get started in just getting something out of this black box? So I noticed that there was a heartbeat. This wait I2C idle that's actually an archive function from another project so I just tried to get that working. So yeah this is the reference that I used for just about the entire project. So this what they this appears many times in like in between transactions and so this is kind of like your milestone marker between each phase.

Great so you start by finding some milestones like this wait and that's presumably scattered in between various steps. So in general with peripherals there's like a setup phase and an activity phase or like you know you set it up with say the resolution or the mode and then after that you're basically just running the device you're saying hey give me pictures. Basically just plug the logic analyzer in and we can see all those transactions taking place. It should be no different between the Arduino and the MicroPython driver.

All right so taking a look at the logic capture here we've got a few different events. So before the Arduino driverDid anything? It initialized a reset. So here we've got this register and it's trying to send to register 87. They're setting this for zero code, that's all in hex, and that just tries to reset the camera. So yeah, here's the wait idle command. It's looking for a change in this bit here. And so this is what we saw before where it's just constantly constantly pulling that message. Yep, and you can see there's lots of these commands in quick succession.

So we've got at start up , we have where do we start doing some config? Right over here. And so is this all copied essentially byte for byte into our new MicroPython driver? Essentially yeah. And so we're just taking that example and extracting out obviously the Arduino driver is setting it up for a certain way and so where we're first copying that but then we have to extract out the bits that we can play with. I'm imagining, you know, things like resolution or capture mode, right? We have to kind of develop those changes now based off what we can gather from here.

Yeah, so just interpreting the three things basically. We've got the Arduino driver, the MicroPython port that we're still trying to work with, and the Salier capture. So how do you, I mean, how do you even interpret what you're looking at here? So we use a timing table and there's a reference as well. Right, so here we've got some timing diagrams for just like bus activity. And this was the real kicker. So there's actually a dummy frame in between the transactions. So that got me pretty good. Every single frame has a dummy byte. That's interesting. In so that like the data sheet is telling you one thing like, oh, load this register with this value, but every single time there's like an interruption.Extra byte just there. Yeah. And you can't and the meaning is only documented in that image. Yeah. I guess you know they've done they've got it right there. They did their best. It's it is it is in the manual. It's it's really easy to overlook these timing diagrams especially when you're familiar with the protocol. Like I know when when I have used I2C a lot you see a lot of these same diagrams in the data sheets. Yeah. But but there's you know every now and again there's like a little edge case like a write often has to go to like the same right. You can't read and write from the same register. You have to write to the same register with like the eighth bit set or something. And it's just completely if you didn't look at the timing diagram you would have missed it. But once you've seen a few of them and they all kind of look the same you kind of stop looking. So it's it can be a bit of a trap to just like cruise past these especially when you've had a bit of experience and you kind of may know maybe get lazy.

But so and where do you where do you get the meaning of the registers like that that's going to be in a data sheet or something right. Even in the Arduino code is like the best place because this is real. This is what's really going on. Yeah. So I've basically just copied across all of these registers and bits up here. It's just been pulled across into MicroPython.

So if initialize the camera what what do we do to read an image. So we're ready we're ready. Oh yeah there it is. And it's changed to two six. Two six. We've got a photo. We know there's something on the camera but now we need to know how big that is. So it's just taking like the X Y dimensions of the camera laying it flat.And that's the number of frames that you need to read out. So there's an actual register on here that tells you the size of the file. Oh, because it's padded with JPEG information and stuff like that. So it's actually the number of bytes, I suppose. Yeah. Cool.

Yeah, there are a few different file formats that the camera can output. So we start reading out the image here. We've got a 3D and there's a bunch of different seemingly random outputs from the camera. And that continues. But it's actually our image. Right. So all very cool.

And so then we just have these massive block reads. Happy days getting the heartbeat out setting the config. Well, that was really good. But this was the first photo that came out of the camera. And it's green. Why is it green? This was the biggest gotcha.

So the camera has a white balance algorithm running on the inside of it. Yeah. In its own little dedicated IC undocumented outside of that one delay in the example code. Right. So in the Arduino source, there's just a delay, like what, a quarter of a second, just in there somewhere with no comment. No comment. It's just delay MS 500.

And so that kind of implies that after you've initialized the camera, the auto white balance needs to do its thing. So this. Yeah. So if the delay were on this image, it would actually look just fine. All the colors would be fine. It wouldn't be grainy. It wouldn't look like Kermit. There it is.

Oh, and just like the big boys, we've left our delay completely undocumented as well. We should fix that. Yeah. And is this then the result that you get when you insert that delay? Yeah. And so it's super good enough. You can get pictures out of it. What do we need to do?From here, making sure that the modes resolutions can be set. There's a bunch of other behind the scenes stuff like contrast brightness. That'd be good to be able to alter just like the Arduino driver.

So if you feel like contributing to this little project, we have the current state on GitHub. This captures, this is about as behind the scenes as it gets. Hey, this is, you know, we're still, we're still working just in a single file. So we have our camera class defined and we just go ham at it, and then right down the bottom of the file is the test code. So we're still very, very much in development.

But we feel like this is just too good to miss out on, especially if you want to move quickly. If you're a maker and you want to get started with using these cameras in MicroPython, we want you to be able to use this right away in whatever state of development we can get it to, and it's open source. If you feel like contributing yourself, you're more than welcome to open a pull request.

So it's, of course, it's still early days, like this driver is so heavy in development, but it's super good enough. You can get a picture out of it for now. And if that's all you want to do, it's ready to go. So grab the code, grab the camera, and have a play. If you feel like contributing to the project as well, please open a pull request. The repo is public, so you're welcome to grab that code and use and abuse as you see fit.

Until next time, thanks for watching and happy making.

Comments


Loading...
Feedback

Please continue if you would like to leave feedback for any of these topics:

  • Website features/issues
  • Content errors/improvements
  • Missing products/categories
  • Product assignments to categories
  • Search results relevance

For all other inquiries (orders status, stock levels, etc), please contact our support team for quick assistance.

Note: click continue and a draft email will be opened to edit. If you don't have an email client on your device, then send a message via the chat icon on the bottom left of our website.

Makers love reviews as much as you do, please follow this link to review the products you have purchased.