atmel/samd: Add filesystem support. 64k is stored in flash.

This commit is contained in:
Scott Shawcroft 2016-09-02 17:00:30 -07:00
parent 559434afca
commit 09be96a6aa
14 changed files with 3046 additions and 12 deletions

View File

@ -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

View File

@ -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&reg; | SMART ARM&reg;-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 */

3
atmel-samd/asf/version.h Normal file
View File

@ -0,0 +1,3 @@
// Update this when the library is updated. Its not included by default.
#define ASF_VERSION "3.32.0"

View File

@ -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 */
}

View File

@ -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 */
}

30
atmel-samd/builtin_open.c Normal file
View File

@ -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);

46
atmel-samd/fatfs_port.c Normal file
View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

385
atmel-samd/moduos.c Normal file
View File

@ -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,
};

View File

@ -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

290
atmel-samd/storage.c Normal file
View File

@ -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;
}

47
atmel-samd/storage.h Normal file
View File

@ -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);