pull/15466/merge
DZ 2024-10-08 18:46:16 +01:00 committed by GitHub
commit e815b31ecc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 2588 additions and 0 deletions

View File

@ -0,0 +1,30 @@
/* mbed Microcontroller Library
* Copyright (c) 2021 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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 MBED_OSPI_FLASH_MX31LF4GE4BC_H
#define MBED_OSPI_FLASH_MX31LF4GE4BC_H
#define MX_FLASH_BLOCK_SIZE 2048*64 /* 64 blocks of 2048 Bytes */
#define MX_FLASH_SECTOR_SIZE 2048*64 /* 64 blocks of 2048 Bytes */
#define MX_FLASH_PAGE_SIZE 512 /* 512 bytes for sub-page */
#define MX_FLASH_CHUNK_SIZE 0x10 /* 16 bytes */
#define MX_FLASH_BANK_SIZE 0x01000000 /* 16 MBytes */
#define MX_FLASH_BANK_SIZE_MASK ~(MX_FLASH_BANK_SIZE - 1) /* 0xFF000000 */
#define MX_FLASH_BLOCK_OFFSET 0x40000
#define MX_FLASH_SECTOR_OFFSET 0x40000
#define MX_FLASH_PAGE_OFFSET 0x1000
#endif // MBED_OSPI_FLASH_MX31LF4GE4BC_H

View File

@ -20,6 +20,7 @@
#include "drivers/QSPI.h"
#include "blockdevice/BlockDevice.h"
#include "platform/Callback.h"
#include "MX31LF4GE4BC_config.h"
#ifndef MBED_CONF_SPINAND_QSPI_IO0
#define MBED_CONF_SPINAND_QSPI_IO0 NC

View File

@ -0,0 +1,504 @@
/* Simple access class for Virtual EEPROM Emulation
* Copyright (c) 2015 Robin Hourahane
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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 MBED_VEEPROM_BLOCK_DEVICE_H
#define MBED_VEEPROM_BLOCK_DEVICE_H
#include "blockdevice/BlockDevice.h"
#include "platform/Callback.h"
#include "platform/PlatformMutex.h"
#if MBED_CONF_RTOS_API_PRESENT
#include "rtos/rtos.h"
#endif
#if COMPONENT_SPIF
#include "SPIFBlockDevice.h"
#endif
#if COMPONENT_QSPIF
#include "QSPIFBlockDevice.h"
#endif
#if COMPONENT_OSPIF
#include "OSPIFBlockDevice.h"
#endif
#if COMPONENT_SPINAND
#include "SPINANDBlockDevice.h"
#endif
/** Enum veef standard error codes
*
* @enum veef_bd_error
*/
enum veef_bd_error {
VEEF_BD_ERROR_OK = 0, /*!< no error */
VEEF_BD_ERROR_DEVICE_ERROR = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
VEEF_BD_ERROR_EINVAL = -4002, /* Invalid argument */
VEEF_BD_ERROR_EFAULT = -4003, /* Bad address */
VEEF_BD_ERROR_ENOSPC = -4004, /* No space left on device */
VEEF_BD_ERROR_ENODEV = -4005, /* No such device */
VEEF_BD_ERROR_ENOMEM = -4006, /* Out of memory */
VEEF_BD_ERROR_EIO = -4007, /* I/O error */
VEEF_BD_ERROR_ENXIO = -4008, /* No such device or address */
VEEF_BD_ERROR_ENOFS = -4009, /* No valid file system */
VEEF_BD_ERROR_EECC = -4010, /* ECC failure */
VEEF_BD_ERROR_EPERM = -4011, /* Operation not permitted */
VEEF_BD_ERROR_EOS = -4012, /* OS error */
};
/* EEPROM physical layout */
#define MX_EEPROM_CLUSTERS_PER_BANK (1)
#define MX_EEPROM_BANKS (4)
#define MX_EEPROM_CLUSTER_SIZE (MX_FLASH_SECTOR_SIZE * MX_EEPROM_SECTORS_PER_CLUSTER)
#define MX_EEPROM_BANK_SIZE (MX_EEPROM_CLUSTER_SIZE * MX_EEPROM_CLUSTERS_PER_BANK)
#if COMPONENT_OSPIF
#define MX_EEPROM_SECTORS_PER_CLUSTER (16)
#elif COMPONENT_SPINAND
#define MX_EEPROM_SECTOR_SIZE MX_FLASH_BLOCK_SIZE
#define MX_EEPROM_SECTOR_OFFSET MX_FLASH_BLOCK_OFFSET
#define MX_EEPROM_SECTORS_PER_CLUSTER (6)
#define MX_EEPROM_CLUSTER_OFFSET (MX_FLASH_SECTOR_OFFSET * MX_EEPROM_SECTORS_PER_CLUSTER)
#endif
#if defined(MX_FLASH_BANKS) && (MX_EEPROM_BANKS > MX_FLASH_BANKS)
#error "too many banks!"
#endif
#if (MX_EEPROM_SECTORS_PER_CLUSTER > 256)
#error "too many sectors per cluster!"
#endif
/* EEPROM parameters */
#define MX_EEPROM_HEADER_SIZE (4)
#define MX_EEPROM_ENTRY_SIZE (MX_FLASH_PAGE_SIZE)
#define MX_EEPROM_PAGE_SIZE (MX_EEPROM_ENTRY_SIZE - MX_EEPROM_HEADER_SIZE)
#define MX_EEPROM_SYSTEM_SECTOR (MX_EEPROM_SECTORS_PER_CLUSTER - 1)
#define MX_EEPROM_SYSTEM_SECTOR_OFFSET (MX_EEPROM_SYSTEM_SECTOR * MX_FLASH_SECTOR_SIZE)
#define MX_EEPROM_SYSTEM_ENTRY_SIZE (16)
#define MX_EEPROM_SYSTEM_ENTRIES (MX_FLASH_SECTOR_SIZE / MX_EEPROM_SYSTEM_ENTRY_SIZE)
#define MX_EEPROM_DATA_SECTORS (MX_EEPROM_SYSTEM_SECTOR)
#define MX_EEPROM_FREE_SECTORS (1)
#define MX_EEPROM_ENTRIES_PER_CLUSTER (MX_EEPROM_ENTRIES_PER_SECTOR * MX_EEPROM_DATA_SECTORS)
#define MX_EEPROM_BLOCK_SIZE (MX_EEPROM_PAGE_SIZE * MX_EEPROM_LPAS_PER_CLUSTER)
#define MX_EEPROM_BLOCKS (MX_EEPROM_CLUSTERS_PER_BANK)
#define MX_EEPROM_SIZE (MX_EEPROM_BLOCK_SIZE * MX_EEPROM_BLOCKS)
#define MX_EEPROMS (MX_EEPROM_BANKS)
#define MX_EEPROM_TOTAL_SIZE (MX_EEPROM_SIZE * MX_EEPROMS)
#if COMPONENT_OSPIF
#define MX_EEPROM_ENTRIES_PER_SECTOR (MX_FLASH_SECTOR_SIZE / MX_EEPROM_ENTRY_SIZE)
#define MX_EEPROM_LPAS_PER_CLUSTER (MX_EEPROM_DATA_SECTORS - MX_EEPROM_FREE_SECTORS)
#elif COMPONENT_SPINAND
#define MX_EEPROM_ENTRIES_PER_SECTOR ((MX_FLASH_SECTOR_SIZE / MX_EEPROM_ENTRY_SIZE) - 6)
#define MX_EEPROM_SYSTEM_ENTRY_OFFSET (0x800)
#define MX_EEPROM_LPAS_PER_SECTOR (8)
#define MX_EEPROM_LPAS_PER_CLUSTER (MX_EEPROM_DATA_SECTORS - MX_EEPROM_FREE_SECTORS)
#endif
#if (MX_EEPROM_ENTRY_SIZE < MX_FLASH_CHUNK_SIZE)
#error "too small data entry size!"
#endif
#if (MX_EEPROM_ENTRIES_PER_SECTOR > 256)
#error "too many entries per sector!"
#endif
#if (MX_EEPROM_SYSTEM_ENTRY_SIZE < MX_FLASH_CHUNK_SIZE)
#error "too small system entry size!"
#endif
#define MX_EEPROM_HASH_CROSSBANK 0 /* Page hash */
#define MX_EEPROM_HASH_HYBRID 1 /* Block hash */
#define MX_EEPROM_HASH_SEQUENTIAL 2 /* Bank hash */
/* Address hash algorithm */
#if COMPONENT_OSPIF
#define MX_EEPROM_HASH_AlGORITHM MX_EEPROM_HASH_CROSSBANK
#elif COMPONENT_SPINAND
#define MX_EEPROM_HASH_AlGORITHM MX_EEPROM_HASH_SEQUENTIAL
#endif
/* Wear leveling interval */
#define MX_EEPROM_WL_INTERVAL 10000
/* Check on-die ECC after each read */
//#define MX_EEPROM_ECC_CHECK
/* read recovery */
//#define MX_EEPROM_READ_ROLLBACK
/* Power cycling protection */
#define MX_EEPROM_PC_PROTECTION
#ifdef MX_EEPROM_PC_PROTECTION
#if !defined(MX_FLASH_SUPPORT_RWW) && !defined(MX_EEPROM_ECC_CHECK)
#define MX_EEPROM_ECC_CHECK
#endif
#ifndef MX_EEPROM_READ_ROLLBACK
#define MX_EEPROM_READ_ROLLBACK
#endif
#endif
#if defined(MX_FLASH_SUPPORT_RWW) && defined(MX_EEPROM_ECC_CHECK)
#error "cannot read ECC status in RWW mode!"
#endif
#define MX_EEPROM_WRITE_RETRIES 2 /* number of write retries */
#define MX_EEPROM_READ_RETRIES 2 /* number of read retries */
#if defined(MX_EEPROM_READ_ROLLBACK) && (MX_EEPROM_READ_RETRIES == 0)
#error "please set the number of read retries!"
#endif
/* RWWEE ID: "MX" */
#define MFTL_ID 0x4D58
/* Maximum unsigned value */
#define DATA_NONE8 0xff
#define DATA_NONE16 0xffff
#define DATA_NONE32 0xffffffffUL
/* Macros */
#undef min_t
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1: __min2; })
/* RWWEE operations */
typedef enum {
OPS_READ = 0x5244,
OPS_WRITE = 0x7772,
OPS_ERASE_BEGIN = 0x4553,
OPS_ERASE_END = 0x6565,
#if COMPONENT_SPINAND
OPS_GC_CP_BEGIN = 0xAAAA,
OPS_GC_CP_END = 0x5555,
#endif
OPS_NONE = 0x4E4E,
} ee_ops;
/* System Entry */
struct system_entry {
uint16_t id;
uint16_t ops;
uint16_t arg;
uint16_t cksum;
// uint8_t pad[MX_EEPROM_SYSTEM_ENTRY_SIZE - 8];
};
/* Data entry header */
struct eeprom_header {
uint8_t LPA;
uint8_t LPA_inv;
uint16_t crc;
uint8_t pad[MX_EEPROM_HEADER_SIZE - 4];
};
#if COMPONENT_SPINAND
/* System Entry Addr*/
// OPS_ERASE_END
#define SYS_ENTRY_ADDR_E_E 0
// OPS_GC_CP_BEGIN + source sector addr (write in Gc destination sector)
#define SYS_ENTRY_ADDR_G_B_D 0 + MX_EEPROM_SYSTEM_ENTRY_SIZE
// OPS_GC_CP_BEGIN + des sector addr (write in Gc source sector)
#define SYS_ENTRY_ADDR_G_B_S 63 * MX_FLASH_PAGE_OFFSET + 2048
// OPS_GC_CP_END (write in Gc source sector)
#define SYS_ENTRY_ADDR_G_E 63 * MX_FLASH_PAGE_OFFSET + 2048 + MX_EEPROM_SYSTEM_ENTRY_SIZE
// OPS_ERASE_END
#define SYS_ENTRY_ADDR_E_B 63 * MX_FLASH_PAGE_OFFSET + 2048 + MX_EEPROM_SYSTEM_ENTRY_SIZE * 2
#endif
/* Data Entry */
struct eeprom_entry {
struct eeprom_header header;
uint8_t data[MX_EEPROM_PAGE_SIZE];
};
/* Bank information */
struct bank_info {
uint32_t bank; /* current bank */
uint32_t bank_offset; /* bank address */
uint32_t block; /* current block */
uint32_t block_offset; /* block address */
struct eeprom_entry cache; /* entry cache */
bool cache_dirty; /* cache status */
/* address mapping */
uint8_t l2ps[MX_EEPROM_LPAS_PER_CLUSTER];
uint8_t l2pe[MX_EEPROM_LPAS_PER_CLUSTER];
uint8_t p2l[MX_EEPROM_DATA_SECTORS]; /* TODO: bitmap */
#if COMPONENT_SPINAND
uint8_t latest_used_entry_per_sector[MX_EEPROM_DATA_SECTORS];
uint8_t l2ps_group[MX_EEPROM_DATA_SECTORS];
#endif
uint32_t dirty_block; /* obsoleted sector to be erased */
uint32_t dirty_sector; /* obsoleted sector to be erased */
/* system entry address */
uint32_t sys_entry[MX_EEPROM_BLOCKS];
};
/* EEPROM information */
struct eeprom_info {
struct bank_info bi[MX_EEPROMS]; /* bank info */
uint32_t rwCnt; /* User R/W statistics */
};
/** BlockDevice for Virtual EEPROM Emulation
*
* @code
* // Here's an example using VEE Block device
* #include "mbed.h"
* #include "VEEBlockDevice.h"
*
* // Create Virtual EEPROM Emulation device
* VEEBlockDevice vee(bd, 32*1024);
*
* int main() {
* printf("vee test\n");
*
* // Initialize the device and print the memory layout
* vee.init();
* printf("vee size: %llu\n", vee.size());
* printf("vee read size: %llu\n", vee.get_read_size());
* printf("vee program size: %llu\n", vee.get_program_size());
* printf("vee erase size: %llu\n", vee.get_erase_size());
*
* // Write "Hello World!" to the first block
* char *buffer = (char*)malloc(vee.get_erase_size());
* sprintf(buffer, "Hello World!\n");
* vee.erase(0, vee.get_erase_size());
* vee.program(buffer, 0, vee.get_erase_size());
*
* // Read back what was stored
* vee.read(buffer, 0, vee.get_erase_size());
* printf("%s", buffer);
*
* // Deinitialize the device
* vee.deinit();
* }
* @endcode
*/
class VEEBlockDevice : public BlockDevice {
public:
/** Constructor to create an VEEBlockDevice
*
* @param bd Block device to back the FlashSimBlockDevice
* @param size The size of the device in bytes
*/
VEEBlockDevice(BlockDevice *bd);
virtual ~VEEBlockDevice();
/** Initialize a block device
*
* @return 0 on success or a negative error code on failure
*/
virtual int init();
/** Deinitialize a block device
*
* @return 0 on success or a negative error code on failure
*/
virtual int deinit();
/** Read blocks from a block device
*
* @param buffer Buffer to write blocks to
* @param addr Address of block to begin reading from
* @param size Size to read in bytes, must be a multiple of read block size
* @return 0 on success, negative error code on failure
*/
virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);
/** Program blocks to a block device
*
* The blocks must have been erased prior to being programmed
*
* @param buffer Buffer of data to write to blocks
* @param addr Address of block to begin writing to
* @param size Size to write in bytes, must be a multiple of program block size
* @return 0 on success, negative error code on failure
*/
virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
/** EEPROM cache write back API.
*
* @return 0 on success, negative error code on failure
*/
virtual int program_back(void);
/** EEPROM sync write API.
*
* @param buffer Buffer of data to write to blocks
* @param addr Address of block to begin writing to
* @param size Size to write in bytes, must be a multiple of program block size
* @return 0 on success, negative error code on failure
*/
virtual int sync_program(const void *buffer, bd_addr_t addr, bd_size_t size);
/** EEPROM user cache and meta data flush API.
*
* NOTE: Call this API just before power down.
* @return 0 on success, negative error code on failure
*/
virtual int flush(void);
/** EEPROM background task API.
* NOTE: Call this API just before MCU sleep.
*/
virtual void background(void);
/** Erase blocks on a block device
*
* The state of an erased block is undefined until it has been programmed
*
* @param addr Address of block to begin erasing
* @param size Size to erase in bytes, must be a multiple of erase block size
* @return 0 on success, negative error code on failure
*/
virtual int erase(bd_addr_t addr, bd_size_t size);
/** Get the size of a readable block
*
* @return Size of a readable block in bytes
*/
virtual bd_size_t get_read_size() const;
/** Get the size of a programable block
*
* @return Size of a programable block in bytes
* @note Must be a multiple of the read size
*/
virtual bd_size_t get_program_size() const;
/** Get the size of a eraseable block
*
* @return Size of a eraseable block in bytes
* @note Must be a multiple of the program size
*/
virtual bd_size_t get_erase_size() const;
/** Get the total size of the underlying device
*
* @return Size of the underlying device in bytes
*/
virtual bd_size_t size() const;
/** Get the BlockDevice class type.
*
* @return A string representation of the BlockDevice class type.
*/
virtual const char *get_type() const;
/** Format EEPROM Emulator.
*
* @return 0 on success, negative error code on failure
*/
virtual int format(void);
private:
// Read NOR flash.
int _ee_device_read(bd_addr_t addr, bd_size_t size, void *buffer);
// Write NOR flash.
int _ee_device_write(bd_addr_t addr, bd_size_t size, void *buffer);
// Erase NOR flash.
int _ee_device_erase(bd_addr_t addr, bd_size_t size);
#if COMPONENT_OSPIF
// Read system entry of current block of current bank.
int _ee_read_sys(struct bank_info *bi, uint32_t entry, struct system_entry *sys);
// Update system entry of current block of current bank.
int _ee_update_sys(struct bank_info *bi, uint32_t block, ee_ops ops, uint32_t arg);
#elif COMPONENT_SPINAND
// Read system entry of current block of current bank.
int _ee_read_sys(struct bank_info *bi, uint32_t sector, uint32_t system_entry_addr,
struct system_entry *sys);
// Update system entry of current block of current bank.
int _ee_update_sys(struct bank_info *bi, uint32_t sector, uint32_t system_entry_addr,
ee_ops ops, uint32_t arg);
#endif
// Read the specified entry of current block of current bank.
int _ee_read(struct bank_info *bi, uint32_t entry, void *buf, bool header);
// Write the specified entry of current block of current bank.
int _ee_write(struct bank_info *bi, uint32_t entry, void *buf);
// Erase the obsoleted sector of current bank.
int _ee_erase(struct bank_info *bi);
// Locate the latest version of specified logical page.
uint32_t _ee_find_latest(struct bank_info *bi, uint32_t LPA, bool free);
// Scan current block to build mapping table.
int _ee_build_mapping(struct bank_info *bi, uint32_t block);
// Find a free entry for given logical page.
uint32_t _ee_search_free(struct bank_info *bi, uint32_t LPA);
// Read specified logical page of current block of current bank.
int _ee_read_page(struct bank_info *bi, uint32_t LPA);
// Write specified logical page of current block of current bank.
int _ee_write_page(struct bank_info *bi, uint32_t LPA);
// Handle buffer and cache.
int _ee_rw_buffer(struct bank_info *bi, bd_addr_t addr, bd_size_t size,
uint8_t *buf, bool rw);
// Distribute continuous logical address into different banks.
int _ee_rw(bd_addr_t addr, bd_size_t size, uint8_t *buf, bool rw);
// Write dirty cache back (For internal use only).
int _eeprom_wb(struct bank_info *bi);
// Handle wear leveling.
int _eeprom_wear_leveling(void);
// Handle insufficient sector erase.
int _ee_check_erase(struct bank_info *bi, uint32_t sector);
// Check system info and handle power cycling.
int _ee_check_sys(void);
// copy data
uint32_t _ee_gc_cp(struct bank_info *bi, uint8_t src_sector, uint8_t des_sector);
// garbage collection
uint32_t _ee_gc(struct bank_info *bi, uint8_t src_sector, uint8_t des_sector);
// check if power is failed during gc
int _ee_check_gc_power_fail(void);
BlockDevice *_bd;
bool _is_initialized;
PlatformMutex _bank_mutex[4];
eeprom_info _eeprom;
};
#endif /* MBED_SD_BLOCK_DEVICE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,333 @@
/*
* Copyright (c) 2020 Arm Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "VEEBlockDevice.h"
#if COMPONENT_SPIF
#include "SPIFBlockDevice.h"
#endif
#if COMPONENT_QSPIF
#include "QSPIFBlockDevice.h"
#endif
#if COMPONENT_OSPIF
#include "OSPIFBlockDevice.h"
#endif
#if COMPONENT_SPINAND
#include "SPINANDBlockDevice.h"
#endif
#include <stdlib.h>
using namespace utest::v1;
#define TEST_BLOCK_COUNT 5
#define TEST_BLOCK_COUNT_FOR_BACKGROUND 100
#define TEST_ERROR_MASK 16
const struct {
const char *name;
bd_size_t (BlockDevice::*method)() const;
} ATTRS[] = {
{"read size", &BlockDevice::get_read_size},
{"program size", &BlockDevice::get_program_size},
{"erase size", &BlockDevice::get_erase_size},
{"total size", &BlockDevice::size},
};
Thread background_thread(osPriorityBelowNormal);
void background_call(VEEBlockDevice *vee_bd)
{
uint32_t cnt;
for (cnt = 0; ; cnt++) {
utest_printf("background_thiread: wake-up times: %lu\r\n", cnt);
vee_bd->background();
/* Wake up periodically */
ThisThread::sleep_for(1000);
}
}
void test_read_write()
{
#if COMPONENT_OSPIF
OSPIFBlockDevice default_bd(
MBED_CONF_OSPIF_OSPI_IO0,
MBED_CONF_OSPIF_OSPI_IO1,
MBED_CONF_OSPIF_OSPI_IO2,
MBED_CONF_OSPIF_OSPI_IO3,
MBED_CONF_OSPIF_OSPI_IO4,
MBED_CONF_OSPIF_OSPI_IO5,
MBED_CONF_OSPIF_OSPI_IO6,
MBED_CONF_OSPIF_OSPI_IO7,
MBED_CONF_OSPIF_OSPI_SCK,
MBED_CONF_OSPIF_OSPI_CSN,
MBED_CONF_OSPIF_OSPI_DQS,
MBED_CONF_OSPIF_OSPI_POLARITY_MODE,
MBED_CONF_OSPIF_OSPI_FREQ
);
#elif COMPONENT_SPINAND
SPINANDBlockDevice default_bd(
MBED_CONF_SPINAND_SPINAND_IO0,
MBED_CONF_SPINAND_SPINAND_IO1,
MBED_CONF_SPINAND_SPINAND_IO2,
MBED_CONF_SPINAND_SPINAND_IO3,
MBED_CONF_SPINAND_SPINAND_SCK,
MBED_CONF_SPINAND_SPINAND_CSN,
MBED_CONF_SPINAND_SPINAND_POLARITY_MODE,
MBED_CONF_SPINAND_SPINAND_FREQ
);
#endif
VEEBlockDevice bd(&default_bd);
int err = bd.init();
TEST_ASSERT_EQUAL(0, err);
for (unsigned a = 0; a < sizeof(ATTRS) / sizeof(ATTRS[0]); a++) {
static const char *prefixes[] = {"", "k", "M", "G"};
for (int i = 3; i >= 0; i--) {
bd_size_t size = (bd.*ATTRS[a].method)();
if (size >= (1ULL << 10 * i)) {
utest_printf("%s: %llu%sbytes (%llubytes)\n",
ATTRS[a].name, size >> 10 * i, prefixes[i], size);
break;
}
}
}
uint8_t *write_block = new uint8_t[30];
uint8_t *read_block = new uint8_t[30];
for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
utest_printf("test number: %u\n", b);
bd_size_t block_size = rand() % 30 + 1;
// Find a random block
bd_addr_t block = rand() % bd.size();
// Use next random number as temporary seed to keep
// the address progressing in the pseudorandom sequence
unsigned seed = rand();
// Fill with random sequence
srand(seed);
for (bd_size_t i = 0; i < block_size; i++) {
write_block[i] = 0xff & rand();
}
// Write, sync, and read the block
utest_printf("test addr 0x%llx: size %llu...\n", block, block_size);
err = bd.program(write_block, block, block_size);
TEST_ASSERT_EQUAL(0, err);
utest_printf("write addr 0x%llx: size %llu... ", block, block_size);
for (uint32_t i = 0; i < block_size && i < 16; i++) {
utest_printf("%02x ", write_block[i]);
}
if (block_size > 16) {
utest_printf("...\n");
}
utest_printf("\n");
err = bd.read(read_block, block, block_size);
TEST_ASSERT_EQUAL(0, err);
utest_printf("read addr 0x%0*llx: size %llu... ", block, block_size);
for (uint32_t i = 0; i < block_size && i < 16; i++) {
utest_printf("%02x ", read_block[i]);
}
if (block_size > 16) {
utest_printf("...");
}
utest_printf("\n");
// Check that the data was unmodified
srand(seed);
int val_rand;
for (bd_size_t i_ind = 0; i_ind < block_size; i_ind++) {
val_rand = rand();
if ((0xff & val_rand) != read_block[i_ind]) {
utest_printf("\n Assert Failed Buf Read - block:size: %llx:%llu \n", block, block_size);
utest_printf("\n pos: %llu, exp: %02x, act: %02x, wrt: %02x \n", i_ind, (0xff & val_rand),
read_block[i_ind], write_block[i_ind]);
}
TEST_ASSERT_EQUAL(0xff & val_rand, read_block[i_ind]);
}
}
err = bd.deinit();
TEST_ASSERT_EQUAL(0, err);
}
void test_background_thread()
{
#if COMPONENT_OSPIF
OSPIFBlockDevice default_bd(
MBED_CONF_OSPIF_OSPI_IO0,
MBED_CONF_OSPIF_OSPI_IO1,
MBED_CONF_OSPIF_OSPI_IO2,
MBED_CONF_OSPIF_OSPI_IO3,
MBED_CONF_OSPIF_OSPI_IO4,
MBED_CONF_OSPIF_OSPI_IO5,
MBED_CONF_OSPIF_OSPI_IO6,
MBED_CONF_OSPIF_OSPI_IO7,
MBED_CONF_OSPIF_OSPI_SCK,
MBED_CONF_OSPIF_OSPI_CSN,
MBED_CONF_OSPIF_OSPI_DQS,
MBED_CONF_OSPIF_OSPI_POLARITY_MODE,
MBED_CONF_OSPIF_OSPI_FREQ
);
#elif COMPONENT_SPINAND
SPINANDBlockDevice default_bd(
MBED_CONF_SPINAND_SPINAND_IO0,
MBED_CONF_SPINAND_SPINAND_IO1,
MBED_CONF_SPINAND_SPINAND_IO2,
MBED_CONF_SPINAND_SPINAND_IO3,
MBED_CONF_SPINAND_SPINAND_SCK,
MBED_CONF_SPINAND_SPINAND_CSN,
MBED_CONF_SPINAND_SPINAND_POLARITY_MODE,
MBED_CONF_SPINAND_SPINAND_FREQ
);
#endif
VEEBlockDevice bd(&default_bd);
int err = bd.init();
TEST_ASSERT_EQUAL(0, err);
background_thread.start(callback(background_call, &bd));
uint8_t *write_block = new uint8_t[30];
uint8_t *read_block = new uint8_t[30];
for (int b = 0; b < TEST_BLOCK_COUNT_FOR_BACKGROUND; b++) {
utest_printf("test number: %u\n", b);
bd_size_t block_size = rand() % 30 + 1;
// Find a random block
bd_addr_t block = rand() % bd.size();
// Use next random number as temporary seed to keep
// the address progressing in the pseudorandom sequence
unsigned seed = rand();
// Fill with random sequence
srand(seed);
for (bd_size_t i = 0; i < block_size; i++) {
write_block[i] = 0xff & rand();
}
// Write, sync, and read the block
utest_printf("test addr 0x%llx: size %llu...\n", block, block_size);
err = bd.program(write_block, block, block_size);
TEST_ASSERT_EQUAL(0, err);
utest_printf("write addr 0x%llx: size %llu... ", block, block_size);
for (uint32_t i = 0; i < block_size && i < 16; i++) {
utest_printf("%02x ", write_block[i]);
}
if (block_size > 16) {
utest_printf("...\n");
}
utest_printf("\n");
err = bd.read(read_block, block, block_size);
TEST_ASSERT_EQUAL(0, err);
utest_printf("read addr 0x%0*llx: size %llu... ", block, block_size);
for (uint32_t i = 0; i < block_size && i < 16; i++) {
utest_printf("%02x ", read_block[i]);
}
if (block_size > 16) {
utest_printf("...");
}
utest_printf("\n");
// Check that the data was unmodified
srand(seed);
int val_rand;
for (bd_size_t i_ind = 0; i_ind < block_size; i_ind++) {
val_rand = rand();
if ((0xff & val_rand) != read_block[i_ind]) {
utest_printf("\n Assert Failed Buf Read - block:size: %llx:%llu \n", block, block_size);
utest_printf("\n pos: %llu, exp: %02x, act: %02x, wrt: %02x \n", i_ind, (0xff & val_rand),
read_block[i_ind], write_block[i_ind]);
}
TEST_ASSERT_EQUAL(0xff & val_rand, read_block[i_ind]);
}
ThisThread::sleep_for(6000);
}
err = bd.deinit();
TEST_ASSERT_EQUAL(0, err);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(3000, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Testing read write random blocks", test_read_write),
Case("Testing background thread", test_background_thread),
};
Specification specification(test_setup, cases);
int main()
{
return !Harness::run(specification);
}