adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.11k stars 1.22k forks source link

SD Card unmount or remount fails on Adalogger M0 #466

Closed stewmystre closed 6 years ago

stewmystre commented 6 years ago

When the SD card has been mounted and is then removed with power still applied, it remains listed when calling os.listdir('/') (as byte string refer #249)

At the moment there doesn't seem to be a way to recover and remount to the same mount path after an SD card has been removed and then reinserted.

stewmystre commented 6 years ago

If you delete the adafruit_sdcard.SDCARD() object associated with the filesystem prior to calling storage.umount('\sd') the unmount is successful, allowing for a 'new' adafruit_sdcard.SDCARD() call and subsequent storage.mount() call to occur ...

dhalbert commented 6 years ago

Do you mean that you do del the_sdcard_object? Could you post code examples for both failure and success?

stewmystre commented 6 years ago

Code snippets for failure 1:

# Function that manages mounting and unmounting the SD card
def mount_sd_card():
    global sd_card
    global vfs
    # Check to make sure an SD card is present
    if sd_cd.value:
        if sd_card:
            del sd_card
        sd_card = adafruit_sdcard.SDCard(spi, sd_cs)
        vfs = storage.VfsFat(sd_card)
        storage.mount(vfs, SD_MOUNT_PATH)  # Mount SD card
        print("SD Card Mounted")
        return True
    else:
        print("No SD Card present")
        return False

def log_data():
    if sd_cd.value and sd_mounted:
        with open(LOG_FILE, LOG_MODE) as outfile:
            while True:
                sentence = read_data()
                if sentence:
                    outfile.write(sentence)
                    outfile.flush()
                    green_led.value = not green_led.value
                else:
                    green_led.value = False
                if not sd_cd.value:  #  SD Card has been removed
                    green_led.value = False
                    # Debug
                    print("4 SD Detected: {}".format(sd_cd.value))
                    print("4 SD Mounted: {}".format(sd_mounted))
                    for item in os.listdir('/'):
                        print(item)
                     storage.umount('/sd')    #Failure point
                    return False
    elif sd_cd.value and not sd_mounted:  # SD Card inserted
        print('SD Card Inserted')
        time.sleep(2)
        print('Mounting...')
        return mount_sd_card()

Code snippets for failure 2:

def log_data():
    if sd_cd.value and sd_mounted:
        with open(LOG_FILE, LOG_MODE) as outfile:
            while True:
                sentence = read_data()
                if sentence:
                    outfile.write(sentence)
                    outfile.flush()
                    green_led.value = not green_led.value
                else:
                    green_led.value = False
                if not sd_cd.value:  #  SD Card has been removed
                    green_led.value = False
                    # Debug
                    print("4 SD Detected: {}".format(sd_cd.value))
                    print("4 SD Mounted: {}".format(sd_mounted))
                    for item in os.listdir('/'):
                        print(item)
                    return False
    elif sd_cd.value and not sd_mounted:  # SD Card inserted
        print('SD Card Inserted')
        time.sleep(2)
        print('Mounting...')
        # Debug
        print("3 SD Detected: {}".format(sd_cd.value))
        print("3 SD Mounted: {}".format(sd_mounted))
        storage.remount('/sd', False)   #Failure point
        return True

Other combinations also resulted in failure Calling the unmount function after deleting of the sdcard works


# Function that manages mounting and unmounting the SD card
def mount_sd_card():
    global sd_card
    global vfs
    # Check to make sure an SD card is present
    if sd_cd.value:
        if sd_card:
            del sd_card
            storage.umount(SD_MOUNT_PATH)
        sd_card = adafruit_sdcard.SDCard(spi, sd_cs)
        vfs = storage.VfsFat(sd_card)
        storage.mount(vfs, SD_MOUNT_PATH)  # Mount SD card
        print("SD Card Mounted")
        return True
    else:
        print("No SD Card present")
        return False

# Initialize the SD card:
SD_CD_PIN = board.SD_CD
sd_cd = digitalio.DigitalInOut(SD_CD_PIN)
sd_cd.switch_to_input(pull=digitalio.Pull.UP)
SD_CS_PIN = board.SD_CS
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
sd_cs = digitalio.DigitalInOut(SD_CS_PIN)
sd_card = None
vfs = None
sd_mounted = mount_sd_card()

# Function that reads the line of text from the uart connection and
# then prints it to serial output and returns it for further processing
def read_data():
    sentence = uart.readline()
    if sentence:
        print(str(sentence, 'ascii').strip())
    else:
        print("No Input - UART timed out after 2 seconds")
        print(" - Is the uart input device connected?")
        print("Board has been running for: {} seconds\n".format(time.monotonic()))
    return sentence

# Function that logs data to the SD card if mounted or mounts the SD card if inserted
# Allows removal and insertion of SD Card with power applied
# DO NOT remove the SD card while green LED is flashing  - remove/disconnect input (UART)
# first so that green LED stops flashing THEN remove and insert another or same SD Card
# Reads data then writes it back out to the output file.  Also flashes the green LED every 
# second loop to show that data is being logged to the SD card.
def log_data():
    if sd_cd.value and sd_mounted:
        with open(LOG_FILE, LOG_MODE) as outfile:
            while True:
                sentence = read_data()
                if sentence:
                    outfile.write(sentence)
                    outfile.flush()
                    green_led.value = not green_led.value
                else:
                    green_led.value = False
                if not sd_cd.value:  #  SD Card has been removed
                    green_led.value = False
                    return False
    elif sd_cd.value and not sd_mounted:  # SD Card inserted
        print('SD Card Inserted')
        time.sleep(2)
        print('Mounting...')
        return mount_sd_card()

# Main loop has two states:
#  - SD card inserted       = logs data
#  - SD card not inserted   = prompt to insert SD card
while True:
    if sd_cd.value:
        print("Logging ...")
        sd_mounted = log_data()
    else:
        print("Please insert an SD card to start logging")
        time.sleep(2)  # give a little time for the SD card to be fully inserted
dhalbert commented 6 years ago

Finally getting around to this -- sorry for the delay!

I did some testing: the code below now works without an error on CircuitPython 3.0. Something has been fixed since this issue was filed.

sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, '/sd')
input("remove card and press enter:")   # card is removed
storage.umount(vfs)    # no longer does OSError 22

So if you are still seeing a problem, let us know. I'll close this for now. Also, here are a few notes:

dhalbert commented 6 years ago

There are some other problems with the sdcard library: see #301. The library doesn't do a good job failing when trying to read or write when the card is missing.