/* * This file is part of the Micro Python project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2015 Daniel Campora * * 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/mpconfig.h" #include MICROPY_HAL_H #include "py/obj.h" #include "py/runtime.h" #include "inc/hw_types.h" #include "inc/hw_gpio.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "rom_map.h" #include "pin.h" #include "prcm.h" #include "gpio.h" #include "sdhost.h" #include "ff.h" #include "diskio.h" #include "sd_diskio.h" #include "pybsd.h" #include "mpexception.h" #include "pybsleep.h" #include "pybpin.h" #include "pins.h" /****************************************************************************** DEFINE PRIVATE CONSTANTS ******************************************************************************/ #define PYBSD_FREQUENCY_HZ 15000000 // 15MHz /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ pybsd_obj_t pybsd_obj = {.pin_clk = MP_OBJ_NULL, .enabled = false}; /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ STATIC const mp_obj_t pyb_sd_def_pin[3] = {&pin_GP10, &pin_GP11, &pin_GP15}; /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ STATIC void pyb_sd_hw_init (pybsd_obj_t *self); STATIC mp_obj_t pyb_sd_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in); /****************************************************************************** DEFINE PRIVATE FUNCTIONS ******************************************************************************/ /// Initalizes the sd card hardware driver STATIC void pyb_sd_hw_init (pybsd_obj_t *self) { if (self->pin_clk) { // Configure the clock pin as output only MAP_PinDirModeSet(((pin_obj_t *)(self->pin_clk))->pin_num, PIN_DIR_MODE_OUT); } // Enable SD peripheral clock MAP_PRCMPeripheralClkEnable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); // Reset MMCHS MAP_PRCMPeripheralReset(PRCM_SDHOST); // Initialize MMCHS MAP_SDHostInit(SDHOST_BASE); // Configure the card clock MAP_SDHostSetExpClk(SDHOST_BASE, MAP_PRCMPeripheralClockGet(PRCM_SDHOST), PYBSD_FREQUENCY_HZ); // Set card rd/wr block len MAP_SDHostBlockSizeSet(SDHOST_BASE, SD_SECTOR_SIZE); self->enabled = true; } STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args) { // assign the pins mp_obj_t pins_o = args[0].u_obj; if (pins_o != mp_const_none) { mp_obj_t *pins; mp_uint_t n_pins = MP_ARRAY_SIZE(pyb_sd_def_pin); if (pins_o == MP_OBJ_NULL) { // use the default pins pins = (mp_obj_t *)pyb_sd_def_pin; } else { mp_obj_get_array(pins_o, &n_pins, &pins); if (n_pins != MP_ARRAY_SIZE(pyb_sd_def_pin)) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } } pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_SD, 0); // save the pins clock self->pin_clk = pin_find(pins[0]); } pyb_sd_hw_init (self); if (sd_disk_init() != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); } // register it with the sleep module pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init); return mp_const_none; } /******************************************************************************/ // Micro Python bindings // STATIC const mp_arg_t pyb_sd_init_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; STATIC mp_obj_t pyb_sd_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) { // parse args mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); mp_arg_val_t args[MP_ARRAY_SIZE(pyb_sd_init_args)]; mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_sd_init_args, args); // check the peripheral id if (args[0].u_int != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); } // setup and initialize the object mp_obj_t self = &pybsd_obj; pybsd_obj.base.type = &pyb_sd_type; pyb_sd_init_helper (self, &args[1]); return self; } STATIC mp_obj_t pyb_sd_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // parse args mp_arg_val_t args[MP_ARRAY_SIZE(pyb_sd_init_args) - 1]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_sd_init_args[1], args); return pyb_sd_init_helper(pos_args[0], args); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_sd_init_obj, 1, pyb_sd_init); STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) { pybsd_obj_t *self = self_in; // disable the peripheral self->enabled = false; MAP_PRCMPeripheralClkDisable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); // de-initialze the sd card at diskio level sd_disk_deinit(); // unregister it from the sleep module pybsleep_remove (self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sd_deinit_obj, pyb_sd_deinit); STATIC const mp_map_elem_t pyb_sd_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_sd_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_sd_deinit_obj }, }; STATIC MP_DEFINE_CONST_DICT(pyb_sd_locals_dict, pyb_sd_locals_dict_table); const mp_obj_type_t pyb_sd_type = { { &mp_type_type }, .name = MP_QSTR_SD, .make_new = pyb_sd_make_new, .locals_dict = (mp_obj_t)&pyb_sd_locals_dict, };