atmel/samd: Add filesystem support. 64k is stored in flash.
This commit is contained in:
parent
559434afca
commit
09be96a6aa
|
@ -35,6 +35,7 @@ HAL_DIR=hal/$(MCU_SERIES)
|
|||
INC += -I.
|
||||
INC += -I..
|
||||
INC += -I../lib/mp-readline
|
||||
INC += -I../lib/timeutils
|
||||
INC += -Iasf/common/boards/
|
||||
INC += -Iasf/common/services/sleepmgr/
|
||||
INC += -Iasf/common/services/usb/
|
||||
|
@ -99,7 +100,7 @@ endif
|
|||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -ggdb
|
||||
CFLAGS += -Os -ggdb
|
||||
else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
endif
|
||||
|
@ -119,6 +120,7 @@ endif
|
|||
SRC_ASF = $(addprefix asf/sam0/,\
|
||||
drivers/adc/adc_sam_d_r/adc.c \
|
||||
drivers/dac/dac_sam_d_c/dac.c \
|
||||
drivers/nvm/nvm.c \
|
||||
drivers/port/port.c \
|
||||
drivers/sercom/sercom.c \
|
||||
drivers/sercom/sercom_interrupt.c \
|
||||
|
@ -137,15 +139,19 @@ SRC_ASF = $(addprefix asf/sam0/,\
|
|||
)
|
||||
|
||||
SRC_C = \
|
||||
builtin_open.c \
|
||||
fatfs_port.c \
|
||||
main.c \
|
||||
modmachine.c \
|
||||
modmachine_adc.c \
|
||||
modmachine_dac.c \
|
||||
modmachine_pin.c \
|
||||
modmachine_pwm.c \
|
||||
moduos.c \
|
||||
modutime.c \
|
||||
mphalport.c \
|
||||
pin_named_pins.c \
|
||||
storage.c \
|
||||
uart.c \
|
||||
asf/common/services/sleepmgr/samd/sleepmgr.c \
|
||||
asf/common/services/usb/class/cdc/device/udi_cdc.c \
|
||||
|
@ -157,6 +163,9 @@ SRC_C = \
|
|||
asf/sam0/utils/cmsis/samd21/source/system_samd21.c \
|
||||
asf/sam0/utils/syscalls/gcc/syscalls.c \
|
||||
boards/$(BOARD)/pins.c \
|
||||
lib/fatfs/ff.c \
|
||||
lib/fatfs/option/ccsbcs.c \
|
||||
lib/timeutils/timeutils.c \
|
||||
lib/utils/stdout_helpers.c \
|
||||
lib/utils/printf.c \
|
||||
lib/utils/pyexec.c \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,944 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Non-Volatile Memory driver
|
||||
*
|
||||
* Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef NVM_H_INCLUDED
|
||||
#define NVM_H_INCLUDED
|
||||
|
||||
/**
|
||||
* \defgroup asfdoc_sam0_nvm_group SAM Non-Volatile Memory (NVM) Driver
|
||||
*
|
||||
* This driver for Atmel® | SMART ARM®-based microcontrollers provides
|
||||
* an interface for the configuration and management of non-volatile memories
|
||||
* within the device, for partitioning, erasing, reading, and writing of data.
|
||||
*
|
||||
* The following peripheral is used by this module:
|
||||
* - NVM (Non-Volatile Memory)
|
||||
*
|
||||
* The following devices can use this module:
|
||||
* - Atmel | SMART SAM D20/D21
|
||||
* - Atmel | SMART SAM R21
|
||||
* - Atmel | SMART SAM D09/D10/D11
|
||||
* - Atmel | SMART SAM L21/L22
|
||||
* - Atmel | SMART SAM DA1
|
||||
* - Atmel | SMART SAM C20/C21
|
||||
* - Atmel | SMART SAM R30
|
||||
*
|
||||
* The outline of this documentation is as follows:
|
||||
* - \ref asfdoc_sam0_nvm_prerequisites
|
||||
* - \ref asfdoc_sam0_nvm_module_overview
|
||||
* - \ref asfdoc_sam0_nvm_special_considerations
|
||||
* - \ref asfdoc_sam0_nvm_extra_info
|
||||
* - \ref asfdoc_sam0_nvm_examples
|
||||
* - \ref asfdoc_sam0_nvm_api_overview
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_prerequisites Prerequisites
|
||||
*
|
||||
* There are no prerequisites for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_module_overview Module Overview
|
||||
*
|
||||
* The Non-Volatile Memory (NVM) module provides an interface to the device's
|
||||
* Non-Volatile Memory controller, so that memory pages can be written, read,
|
||||
* erased, and reconfigured in a standardized manner.
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_features Driver Feature Macro Definition
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Driver feature macro</th>
|
||||
* <th>Supported devices</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>FEATURE_NVM_RWWEE</td>
|
||||
* <td>SAM L21/L22, SAM D21-64K, SAM DA1, SAM C20/C21, SAM R30</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>FEATURE_BOD12</td>
|
||||
* <td>SAM L21, SAMR30</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* \note The specific features are only available in the driver when the
|
||||
* selected device supports those features.
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_module_overview_regions Memory Regions
|
||||
* The NVM memory space of the SAM devices is divided into two sections:
|
||||
* a Main Array section, and an Auxiliary space section. The Main Array space
|
||||
* can be configured to have an (emulated) EEPROM and/or boot loader section.
|
||||
* The memory layout with the EEPROM and bootloader partitions is shown in
|
||||
* \ref asfdoc_sam0_nvm_module_mem_layout "the figure below".
|
||||
*
|
||||
* \anchor asfdoc_sam0_nvm_module_mem_layout
|
||||
* \dot
|
||||
* digraph memory_layout {
|
||||
* size="5,5"
|
||||
* node [shape=plaintext, fontname=arial]
|
||||
* memory [label=<
|
||||
* <table border="0" cellborder="1" cellspacing="0" >
|
||||
* <tr>
|
||||
* <td align="right" border="0"> End of NVM Memory </td>
|
||||
* <td rowspan="3" align="center"> Reserved EEPROM Section </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> Start of EEPROM Memory </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> End of Application Memory </td>
|
||||
* <td rowspan="3" align="center"> Application Section </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td height="300" align="right" border="0"> </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> Start of Application Memory </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> End of Bootloader Memory </td>
|
||||
* <td rowspan="3" align="center"> BOOT Section </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border="0"> Start of NVM Memory</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* >]
|
||||
* }
|
||||
* \enddot
|
||||
*
|
||||
* The Main Array is divided into rows and pages, where each row contains four
|
||||
* pages. The size of each page may vary from 8-1024 bytes dependent of the
|
||||
* device. Device specific parameters such as the page size and total number of
|
||||
* pages in the NVM memory space are available via the \ref nvm_get_parameters()
|
||||
* function.
|
||||
*
|
||||
* An NVM page number and address can be computed via the following equations:
|
||||
*
|
||||
* \f[ PageNum = (RowNum \times 4) + PagePosInRow \f]
|
||||
* \f[ PageAddr = PageNum \times PageSize \f]
|
||||
*
|
||||
* \ref asfdoc_sam0_nvm_module_row_layout "The figure below" shows an example
|
||||
* of the memory page and address values associated with logical row 7 of the
|
||||
* NVM memory space.
|
||||
*
|
||||
* \anchor asfdoc_sam0_nvm_module_row_layout
|
||||
* \dot
|
||||
* digraph row_layout {
|
||||
* size="4,4"
|
||||
* node [shape=plaintext, fontname=arial]
|
||||
* row [label=<
|
||||
* <table border="0" cellborder="1" cellspacing="0">
|
||||
* <tr>
|
||||
* <td align="right" border ="0"> Row 0x07 </td>
|
||||
* <td > Page 0x1F </td>
|
||||
* <td > Page 0x1E </td>
|
||||
* <td > Page 0x1D </td>
|
||||
* <td > Page 0x1C </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="right" border ="0"> Address </td>
|
||||
* <td border="0"> 0x7C0 </td>
|
||||
* <td border="0"> 0x780 </td>
|
||||
* <td border="0"> 0x740 </td>
|
||||
* <td border="0"> 0x700 </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* >]
|
||||
* }
|
||||
* \enddot
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_module_overview_locking_regions Region Lock Bits
|
||||
* As mentioned in \ref asfdoc_sam0_nvm_module_overview_regions, the main
|
||||
* block of the NVM memory is divided into a number of individually addressable
|
||||
* pages. These pages are grouped into 16 equal sized regions, where each region
|
||||
* can be locked separately issuing an \ref NVM_COMMAND_LOCK_REGION command or
|
||||
* by writing the LOCK bits in the User Row. Rows reserved for the EEPROM
|
||||
* section are not affected by the lock bits or commands.
|
||||
*
|
||||
* \note By using the \ref NVM_COMMAND_LOCK_REGION or
|
||||
* \ref NVM_COMMAND_UNLOCK_REGION commands the settings will remain in
|
||||
* effect until the next device reset. By changing the default lock
|
||||
* setting for the regions, the auxiliary space must to be written,
|
||||
* however the adjusted configuration will not take effect until the next
|
||||
* device reset.
|
||||
*
|
||||
* \note If the \ref asfdoc_sam0_nvm_special_consideration_security_bit is
|
||||
* set, the auxiliary space cannot be written to. Clearing of the security
|
||||
* bit can only be performed by a full chip erase.
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_module_overview_sub_rw Read/Write
|
||||
* Reading from the NVM memory can be performed using direct addressing into the
|
||||
* NVM memory space, or by calling the \ref nvm_read_buffer() function.
|
||||
*
|
||||
* Writing to the NVM memory must be performed by the \ref nvm_write_buffer()
|
||||
* function - additionally, a manual page program command must be issued if
|
||||
* the NVM controller is configured in manual page writing mode.
|
||||
*
|
||||
* Before a page can be updated, the associated NVM memory row must be erased
|
||||
* first via the \ref nvm_erase_row() function. Writing to a non-erased page
|
||||
* will result in corrupt data being stored in the NVM memory space.
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_special_considerations Special Considerations
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_special_consideration_pageerase Page Erasure
|
||||
* The granularity of an erase is per row, while the granularity of a write is
|
||||
* per page. Thus, if the user application is modifying only one page of a row,
|
||||
* the remaining pages in the row must be buffered and the row erased, as an
|
||||
* erase is mandatory before writing to a page.
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_special_consideration_clocks Clocks
|
||||
* The user must ensure that the driver is configured with a proper number of
|
||||
* wait states when the CPU is running at high frequencies.
|
||||
*
|
||||
* \subsection asfdoc_sam0_nvm_special_consideration_security_bit Security Bit
|
||||
* The User Row in the Auxiliary Space cannot be read or written when
|
||||
* the Security Bit is set. The Security Bit can be set by using passing
|
||||
* \ref NVM_COMMAND_SET_SECURITY_BIT to the \ref nvm_execute_command() function,
|
||||
* or it will be set if one tries to access a locked region. See
|
||||
* \ref asfdoc_sam0_nvm_module_overview_locking_regions.
|
||||
*
|
||||
* The Security Bit can only be cleared by performing a chip erase.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_extra_info Extra Information
|
||||
*
|
||||
* For extra information, see \ref asfdoc_sam0_nvm_extra. This includes:
|
||||
* - \ref asfdoc_sam0_nvm_extra_acronyms
|
||||
* - \ref asfdoc_sam0_nvm_extra_dependencies
|
||||
* - \ref asfdoc_sam0_nvm_extra_errata
|
||||
* - \ref asfdoc_sam0_nvm_extra_history
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_examples Examples
|
||||
*
|
||||
* For a list of examples related to this driver, see
|
||||
* \ref asfdoc_sam0_nvm_exqsg.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_api_overview API Overview
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include <status_codes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Define SAMD21-64K devices */
|
||||
#if defined(SAMD21E15L) || defined(SAMD21E16L) || defined(__SAMD21E15L__) || defined(__SAMD21E16L__) \
|
||||
|| defined(SAMD21E15B) || defined(SAMD21E16B) || defined(__SAMD21E15B__) || defined(__SAMD21E16B__) \
|
||||
|| defined(SAMD21E15BU) || defined(SAMD21E16BU) || defined(__SAMD21E15BU__) || defined(__SAMD21E16BU__) \
|
||||
|| defined(SAMD21G15L) || defined(SAMD21G16L) || defined(__SAMD21G15L__) || defined(__SAMD21G16L__) \
|
||||
|| defined(SAMD21G15B) || defined(SAMD21G16B) || defined(__SAMD21G15B__) || defined(__SAMD21G16B__) \
|
||||
|| defined(SAMD21J15B) || defined(SAMD21J16B) || defined(__SAMD21J15B__) || defined(__SAMD21J16B__)
|
||||
|
||||
# define SAMD21_64K
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \name Driver Feature Definition
|
||||
*
|
||||
* Define NVM features set according to the different device families.
|
||||
* @{
|
||||
*/
|
||||
#if (SAML21) || (SAML22) || (SAMDA1) || (SAMC20) || (SAMC21) || (SAMR30) || defined(SAMD21_64K) || defined(__DOXYGEN__)
|
||||
/** Read while write EEPROM emulation feature. */
|
||||
# define FEATURE_NVM_RWWEE
|
||||
#endif
|
||||
#if (SAML21) || (SAMR30) || defined(__DOXYGEN__)
|
||||
/** Brown-out detector internal to the voltage regulator for VDDCORE. */
|
||||
#define FEATURE_BOD12
|
||||
#endif
|
||||
/*@}*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
/**
|
||||
* \brief Mask for the error flags in the status register.
|
||||
*/
|
||||
# define NVM_ERRORS_MASK (NVMCTRL_STATUS_PROGE | \
|
||||
NVMCTRL_STATUS_LOCKE | \
|
||||
NVMCTRL_STATUS_NVME)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief NVM error flags.
|
||||
*
|
||||
* Possible NVM controller error codes, which can be returned by the NVM
|
||||
* controller after a command is issued.
|
||||
*/
|
||||
enum nvm_error {
|
||||
/** No errors */
|
||||
NVM_ERROR_NONE = 0,
|
||||
/** Lock error, a locked region was attempted accessed */
|
||||
NVM_ERROR_LOCK = NVMCTRL_STATUS_NVME | NVMCTRL_STATUS_LOCKE,
|
||||
/** Program error, invalid command was executed */
|
||||
NVM_ERROR_PROG = NVMCTRL_STATUS_NVME | NVMCTRL_STATUS_PROGE,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NVM controller commands.
|
||||
*/
|
||||
enum nvm_command {
|
||||
/** Erases the addressed memory row */
|
||||
NVM_COMMAND_ERASE_ROW = NVMCTRL_CTRLA_CMD_ER,
|
||||
|
||||
/** Write the contents of the page buffer to the addressed memory page */
|
||||
NVM_COMMAND_WRITE_PAGE = NVMCTRL_CTRLA_CMD_WP,
|
||||
|
||||
/** Erases the addressed auxiliary memory row.
|
||||
*
|
||||
* \note This command can only be given when the security bit is not set.
|
||||
*/
|
||||
NVM_COMMAND_ERASE_AUX_ROW = NVMCTRL_CTRLA_CMD_EAR,
|
||||
|
||||
/** Write the contents of the page buffer to the addressed auxiliary memory
|
||||
* row.
|
||||
*
|
||||
* \note This command can only be given when the security bit is not set.
|
||||
*/
|
||||
NVM_COMMAND_WRITE_AUX_ROW = NVMCTRL_CTRLA_CMD_WAP,
|
||||
|
||||
/** Locks the addressed memory region, preventing further modifications
|
||||
* until the region is unlocked or the device is erased
|
||||
*/
|
||||
NVM_COMMAND_LOCK_REGION = NVMCTRL_CTRLA_CMD_LR,
|
||||
|
||||
/** Unlocks the addressed memory region, allowing the region contents to be
|
||||
* modified
|
||||
*/
|
||||
NVM_COMMAND_UNLOCK_REGION = NVMCTRL_CTRLA_CMD_UR,
|
||||
|
||||
/** Clears the page buffer of the NVM controller, resetting the contents to
|
||||
* all zero values
|
||||
*/
|
||||
NVM_COMMAND_PAGE_BUFFER_CLEAR = NVMCTRL_CTRLA_CMD_PBC,
|
||||
|
||||
/** Sets the device security bit, disallowing the changing of lock bits and
|
||||
* auxiliary row data until a chip erase has been performed
|
||||
*/
|
||||
NVM_COMMAND_SET_SECURITY_BIT = NVMCTRL_CTRLA_CMD_SSB,
|
||||
|
||||
/** Enter power reduction mode in the NVM controller to reduce the power
|
||||
* consumption of the system
|
||||
*/
|
||||
NVM_COMMAND_ENTER_LOW_POWER_MODE = NVMCTRL_CTRLA_CMD_SPRM,
|
||||
|
||||
/** Exit power reduction mode in the NVM controller to allow other NVM
|
||||
* commands to be issued
|
||||
*/
|
||||
NVM_COMMAND_EXIT_LOW_POWER_MODE = NVMCTRL_CTRLA_CMD_CPRM,
|
||||
#ifdef FEATURE_NVM_RWWEE
|
||||
/** Read while write (RWW) EEPROM area erase row */
|
||||
NVM_COMMAND_RWWEE_ERASE_ROW = NVMCTRL_CTRLA_CMD_RWWEEER,
|
||||
/** RWW EEPROM write page */
|
||||
NVM_COMMAND_RWWEE_WRITE_PAGE = NVMCTRL_CTRLA_CMD_RWWEEWP,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NVM controller power reduction mode configurations.
|
||||
*
|
||||
* Power reduction modes of the NVM controller, to conserve power while the
|
||||
* device is in sleep.
|
||||
*/
|
||||
enum nvm_sleep_power_mode {
|
||||
/** NVM controller exits low-power mode on first access after sleep */
|
||||
NVM_SLEEP_POWER_MODE_WAKEONACCESS = NVMCTRL_CTRLB_SLEEPPRM_WAKEONACCESS_Val,
|
||||
/** NVM controller exits low-power mode when the device exits sleep mode */
|
||||
NVM_SLEEP_POWER_MODE_WAKEUPINSTANT = NVMCTRL_CTRLB_SLEEPPRM_WAKEUPINSTANT_Val,
|
||||
/** Power reduction mode in the NVM controller disabled */
|
||||
NVM_SLEEP_POWER_MODE_ALWAYS_AWAKE = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NVM controller cache readmode configuration.
|
||||
*
|
||||
* Control how the NVM cache prefetch data from flash.
|
||||
*
|
||||
*/
|
||||
enum nvm_cache_readmode {
|
||||
/** The NVM Controller (cache system) does not insert wait states on
|
||||
* a cache miss. Gives the best system performance.
|
||||
*/
|
||||
NVM_CACHE_READMODE_NO_MISS_PENALTY,
|
||||
/** Reduces power consumption of the cache system, but inserts a
|
||||
* wait state each time there is a cache miss
|
||||
*/
|
||||
NVM_CACHE_READMODE_LOW_POWER,
|
||||
/** The cache system ensures that a cache hit or miss takes the same
|
||||
* amount of time, determined by the number of programmed flash
|
||||
* wait states
|
||||
*/
|
||||
NVM_CACHE_READMODE_DETERMINISTIC,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NVM controller configuration structure.
|
||||
*
|
||||
* Configuration structure for the NVM controller within the device.
|
||||
*/
|
||||
struct nvm_config {
|
||||
/** Power reduction mode during device sleep */
|
||||
enum nvm_sleep_power_mode sleep_power_mode;
|
||||
/** Manual write mode; if enabled, pages loaded into the NVM buffer will
|
||||
* not be written until a separate write command is issued. If disabled,
|
||||
* writing to the last byte in the NVM page buffer will trigger an automatic
|
||||
* write.
|
||||
*
|
||||
* \note If a partial page is to be written, a manual write command must be
|
||||
* executed in either mode.
|
||||
*/
|
||||
bool manual_page_write;
|
||||
/** Number of wait states to insert when reading from flash, to prevent
|
||||
* invalid data from being read at high clock frequencies
|
||||
*/
|
||||
uint8_t wait_states;
|
||||
|
||||
/**
|
||||
* Setting this to true will disable the pre-fetch cache in front of the
|
||||
* NVM controller
|
||||
*/
|
||||
bool disable_cache;
|
||||
#if (SAMC20) || (SAMC21)
|
||||
/**
|
||||
* Setting this to true will disable the pre-fetch RWW cache in front of the
|
||||
* NVM controller.
|
||||
* If RWW cache is enabled, NVM cache will also be enabled.
|
||||
*/
|
||||
bool disable_rww_cache;
|
||||
#endif
|
||||
/**
|
||||
* Select the mode for how the cache will pre-fetch data from the flash
|
||||
*/
|
||||
enum nvm_cache_readmode cache_readmode;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NVM memory parameter structure.
|
||||
*
|
||||
* Structure containing the memory layout parameters of the NVM module.
|
||||
*/
|
||||
struct nvm_parameters {
|
||||
/** Number of bytes per page */
|
||||
uint8_t page_size;
|
||||
/** Number of pages in the main array */
|
||||
uint16_t nvm_number_of_pages;
|
||||
/** Size of the emulated EEPROM memory section configured in the NVM
|
||||
* auxiliary memory space */
|
||||
uint32_t eeprom_number_of_pages;
|
||||
/** Size of the Bootloader memory section configured in the NVM auxiliary
|
||||
* memory space */
|
||||
uint32_t bootloader_number_of_pages;
|
||||
#ifdef FEATURE_NVM_RWWEE
|
||||
/** Number of pages in read while write EEPROM (RWWEE) emulation area */
|
||||
uint16_t rww_eeprom_number_of_pages;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Bootloader size.
|
||||
*
|
||||
* Available bootloader protection sizes in kilobytes.
|
||||
*
|
||||
*/
|
||||
enum nvm_bootloader_size {
|
||||
/** Boot Loader Size is 32768 bytes */
|
||||
NVM_BOOTLOADER_SIZE_128,
|
||||
/** Boot Loader Size is 16384 bytes */
|
||||
NVM_BOOTLOADER_SIZE_64,
|
||||
/** Boot Loader Size is 8192 bytes */
|
||||
NVM_BOOTLOADER_SIZE_32,
|
||||
/** Boot Loader Size is 4096 bytes */
|
||||
NVM_BOOTLOADER_SIZE_16,
|
||||
/** Boot Loader Size is 2048 bytes */
|
||||
NVM_BOOTLOADER_SIZE_8,
|
||||
/** Boot Loader Size is 1024 bytes */
|
||||
NVM_BOOTLOADER_SIZE_4,
|
||||
/** Boot Loader Size is 512 bytes */
|
||||
NVM_BOOTLOADER_SIZE_2,
|
||||
/** Boot Loader Size is 0 bytes */
|
||||
NVM_BOOTLOADER_SIZE_0,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief EEPROM emulator size.
|
||||
*
|
||||
* Available space in flash dedicated for EEPROM emulator in bytes.
|
||||
*
|
||||
*/
|
||||
enum nvm_eeprom_emulator_size {
|
||||
/** EEPROM Size for EEPROM emulation is 16384 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_16384,
|
||||
/** EEPROM Size for EEPROM emulation is 8192 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_8192,
|
||||
/** EEPROM Size for EEPROM emulation is 4096 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_4096,
|
||||
/** EEPROM Size for EEPROM emulation is 2048 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_2048,
|
||||
/** EEPROM Size for EEPROM emulation is 1024 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_1024,
|
||||
/** EEPROM Size for EEPROM emulation is 512 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_512,
|
||||
/** EEPROM Size for EEPROM emulation is 256 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_256,
|
||||
/** EEPROM Size for EEPROM emulation is 0 bytes */
|
||||
NVM_EEPROM_EMULATOR_SIZE_0,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief BOD33 Action.
|
||||
*
|
||||
* What action should be triggered when BOD33 is detected.
|
||||
*
|
||||
*/
|
||||
enum nvm_bod33_action {
|
||||
/** No action */
|
||||
NVM_BOD33_ACTION_NONE,
|
||||
/** The BOD33 generates a reset */
|
||||
NVM_BOD33_ACTION_RESET,
|
||||
/** The BOD33 generates an interrupt */
|
||||
NVM_BOD33_ACTION_INTERRUPT,
|
||||
};
|
||||
|
||||
#ifdef FEATURE_BOD12
|
||||
/**
|
||||
* \brief BOD12 Action.
|
||||
*
|
||||
* What action should be triggered when BOD12 is detected.
|
||||
*
|
||||
*/
|
||||
enum nvm_bod12_action {
|
||||
/** No action */
|
||||
NVM_BOD12_ACTION_NONE,
|
||||
/** The BOD12 generates a reset */
|
||||
NVM_BOD12_ACTION_RESET,
|
||||
/** The BOD12 generates an interrupt */
|
||||
NVM_BOD12_ACTION_INTERRUPT,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief WDT Window time-out period.
|
||||
*
|
||||
* Window mode time-out period in clock cycles.
|
||||
*
|
||||
*/
|
||||
enum nvm_wdt_window_timeout {
|
||||
/** 8 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_8,
|
||||
/** 16 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_16,
|
||||
/** 32 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_32,
|
||||
/** 64 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_64,
|
||||
/** 128 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_128,
|
||||
/** 256 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_256,
|
||||
/** 512 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_512,
|
||||
/** 1024 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_1024,
|
||||
/** 2048 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_2048,
|
||||
/** 4096 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_4096,
|
||||
/** 8192 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_8192,
|
||||
/** 16384 clock cycles */
|
||||
NVM_WDT_WINDOW_TIMEOUT_PERIOD_16384,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief WDT Early warning offset.
|
||||
*
|
||||
* This setting determine how many GCLK_WDT cycles before a watchdog time-out period
|
||||
* an early warning interrupt should be triggered.
|
||||
*
|
||||
*/
|
||||
enum nvm_wdt_early_warning_offset {
|
||||
/** 8 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_8,
|
||||
/** 16 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_16,
|
||||
/** 32 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_32,
|
||||
/** 64 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_64,
|
||||
/** 128 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_128,
|
||||
/** 256 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_256,
|
||||
/** 512 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_512,
|
||||
/** 1024 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_1024,
|
||||
/** 2048 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_2048,
|
||||
/** 4096 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_4096,
|
||||
/** 8192 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_8192,
|
||||
/** 16384 clock cycles */
|
||||
NVM_WDT_EARLY_WARNING_OFFSET_16384,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NVM user row fuse setting structure.
|
||||
*
|
||||
* This structure contain the layout of the first 64 bits of the user row
|
||||
* which contain the fuse settings.
|
||||
*/
|
||||
struct nvm_fusebits {
|
||||
/** Bootloader size */
|
||||
enum nvm_bootloader_size bootloader_size;
|
||||
/** EEPROM emulation area size */
|
||||
enum nvm_eeprom_emulator_size eeprom_size;
|
||||
#if (SAMC20) || (SAMC21)
|
||||
/** BODVDD Threshold level at power on */
|
||||
uint8_t bodvdd_level;
|
||||
/** BODVDD Enable at power on */
|
||||
bool bodvdd_enable;
|
||||
/** BODVDD Action at power on */
|
||||
enum nvm_bod33_action bodvdd_action;
|
||||
/* BODVDD Hysteresis at power on */
|
||||
bool bodvdd_hysteresis;
|
||||
#else
|
||||
/** BOD33 Threshold level at power on */
|
||||
uint8_t bod33_level;
|
||||
/** BOD33 Enable at power on */
|
||||
bool bod33_enable;
|
||||
/** BOD33 Action at power on */
|
||||
enum nvm_bod33_action bod33_action;
|
||||
/* BOD33 Hysteresis at power on */
|
||||
bool bod33_hysteresis;
|
||||
#endif
|
||||
/** WDT Enable at power on */
|
||||
bool wdt_enable;
|
||||
/** WDT Always-on at power on */
|
||||
bool wdt_always_on;
|
||||
/** WDT Period at power on */
|
||||
uint8_t wdt_timeout_period;
|
||||
/** WDT Window mode time-out at power on */
|
||||
enum nvm_wdt_window_timeout wdt_window_timeout;
|
||||
/** WDT Early warning interrupt time offset at power on */
|
||||
enum nvm_wdt_early_warning_offset wdt_early_warning_offset;
|
||||
/** WDT Window mode enabled at power on */
|
||||
bool wdt_window_mode_enable_at_poweron;
|
||||
/** NVM Lock bits */
|
||||
uint16_t lockbits;
|
||||
#ifdef FEATURE_BOD12
|
||||
/** BOD12 Threshold level at power on */
|
||||
uint8_t bod12_level;
|
||||
/** BOD12 Enable at power on */
|
||||
bool bod12_enable;
|
||||
/** BOD12 Action at power on */
|
||||
enum nvm_bod12_action bod12_action;
|
||||
/* BOD12 Hysteresis at power on */
|
||||
bool bod12_hysteresis;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* \name Configuration and Initialization
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Initializes an NVM controller configuration structure to defaults.
|
||||
*
|
||||
* Initializes a given NVM controller configuration structure to a set of
|
||||
* known default values. This function should be called on all new
|
||||
* instances of these configuration structures before being modified by the
|
||||
* user application.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li Power reduction mode enabled after sleep mode until first NVM access
|
||||
* \li Automatic page write mode disabled
|
||||
* \li Number of FLASH wait states left unchanged
|
||||
*
|
||||
* \param[out] config Configuration structure to initialize to default values
|
||||
*
|
||||
*/
|
||||
static inline void nvm_get_config_defaults(
|
||||
struct nvm_config *const config)
|
||||
{
|
||||
/* Sanity check the parameters */
|
||||
Assert(config);
|
||||
|
||||
/* Write the default configuration for the NVM configuration */
|
||||
config->sleep_power_mode = NVM_SLEEP_POWER_MODE_WAKEONACCESS;
|
||||
config->manual_page_write = true;
|
||||
config->wait_states = NVMCTRL->CTRLB.bit.RWS;
|
||||
config->disable_cache = false;
|
||||
#if (SAMC20) || (SAMC21)
|
||||
config->disable_rww_cache = false;
|
||||
#endif
|
||||
config->cache_readmode = NVM_CACHE_READMODE_NO_MISS_PENALTY;
|
||||
}
|
||||
|
||||
enum status_code nvm_set_config(
|
||||
const struct nvm_config *const config);
|
||||
|
||||
/**
|
||||
* \brief Checks if the NVM controller is ready to accept a new command.
|
||||
*
|
||||
* Checks the NVM controller to determine if it is currently busy execution an
|
||||
* operation, or ready for a new command.
|
||||
*
|
||||
* \return Busy state of the NVM controller.
|
||||
*
|
||||
* \retval true If the hardware module is ready for a new command
|
||||
* \retval false If the hardware module is busy executing a command
|
||||
*
|
||||
*/
|
||||
static inline bool nvm_is_ready(void)
|
||||
{
|
||||
/* Get a pointer to the module hardware instance */
|
||||
Nvmctrl *const nvm_module = NVMCTRL;
|
||||
|
||||
return nvm_module->INTFLAG.reg & NVMCTRL_INTFLAG_READY;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \name NVM Access Management
|
||||
* @{
|
||||
*/
|
||||
|
||||
void nvm_get_parameters(
|
||||
struct nvm_parameters *const parameters);
|
||||
|
||||
enum status_code nvm_write_buffer(
|
||||
const uint32_t destination_address,
|
||||
const uint8_t *buffer,
|
||||
uint16_t length);
|
||||
|
||||
enum status_code nvm_read_buffer(
|
||||
const uint32_t source_address,
|
||||
uint8_t *const buffer,
|
||||
uint16_t length);
|
||||
|
||||
enum status_code nvm_update_buffer(
|
||||
const uint32_t destination_address,
|
||||
uint8_t *const buffer,
|
||||
uint16_t offset,
|
||||
uint16_t length);
|
||||
|
||||
enum status_code nvm_erase_row(
|
||||
const uint32_t row_address);
|
||||
|
||||
enum status_code nvm_execute_command(
|
||||
const enum nvm_command command,
|
||||
const uint32_t address,
|
||||
const uint32_t parameter);
|
||||
|
||||
enum status_code nvm_get_fuses(struct nvm_fusebits *fusebits);
|
||||
enum status_code nvm_set_fuses(struct nvm_fusebits *fb);
|
||||
|
||||
bool nvm_is_page_locked(uint16_t page_number);
|
||||
|
||||
/**
|
||||
* \brief Retrieves the error code of the last issued NVM operation.
|
||||
*
|
||||
* Retrieves the error code from the last executed NVM operation. Once
|
||||
* retrieved, any error state flags in the controller are cleared.
|
||||
*
|
||||
* \note The \ref nvm_is_ready() function is an exception. Thus, errors
|
||||
* retrieved after running this function should be valid for the function
|
||||
* executed before \ref nvm_is_ready().
|
||||
*
|
||||
* \return Error caused by the last NVM operation.
|
||||
*
|
||||
* \retval NVM_ERROR_NONE No error occurred in the last NVM operation
|
||||
*
|
||||
* \retval NVM_ERROR_LOCK The last NVM operation attempted to access a locked
|
||||
* region
|
||||
* \retval NVM_ERROR_PROG An invalid NVM command was issued
|
||||
*/
|
||||
static inline enum nvm_error nvm_get_error(void)
|
||||
{
|
||||
enum nvm_error ret_val;
|
||||
|
||||
/* Get a pointer to the module hardware instance */
|
||||
Nvmctrl *const nvm_module = NVMCTRL;
|
||||
|
||||
/* Mask out non-error bits */
|
||||
ret_val = (enum nvm_error)(nvm_module->STATUS.reg & NVM_ERRORS_MASK);
|
||||
|
||||
/* Clear error flags */
|
||||
nvm_module->STATUS.reg = NVM_ERRORS_MASK;
|
||||
|
||||
/* Return error code from the NVM controller */
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \page asfdoc_sam0_nvm_extra Extra Information for NVM Driver
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_extra_acronyms Acronyms
|
||||
* The table below presents the acronyms used in this module:
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Acronym</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>NVM</td>
|
||||
* <td>Non-Volatile Memory</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>EEPROM</td>
|
||||
* <td>Electrically Erasable Programmable Read-Only Memory</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_extra_dependencies Dependencies
|
||||
* This driver has the following dependencies:
|
||||
*
|
||||
* - None
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_extra_errata Errata
|
||||
* There are no errata related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_nvm_extra_history Module History
|
||||
* An overview of the module history is presented in the table below, with
|
||||
* details on the enhancements and fixes made to the module since its first
|
||||
* release. The current version of this corresponds to the newest version in
|
||||
* the table.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Changelog</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Removed BOD12 reference, removed nvm_set_fuses() API</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Added functions to read/write fuse settings</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Added support for NVM cache configuration</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Updated initialization function to also enable the digital interface
|
||||
* clock to the module if it is disabled</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Initial Release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page asfdoc_sam0_nvm_exqsg Examples for NVM Driver
|
||||
*
|
||||
* This is a list of the available Quick Start guides (QSGs) and example
|
||||
* applications for \ref asfdoc_sam0_nvm_group. QSGs are simple examples with
|
||||
* step-by-step instructions to configure and use this driver in a selection of
|
||||
* use cases. Note that a QSG can be compiled as a standalone application or be
|
||||
* added to the user application.
|
||||
*
|
||||
* - \subpage asfdoc_sam0_nvm_basic_use_case
|
||||
*
|
||||
* \page asfdoc_sam0_nvm_document_revision_history Document Revision History
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Doc. Rev.</th>
|
||||
* <th>Date</th>
|
||||
* <th>Comments</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42114E</td>
|
||||
* <td>12/2015</td>
|
||||
* <td>Added support for SAM L21/L22, SAM C21, SAM D09, SAMR30 and SAM DA1</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42114D</td>
|
||||
* <td>12/2014</td>
|
||||
* <td>Added support for SAM R21 and SAM D10/D11</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42114C</td>
|
||||
* <td>01/2014</td>
|
||||
* <td>Added support for SAM D21</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42114B</td>
|
||||
* <td>06/2013</td>
|
||||
* <td>Corrected documentation typos</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42114A</td>
|
||||
* <td>06/2013</td>
|
||||
* <td>Initial document release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#endif /* NVM_H_INCLUDED */
|
|
@ -0,0 +1,3 @@
|
|||
// Update this when the library is updated. Its not included by default.
|
||||
|
||||
#define ASF_VERSION "3.32.0"
|
|
@ -5,7 +5,7 @@
|
|||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* Leave 8KiB for the bootloader. */
|
||||
FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000 - 0x2000 - 0x010000 /* Leave 8KiB for the bootloader and 64k for the flash file system. */
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 - 0x010000 /* Leave 64k for the flash file system. */
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x008000 /* 32 KiB */
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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/runtime.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, fatfs_builtin_open);
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/fatfs/ff.h" /* FatFs lower layer API */
|
||||
#include "lib/fatfs/diskio.h" /* FatFs lower layer API */
|
||||
|
||||
const PARTITION VolToPart[MICROPY_FATFS_VOLUMES] = {
|
||||
{0, 1}, // Logical drive 0 ==> Physical drive 0, 1st partition
|
||||
{1, 0}, // Logical drive 1 ==> Physical drive 1 (auto detection)
|
||||
{2, 0}, // Logical drive 2 ==> Physical drive 2 (auto detection)
|
||||
{3, 0}, // Logical drive 3 ==> Physical drive 3 (auto detection)
|
||||
/*
|
||||
{0, 2}, // Logical drive 2 ==> Physical drive 0, 2nd partition
|
||||
{0, 3}, // Logical drive 3 ==> Physical drive 0, 3rd partition
|
||||
*/
|
||||
};
|
||||
|
||||
DWORD get_fattime(void) {
|
||||
// TODO(tannewt): Support the RTC.
|
||||
return ((2016) << 25) | ((9) << 21) | ((1) << 16) | ((16) << 11) | ((43) << 5) | (35 / 2);
|
||||
}
|
|
@ -8,7 +8,10 @@
|
|||
#include "py/runtime.h"
|
||||
#include "py/repl.h"
|
||||
#include "py/gc.h"
|
||||
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
#include "asf/common/services/sleepmgr/sleepmgr.h"
|
||||
#include "asf/common/services/usb/udc/udc.h"
|
||||
|
@ -19,8 +22,11 @@
|
|||
|
||||
#include "mpconfigboard.h"
|
||||
#include "modmachine_pin.h"
|
||||
#include "storage.h"
|
||||
#include "uart.h"
|
||||
|
||||
fs_user_mount_t fs_user_mount_flash;
|
||||
|
||||
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
if (lex == NULL) {
|
||||
|
@ -41,6 +47,114 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
|||
}
|
||||
}
|
||||
|
||||
static const char fresh_boot_py[] =
|
||||
"# boot.py -- run on boot-up\r\n"
|
||||
"# can run arbitrary Python, but best to keep it minimal\r\n"
|
||||
"\r\n"
|
||||
;
|
||||
|
||||
static const char fresh_main_py[] =
|
||||
"# main.py -- put your code here!\r\n"
|
||||
;
|
||||
|
||||
static const char fresh_readme_txt[] =
|
||||
"This is a MicroPython board\r\n"
|
||||
"\r\n"
|
||||
"You can get started right away by writing your Python code in 'main.py'.\r\n"
|
||||
"\r\n"
|
||||
"For a serial prompt:\r\n"
|
||||
" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n"
|
||||
" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n"
|
||||
" Then use a terminal program like Hyperterminal or putty.\r\n"
|
||||
" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n"
|
||||
" - Linux: use the command: screen /dev/ttyACM0\r\n"
|
||||
"\r\n"
|
||||
"Please visit http://micropython.org/help/ for further help.\r\n"
|
||||
;
|
||||
|
||||
// we don't make this function static because it needs a lot of stack and we
|
||||
// want it to be executed without using stack within main() function
|
||||
void init_flash_fs() {
|
||||
// init the vfs object
|
||||
fs_user_mount_t *vfs = &fs_user_mount_flash;
|
||||
vfs->str = "/flash";
|
||||
vfs->len = 6;
|
||||
vfs->flags = 0;
|
||||
flash_init_vfs(vfs);
|
||||
|
||||
// put the flash device in slot 0 (it will be unused at this point)
|
||||
MP_STATE_PORT(fs_user_mount)[0] = vfs;
|
||||
|
||||
// try to mount the flash
|
||||
FRESULT res = f_mount(&vfs->fatfs, vfs->str, 1);
|
||||
|
||||
if (res == FR_NO_FILESYSTEM) {
|
||||
// no filesystem, or asked to reset it, so create a fresh one
|
||||
|
||||
res = f_mkfs("/flash", 0, 0);
|
||||
if (res == FR_OK) {
|
||||
// success creating fresh LFS
|
||||
} else {
|
||||
printf("PYB: can't create flash filesystem\n");
|
||||
MP_STATE_PORT(fs_user_mount)[0] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// set label
|
||||
f_setlabel("/flash/internalflash");
|
||||
|
||||
// create empty main.py
|
||||
FIL fp;
|
||||
f_open(&fp, "/flash/main.py", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
UINT n;
|
||||
f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n);
|
||||
f_close(&fp);
|
||||
|
||||
// TODO(tannewt): Create an .inf driver file for Windows.
|
||||
|
||||
// create readme file
|
||||
f_open(&fp, "/flash/README.txt", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n);
|
||||
f_close(&fp);
|
||||
} else if (res == FR_OK) {
|
||||
// mount successful
|
||||
} else {
|
||||
printf("PYB: can't mount flash\n");
|
||||
MP_STATE_PORT(fs_user_mount)[0] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// The current directory is used as the boot up directory.
|
||||
// It is set to the internal flash filesystem by default.
|
||||
f_chdrive("/flash");
|
||||
|
||||
// Make sure we have a /flash/boot.py. Create it if needed.
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
res = f_stat("/flash/boot.py", &fno);
|
||||
if (res == FR_OK) {
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
// exists as a directory
|
||||
// TODO handle this case
|
||||
// see http://elm-chan.org/fsw/ff/img/app2.c for a "rm -rf" implementation
|
||||
} else {
|
||||
// exists as a file, good!
|
||||
}
|
||||
} else {
|
||||
// doesn't exist, create fresh file
|
||||
|
||||
FIL fp;
|
||||
f_open(&fp, "/flash/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
UINT n;
|
||||
f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
|
||||
// TODO check we could write n bytes
|
||||
f_close(&fp);
|
||||
}
|
||||
}
|
||||
|
||||
static char *stack_top;
|
||||
static char heap[8192];
|
||||
|
||||
|
@ -63,6 +177,10 @@ int main(int argc, char **argv) {
|
|||
|
||||
pin_init0();
|
||||
|
||||
// Initialise the local flash filesystem.
|
||||
// Create it if needed, mount in on /flash, and set it as current dir.
|
||||
init_flash_fs();
|
||||
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
pyexec_event_repl_init();
|
||||
for (;;) {
|
||||
|
@ -98,11 +216,6 @@ mp_import_stat_t mp_import_stat(const char *path) {
|
|||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void mp_keyboard_interrupt(void) {
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(mp_kbd_exception);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "modmachine_dac.h"
|
||||
#include "modmachine_pin.h"
|
||||
#include "modmachine_pwm.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
|
@ -44,6 +45,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&dac_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pwm_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&flash_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objstr.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "timeutils.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
/// \module os - basic "operating system" services
|
||||
///
|
||||
/// The `os` module contains functions for filesystem access and `urandom`.
|
||||
///
|
||||
/// The filesystem has `/` as the root directory, and the available physical
|
||||
/// drives are accessible from here. They are currently:
|
||||
///
|
||||
/// /flash -- the internal flash filesystem
|
||||
/// /sd -- the SD card (if it exists)
|
||||
///
|
||||
/// On boot up, the current directory is `/flash` if no SD card is inserted,
|
||||
/// otherwise it is `/sd`.
|
||||
|
||||
STATIC const qstr os_uname_info_fields[] = {
|
||||
MP_QSTR_sysname, MP_QSTR_nodename,
|
||||
MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
|
||||
};
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, "samd21");
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "samd21");
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING);
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
|
||||
STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
|
||||
STATIC MP_DEFINE_ATTRTUPLE(
|
||||
os_uname_info_obj,
|
||||
os_uname_info_fields,
|
||||
5,
|
||||
(mp_obj_t)&os_uname_info_sysname_obj,
|
||||
(mp_obj_t)&os_uname_info_nodename_obj,
|
||||
(mp_obj_t)&os_uname_info_release_obj,
|
||||
(mp_obj_t)&os_uname_info_version_obj,
|
||||
(mp_obj_t)&os_uname_info_machine_obj
|
||||
);
|
||||
|
||||
STATIC mp_obj_t os_uname(void) {
|
||||
return (mp_obj_t)&os_uname_info_obj;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
|
||||
|
||||
/// \function chdir(path)
|
||||
/// Change current directory.
|
||||
STATIC mp_obj_t os_chdir(mp_obj_t path_in) {
|
||||
const char *path;
|
||||
path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FRESULT res = f_chdrive(path);
|
||||
|
||||
if (res == FR_OK) {
|
||||
res = f_chdir(path);
|
||||
}
|
||||
|
||||
if (res != FR_OK) {
|
||||
// TODO should be mp_type_FileNotFoundError
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "No such file or directory: '%s'", path));
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir);
|
||||
|
||||
/// \function getcwd()
|
||||
/// Get the current directory.
|
||||
STATIC mp_obj_t os_getcwd(void) {
|
||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||
FRESULT res = f_getcwd(buf, sizeof buf);
|
||||
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
|
||||
return mp_obj_new_str(buf, strlen(buf), false);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd);
|
||||
|
||||
/// \function listdir([dir])
|
||||
/// With no argument, list the current directory. Otherwise list the given directory.
|
||||
STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
bool is_str_type = true;
|
||||
const char *path;
|
||||
if (n_args == 1) {
|
||||
if (mp_obj_get_type(args[0]) == &mp_type_bytes) {
|
||||
is_str_type = false;
|
||||
}
|
||||
path = mp_obj_str_get_str(args[0]);
|
||||
} else {
|
||||
path = "";
|
||||
}
|
||||
|
||||
// "hack" to list root directory
|
||||
if (path[0] == '/' && path[1] == '\0') {
|
||||
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
|
||||
if (vfs != NULL) {
|
||||
mp_obj_list_append(dir_list, mp_obj_new_str(vfs->str + 1, vfs->len - 1, false));
|
||||
}
|
||||
}
|
||||
return dir_list;
|
||||
}
|
||||
|
||||
return fat_vfs_listdir(path, is_str_type);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
|
||||
|
||||
/// \function mkdir(path)
|
||||
/// Create a new directory.
|
||||
STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
FRESULT res = f_mkdir(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
case FR_EXIST:
|
||||
// TODO should be FileExistsError
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path));
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
|
||||
|
||||
/// \function remove(path)
|
||||
/// Remove a file.
|
||||
STATIC mp_obj_t os_remove(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
// TODO check that path is actually a file before trying to unlink it
|
||||
FRESULT res = f_unlink(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
|
||||
|
||||
/// \function rename(old_path, new_path)
|
||||
/// Rename a file
|
||||
STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) {
|
||||
const char *old_path = mp_obj_str_get_str(path_in);
|
||||
const char *new_path = mp_obj_str_get_str(path_out);
|
||||
FRESULT res = f_rename(old_path, new_path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error renaming file '%s' to '%s'", old_path, new_path));
|
||||
}
|
||||
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
|
||||
|
||||
/// \function rmdir(path)
|
||||
/// Remove a directory.
|
||||
STATIC mp_obj_t os_rmdir(mp_obj_t path_o) {
|
||||
const char *path = mp_obj_str_get_str(path_o);
|
||||
// TODO check that path is actually a directory before trying to unlink it
|
||||
FRESULT res = f_unlink(path);
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return mp_const_none;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing directory '%s'", path));
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir);
|
||||
|
||||
// Checks for path equality, ignoring trailing slashes:
|
||||
// path_equal(/, /) -> true
|
||||
// path_equal(/flash//, /flash) -> true
|
||||
// second argument must be in canonical form (meaning no trailing slash, unless it's just /)
|
||||
STATIC bool path_equal(const char *path, const char *path_canonical) {
|
||||
for (; *path_canonical != '\0' && *path == *path_canonical; ++path, ++path_canonical) {
|
||||
}
|
||||
if (*path_canonical != '\0') {
|
||||
return false;
|
||||
}
|
||||
for (; *path == '/'; ++path) {
|
||||
}
|
||||
return *path == '\0';
|
||||
}
|
||||
|
||||
/// \function stat(path)
|
||||
/// Get the status of a file or directory.
|
||||
STATIC mp_obj_t os_stat(mp_obj_t path_in) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
fno.lfsize = 0;
|
||||
#endif
|
||||
|
||||
FRESULT res;
|
||||
if (path_equal(path, "/")) {
|
||||
// stat root directory
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
} else {
|
||||
res = FR_NO_PATH;
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
|
||||
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
|
||||
if (vfs != NULL && path_equal(path, vfs->str)) {
|
||||
// stat mounted device directory
|
||||
fno.fsize = 0;
|
||||
fno.fdate = 0;
|
||||
fno.ftime = 0;
|
||||
fno.fattrib = AM_DIR;
|
||||
res = FR_OK;
|
||||
}
|
||||
}
|
||||
if (res == FR_NO_PATH) {
|
||||
// stat normal file
|
||||
res = f_stat(path, &fno);
|
||||
}
|
||||
if (res != FR_OK) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
|
||||
mp_int_t mode = 0;
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
mode |= 0x4000; // stat.S_IFDIR
|
||||
} else {
|
||||
mode |= 0x8000; // stat.S_IFREG
|
||||
}
|
||||
mp_int_t seconds = timeutils_seconds_since_2000(
|
||||
1980 + ((fno.fdate >> 9) & 0x7f),
|
||||
(fno.fdate >> 5) & 0x0f,
|
||||
fno.fdate & 0x1f,
|
||||
(fno.ftime >> 11) & 0x1f,
|
||||
(fno.ftime >> 5) & 0x3f,
|
||||
2 * (fno.ftime & 0x1f)
|
||||
);
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(fno.fsize); // st_size
|
||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime
|
||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime
|
||||
|
||||
return t;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
|
||||
|
||||
STATIC mp_obj_t os_statvfs(mp_obj_t path_in) {
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
||||
DWORD nclst;
|
||||
FATFS *fatfs;
|
||||
FRESULT res = f_getfree(path, &nclst, &fatfs);
|
||||
if (res != FR_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL);
|
||||
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * 512); // f_bsize - block size
|
||||
t->items[1] = t->items[0]; // f_frsize - fragment size
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // f_blocks - total number of blocks
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree - number of free blocks
|
||||
t->items[4] = t->items[3]; // f_bavail - free blocks avail to unpriviledged users
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files - # inodes
|
||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree - # free inodes
|
||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail - # free inodes avail to unpriviledges users
|
||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax
|
||||
|
||||
return t;
|
||||
|
||||
error:
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res])));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_statvfs_obj, os_statvfs);
|
||||
|
||||
/// \function sync()
|
||||
/// Sync all filesystems.
|
||||
STATIC mp_obj_t os_sync(void) {
|
||||
disk_ioctl(0, CTRL_SYNC, NULL);
|
||||
disk_ioctl(1, CTRL_SYNC, NULL);
|
||||
disk_ioctl(2, CTRL_SYNC, NULL);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync);
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
/// \function urandom(n)
|
||||
/// Return a bytes object with n random bytes, generated by the hardware
|
||||
/// random number generator.
|
||||
STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
mp_int_t n = mp_obj_get_int(num);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
vstr.buf[i] = rng_get();
|
||||
}
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uname), (mp_obj_t)&os_uname_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chdir), (mp_obj_t)&os_chdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getcwd), (mp_obj_t)&os_getcwd_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_listdir), (mp_obj_t)&os_listdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&os_mkdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&os_remove_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rename),(mp_obj_t)&os_rename_obj},
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_rmdir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&os_stat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_statvfs), (mp_obj_t)&os_statvfs_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&mod_os_sync_obj },
|
||||
|
||||
/// \constant sep - separation character used in paths
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },
|
||||
|
||||
#if MICROPY_HW_ENABLE_RNG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_urandom), (mp_obj_t)&os_urandom_obj },
|
||||
#endif
|
||||
|
||||
// these are MicroPython extensions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&fsuser_mount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umount), (mp_obj_t)&fsuser_umount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&fsuser_mkfs_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
||||
const mp_obj_module_t uos_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uos,
|
||||
.globals = (mp_obj_dict_t*)&os_module_globals,
|
||||
};
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef __INCLUDED_MPCONFIGPORT_H
|
||||
#define __INCLUDED_MPCONFIGPORT_H
|
||||
|
||||
#define MICROPY_PY_SYS_PLATFORM "Atmel SAMD21"
|
||||
|
||||
// options to control how Micro Python is built
|
||||
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
|
@ -28,8 +30,8 @@
|
|||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
||||
#define MICROPY_PY_ASYNC_AWAIT (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
|
||||
#define MICROPY_PY_BUILTINS_FILTER (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
|
@ -40,8 +42,8 @@
|
|||
#define MICROPY_PY_BUILTINS_MIN_MAX (0)
|
||||
#define MICROPY_PY___FILE__ (0)
|
||||
#define MICROPY_PY_GC (0)
|
||||
#define MICROPY_PY_ARRAY (0)
|
||||
#define MICROPY_PY_ATTRTUPLE (0)
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#define MICROPY_PY_ATTRTUPLE (1)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
|
@ -53,6 +55,16 @@
|
|||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||
|
||||
// fatfs configuration used in ffconf.h
|
||||
#define MICROPY_FATFS_ENABLE_LFN (1)
|
||||
#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
|
||||
#define MICROPY_FATFS_USE_LABEL (1)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
#define MICROPY_FATFS_VOLUMES (4)
|
||||
#define MICROPY_FATFS_MULTI_PARTITION (1)
|
||||
#define MICROPY_FSUSERMOUNT (1)
|
||||
|
||||
#define MICROPY_VFS_FAT (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||
|
@ -78,16 +90,23 @@ typedef long mp_off_t;
|
|||
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
// extra built in modules to add to the list of known ones
|
||||
extern const struct _mp_obj_module_t machine_module;
|
||||
extern const struct _mp_obj_module_t uos_module;
|
||||
extern const struct _mp_obj_module_t utime_module;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module } \
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module } \
|
||||
|
||||
// board specific definitions
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
#include "asf/sam0/drivers/nvm/nvm.h"
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
#define TOTAL_FLASH_SIZE 0x010000
|
||||
|
||||
#define FLASH_MEM_SEG1_START_ADDR (0x00040000 - TOTAL_FLASH_SIZE)
|
||||
#define FLASH_PART1_START_BLOCK (0x100)
|
||||
#define FLASH_PART1_NUM_BLOCKS (TOTAL_FLASH_SIZE / FLASH_BLOCK_SIZE)
|
||||
|
||||
static bool flash_is_initialised = false;
|
||||
|
||||
void storage_init(void) {
|
||||
if (!flash_is_initialised) {
|
||||
struct nvm_config config_nvm;
|
||||
nvm_get_config_defaults(&config_nvm);
|
||||
config_nvm.manual_page_write = false;
|
||||
nvm_set_config(&config_nvm);
|
||||
flash_is_initialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t storage_get_block_size(void) {
|
||||
return FLASH_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
uint32_t storage_get_block_count(void) {
|
||||
return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS;
|
||||
}
|
||||
|
||||
void storage_flush(void) {
|
||||
}
|
||||
|
||||
static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
|
||||
buf[0] = boot;
|
||||
|
||||
if (num_blocks == 0) {
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
} else {
|
||||
buf[1] = 0xff;
|
||||
buf[2] = 0xff;
|
||||
buf[3] = 0xff;
|
||||
}
|
||||
|
||||
buf[4] = type;
|
||||
|
||||
if (num_blocks == 0) {
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
buf[7] = 0;
|
||||
} else {
|
||||
buf[5] = 0xff;
|
||||
buf[6] = 0xff;
|
||||
buf[7] = 0xff;
|
||||
}
|
||||
|
||||
buf[8] = start_block;
|
||||
buf[9] = start_block >> 8;
|
||||
buf[10] = start_block >> 16;
|
||||
buf[11] = start_block >> 24;
|
||||
|
||||
buf[12] = num_blocks;
|
||||
buf[13] = num_blocks >> 8;
|
||||
buf[14] = num_blocks >> 16;
|
||||
buf[15] = num_blocks >> 24;
|
||||
}
|
||||
|
||||
static uint32_t convert_block_to_flash_addr(uint32_t block) {
|
||||
if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
|
||||
// a block in partition 1
|
||||
block -= FLASH_PART1_START_BLOCK;
|
||||
return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE;
|
||||
}
|
||||
// bad block
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool storage_read_block(uint8_t *dest, uint32_t block) {
|
||||
//printf("RD %u\n", block);
|
||||
if (block == 0) {
|
||||
// fake the MBR so we can decide on our own partition table
|
||||
|
||||
for (int i = 0; i < 446; i++) {
|
||||
dest[i] = 0;
|
||||
}
|
||||
|
||||
build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, FLASH_PART1_NUM_BLOCKS);
|
||||
build_partition(dest + 462, 0, 0, 0, 0);
|
||||
build_partition(dest + 478, 0, 0, 0, 0);
|
||||
build_partition(dest + 494, 0, 0, 0, 0);
|
||||
|
||||
dest[510] = 0x55;
|
||||
dest[511] = 0xaa;
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// non-MBR block, get data from flash memory
|
||||
uint32_t src = convert_block_to_flash_addr(block);
|
||||
if (src == -1) {
|
||||
// bad block number
|
||||
return false;
|
||||
}
|
||||
enum status_code error_code;
|
||||
// A block is made up of multiple pages. Read each page
|
||||
// sequentially.
|
||||
for (int i = 0; i < FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
do
|
||||
{
|
||||
error_code = nvm_read_buffer(src + i * NVMCTRL_PAGE_SIZE,
|
||||
dest + i * NVMCTRL_PAGE_SIZE,
|
||||
NVMCTRL_PAGE_SIZE);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool storage_write_block(const uint8_t *src, uint32_t block) {
|
||||
if (block == 0) {
|
||||
// can't write MBR, but pretend we did
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// non-MBR block, copy to cache
|
||||
volatile uint32_t dest = convert_block_to_flash_addr(block);
|
||||
if (dest == -1) {
|
||||
// bad block number
|
||||
return false;
|
||||
}
|
||||
enum status_code error_code;
|
||||
// A block is formed by two rows of flash. We must erase each row
|
||||
// before we write back to it.
|
||||
do
|
||||
{
|
||||
error_code = nvm_erase_row(dest);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
if (error_code != STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
do
|
||||
{
|
||||
error_code = nvm_erase_row(dest + NVMCTRL_ROW_SIZE);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
if (error_code != STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A block is made up of multiple pages. Write each page
|
||||
// sequentially.
|
||||
for (int i = 0; i < FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
do
|
||||
{
|
||||
error_code = nvm_write_buffer(dest + i * NVMCTRL_PAGE_SIZE,
|
||||
src + i * NVMCTRL_PAGE_SIZE,
|
||||
NVMCTRL_PAGE_SIZE);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
if (error_code != STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
for (size_t i = 0; i < num_blocks; i++) {
|
||||
if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
|
||||
for (size_t i = 0; i < num_blocks; i++) {
|
||||
if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
//
|
||||
// Expose the flash as an object with the block protocol.
|
||||
|
||||
// there is a singleton Flash object
|
||||
STATIC const mp_obj_base_t flash_obj = {&flash_type};
|
||||
|
||||
STATIC mp_obj_t flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// return singleton object
|
||||
return (mp_obj_t)&flash_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
|
||||
mp_uint_t ret = storage_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(flash_readblocks_obj, flash_readblocks);
|
||||
|
||||
STATIC mp_obj_t flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
mp_uint_t ret = storage_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(flash_writeblocks_obj, flash_writeblocks);
|
||||
|
||||
STATIC mp_obj_t flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
switch (cmd) {
|
||||
case BP_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
|
||||
case BP_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count());
|
||||
case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size());
|
||||
default: return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(flash_ioctl_obj, flash_ioctl);
|
||||
|
||||
STATIC const mp_map_elem_t flash_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readblocks), (mp_obj_t)&flash_readblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeblocks), (mp_obj_t)&flash_writeblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&flash_ioctl_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(flash_locals_dict, flash_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t flash_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Flash,
|
||||
.make_new = flash_make_new,
|
||||
.locals_dict = (mp_obj_t)&flash_locals_dict,
|
||||
};
|
||||
|
||||
void flash_init_vfs(fs_user_mount_t *vfs) {
|
||||
vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
|
||||
vfs->readblocks[0] = (mp_obj_t)&flash_readblocks_obj;
|
||||
vfs->readblocks[1] = (mp_obj_t)&flash_obj;
|
||||
vfs->readblocks[2] = (mp_obj_t)storage_read_blocks; // native version
|
||||
vfs->writeblocks[0] = (mp_obj_t)&flash_writeblocks_obj;
|
||||
vfs->writeblocks[1] = (mp_obj_t)&flash_obj;
|
||||
vfs->writeblocks[2] = (mp_obj_t)storage_write_blocks; // native version
|
||||
vfs->u.ioctl[0] = (mp_obj_t)&flash_ioctl_obj;
|
||||
vfs->u.ioctl[1] = (mp_obj_t)&flash_obj;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define FLASH_BLOCK_SIZE (512)
|
||||
|
||||
#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms
|
||||
#define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2)
|
||||
|
||||
void storage_init(void);
|
||||
uint32_t storage_get_block_size(void);
|
||||
uint32_t storage_get_block_count(void);
|
||||
void storage_irq_handler(void);
|
||||
void storage_flush(void);
|
||||
bool storage_read_block(uint8_t *dest, uint32_t block);
|
||||
bool storage_write_block(const uint8_t *src, uint32_t block);
|
||||
|
||||
// these return 0 on success, non-zero on error
|
||||
mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
|
||||
mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
|
||||
|
||||
extern const struct _mp_obj_type_t flash_type;
|
||||
|
||||
struct _fs_user_mount_t;
|
||||
void flash_init_vfs(struct _fs_user_mount_t *vfs);
|
Loading…
Reference in New Issue