Writable USB Flash Filesystem

When CircuitPython starts up, the internal flash filesystem is read only. If you want to save bitmaps or screenshots to it, you must remount it as writable:

Download: file
    import storage
     
    storage.remount("/", False)

The catch is that it can only be writable by the MCU or USB. The common solution to this is to check an input to see which should be able to write it. Something like:

Download: file
    import board
    import digitalio
    import storage
     
    switch = digitalio.DigitalInOut(board.D0)
    switch.direction = digitalio.Direction.INPUT
    switch.pull = digitalio.Pull.UP
     
    # If the D0 is connected to ground with a wire
    # CircuitPython can write to the drive
    storage.remount("/", switch.value)

SD Card Support

Setting up the SD card for use is shown below. From then on files can be saved to files in the /sd directory.

Download: file
import board
import digitalio
import busio
import adafruit_sdcard
import storage

spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.SD_CS)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

Taking a Screenshot

This can be as simple as importing the library and calling the save_pixels() function with an argument of either a file object or an absolute filename. The example below configures the SD card support and saves a screenshot onto the card.

If a file object is passed, it is written to. If a filename is passed, the named file is opened for writing and written to. In either case, the file is closed once the screenshot has been written.

Download: file
import board
import digitalio
import busio
import adafruit_sdcard
import storage
from adafruit_bitmapsaver import save_pixels

spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.SD_CS)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

print('Taking Screenshot...')
save_pixels('/sd/screenshot.bmp')
print('Screenshot taken')

Handling rotation

A wrinkle with taking screenshots is that some boards use a rotated buffer and some don't. The library takes this into account. On some boards, e.g. the PyPortal, the screenshot will be oriented as expected (shown at the top of this page).

However, on some otherboards, e.g. the PyGamer, it will be rotated 90 degrees. This can be correctly with any image editing software.

Saving a Bitmap

Saving a bitmap is only slightly more involved than saving a screenshot.

A file or filename is passed and used in the same way.

Since this saves the contents of a Bitmap object and not the contents of the screen, that Bitmap must be passed as well. Furthermore, Bitmaps don't contain the actual 24-bit color that ends up on the screen. Instead, they contain indecies into a Palette. The result of this is a dramatic memory savings, but at the cost of an additional step between the bitmap and the screen. The practical result of this is that the associated displayio.Palette object must be passed along with the bitmap.

Consider the PyPaint project found in this guide. The ability to save the painting can be added with a few lines, essentially:

Download: file
from adafruit_bitmapsaver import save_pixels
.
.
.
save_pixels('/sd/pypaint.bmp', self._fg_bitmap, self._fg_palette)

Because saving a PyPortal sized bitmap blocks other code from running and takes a noticeable amount of time, it can be useful to display a message to the user while the saving is taking place.

This results in a BMP file as shown below:

This guide was first published on Sep 03, 2019. It was last updated on Sep 03, 2019. This page (Use) was last updated on Jan 11, 2020.