Run code.py from SD card

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Run code.py from SD card

Post by blakebr »

Hello,

Is there a way to run programs from an SD card?

Run them directly from the SD card or delete code.py from flash,
copy a program from the SD card on to flash, then reboot the microcontroller.

Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

Oddly enough there is a guide for this. It looks like it was influenced from the early CircuitPython boards that were not Express based and were tight on flash.

Let us know if this meets your needs.

https://learn.adafruit.com/micropython- ... on-sd-card

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

I have been able to replicate the REPL results shown in the article.
However I have not been able to use the results in a code.py program.
I can execute a code.py in /sd/ from REPL.

These are some of my failures:
1) I can't import a program in the / directory from a code.py in the /sd/ directory.
2) I can't import a program in the /sd/ directory from a code.py in the / directory.
3) I can't call library functions from the /sd/lib/ directory. Ports etc. opened in the sdmount.py file don't seem to carry into the /code.py file. However they seem to be busy (can't open pin, it is busy from sdmount.py)
4) I can't access the library files in /sd/lib/ directory before I open SD card access requiring some of the files in /sd/lib/. Catch 22!

My sdmount.py file:

Code: Select all

# SPDX-FileCopyrightText: 2018 Jerry Needell for Adafruit Industries
# Modified by B.B.Blake 9/23/2022
# SPDX-License-Identifier: MIT

import sys
import board
import busio
import storage
import digitalio
import adafruit_sdcard

import builtins
# Import the devices and I/O ports on the Maker Pi Pico Board as MPPio
if True: import Maker_Pi_Pico_Base as MPPio
else: MPPio = builtins.__import__(board.board_id)

print("Start")
SCK    = MPPio.SCK   # board.GP10
MOSI   = MPPio.MOSI  # board.GP11
MISO   = MPPio.MISO  # board.GP12
SD_CS  = MPPio.SD_CS # board.GP15
# Connect to the card and mount the filesystem.
spi = busio.SPI(SCK, MOSI, MISO)
cs = digitalio.DigitalInOut(SD_CS)
cs.direction = digitalio.Direction.OUTPUT
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
sys.path.append("/sd")
sys.path.append("/sd/lib")
print("Stop")

# Saved code
#sdcard = adafruit_sdcard.SDCard(spi, cs)
#vfs = storage.VfsFat(sdcard)
This is Maker_Pi_Pico_Base.py. The file adds port definitions.

Code: Select all

#
# Maker_Pi_Pico_Base.py extensions Rev.2
# 
# e.g. import Maker_Pi_Pico_Base as MPPio
# e.g. SCK = MPPio.SCK
import board
#
# grove ports (based on port numbers on the silkscreen)
GROVE_1 = (board.GP1, board.GP0)
GROVE_2 = (board.GP3, board.GP2)
GROVE_3 = (board.GP5, board.GP4)
GROVE_4 = (board.GP7, board.GP6)
GROVE_5 = (board.GP9, board.GP8)
GROVE_6 = (board.GP27, board.GP26)
# on-board default SPI for SD card
SCK     = board.GP10
MOSI    = board.GP11
MISO    = board.GP12
SD_CS   = board.GP15
# alternate SD card pins names
SD_CMD  = board.GP11
SD_DAT0 = board.GP12
SD_DAT1 = board.GP13
SD_DAT2 = board.GP14
SD_DAT3 = board.GP15
# ESP-01 connector (TX on the board is RX on the ESP-01)
ESP_TX  = board.GP16
ESP_RX  = board.GP17
# buzzer
BUZZER  = board.GP18
# headphone connector
AUDIO_LEFT  = board.GP18
AUDIO_RIGHT = board.GP19
# buttons
BUTTON_20 = board.GP20
BUTTON_21 = board.GP21
BUTTON_22 = board.GP22
# neopixel
NEOPIXEL  = board.GP28
I am open to suggestions. TIA
Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

The Maker Pi Pico pin abstractions might be adding a level of complexity at this point. Can you just simplicity to the basics for initial testing? Otherwise your sdmount.py file looks good. As shown with the sdmount_lib.py you should be able to load just the SD module and have access to the entire python library bundle if it is on your SD card.

Code: Select all

spi = busio.SPI(board.GP10, MOSI=board.GP11, MISO=board.GP12) 
cs = digitalio.DigitalInOut(board.GP15) 
sdcard = adafruit_sdcard.SDCard(spi, cs)

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

This version of sdmount.py does not work either:

Code: Select all

# SPDX-FileCopyrightText: 2018 Jerry Needell for Adafruit Industries
# Changes by B.B.Blake 9/23/2023
# SPDX-License-Identifier: MIT

import sys
import time
import board
import busio
import storage
import digitalio
import adafruit_sdcard

print("Start")
spi = busio.SPI(board.GP10, MOSI=board.GP11, MISO=board.GP12) 
cs = digitalio.DigitalInOut(board.GP15) 
cs.direction = digitalio.Direction.OUTPUT
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
sys.path.append("/sd")
sys.path.append("/sd/lib")
print("Stop")
time.sleep(10)
When I load it from REPL I get the Start/Stop and the 10 second delay. When I pull and restore power, I do not see the 10 second delay. I can't get putty.exe up on the com: port fast enough to see the Start/Stop. It's like sdmount.py is ignored at power application. What is the boot sequence (boot.py, sdmount.py, code.py, etc.) This is all on a RPi Pico. Looking to put all or most libraries on /sd/lib/.

Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

I suspect the guide is missing the key point here which is the sdmount_lib.py example needs to be renamed to “boot.py” for everything to work. Can you give that a try?

boot.py always runs first on startup and is run once.

code.py or main.py follows.

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

Renamed sdmount.py to boot.py. No joy in Muddville.

boot.py is opened because it complained it could not find simplio.py and adafruit_sdcard.py.
I put a copy of each in the root directory.
Then I get a error that code.py can't find adafruit_ntp.py. It is in /sd/lib/.

Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

Bruce,

New approach. Remove the sdmount_lib.py, code.py and boot.py. Let the controller boot to the REPL prompt and manually paste in the sdmount_lib.py line by line. Let’s understand where things are not working.

Code: Select all

 import adafruit_sdcard
import busio
import digitalio
import board
import storage
import sys
# Connect to the card and mount the filesystem.
spi = busio.SPI(board.GP10, MOSI=board.GP11, MISO=board.GP12) 
cs = digitalio.DigitalInOut(board.GP15) 
sdcard = adafruit_sdcard.SDCard(spi, cs) sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
sys.path.append("/sd")
sys.path.append("/sd/lib")

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

boot.py is now boot.py.mike and code.py is code.py.mike ;-) I do not have a boot.txt or code.txt.
Worked without error after I fixed the line:

Code: Select all

sdcard = adafruit_sdcard.SDCard(spi, cs) sdcard = adafruit_sdcard.SDCard(spi, cs)
to read:

Code: Select all

sdcard = adafruit_sdcard.SDCard(spi, cs)
I then got:

Code: Select all

>>> sys.path
['', '/', '/lib', '/sd', '/sd/lib']
>>>
also this imported without error after a reboot:

Code: Select all

import sdmount
If I power reboot, import sdmount, import code.py, code.py works as long as I do not

Code: Select all

storage.mount(vfs, "/sd")
where I get an error. If I don't try to open a connection to /sd, code.py runs just fine. Just very slow (15 seconds) to start.

Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

Bruce,

Paste in the error message you see when you hit this line:
storage.mount(vfs, "/sd")
Is it this message:

Code: Select all

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
OSError: [Errno 19] ENODEV
Can you run this command and share the output?

Code: Select all

>>>dir(vfs)

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

The error:

Code: Select all

Traceback (most recent call last):
  File "code.py", line 148, in <module>
NameError: name 'vfs' is not defined
Line 148 in code.py

Code: Select all

storage.mount(vfs, "/sd")

Code: Select all

>>> dir(vfs)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'vfs' is not defined
>>>
It looks like vfs, etc. does not carry into code.py. However the board.GPxx definitions leave some residual configuration behind. The question remains why can I read library stuff, but not open to access the SD card?

Also without storage.mount(vfs, "/sd") everything works from REPL.

Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

One minor difference I see in some example code is the switch to single quotes around paths. I don't think will change anything, but why not give it a try since the code is erroring out on the mount line about vfs not being defined.

https://docs.circuitpython.org/projects ... tion-notes

Code: Select all

vfs = storage.VfsFat(sdcard)

Code: Select all

 import adafruit_sdcard
import busio
import digitalio
import board
import storage
import sys
# Connect to the card and mount the filesystem.
spi = busio.SPI(board.GP10, MOSI=board.GP11, MISO=board.GP12) 
cs = digitalio.DigitalInOut(board.GP15) 
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, '/sd')
sys.path.append('/sd')
sys.path.append('/sd/lib')

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

I changed all the " to ', no change. import boot.py, import code.py only works from REPL.

At RESET/Power On boot.py may not be running or all/some settings created by boot.py are dropped when boot.py exits. I have noticed that after running boot.py from REPL, I must run import sys to be able to run sys.path. sys can be imported before or after boot.py.

The vfs = storage.VfsFat(sdcard) error was a red herring. I fat-fingered an extra character into boot.py.

What is different between RESET and REPL import boot.py/import code.py? That is the issue.

Bruce

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Run code.py from SD card

Post by mikeysklar »

Glad the vfs line was just a typo issue.

Are you able to achieve your goal of running the sdmount_lib.py example code as 'code.py' and adding your user code to the same script?

Looking at a somewhat related issue from the CircuitPython forum makes me think that boot.py is not going to be helpful and using 'code.py' to initialize the mount and access the libraries will be necessary. You will have to have your user code appended to the same script to keep the filesystem accessible.

https://github.com/adafruit/circuitpython/pull/6555

User avatar
blakebr
 
Posts: 956
Joined: Tue Apr 17, 2012 6:23 pm

Re: Run code.py from SD card

Post by blakebr »

Mike,

Great idea!! This is my new code.py. It then imports the program.py I want to run, and it works!

Code: Select all

import sys
import time
import board
import busio
import storage
import digitalio
import adafruit_sdcard

print("\f", end="")
print("\t\t#####################")
print("\t\t##  Program Start  ##")
print("\t\t#####################")
for x in range(5, -1, -1):
    print("\t\t\t ", x, end='  \r')
    time.sleep(1)
print("\r\t\t##   Run Program   ##")
print("\t\t#####################")
print("")
time.sleep(0.1)

import Maker_Pi_Pico_Base as MPPio
print('Start')
SCK    = MPPio.SCK   # board.GP10
MOSI   = MPPio.MOSI  # board.GP11
MISO   = MPPio.MISO  # board.GP12
SD_CS  = MPPio.SD_CS # board.GP15
# Connect to the card and mount the filesystem.
spi = busio.SPI(SCK, MOSI, MISO)
cs = digitalio.DigitalInOut(SD_CS)
cs.direction = digitalio.Direction.OUTPUT
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, '/sd')
sys.path.append('/sd')
sys.path.append('/sd/lib')
print('Stop')

_ = 2
if   _ == 1: import Demo_code
elif _ == 2: import NTP_Clock_code
elif _ == 3: import IR_code
elif _ == 4: import FRAM_code
elif _ == 5: import asyncioo
elif _ == 6: import fixed_ip
elif _ == 7: import Thonny

The downside is it takes 75 seconds for the 700 line program.py to start. What is CircuitPython doing during those 75 seconds that takes that long? If I don't use the libraries on /sd/lib/ it still takes 75 seconds. The wait is after Stop is printed to REPL. ???

Bruce

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”