risc-v/espressif: Add SPI Flash support

This commit is contained in:
Eren Terzioglu
2024-02-21 07:19:51 -08:00
committed by Xiang Xiao
parent 7b37dd1224
commit aa0dccb7bc
31 changed files with 3408 additions and 1 deletions
+62
View File
@@ -43,6 +43,12 @@ config ESPRESSIF_FLASH_2M
config ESPRESSIF_FLASH_4M
bool "4 MB"
config ESPRESSIF_FLASH_8M
bool "8 MB"
config ESPRESSIF_FLASH_16M
bool "16 MB"
endchoice # ESPRESSIF_FLASH
config ESPRESSIF_FLASH_DETECT
@@ -281,6 +287,10 @@ config ESPRESSIF_LEDC
select PWM
select ARCH_HAVE_PWM_MULTICHAN
config ESPRESSIF_SPIFLASH
bool "SPI Flash"
default n
config ESPRESSIF_HR_TIMER
bool
default RTC_DRIVER
@@ -408,6 +418,35 @@ config ESPRESSIF_FLASH_MODE_QOUT
endchoice # ESPRESSIF_FLASH_MODE
if ESPRESSIF_SPIFLASH
comment "General storage MTD configuration"
config ESPRESSIF_MTD
bool "MTD driver"
default y
select MTD
select MTD_BYTE_WRITE
select MTD_PARTITION
---help---
Initialize an MTD driver for the SPI Flash, which will
add an entry at /dev for application access from userspace.
config ESPRESSIF_SPIFLASH_MTD_BLKSIZE
int "Storage MTD block size"
default 64
depends on ESPRESSIF_MTD
---help---
Block size for MTD driver in kB. This size must be divisible by 2
config ESPRESSIF_STORAGE_MTD_DEBUG
bool "Storage MTD Debug"
default n
depends on ESPRESSIF_MTD && DEBUG_FS_INFO
---help---
If this option is enabled, Storage MTD driver read and write functions
will output input parameters and return values (if applicable).
endif # ESPRESSIF_SPIFLASH
choice ESPRESSIF_FLASH_FREQ
prompt "SPI Flash frequency"
default ESPRESSIF_FLASH_FREQ_80M if ESPRESSIF_ESP32C3 || ESPRESSIF_ESP32C6
@@ -437,6 +476,29 @@ config ESPRESSIF_FLASH_FREQ_20M
endchoice # ESPRESSIF_FLASH_FREQ
config ESPRESSIF_SPI_FLASH_USE_32BIT_ADDRESS
bool "SPI flash uses 32-bit address"
default n
---help---
SPI flash driver in ROM only support 24-bit address access,
if select the option, it will force to use source code instead
of functions in ROM, so that SPI flash driver can access full
32-bit address.
config ESPRESSIF_STORAGE_MTD_OFFSET
hex "Storage MTD base address in SPI Flash"
default 0x180000
depends on ESPRESSIF_MTD
---help---
MTD base address in SPI Flash.
config ESPRESSIF_STORAGE_MTD_SIZE
hex "Storage MTD size in SPI Flash"
default 0x100000
depends on ESPRESSIF_MTD
---help---
MTD size in SPI Flash.
endmenu # SPI Flash Configuration
menu "LEDC configuration"
+8 -1
View File
@@ -80,6 +80,13 @@ ifeq ($(CONFIG_ESP_RMT),y)
endif
endif
ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
CHIP_CSRCS += esp_spiflash.c
ifeq ($(CONFIG_ESPRESSIF_MTD),y)
CHIP_CSRCS += esp_spiflash_mtd.c
endif
endif
#############################################################################
# Espressif HAL for 3rd Party Platforms
#############################################################################
@@ -88,7 +95,7 @@ endif
ESP_HAL_3RDPARTY_REPO = esp-hal-3rdparty
ifndef ESP_HAL_3RDPARTY_VERSION
ESP_HAL_3RDPARTY_VERSION = b6a943764f5e5a12d12edd8a6d71bdecc505428c
ESP_HAL_3RDPARTY_VERSION = 7951b5b282384ec43858a28ddfabbef7b6b326cb
endif
ifndef ESP_HAL_3RDPARTY_URL
@@ -115,6 +115,19 @@ static volatile uint8_t g_irq_map[NR_IRQS];
static uint32_t g_cpuint_freelist = ESP_CPUINT_PERIPHSET;
/* This bitmask has an 1 if the int should be disabled
* when the flash is disabled.
*/
static uint32_t non_iram_int_mask[CONFIG_ESPRESSIF_NUM_CPUS];
/* This bitmask has 1 in it if the int was disabled
* using esp_intr_noniram_disable.
*/
static uint32_t non_iram_int_disabled[CONFIG_ESPRESSIF_NUM_CPUS];
static bool non_iram_int_disabled_flag[CONFIG_ESPRESSIF_NUM_CPUS];
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -280,6 +293,15 @@ static void esp_cpuint_initialize(void)
void up_irqinitialize(void)
{
/* All CPU ints are non-IRAM interrupts at the beginning and should be
* disabled during a SPI flash operation
*/
for (int i = 0; i < CONFIG_SMP_NCPUS; i++)
{
non_iram_int_mask[i] = UINT32_MAX;
}
/* Indicate that no interrupt sources are assigned to CPU interrupts */
for (int i = 0; i < NR_IRQS; i++)
@@ -584,3 +606,77 @@ irqstate_t up_irq_enable(void)
flags = READ_AND_SET_CSR(mstatus, MSTATUS_MIE);
return flags;
}
/****************************************************************************
* Name: esp_intr_noniram_disable
*
* Description:
* Disable interrupts that aren't specifically marked as running from IRAM.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void IRAM_ATTR esp_intr_noniram_disable(void)
{
uint32_t oldint;
irqstate_t irqstate;
uint32_t cpu;
uint32_t non_iram_ints;
irqstate = enter_critical_section();
cpu = esp_cpu_get_core_id();
non_iram_ints = non_iram_int_mask[cpu];
if (non_iram_int_disabled_flag[cpu])
{
abort();
}
non_iram_int_disabled_flag[cpu] = true;
oldint = esp_cpu_intr_get_enabled_mask();
esp_cpu_intr_disable(non_iram_ints);
/* Save disabled ints */
non_iram_int_disabled[cpu] = oldint & non_iram_ints;
leave_critical_section(irqstate);
}
/****************************************************************************
* Name: esp_intr_noniram_enable
*
* Description:
* Enable interrupts that aren't specifically marked as running from IRAM.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void IRAM_ATTR esp_intr_noniram_enable(void)
{
irqstate_t irqstate;
uint32_t cpu;
int non_iram_ints;
irqstate = enter_critical_section();
cpu = esp_cpu_get_core_id();
non_iram_ints = non_iram_int_disabled[cpu];
if (!non_iram_int_disabled_flag[cpu])
{
abort();
}
non_iram_int_disabled_flag[cpu] = false;
esp_cpu_intr_enable(non_iram_ints);
leave_critical_section(irqstate);
}
@@ -142,6 +142,38 @@ int esp_setup_irq(int source, irq_priority_t priority, irq_trigger_t type);
void esp_teardown_irq(int source, int cpuint);
/****************************************************************************
* Name: esp_intr_noniram_disable
*
* Description:
* Disable interrupts that aren't specifically marked as running from IRAM.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void esp_intr_noniram_disable(void);
/****************************************************************************
* Name: esp_intr_noniram_enable
*
* Description:
* Enable interrupts that aren't specifically marked as running from IRAM.
*
* Input Parameters:
* None.
*
* Returned Value:
* None.
*
****************************************************************************/
void esp_intr_noniram_enable(void);
#undef EXTERN
#if defined(__cplusplus)
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,188 @@
/****************************************************************************
* arch/risc-v/src/common/espressif/esp_spiflash.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_SPIFLASH_H
#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_SPIFLASH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <nuttx/mtd/mtd.h>
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Types
****************************************************************************/
/**
* Structure holding SPI flash access critical sections management functions.
*
* Flash API uses two types of functions for flash access management:
* 1) Functions which prepare/restore flash cache and interrupts before
* calling appropriate ROM functions (spi_flash_write, spi_flash_read,
* spi_flash_erase_sector and spi_flash_erase_range):
* - 'start' function should disable flash cache and non-IRAM interrupts
* and is invoked before the call to one of ROM functions from
* "struct spiflash_guard_funcs".
* - 'end' function should restore state of flash cache and non-IRAM
* interrupts and is invoked after the call to one of ROM
* functions from "struct spiflash_guard_funcs".
* These two functions are not reentrant.
* 2) Functions which synchronizes access to internal data used by flash API.
* These functions are mostly intended to synchronize access to flash API
* internal data in multithreaded environment and use OS primitives:
* - 'op_lock' locks access to flash API internal data.
* - 'op_unlock' unlocks access to flash API internal data.
* These two functions are reentrant and can be used around the outside of
* multiple calls to 'start' & 'end', in order to create atomic multi-part
* flash operations.
*
* Structure and corresponding guard functions should not reside
* in flash. For example structure can be placed in DRAM and functions
* in IRAM sections.
*/
struct spiflash_guard_funcs
{
void (*start)(void); /* critical section start function */
void (*end)(void); /* critical section end function */
void (*op_lock)(void); /* flash access API lock function */
void (*op_unlock)(void); /* flash access API unlock function */
/* checks flash write addresses */
bool (*address_is_safe)(size_t addr, size_t size);
void (*yield)(void); /* yield to the OS during flash erase */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: spi_flash_read
*
* Description:
* Read data from Flash.
*
* Parameters:
* address - source address of the data in Flash.
* buffer - pointer to the destination buffer
* length - length of data
*
* Returned Values:
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
int spi_flash_read(uint32_t address, void *buffer, uint32_t length);
/****************************************************************************
* Name: spi_flash_erase_sector
*
* Description:
* Erase the Flash sector.
*
* Parameters:
* sector - Sector number, the count starts at sector 0, 4KB per sector.
*
* Returned Values: esp_err_t
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
int spi_flash_erase_sector(uint32_t sector);
/****************************************************************************
* Name: spi_flash_erase_range
*
* Description:
* Erase a range of flash sectors
*
* Parameters:
* start_address - Address where erase operation has to start.
* Must be 4kB-aligned
* size - Size of erased range, in bytes. Must be divisible by
* 4kB.
*
* Returned Values:
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
int spi_flash_erase_range(uint32_t start_address, uint32_t size);
/****************************************************************************
* Name: spi_flash_write
*
* Description:
* Write data to Flash.
*
* Parameters:
* dest_addr - Destination address in Flash.
* src - Pointer to the source buffer.
* size - Length of data, in bytes.
*
* Returned Values:
* Zero (OK) is returned or a negative error.
*
****************************************************************************/
int spi_flash_write(uint32_t dest_addr, const void *buffer, uint32_t size);
/****************************************************************************
* Name: esp_spiflash_init
*
* Description:
* Initialize ESP SPI flash driver.
*
* Input Parameters:
* None.
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
int esp_spiflash_init(void);
#ifdef __cplusplus
}
#endif
#undef EXTERN
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_SPIFLASH_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,89 @@
/****************************************************************************
* arch/risc-v/src/common/espressif/esp_spiflash_mtd.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_SPIFLASH_MTD_H
#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_SPIFLASH_MTD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <nuttx/mtd/mtd.h>
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: esp_spiflash_mtd
*
* Description:
* Get SPI Flash MTD.
*
* Input Parameters:
* None
*
* Returned Value:
* SPI Flash MTD pointer.
*
****************************************************************************/
struct mtd_dev_s *esp_spiflash_mtd(void);
/****************************************************************************
* Name: esp_spiflash_alloc_mtdpart
*
* Description:
* Allocate an MTD partition from the SPI Flash.
*
* Input Parameters:
* mtd_offset - MTD Partition offset from the base address in SPI Flash.
* mtd_size - Size for the MTD partition.
*
* Returned Value:
* SPI Flash MTD data pointer if success or NULL if fail.
*
****************************************************************************/
struct mtd_dev_s *esp_spiflash_alloc_mtdpart(uint32_t mtd_offset,
uint32_t mtd_size);
#ifdef __cplusplus
}
#endif
#undef EXTERN
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_SPIFLASH_MTD_H */
+2
View File
@@ -49,6 +49,8 @@ INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/compone
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/riscv/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/soc/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/soc/$(CHIP_SERIES)/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/spi_flash/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/spi_flash/include/spi_flash
ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y)
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/bootloader_support/include
+2
View File
@@ -49,6 +49,8 @@ INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/compone
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/riscv/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/soc/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/soc/$(CHIP_SERIES)/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/spi_flash/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/spi_flash/include/spi_flash
# Linker scripts
+2
View File
@@ -49,6 +49,8 @@ INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/compone
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/riscv/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/soc/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/soc/$(CHIP_SERIES)/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/spi_flash/include
INCLUDES += $(INCDIR_PREFIX)$(ARCH_SRCDIR)/chip/$(ESP_HAL_3RDPARTY_REPO)/components/spi_flash/include/spi_flash
# Linker scripts
+37
View File
@@ -11,3 +11,40 @@ config ESPRESSIF_MERGE_BINS
device.
This is only useful when the path to binary files (e.g. bootloader)
is provided via the ESPTOOL_BINDIR variable.
choice ESPRESSIF_SPIFLASH_FS
prompt "Mount SPI Flash MTD on bring-up"
default ESPRESSIF_SPIFLASH_SMARTFS
depends on ESPRESSIF_MTD
optional
---help---
Mount the SPI Flash MTD with the selected File System format on board
bring-up.
If not selected, the MTD will be registered as a device node on /dev.
config ESPRESSIF_SPIFLASH_SMARTFS
bool "SmartFS"
select FS_SMARTFS
select MTD_SMART
config ESPRESSIF_SPIFLASH_NXFFS
bool "NXFFS"
select FS_NXFFS
config ESPRESSIF_SPIFLASH_SPIFFS
bool "SPIFFS"
select FS_SPIFFS
config ESPRESSIF_SPIFLASH_LITTLEFS
bool "LittleFS"
select FS_LITTLEFS
config ESPRESSIF_SPIFLASH_MTD_CONFIG
bool "Non-volatile storage"
endchoice # ESPRESSIF_SPIFLASH_FS
config ESPRESSIF_SPIFLASH_FS_MOUNT_PT
string "File-system Mount Point"
depends on ESPRESSIF_SPIFLASH_LITTLEFS
default "/data"
@@ -0,0 +1,74 @@
/****************************************************************************
* boards/risc-v/esp32c3/common/include/esp_board_spiflash.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H
#define __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPIFLASH and register the MTD device.
*
* Input Parameters:
* None.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_ESPRESSIF_SPIFLASH
int board_spiflash_init(void);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H */
@@ -28,6 +28,10 @@ ifeq ($(CONFIG_ESP_RMT),y)
CSRCS += esp_board_rmt.c
endif
ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
CSRCS += esp_board_spiflash.c
endif
DEPPATH += --dep-path src
VPATH += :src
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
@@ -0,0 +1,417 @@
/****************************************************************************
* boards/risc-v/esp32c3/common/src/esp_board_spiflash.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/mount.h>
#include "inttypes.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <sys/param.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/mtd/configdata.h>
#include <nuttx/fs/nxffs.h>
#ifdef CONFIG_BCH
#include <nuttx/drivers/drivers.h>
#endif
#include "espressif/esp_spiflash.h"
#include "espressif/esp_spiflash_mtd.h"
#include "esp_board_spiflash.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: setup_smartfs
*
* Description:
* Provide a block driver wrapper around MTD partition and mount a
* SMART FS over it.
*
* Parameters:
* smartn - Number used to register the mtd partition: /dev/smartx, where
* x = smartn.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SMARTFS)
static int setup_smartfs(int smartn, struct mtd_dev_s *mtd,
const char *mnt_pt)
{
int ret = OK;
char path[22];
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
syslog(LOG_INFO, "smart_initialize failed, "
"Trying to erase first...\n");
ret = mtd->ioctl(mtd, MTDIOC_BULKERASE, 0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: ioctl(BULKERASE) failed: %d\n", ret);
return ret;
}
syslog(LOG_INFO, "Erase successful, initializing it again.\n");
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: smart_initialize failed: %d\n", ret);
return ret;
}
}
if (mnt_pt != NULL)
{
snprintf(path, sizeof(path), "/dev/smart%d", smartn);
ret = nx_mount(path, mnt_pt, "smartfs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
if (ret == -ENODEV)
{
syslog(LOG_WARNING, "Smartfs seems unformatted. "
"Did you run 'mksmartfs /dev/smart%d'?\n", smartn);
}
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_littlefs
*
* Description:
* Register a mtd driver and mount a Little FS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_LITTLEFS)
static int setup_littlefs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, NULL);
if (ret < 0)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, "forceformat");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n",
ret);
return ret;
}
}
}
return OK;
}
#endif
/****************************************************************************
* Name: setup_spiffs
*
* Description:
* Register a mtd driver and mount a SPIFFS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SPIFFS)
static int setup_spiffs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "spiffs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_nxffs
*
* Description:
* Register a mtd driver and mount a NXFFS over it.
*
* Parameters:
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_NXFFS)
static int setup_nxffs(struct mtd_dev_s *mtd, const char *mnt_pt)
{
int ret = OK;
ret = nxffs_initialize(mtd);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: NXFFS init failed: %d\n", ret);
return ret;
}
if (mnt_pt != NULL)
{
ret = nx_mount(NULL, mnt_pt, "nxffs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: init_storage_partition
*
* Description:
* Initialize partition that is dedicated to general use.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int init_storage_partition(void)
{
int ret = OK;
struct mtd_dev_s *mtd;
mtd = esp_spiflash_alloc_mtdpart(CONFIG_ESPRESSIF_STORAGE_MTD_OFFSET,
CONFIG_ESPRESSIF_STORAGE_MTD_SIZE);
if (!mtd)
{
syslog(LOG_ERR, "ERROR: Failed to alloc MTD partition of SPI Flash\n");
return ERROR;
}
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SMARTFS)
ret = setup_smartfs(0, mtd, "/data");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup smartfs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_NXFFS)
ret = setup_nxffs(mtd, "/data");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup nxffs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_LITTLEFS)
const char *path = "/dev/espflash";
ret = setup_littlefs(path, mtd, "/data", 0755);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup littlefs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_SPIFFS)
const char *path = "/dev/espflash";
ret = setup_spiffs(path, mtd, "/data", 0755);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup spiffs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_MTD_CONFIG)
# if defined (CONFIG_TESTING_MTD_CONFIG_FAIL_SAFE)
/* To test power-loss resilient kv system,
* we write possible power-loss flash layout into flash
* then start kv system to see if it recovers.
* To do so, we need a mtd driver so that test code can
* write into flash.
*/
const char *path = CONFIG_TESTING_MTD_CONFIG_FAIL_SAFE_MOUNTPT_NAME;
ret = register_mtddriver(path, mtd, 0777, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
# else
ret = mtdconfig_register(mtd);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup mtd config\n");
return ret;
}
# endif
#else
ret = register_mtddriver("/dev/espflash", mtd, 0755, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
#endif
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPI Flash and register the MTD device.
*
* Input Parameters:
* None.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
int board_spiflash_init(void)
{
int ret = OK;
esp_spiflash_init();
ret = init_storage_partition();
if (ret < 0)
{
return ret;
}
return ret;
}
@@ -0,0 +1,54 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32c3-generic"
CONFIG_ARCH_BOARD_COMMON=y
CONFIG_ARCH_BOARD_ESP32C3_GENERIC=y
CONFIG_ARCH_CHIP="esp32c3"
CONFIG_ARCH_CHIP_ESP32C3_GENERIC=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_ESPRESSIF_SPIFLASH=y
CONFIG_ESPRESSIF_SPIFLASH_SMARTFS=y
CONFIG_ESPRESSIF_STORAGE_MTD_OFFSET=0x110000
CONFIG_ESPRESSIF_STORAGE_MTD_SIZE=0xf0000
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_PERROR_STDOUT=y
CONFIG_LIBC_STRERROR=y
CONFIG_NAME_MAX=48
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_DISABLE_LOSMART=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
CONFIG_SMARTFS_MAXNAMLEN=48
CONFIG_START_DAY=29
CONFIG_START_MONTH=11
CONFIG_START_YEAR=2019
CONFIG_SYSTEM_DUMPSTACK=y
CONFIG_SYSTEM_FLASH_ERASEALL=y
CONFIG_SYSTEM_NSH=y
CONFIG_TESTING_FSTEST=y
CONFIG_TESTING_FSTEST_MOUNTPT="/mnt"
CONFIG_UART0_SERIAL_CONSOLE=y
@@ -35,6 +35,7 @@
#include <nuttx/fs/fs.h>
#include "esp_board_ledc.h"
#include "esp_board_spiflash.h"
#ifdef CONFIG_WATCHDOG
# include "espressif/esp_wdt.h"
@@ -143,6 +144,14 @@ int esp_bringup(void)
#endif
#endif
#ifdef CONFIG_ESPRESSIF_SPIFLASH
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
}
#endif
#ifdef CONFIG_ONESHOT
ret = esp_oneshot_initialize();
if (ret < 0)
+37
View File
@@ -11,3 +11,40 @@ config ESPRESSIF_MERGE_BINS
device.
This is only useful when the path to binary files (e.g. bootloader)
is provided via the ESPTOOL_BINDIR variable.
choice ESPRESSIF_SPIFLASH_FS
prompt "Mount SPI Flash MTD on bring-up"
default ESPRESSIF_SPIFLASH_SMARTFS
depends on ESPRESSIF_MTD
optional
---help---
Mount the SPI Flash MTD with the selected File System format on board
bring-up.
If not selected, the MTD will be registered as a device node on /dev.
config ESPRESSIF_SPIFLASH_SMARTFS
bool "SmartFS"
select FS_SMARTFS
select MTD_SMART
config ESPRESSIF_SPIFLASH_NXFFS
bool "NXFFS"
select FS_NXFFS
config ESPRESSIF_SPIFLASH_SPIFFS
bool "SPIFFS"
select FS_SPIFFS
config ESPRESSIF_SPIFLASH_LITTLEFS
bool "LittleFS"
select FS_LITTLEFS
config ESPRESSIF_SPIFLASH_MTD_CONFIG
bool "Non-volatile storage"
endchoice # ESPRESSIF_SPIFLASH_FS
config ESPRESSIF_SPIFLASH_FS_MOUNT_PT
string "File-system Mount Point"
depends on ESPRESSIF_SPIFLASH_LITTLEFS
default "/data"
@@ -0,0 +1,74 @@
/****************************************************************************
* boards/risc-v/esp32c6/common/include/esp_board_spiflash.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H
#define __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPIFLASH and register the MTD device.
*
* Input Parameters:
* None.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_ESPRESSIF_SPIFLASH
int board_spiflash_init(void);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H */
@@ -18,6 +18,9 @@
*
****************************************************************************/
cache_resume_icache = Cache_Resume_ICache;
cache_suspend_icache = Cache_Suspend_ICache;
#ifdef CONFIG_ESPRESSIF_BLE
/* Lower-case aliases for BLE library symbols not compliant to nxstyle */
@@ -28,6 +28,10 @@ ifeq ($(CONFIG_ESP_RMT),y)
CSRCS += esp_board_rmt.c
endif
ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
CSRCS += esp_board_spiflash.c
endif
DEPPATH += --dep-path src
VPATH += :src
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
@@ -0,0 +1,417 @@
/****************************************************************************
* boards/risc-v/esp32c6/common/src/esp_board_spiflash.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/mount.h>
#include "inttypes.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <sys/param.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/mtd/configdata.h>
#include <nuttx/fs/nxffs.h>
#ifdef CONFIG_BCH
#include <nuttx/drivers/drivers.h>
#endif
#include "espressif/esp_spiflash.h"
#include "espressif/esp_spiflash_mtd.h"
#include "esp_board_spiflash.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: setup_smartfs
*
* Description:
* Provide a block driver wrapper around MTD partition and mount a
* SMART FS over it.
*
* Parameters:
* smartn - Number used to register the mtd partition: /dev/smartx, where
* x = smartn.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SMARTFS)
static int setup_smartfs(int smartn, struct mtd_dev_s *mtd,
const char *mnt_pt)
{
int ret = OK;
char path[22];
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
syslog(LOG_INFO, "smart_initialize failed, "
"Trying to erase first...\n");
ret = mtd->ioctl(mtd, MTDIOC_BULKERASE, 0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: ioctl(BULKERASE) failed: %d\n", ret);
return ret;
}
syslog(LOG_INFO, "Erase successful, initializing it again.\n");
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: smart_initialize failed: %d\n", ret);
return ret;
}
}
if (mnt_pt != NULL)
{
snprintf(path, sizeof(path), "/dev/smart%d", smartn);
ret = nx_mount(path, mnt_pt, "smartfs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
if (ret == -ENODEV)
{
syslog(LOG_WARNING, "Smartfs seems unformatted. "
"Did you run 'mksmartfs /dev/smart%d'?\n", smartn);
}
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_littlefs
*
* Description:
* Register a mtd driver and mount a Little FS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_LITTLEFS)
static int setup_littlefs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, NULL);
if (ret < 0)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, "forceformat");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n",
ret);
return ret;
}
}
}
return OK;
}
#endif
/****************************************************************************
* Name: setup_spiffs
*
* Description:
* Register a mtd driver and mount a SPIFFS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SPIFFS)
static int setup_spiffs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "spiffs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_nxffs
*
* Description:
* Register a mtd driver and mount a NXFFS over it.
*
* Parameters:
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_NXFFS)
static int setup_nxffs(struct mtd_dev_s *mtd, const char *mnt_pt)
{
int ret = OK;
ret = nxffs_initialize(mtd);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: NXFFS init failed: %d\n", ret);
return ret;
}
if (mnt_pt != NULL)
{
ret = nx_mount(NULL, mnt_pt, "nxffs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: init_storage_partition
*
* Description:
* Initialize partition that is dedicated to general use.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int init_storage_partition(void)
{
int ret = OK;
struct mtd_dev_s *mtd;
mtd = esp_spiflash_alloc_mtdpart(CONFIG_ESPRESSIF_STORAGE_MTD_OFFSET,
CONFIG_ESPRESSIF_STORAGE_MTD_SIZE);
if (!mtd)
{
syslog(LOG_ERR, "ERROR: Failed to alloc MTD partition of SPI Flash\n");
return ERROR;
}
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SMARTFS)
ret = setup_smartfs(0, mtd, "/data");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup smartfs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_NXFFS)
ret = setup_nxffs(mtd, "/data");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup nxffs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_LITTLEFS)
const char *path = "/dev/espflash";
ret = setup_littlefs(path, mtd, "/data", 0755);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup littlefs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_SPIFFS)
const char *path = "/dev/espflash";
ret = setup_spiffs(path, mtd, "/data", 0755);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup spiffs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_MTD_CONFIG)
# if defined (CONFIG_TESTING_MTD_CONFIG_FAIL_SAFE)
/* To test power-loss resilient kv system,
* we write possible power-loss flash layout into flash
* then start kv system to see if it recovers.
* To do so, we need a mtd driver so that test code can
* write into flash.
*/
const char *path = CONFIG_TESTING_MTD_CONFIG_FAIL_SAFE_MOUNTPT_NAME;
ret = register_mtddriver(path, mtd, 0777, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
# else
ret = mtdconfig_register(mtd);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup mtd config\n");
return ret;
}
# endif
#else
ret = register_mtddriver("/dev/espflash", mtd, 0755, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
#endif
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPI Flash and register the MTD device.
*
* Input Parameters:
* None.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
int board_spiflash_init(void)
{
int ret = OK;
esp_spiflash_init();
ret = init_storage_partition();
if (ret < 0)
{
return ret;
}
return ret;
}
@@ -0,0 +1,55 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32c6-devkit"
CONFIG_ARCH_BOARD_COMMON=y
CONFIG_ARCH_BOARD_ESP32C6_DEVKIT=y
CONFIG_ARCH_CHIP="esp32c6"
CONFIG_ARCH_CHIP_ESP32C6=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_ESPRESSIF_ESP32C6=y
CONFIG_ESPRESSIF_SPIFLASH=y
CONFIG_ESPRESSIF_SPIFLASH_SMARTFS=y
CONFIG_ESPRESSIF_STORAGE_MTD_OFFSET=0x110000
CONFIG_ESPRESSIF_STORAGE_MTD_SIZE=0xf0000
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_PERROR_STDOUT=y
CONFIG_LIBC_STRERROR=y
CONFIG_NAME_MAX=48
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_DISABLE_LOSMART=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
CONFIG_SMARTFS_MAXNAMLEN=48
CONFIG_START_DAY=29
CONFIG_START_MONTH=11
CONFIG_START_YEAR=2019
CONFIG_SYSTEM_DUMPSTACK=y
CONFIG_SYSTEM_FLASH_ERASEALL=y
CONFIG_SYSTEM_NSH=y
CONFIG_TESTING_FSTEST=y
CONFIG_TESTING_FSTEST_MOUNTPT="/mnt"
CONFIG_UART0_SERIAL_CONSOLE=y
@@ -35,6 +35,7 @@
#include <nuttx/fs/fs.h>
#include "esp_board_ledc.h"
#include "esp_board_spiflash.h"
#ifdef CONFIG_WATCHDOG
# include "espressif/esp_wdt.h"
@@ -175,6 +176,14 @@ int esp_bringup(void)
}
#endif
#ifdef CONFIG_ESPRESSIF_SPIFLASH
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
}
#endif
#ifdef CONFIG_DEV_GPIO
ret = esp_gpio_init();
if (ret < 0)
+37
View File
@@ -11,3 +11,40 @@ config ESPRESSIF_MERGE_BINS
device.
This is only useful when the path to binary files (e.g. bootloader)
is provided via the ESPTOOL_BINDIR variable.
choice ESPRESSIF_SPIFLASH_FS
prompt "Mount SPI Flash MTD on bring-up"
default ESPRESSIF_SPIFLASH_SMARTFS
depends on ESPRESSIF_MTD
optional
---help---
Mount the SPI Flash MTD with the selected File System format on board
bring-up.
If not selected, the MTD will be registered as a device node on /dev.
config ESPRESSIF_SPIFLASH_SMARTFS
bool "SmartFS"
select FS_SMARTFS
select MTD_SMART
config ESPRESSIF_SPIFLASH_NXFFS
bool "NXFFS"
select FS_NXFFS
config ESPRESSIF_SPIFLASH_SPIFFS
bool "SPIFFS"
select FS_SPIFFS
config ESPRESSIF_SPIFLASH_LITTLEFS
bool "LittleFS"
select FS_LITTLEFS
config ESPRESSIF_SPIFLASH_MTD_CONFIG
bool "Non-volatile storage"
endchoice # ESPRESSIF_SPIFLASH_FS
config ESPRESSIF_SPIFLASH_FS_MOUNT_PT
string "File-system Mount Point"
depends on ESPRESSIF_SPIFLASH_LITTLEFS
default "/data"
@@ -0,0 +1,74 @@
/****************************************************************************
* boards/risc-v/esp32h2/common/include/esp_board_spiflash.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H
#define __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPIFLASH and register the MTD device.
*
* Input Parameters:
* None.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_ESPRESSIF_SPIFLASH
int board_spiflash_init(void);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_SPIFLASH_H */
@@ -18,6 +18,9 @@
*
****************************************************************************/
cache_resume_icache = Cache_Resume_ICache;
cache_suspend_icache = Cache_Suspend_ICache;
#ifdef CONFIG_ESPRESSIF_BLE
/* Lower-case aliases for BLE library symbols not compliant to nxstyle */
@@ -28,6 +28,10 @@ ifeq ($(CONFIG_ESP_RMT),y)
CSRCS += esp_board_rmt.c
endif
ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
CSRCS += esp_board_spiflash.c
endif
DEPPATH += --dep-path src
VPATH += :src
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
@@ -0,0 +1,417 @@
/****************************************************************************
* boards/risc-v/esp32h2/common/src/esp_board_spiflash.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/mount.h>
#include "inttypes.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <sys/param.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spi/spi.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/mtd/configdata.h>
#include <nuttx/fs/nxffs.h>
#ifdef CONFIG_BCH
#include <nuttx/drivers/drivers.h>
#endif
#include "espressif/esp_spiflash.h"
#include "espressif/esp_spiflash_mtd.h"
#include "esp_board_spiflash.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: setup_smartfs
*
* Description:
* Provide a block driver wrapper around MTD partition and mount a
* SMART FS over it.
*
* Parameters:
* smartn - Number used to register the mtd partition: /dev/smartx, where
* x = smartn.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SMARTFS)
static int setup_smartfs(int smartn, struct mtd_dev_s *mtd,
const char *mnt_pt)
{
int ret = OK;
char path[22];
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
syslog(LOG_INFO, "smart_initialize failed, "
"Trying to erase first...\n");
ret = mtd->ioctl(mtd, MTDIOC_BULKERASE, 0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: ioctl(BULKERASE) failed: %d\n", ret);
return ret;
}
syslog(LOG_INFO, "Erase successful, initializing it again.\n");
ret = smart_initialize(smartn, mtd, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: smart_initialize failed: %d\n", ret);
return ret;
}
}
if (mnt_pt != NULL)
{
snprintf(path, sizeof(path), "/dev/smart%d", smartn);
ret = nx_mount(path, mnt_pt, "smartfs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
if (ret == -ENODEV)
{
syslog(LOG_WARNING, "Smartfs seems unformatted. "
"Did you run 'mksmartfs /dev/smart%d'?\n", smartn);
}
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_littlefs
*
* Description:
* Register a mtd driver and mount a Little FS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_LITTLEFS)
static int setup_littlefs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, NULL);
if (ret < 0)
{
ret = nx_mount(path, mnt_pt, "littlefs", 0, "forceformat");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n",
ret);
return ret;
}
}
}
return OK;
}
#endif
/****************************************************************************
* Name: setup_spiffs
*
* Description:
* Register a mtd driver and mount a SPIFFS over it.
*
* Parameters:
* path - Path name used to register the mtd driver.
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
* priv - Privileges
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SPIFFS)
static int setup_spiffs(const char *path, struct mtd_dev_s *mtd,
const char *mnt_pt, int priv)
{
int ret = OK;
ret = register_mtddriver(path, mtd, priv, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ERROR;
}
if (mnt_pt != NULL)
{
ret = nx_mount(path, mnt_pt, "spiffs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: setup_nxffs
*
* Description:
* Register a mtd driver and mount a NXFFS over it.
*
* Parameters:
* mtd - Pointer to a pre-allocated mtd partition.
* mnt_pt - Mount point
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#if defined (CONFIG_ESPRESSIF_SPIFLASH_NXFFS)
static int setup_nxffs(struct mtd_dev_s *mtd, const char *mnt_pt)
{
int ret = OK;
ret = nxffs_initialize(mtd);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: NXFFS init failed: %d\n", ret);
return ret;
}
if (mnt_pt != NULL)
{
ret = nx_mount(NULL, mnt_pt, "nxffs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount the FS volume: %d\n", ret);
return ret;
}
}
return ret;
}
#endif
/****************************************************************************
* Name: init_storage_partition
*
* Description:
* Initialize partition that is dedicated to general use.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int init_storage_partition(void)
{
int ret = OK;
struct mtd_dev_s *mtd;
mtd = esp_spiflash_alloc_mtdpart(CONFIG_ESPRESSIF_STORAGE_MTD_OFFSET,
CONFIG_ESPRESSIF_STORAGE_MTD_SIZE);
if (!mtd)
{
syslog(LOG_ERR, "ERROR: Failed to alloc MTD partition of SPI Flash\n");
return ERROR;
}
#if defined (CONFIG_ESPRESSIF_SPIFLASH_SMARTFS)
ret = setup_smartfs(0, mtd, "/data");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup smartfs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_NXFFS)
ret = setup_nxffs(mtd, "/data");
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup nxffs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_LITTLEFS)
const char *path = "/dev/espflash";
ret = setup_littlefs(path, mtd, "/data", 0755);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup littlefs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_SPIFFS)
const char *path = "/dev/espflash";
ret = setup_spiffs(path, mtd, "/data", 0755);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup spiffs\n");
return ret;
}
#elif defined (CONFIG_ESPRESSIF_SPIFLASH_MTD_CONFIG)
# if defined (CONFIG_TESTING_MTD_CONFIG_FAIL_SAFE)
/* To test power-loss resilient kv system,
* we write possible power-loss flash layout into flash
* then start kv system to see if it recovers.
* To do so, we need a mtd driver so that test code can
* write into flash.
*/
const char *path = CONFIG_TESTING_MTD_CONFIG_FAIL_SAFE_MOUNTPT_NAME;
ret = register_mtddriver(path, mtd, 0777, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
# else
ret = mtdconfig_register(mtd);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to setup mtd config\n");
return ret;
}
# endif
#else
ret = register_mtddriver("/dev/espflash", mtd, 0755, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register MTD: %d\n", ret);
return ret;
}
#endif
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_spiflash_init
*
* Description:
* Initialize the SPI Flash and register the MTD device.
*
* Input Parameters:
* None.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
int board_spiflash_init(void)
{
int ret = OK;
esp_spiflash_init();
ret = init_storage_partition();
if (ret < 0)
{
return ret;
}
return ret;
}
@@ -0,0 +1,55 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32h2-devkit"
CONFIG_ARCH_BOARD_COMMON=y
CONFIG_ARCH_BOARD_ESP32H2_DEVKIT=y
CONFIG_ARCH_CHIP="esp32h2"
CONFIG_ARCH_CHIP_ESP32H2=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_ESPRESSIF_ESP32H2=y
CONFIG_ESPRESSIF_SPIFLASH=y
CONFIG_ESPRESSIF_SPIFLASH_SMARTFS=y
CONFIG_ESPRESSIF_STORAGE_MTD_OFFSET=0x110000
CONFIG_ESPRESSIF_STORAGE_MTD_SIZE=0xf0000
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_PERROR_STDOUT=y
CONFIG_LIBC_STRERROR=y
CONFIG_NAME_MAX=48
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_DISABLE_LOSMART=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
CONFIG_SMARTFS_MAXNAMLEN=48
CONFIG_START_DAY=29
CONFIG_START_MONTH=11
CONFIG_START_YEAR=2019
CONFIG_SYSTEM_DUMPSTACK=y
CONFIG_SYSTEM_FLASH_ERASEALL=y
CONFIG_SYSTEM_NSH=y
CONFIG_TESTING_FSTEST=y
CONFIG_TESTING_FSTEST_MOUNTPT="/mnt"
CONFIG_UART0_SERIAL_CONSOLE=y
@@ -35,6 +35,7 @@
#include <nuttx/fs/fs.h>
#include "esp_board_ledc.h"
#include "esp_board_spiflash.h"
#ifdef CONFIG_WATCHDOG
# include "espressif/esp_wdt.h"
@@ -175,6 +176,14 @@ int esp_bringup(void)
}
#endif
#ifdef CONFIG_ESPRESSIF_SPIFLASH
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
}
#endif
#ifdef CONFIG_DEV_GPIO
ret = esp_gpio_init();
if (ret < 0)