2020-05-06 12:04:53 -04:00
|
|
|
/*
|
|
|
|
* This file is part of the Micro Python project, http://micropython.org/
|
|
|
|
*
|
|
|
|
* The MIT License (MIT)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "py/obj.h"
|
|
|
|
#include "py/objproperty.h"
|
|
|
|
#include "py/runtime.h"
|
|
|
|
#include "py/objarray.h"
|
|
|
|
|
|
|
|
#include "shared-bindings/sdcardio/SDCard.h"
|
|
|
|
#include "shared-module/sdcardio/SDCard.h"
|
|
|
|
#include "common-hal/busio/SPI.h"
|
|
|
|
#include "shared-bindings/busio/SPI.h"
|
|
|
|
#include "shared-bindings/microcontroller/Pin.h"
|
|
|
|
#include "supervisor/flash.h"
|
|
|
|
|
|
|
|
//| class SDCard:
|
|
|
|
//| """SD Card Block Interface
|
|
|
|
//|
|
|
|
|
//| Controls an SD card over SPI. This built-in module has higher read
|
|
|
|
//| performance than the library adafruit_sdcard, but it is only compatible with
|
|
|
|
//| `busio.SPI`, not `bitbangio.SPI`. Usually an SDCard object is used
|
|
|
|
//| with ``storage.VfsFat`` to allow file I/O to an SD card."""
|
|
|
|
//|
|
2022-09-27 16:21:42 -04:00
|
|
|
//| def __init__(
|
|
|
|
//| self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000
|
|
|
|
//| ) -> None:
|
2020-05-06 12:04:53 -04:00
|
|
|
//| """Construct an SPI SD Card object with the given properties
|
|
|
|
//|
|
|
|
|
//| :param busio.SPI spi: The SPI bus
|
|
|
|
//| :param microcontroller.Pin cs: The chip select connected to the card
|
|
|
|
//| :param int baudrate: The SPI data rate to use after card setup
|
|
|
|
//|
|
|
|
|
//| Note that during detection and configuration, a hard-coded low baudrate is used.
|
|
|
|
//| Data transfers use the specified baurate (rounded down to one that is supported by
|
|
|
|
//| the microcontroller)
|
|
|
|
//|
|
2021-02-09 11:07:12 -05:00
|
|
|
//| .. important::
|
|
|
|
//| If the same SPI bus is shared with other peripherals, it is important that
|
|
|
|
//| the SD card be initialized before accessing any other peripheral on the bus.
|
|
|
|
//| Failure to do so can prevent the SD card from being recognized until it is
|
|
|
|
//| powered off or re-inserted.
|
|
|
|
//|
|
2020-05-06 12:04:53 -04:00
|
|
|
//| Example usage:
|
|
|
|
//|
|
|
|
|
//| .. code-block:: python
|
|
|
|
//|
|
|
|
|
//| import os
|
|
|
|
//|
|
|
|
|
//| import board
|
|
|
|
//| import sdcardio
|
|
|
|
//| import storage
|
|
|
|
//|
|
|
|
|
//| sd = sdcardio.SDCard(board.SPI(), board.SD_CS)
|
|
|
|
//| vfs = storage.VfsFat(sd)
|
|
|
|
//| storage.mount(vfs, '/sd')
|
|
|
|
//| os.listdir('/sd')"""
|
|
|
|
|
2021-10-15 14:43:12 -04:00
|
|
|
STATIC mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
2021-10-21 18:23:31 -04:00
|
|
|
enum { ARG_spi, ARG_cs, ARG_baudrate, NUM_ARGS };
|
2020-05-06 12:04:53 -04:00
|
|
|
static const mp_arg_t allowed_args[] = {
|
|
|
|
{ MP_QSTR_spi, MP_ARG_OBJ, {.u_obj = mp_const_none } },
|
|
|
|
{ MP_QSTR_cs, MP_ARG_OBJ, {.u_obj = mp_const_none } },
|
|
|
|
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 8000000} },
|
|
|
|
};
|
2021-03-15 09:57:36 -04:00
|
|
|
MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
|
2020-05-06 12:04:53 -04:00
|
|
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
2021-10-15 14:43:12 -04:00
|
|
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
2020-05-06 12:04:53 -04:00
|
|
|
|
2023-01-10 13:39:10 -05:00
|
|
|
busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj, MP_QSTR_spi);
|
|
|
|
const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs);
|
2020-05-06 12:04:53 -04:00
|
|
|
|
2023-08-07 20:45:57 -04:00
|
|
|
sdcardio_sdcard_obj_t *self = mp_obj_malloc(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type);
|
2020-05-06 12:04:53 -04:00
|
|
|
|
|
|
|
common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int);
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-23 14:22:41 -04:00
|
|
|
//| def count(self) -> int:
|
2020-05-06 12:04:53 -04:00
|
|
|
//| """Returns the total number of sectors
|
|
|
|
//|
|
|
|
|
//| Due to technical limitations, this is a function and not a property.
|
|
|
|
//|
|
|
|
|
//| :return: The number of 512-byte blocks, as a number"""
|
2021-11-10 09:42:21 -05:00
|
|
|
STATIC mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) {
|
2021-03-15 09:57:36 -04:00
|
|
|
sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
|
2020-05-06 12:04:53 -04:00
|
|
|
return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self));
|
|
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count);
|
|
|
|
|
2020-07-23 14:22:41 -04:00
|
|
|
//| def deinit(self) -> None:
|
2020-05-06 12:04:53 -04:00
|
|
|
//| """Disable permanently.
|
|
|
|
//|
|
|
|
|
//| :return: None"""
|
2021-11-10 09:42:21 -05:00
|
|
|
STATIC mp_obj_t sdcardio_sdcard_deinit(mp_obj_t self_in) {
|
2021-03-15 09:57:36 -04:00
|
|
|
sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
|
2020-05-06 12:04:53 -04:00
|
|
|
common_hal_sdcardio_sdcard_deinit(self);
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit);
|
|
|
|
|
|
|
|
|
2020-07-25 04:58:37 -04:00
|
|
|
//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None:
|
2020-05-06 12:04:53 -04:00
|
|
|
//| """Read one or more blocks from the card
|
|
|
|
//|
|
|
|
|
//| :param int start_block: The block to start reading from
|
2021-12-21 15:28:49 -05:00
|
|
|
//| :param ~circuitpython_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
|
2020-05-06 12:04:53 -04:00
|
|
|
//|
|
|
|
|
//| :return: None"""
|
|
|
|
|
2021-11-10 09:42:21 -05:00
|
|
|
STATIC mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
|
2020-05-06 12:04:53 -04:00
|
|
|
uint32_t start_block = mp_obj_get_int(start_block_in);
|
|
|
|
mp_buffer_info_t bufinfo;
|
|
|
|
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
|
2021-03-15 09:57:36 -04:00
|
|
|
sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
|
2020-05-06 12:04:53 -04:00
|
|
|
int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo);
|
|
|
|
if (result < 0) {
|
|
|
|
mp_raise_OSError(-result);
|
|
|
|
}
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, sdcardio_sdcard_readblocks);
|
|
|
|
|
2021-10-25 11:03:07 -04:00
|
|
|
//| def sync(self) -> None:
|
|
|
|
//| """Ensure all blocks written are actually committed to the SD card
|
|
|
|
//|
|
|
|
|
//| :return: None"""
|
|
|
|
//| ...
|
2021-11-10 09:42:21 -05:00
|
|
|
STATIC mp_obj_t sdcardio_sdcard_sync(mp_obj_t self_in) {
|
2021-10-25 11:03:07 -04:00
|
|
|
sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
|
|
|
|
int result = common_hal_sdcardio_sdcard_sync(self);
|
|
|
|
if (result < 0) {
|
|
|
|
mp_raise_OSError(-result);
|
|
|
|
}
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_sync_obj, sdcardio_sdcard_sync);
|
|
|
|
|
|
|
|
|
2020-07-25 04:58:37 -04:00
|
|
|
//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None:
|
2020-05-06 12:04:53 -04:00
|
|
|
//| """Write one or more blocks to the card
|
|
|
|
//|
|
|
|
|
//| :param int start_block: The block to start writing from
|
2021-12-21 15:28:49 -05:00
|
|
|
//| :param ~circuitpython_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512.
|
2020-05-06 12:04:53 -04:00
|
|
|
//|
|
|
|
|
//| :return: None"""
|
2022-09-29 20:22:32 -04:00
|
|
|
//|
|
2020-05-06 12:04:53 -04:00
|
|
|
|
2021-11-10 09:42:21 -05:00
|
|
|
STATIC mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
|
2020-05-06 12:04:53 -04:00
|
|
|
uint32_t start_block = mp_obj_get_int(start_block_in);
|
|
|
|
mp_buffer_info_t bufinfo;
|
|
|
|
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
2021-03-15 09:57:36 -04:00
|
|
|
sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
|
2020-05-06 12:04:53 -04:00
|
|
|
int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo);
|
|
|
|
if (result < 0) {
|
|
|
|
mp_raise_OSError(-result);
|
|
|
|
}
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, sdcardio_sdcard_writeblocks);
|
|
|
|
|
|
|
|
STATIC const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = {
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) },
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) },
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) },
|
2021-10-25 11:03:07 -04:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&sdcardio_sdcard_sync_obj) },
|
2020-05-06 12:04:53 -04:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) },
|
|
|
|
};
|
|
|
|
STATIC MP_DEFINE_CONST_DICT(sdcardio_sdcard_locals_dict, sdcardio_sdcard_locals_dict_table);
|
|
|
|
|
|
|
|
const mp_obj_type_t sdcardio_SDCard_type = {
|
|
|
|
{ &mp_type_type },
|
|
|
|
.name = MP_QSTR_SDCard,
|
|
|
|
.make_new = sdcardio_sdcard_make_new,
|
2021-03-15 09:57:36 -04:00
|
|
|
.locals_dict = (mp_obj_dict_t *)&sdcardio_sdcard_locals_dict,
|
2020-05-06 12:04:53 -04:00
|
|
|
};
|