Using CircuitPython on an Arduino Nano RP2040 Connect to capture a still image from an Arducam Mini 2MP and store it locally

  1. Where did you get the camera module(s)?
    PiHut, UK
  2. Model number of the product(s)?
    B0067 Mini 2MP Plus - OV2640
  3. What hardware/platform were you working on?
    Arduino Nano RP2040 Connect, PC, Thonny
  4. Instructions you have followed. (link/manual/etc.)
    ArduCAM_Mini_2MP_Plus_VideoStreaming
  5. Problems you were having?
    Converting the code to store the image locally in a readable format
  6. The dmesg log from your hardware?
    No error messages
  7. Troubleshooting attempts you’ve made?
    See attached code
  8. What help do you need?
    Hi, so I’ve adapted the Arducam.py library file to hook up to the Nano and get the video streaming example to work: great, no hardware issues. I’ve then copied the code in this example to write the buffer to the device locally as I want to send the image in a POST request (as the Nano has wifi). I’m able to write the files as bytes or encoded (to add to a JSON payload) however what gets finally output can’t be read by a jpeg reader and the .txt version looks very different in anatomy to other encoded jpeg’s. I think I’m very close - I need help with constructing the file with whatever headers etc are needed? If anybody has a simple version of writing an image in circuitpython locally that’d be mighty useful. thanks?

Code used (note that a boot.py file is also used to remount the flash on the board to be writable)


import time 
import busio
import board
from digitalio import DigitalInOut
from Arducam import * # requires Arducam files to be in same dir as 'code': Arducam.py, ov2640_reg.py (& ov5642_reg.py)
import circuitpython_base64 as b64 # requires package install of: circuitpython-base64

# Set up Cam board
mycam = ArducamClass(OV2640)
mycam.Camera_Detection()
mycam.Spi_Test()
mycam.Camera_Init()
time.sleep(1)
mycam.OV2640_set_JPEG_size(OV2640_160x120)
mycam.set_format(JPEG)

# Create files to write into
with open('/test.jpg', 'wb'):
    pass
with open('/test.txt', 'wt'):
    pass

# Save a jpg to file ready to go in a JSON payload
def get_still(mycam):
  
    mycam.flush_fifo()
    mycam.clear_fifo_flag()
    mycam.start_capture()
    once_number = 128
    buffer=bytearray(once_number)
    count = 0
    finished = 0
    length = mycam.read_fifo_length()
    mycam.SPI_CS_LOW()
    mycam.set_fifo_burst()
    
    
    while finished == 0:
        mycam.spi.readinto(buffer, start=0, end=once_number)
        print(str(count) + ' of ' + str(length))
        buffer_txt = b64.encodebytes(buffer)
        print(buffer_txt[:20])
        with open('/test.jpg', 'ab') as fj:
            fj.write(buffer)
        with open('/test.txt', 'at') as ft:
            ft.write(buffer_txt)
        count += once_number
        
        if count + once_number > length:
            print(str(count) + ' of ' + str(length))
            count = length - count
            mycam.spi.readinto(buffer, start=0, end=count)
            buffer_txt = b64.encodebytes(buffer)
            print(buffer_txt[:20])
            with open('/test.jpg', 'ab') as fj:
                fj.write(buffer)
            with open('/test.txt', 'at') as ft:
                ft.write(buffer_txt)
            mycam.SPI_CS_HIGH()
            finished = 1
   
 
def main():
    get_still(mycam)
    print('Finished!')

if __name__ == '__main__':
    main()

Update: it looks like it just needed to be told when to start the fifo_burst that was in the original code.

I still need to figure out how to get it off the Nano via a POST request. The decoded txt file this appending creates doesn’t load as a jpg once off board but I suppose that’s now not an Arducam question!

Refactored code:

import time 
import busio
import board
from digitalio import DigitalInOut
from Arducam import * # requires Arducam files to be in same dir as 'code': Arducam.py, ov2640_reg.py (& ov5642_reg.py)
import circuitpython_base64 as b64 # requires package install of: circuitpython-base64


# Create files to write into
with open('/test.jpg', 'wb'):
    pass
with open('/test.txt', 'wt'):
    pass

# Set up Cam board
mycam = ArducamClass(OV2640)
mycam.Camera_Detection()
mycam.Spi_Test()
mycam.Camera_Init()
time.sleep(1)
mycam.set_format(JPEG)
mycam.OV2640_set_JPEG_size(OV2640_160x120)


# Save a jpg to file ready to go in a JSON payload
def get_still(mycam):
    once_number = 128
    buffer=bytearray(once_number)
    count = 0
    finished = 0
    length = mycam.read_fifo_length()
    mycam.SPI_CS_LOW()
    mycam.set_fifo_burst()

    while finished == 0:
        mycam.spi.readinto(buffer, start=0, end=once_number)
        print(str(count) + ' of ' + str(length))
        buffer_txt = b64.encodebytes(buffer)
        print(buffer_txt[:20])
        with open('/test.jpg', 'ab') as fj:
            fj.write(buffer)
        with open('/test.txt', 'at') as ft:
            ft.write(buffer_txt)
        count += once_number
        
        if count + once_number > length:
            print(str(count) + ' of ' + str(length))
            count = length - count
            mycam.spi.readinto(buffer, start=0, end=count)
            buffer_txt = b64.encodebytes(buffer)
            print(buffer_txt[:20])
            with open('/test.jpg', 'ab') as fj:
                fj.write(buffer)
            with open('/test.txt', 'at') as ft:
                ft.write(buffer_txt)
            mycam.SPI_CS_HIGH()
            mycam.clear_fifo_flag()
            finished = 1
            return finished
   
 
def main():
    mycam.flush_fifo()
    mycam.clear_fifo_flag()
    mycam.start_capture()
    finished = 0
    while finished == 0:
        if mycam.get_bit(ARDUCHIP_TRIG,CAP_DONE_MASK)!=0:
            finished = get_still(mycam)
    print('Finished!')

if __name__ == '__main__':
    main()