In this guide, we’ll show you how to interface a microSD card with the Raspberry Pi Pico, how to create, write, read, and delete files, and we’ll also create a datalogging project example. The Raspberry Pi Pico will be programmed using MicroPython.
Using a microSD card can be useful in different scenarios. For example, to log a large amount of data over an extended period.
Additionally, you can easily extract the card from the microcontroller and transfer the data to another system for later analysis.
It might also be useful to save configuration files that need to be changed occasionally, without the need to modify the code running on the Raspberry Pi Pico.
Table of Contents:
In this tutorial, we’ll cover the following topics:
- Introducing the MicroSD Card Module
- MicroSD Card Module Pinout – SPI Communication
- Uploading the sdcard.py Module
- Testing the MicroSD Card
- Create, Write, and Read Files on a MicroSD Card
- Deleting Files
- Datalogging Temperature to the MicroSD Card
Prerequisites – MicroPython Firmware
To follow this tutorial you need MicroPython firmware installed in your Raspberry Pi Pico board. You also need an IDE to write and upload the code to your board.
The recommended MicroPython IDE for the Raspberry Pi Pico is Thonny IDE. Follow the next tutorial to learn how to install Thonny IDE, flash MicroPython firmware, and upload code to the board.
Introducing the MicroSD Card Module
The easiest way to interface a microSD card with a microcontroller is by using a microSD card module. These modules typically include all the necessary components like voltage regulators, level shifters, and pull-up resistors, making it easier to connect the microSD card to a microcontroller.
You can communicate with the microSD card using SPI or SDMMC protocols. SDMMC protocol is usually faster than SPI, but requires more GPIOs and is usually more complex. At the moment, there isn’t great support for SDMMC communication with the Raspberry Pi Pico. So, we’ll prioritize using SPI protocol with the microSD card.
There are different microSD card modules compatible with the Raspberry Pi Pico. We’re using the microSD card module shown in the figure above—it communicates using SPI communication protocol. You can use any other microSD card module with an SPI interface. Some microSD card modules even support both SPI and SDMMC protocols.
Parts Required
For this tutorial, you’ll need the following parts:
- Raspberry Pi Pico
- MicroSD card module
- MicroSD card that can be formatted as FAT32
- Breadboard
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
MicroSD Card Module Pinout – SPI Communication
You can wire the microSD card to any combination of Raspberry Pi Pico SPI pins. We’ll use the pins shown in the following table.
MicroSD Card Module | Raspberry Pi Pico |
3V3* | 3V3(OUT) |
CS | GPIO 5 |
MOSI (TX) | GPIO 3 |
CLK/SCK | GPIO 2 |
MISO (RX) | GPIO 4 |
GND | GND |
* The microSD card module we’re using only requires 3V3. Some modules might need 5V. In that case, you need to power them using the VBUS pin.
You can also use the following schematic diagram as a reference.
Formatting the MicroSD Card
Before proceeding with the tutorial, make sure you format your microSD card as FAT32. Follow the next instructions to format your microSD card or use a software tool like SD Card Formatter (compatible with Windows and Mac OS).
1. Insert the microSD card into your computer. Go to My Computer and right-click on the SD card. Select Format… as shown in the figure below.
2. A new window pops up. Select FAT32, press Start to initialize the formatting process, and follow the onscreen instructions. After a few seconds, the process will be completed.
Uploading the sdcard.py Module
At the moment, there isn’t much support in terms of libraries to use the microSD card with the Raspberry Pi Pico. We’ve found the sdcard.py module that seems to work just fine to handle files on the microSD card. Follow the next steps to install the library.
- Click here to download the sdcard.py library code.
- Create a new file in Thonny IDE and copy the library code.
- Go to File > Save as and select Raspberry Pi Pico.
- Name the file sdcard.py and click OK to save the file on the Raspberry Pi Pico.
And that’s it. The library was uploaded to your board. Now, you can use the library functionalities in your code by importing the library.
Testing the MicroSD Card
Upload the following code to your Raspberry Pi Pico to check if it can communicate with the microSD card.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-microsd-card-micropython/
from machine import SPI, Pin
import sdcard, os
# Constants
SPI_BUS = 0
SCK_PIN = 2
MOSI_PIN = 3
MISO_PIN = 4
CS_PIN = 5
SD_MOUNT_PATH = '/sd'
try:
# Init SPI communication
spi = SPI(SPI_BUS,sck=Pin(SCK_PIN), mosi=Pin(MOSI_PIN), miso=Pin(MISO_PIN))
cs = Pin(CS_PIN)
sd = sdcard.SDCard(spi, cs)
# Mount microSD card
os.mount(sd, SD_MOUNT_PATH)
# List files on the microSD card
print(os.listdir(SD_MOUNT_PATH))
except Exception as e:
print('An error occurred:', e)
The previous code starts SPI communication on the pins that the microSD card is connected to, tries to mount the microSD card, and then, tries to list the files there.
If you’re using different SPI pins, you should modify the code accordingly. Also notice that depending on the pins used, you might need to change the SPI bus. On the Raspberry Pi Pico pinout, you can see which pins are on SPI bus 1 or 0.
SPI_BUS = 0
SCK_PIN = 2
MOSI_PIN = 3
MISO_PIN = 4
CS_PIN = 5
Related content: Raspberry Pi Pico and Pico W Pinout Guide: GPIOs Explained
Testing the Code
Run the previous code on your Raspberry Pi Pico by clicking on the Thonny IDE run green button.
You should get a similar message on the Shell (see the screenshot below). If that’s the case, it means everything is working as expected. If not, check the wiring, if the microSD card is properly inserted, and if you’re using the right SPI Bus number for the pins you’re using.
Create, Write, and Read Files on a MicroSD Card
Now that you know that the Raspberry Pi Pico is properly connected to the microSD card, let’s test some basic file operations.
The following code mounts the microSD card, creates a new file, writes to it, and then reads its content.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-microsd-card-micropython/
from machine import SPI, Pin
import sdcard, os
# Constants
SPI_BUS = 0
SCK_PIN = 2
MOSI_PIN = 3
MISO_PIN = 4
CS_PIN = 5
SD_MOUNT_PATH = '/sd'
FILE_PATH = 'sd/sd_file.txt'
try:
# Init SPI communication
spi = SPI(SPI_BUS,sck=Pin(SCK_PIN), mosi=Pin(MOSI_PIN), miso=Pin(MISO_PIN))
cs = Pin(CS_PIN)
sd = sdcard.SDCard(spi, cs)
# Mount microSD card
os.mount(sd, SD_MOUNT_PATH)
# List files on the microSD card
print(os.listdir(SD_MOUNT_PATH))
# Create new file on the microSD card
with open(FILE_PATH, "w") as file:
# Write to the file
file.write("Testing microSD Card \n")
# Check that the file was created:
print(os.listdir(SD_MOUNT_PATH))
# Open the file in reading mode
with open(FILE_PATH, "r") as file:
# read the file content
content = file.read()
print("File content:", content)
except Exception as e:
print('An error occurred:', e)
How the Code Works
First, import the required modules and classes. We need to import SPI and Pin classes from the machine module, the os module to use operations on the filesystem, and the sdcard to interact with the microSD card.
from machine import SPI, Pin
import sdcard, os
The os module
In MicroPython, there’s a module called os that includes a wide range of functions to manage file operations. Additionally, it also comes with methods for tasks like managing directories, accessing environment variables, and executing system commands. The os module comes included by default on MicroPython firmware. More details about the os module can be found here.
Define the SD card pins and SPI bus number you’re using on the following lines.
SPI_BUS = 0
SCK_PIN = 2
MOSI_PIN = 3
MISO_PIN = 4
CS_PIN = 5
Create variables to hold the SD card path and the file path that we’ll create.
SD_MOUNT_PATH = '/sd'
FILE_PATH = 'sd/sd_file.txt'
Then, initialize SPI communication and mount the microSD card.
try:
# Init SPI communication
spi = SPI(SPI_BUS,sck=Pin(SCK_PIN), mosi=Pin(MOSI_PIN), miso=Pin(MISO_PIN))
cs = Pin(CS_PIN)
sd = sdcard.SDCard(spi, cs)
# Mount microSD card
os.mount(sd, SD_MOUNT_PATH)
List all files on the SD card filesystem.
# List files on the microSD card
print(os.listdir(SD_MOUNT_PATH))
Creating a File
Creating a file in MicroPython is as easy as using the open() function and passing as argument the filename and the file opening mode. The open() function will open the file if it already exists, or it will create a new file if it doesn’t.
The different modes for opening a file are ‘w’, ‘r’, and ‘a’:
- ‘w’: writing mode — allows writing to a file, overwriting existing content;
- ‘r’: reading mode — enables reading from an existing file;
- ‘a’: appending mode — appending new data to the end of an existing file.
To create a new file, we can use the writing mode (‘w’). The following line of code will create a new file on the Raspberry Pi Pico filesystem using the open() method. The file is called sd_file.txt (defined previously on the FILE_PATH variable), but you can rename it to whatever you want.
# Create new file on the microSD card
with open(FILE_PATH, "w") as file:
The ‘with’ Keyword for File Operations
The with keyword is used in conjunction with file operations to ensure proper handling of resources and to simplify code. Specifically, it’s often used with the open() function when dealing with files.
with open(FILE_PATH, "w") as file:
This syntax automatically handles opening and closing the file, ensuring that the file is properly closed when you’re done with it, even if an exception occurs during file operations.
Writing to the File
Writing to a file is very straightforward. You just need to use the write() method on the file object and pass as argument the data you want to write (it must be a string). In our example:
with open(FILE_PATH, "w") as file:
# Write to the file
file.write("Testing microSD Card \n")
The Newline Character
In the previous code, notice that we use a \n at the end of our first line:
file.write("Writing my first line \n")
In Python/MicroPython, the \n represents a newline character. It is used to represent the end of a line in a text file. It is a control character that signifies the beginning of a new line of text. When working with files, the newline character is useful for formatting text. When writing multiple lines to a file, you use \n to separate each line.
Reading a File
After writing to the file, let’s open it in reading mode to check that it was actually written. To read the file, use the read() method as follows.
# Open the file in reading mode
with open(FILE_PATH, "r") as file:
# read the file content
content = file.read()
print("File content:", content)
Testing the Code
Run the previous code on your Raspberry Pi Pico. You should get a similar message on the Shell.
The first line means that there aren’t any files on the microSD card filesystem. The second line shows the file we created with the code called sd_file.txt. Finally, the last line shows the contents of the sd_file.txt file.
Deleting Files
Deleting a file on the microSD card is as easy as using the command os.remove() and passing as an argument the file path.
For example, you can simply add the following line to the previous example to delete the sd_file.txt.
# Delete file from the microSD card
os.remove(FILE_PATH)
The complete code can be found below:
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-microsd-card-micropython/
from machine import SPI, Pin
import sdcard, os
# Constants
SPI_BUS = 0
SCK_PIN = 2
MOSI_PIN = 3
MISO_PIN = 4
CS_PIN = 5
SD_MOUNT_PATH = '/sd'
FILE_PATH = 'sd/sd_file.txt'
try:
# Init SPI communication
spi = SPI(SPI_BUS,sck=Pin(SCK_PIN), mosi=Pin(MOSI_PIN), miso=Pin(MISO_PIN))
cs = Pin(CS_PIN)
sd = sdcard.SDCard(spi, cs)
# Mount microSD card
os.mount(sd, SD_MOUNT_PATH)
# List files on the microSD card
print(os.listdir(SD_MOUNT_PATH))
# Create new file on the microSD card
with open(FILE_PATH, "w") as file:
# Write to the file
file.write("Testing microSD Card \n")
# Check that the file was created:
print(os.listdir(SD_MOUNT_PATH))
# Open the file in reading mode
with open(FILE_PATH, "r") as file:
# read the file content
content = file.read()
print("File content:", content)
# Delete file from the microSD card
os.remove(FILE_PATH)
# Check that the file was deleted
print(os.listdir(SD_MOUNT_PATH))
except Exception as e:
print('An error occurred:', e)
We also list the contents of the microSD card again to make sure the file was removed.
Testing the Code
Run the previous code on your Raspberry Pi. You should see that the microSD card filesystem is empty in the end. It means we successfully removed the sd_file.txt file.
Datalogging Temperature to the MicroSD Card
Datalogging to the microSD card with the Raspberry Pi Pico is simple. You just need to mount the microSD card, and then, use the right file paths to create files and save the data.
To show you how it’s done, we’ll create a simple project that saves the Raspberry Pi Pico internal temperature to the microSD card every 30 seconds. Note that you need the picozero package installed on your board (check this tutorial).
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-microsd-card-micropython/
from time import sleep
from machine import Timer, SPI, Pin
from picozero import pico_temp_sensor
import sdcard, os
# Constants
SPI_BUS = 0
SCK_PIN = 2
MOSI_PIN = 3
MISO_PIN = 4
CS_PIN = 5
SD_MOUNT_PATH = '/sd'
FILE_PATH = '/sd/temperature.txt'
# Init SPI communication
spi = SPI(SPI_BUS, sck=Pin(SCK_PIN), mosi=Pin(MOSI_PIN), miso=Pin(MISO_PIN))
cs = Pin(CS_PIN)
def mount_sdcard(spi, cs_pin):
try:
sd = sdcard.SDCard(spi, cs_pin)
# Mount microSD card
os.mount(sd, SD_MOUNT_PATH)
# List files on the microSD card
print(os.listdir(SD_MOUNT_PATH))
except Exception as e:
print('An error occurred mounting the SD card:', e)
def log_temperature(timer):
try:
# Read the internal temperature sensor value
temperature = pico_temp_sensor.temp
# Format temperature
temperature_string = "{:.2f} °C\n".format(temperature)
# Write to the file
with open(FILE_PATH, 'a') as file:
file.write(temperature_string)
print("Temperature logged successfully.")
except Exception as e:
print('An error occurred accessing the file or getting temperature', e)
# Mount SD card
mount_sdcard(spi, cs)
# Log temperature when the program first runs
log_temperature(None)
# Create a timer that calls log_temperature every 30 seconds
log_timer = Timer(period=30000, mode=Timer.PERIODIC, callback=log_temperature)
# Keep the program running
try:
while True:
sleep(0.1)
except KeyboardInterrupt:
# Clean up and stop the timer on keyboard interrupt
log_timer.deinit()
print("Keyboard Interrupt")
How the Code Works
We start by including the required libraries
from time import sleep
from machine import Timer, SPI, Pin
from picozero import pico_temp_sensor
import sdcard, os
We create a function called log_temperature() that will be responsible for getting the internal temperature reading and logging the value to a file on the filesystem. This function will then be called by a timer interrupt (that’s why we need the function to have one parameter for the time).
def log_temperature(timer):
try:
# Read the internal temperature sensor value
temperature = pico_temp_sensor.temp
# Format temperature
temperature_string = "{:.2f} °C\n".format(temperature)
# Write to the file
with open(FILE_PATH, 'a') as file:
file.write(temperature_string)
print("Temperature logged successfully.")
except Exception as e:
print('An error occurred accessing the file or getting temperature', e)
Inside that function, we start by getting the Pico’s internal temperature sensor:
# Read the internal temperature sensor value
temperature = pico_temp_sensor.temp
Then, create a new variable to save the temperature as a string with two decimal places and with the Celsius degrees unit. We also add a newline character \n, so that new data is appended to the next line.
# Format temperature
temperature_string = "{:.2f} °C\n".format(temperature)
Open the new file in appending mode, ‘a’ ,(we want to append new data to the file, not overwriting it). We write the temperature reading to the file.
# Write to the file
with open(FILE_PATH, 'a') as file:
file.write(temperature_string)
print("Temperature logged successfully.")
Then, we want to call that function as soon as the code starts running, so we don’t have to wait 60 seconds for the first log triggered by the timer. Because this function is expecting a value referring to the timer, we can simply pass None to run that function right away.
# Log temperature when the program first runs
log_temperature(None)
Set a periodic timer interrupt that calls the log_temperature() function every minute, thus logging data continuously until you stop the program.
log_timer = Timer(period=60000, mode=Timer.PERIODIC, callback=log_temperature)
To keep our program running, we add an empty while loop, but you can add any other tasks to the loop, and it will still log the temperature when it’s the right time.
# Keep the program running
try:
while True:
sleep(0.1)
Additionally, we also added the KeyboardInterrupt exception to stop the timer when the program is interrupted by the user.
except KeyboardInterrupt:
# Clean up and stop the timer on keyboard interrupt
log_timer.deinit()
print("Keyboard Interrupt")
Testing the Code
Let the code run for a considerable amount of time until you get some data. When you’re happy, stop the program.
Remove the microSD card from the Raspberry Pi Pico and open it on your computer to check the file and its content. You should have a temperature.txt file with the record of the Raspberry Pi Pico internal temperature.
Wrapping Up
In this guide you learned how to interface a microSD card with the Raspberry Pi Pico programmed with Micropython.We covered how to create a file, write data to it, read data from a file, and how to log data periodically using a timer.
We hope you’ve found this guide useful. Instead of logging the Pico’s internal temperature, you may want to log data from other sensors. We have guides for other sensors you may find useful:
- Raspberry Pi Pico: BH1750 Ambient Light Sensor (MicroPython)
- Raspberry Pi Pico: BME680 Environmental Sensor (MicroPython)
- Raspberry Pi Pico: BME280 Get Temperature, Humidity, and Pressure (MicroPython)
- Raspberry Pi Pico: Detect Motion using a PIR Sensor (Arduino IDE)
If you’d like to learn more about programming the Raspberry Pi Pico with MicroPython, take a look at our resources:
- Learn Raspberry Pi Pico/Pico W with MicroPython (eBook)
- Free Raspberry Pi Pico Projects and Tutorials
Thanks for reading.