takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Revision:
0:8fdf9a60065b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os/TESTS/mbed_drivers/flashiap/main.cpp	Wed Oct 10 00:33:53 2018 +0000
@@ -0,0 +1,289 @@
+
+/* mbed Microcontroller Library
+ * Copyright (c) 2017 ARM Limited
+ *
+ * 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.
+ */
+
+#if !DEVICE_FLASH
+#error [NOT_SUPPORTED] Flash API not supported for this target
+#endif
+
+#include "utest/utest.h"
+#include "utest/utest_serial.h"
+#include "unity/unity.h"
+#include "greentea-client/test_env.h"
+#include "FlashIAP.h"
+#include "unity.h"
+#include <algorithm>
+
+#include "mbed.h"
+
+using namespace utest::v1;
+
+
+void flashiap_init_test()
+{
+    FlashIAP flash_device;
+    uint32_t ret = flash_device.init();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+    ret = flash_device.deinit();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+}
+
+void flashiap_program_test()
+{
+    FlashIAP flash_device;
+    uint32_t ret = flash_device.init();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+
+    // get the last sector size (flash size - 1)
+    uint32_t sector_size = flash_device.get_sector_size(flash_device.get_flash_start() + flash_device.get_flash_size() - 1UL);
+    uint32_t page_size = flash_device.get_page_size();
+    TEST_ASSERT_NOT_EQUAL(0, sector_size);
+    TEST_ASSERT_NOT_EQUAL(0, page_size);
+    TEST_ASSERT_TRUE(sector_size % page_size == 0);
+    uint32_t prog_size = std::max(page_size, (uint32_t)8);
+    uint8_t *data = new uint8_t[prog_size + 2];
+    for (uint32_t i = 0; i < prog_size + 2; i++) {
+        data[i] = i;
+    }
+
+    // the one before the last sector in the system
+    uint32_t address = (flash_device.get_flash_start() + flash_device.get_flash_size()) - (sector_size);
+    TEST_ASSERT_TRUE(address != 0UL);
+    utest_printf("ROM ends at 0x%lx, test starts at 0x%lx\n", FLASHIAP_ROM_END, address);
+    TEST_SKIP_UNLESS_MESSAGE(address >= FLASHIAP_ROM_END, "Test skipped. Test region overlaps code.");
+
+    ret = flash_device.erase(address, sector_size);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+
+
+    for (uint32_t i = 0; i < sector_size / prog_size; i++) {
+        uint32_t prog_addr = address + i * prog_size;
+        ret = flash_device.program(data, prog_addr, prog_size);
+        TEST_ASSERT_EQUAL_INT32(0, ret);
+    }
+
+    uint8_t *data_flashed = new uint8_t[prog_size];
+    for (uint32_t i = 0; i < sector_size / prog_size; i++) {
+        uint32_t page_addr = address + i * prog_size;
+        ret = flash_device.read(data_flashed, page_addr, prog_size);
+        TEST_ASSERT_EQUAL_INT32(0, ret);
+        TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, prog_size);
+    }
+
+    // check programming of unaligned buffer and size
+    ret = flash_device.erase(address, sector_size);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+    ret = flash_device.program(data + 2, address, prog_size);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+    ret = flash_device.read(data_flashed, address, prog_size - 1);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+    TEST_ASSERT_EQUAL_UINT8_ARRAY(data + 2, data_flashed, prog_size - 1);
+
+    delete[] data;
+    delete[] data_flashed;
+
+    ret = flash_device.deinit();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+}
+
+
+void flashiap_cross_sector_program_test()
+{
+    FlashIAP flash_device;
+    uint32_t ret = flash_device.init();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+
+    uint32_t page_size = flash_device.get_page_size();
+
+    // Erase last two sectors
+    uint32_t address = flash_device.get_flash_start() + flash_device.get_flash_size();
+    uint32_t sector_size, agg_size = 0;
+    for (uint32_t i = 0; i < 2; i++) {
+        sector_size = flash_device.get_sector_size(address - 1UL);
+        TEST_ASSERT_NOT_EQUAL(0, sector_size);
+        TEST_ASSERT_TRUE(sector_size % page_size == 0);
+        agg_size += sector_size;
+        address -= sector_size;
+    }
+    TEST_SKIP_UNLESS_MESSAGE(address >= FLASHIAP_ROM_END, "Test skipped. Test region overlaps code.");
+    ret = flash_device.erase(address, agg_size);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+
+    address += sector_size - page_size;
+    uint32_t aligned_prog_size = 2 * page_size;
+    uint32_t prog_size = aligned_prog_size;
+    if (page_size > 1) {
+        prog_size--;
+    }
+    uint8_t *data = new uint8_t[aligned_prog_size];
+    for (uint32_t i = 0; i < prog_size; i++) {
+        data[i] = rand() % 256;
+    }
+    for (uint32_t i = prog_size; i < aligned_prog_size; i++) {
+        data[i] = 0xFF;
+    }
+
+    ret = flash_device.program(data, address, prog_size);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+
+    uint8_t *data_flashed = new uint8_t[aligned_prog_size];
+    ret = flash_device.read(data_flashed, address, aligned_prog_size);
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+    TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, aligned_prog_size);
+
+    delete[] data;
+    delete[] data_flashed;
+
+    ret = flash_device.deinit();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+}
+
+void flashiap_program_error_test()
+{
+    FlashIAP flash_device;
+    uint32_t ret = flash_device.init();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+
+    // get the last sector size (flash size - 1)
+    uint32_t sector_size = flash_device.get_sector_size(flash_device.get_flash_start() + flash_device.get_flash_size() - 1UL);
+    uint32_t page_size = flash_device.get_page_size();
+    TEST_ASSERT_NOT_EQUAL(0, sector_size);
+    TEST_ASSERT_NOT_EQUAL(0, page_size);
+    TEST_ASSERT_TRUE(sector_size % page_size == 0);
+    const uint8_t test_value = 0xCE;
+    uint8_t *data = new uint8_t[page_size];
+    for (uint32_t i = 0; i < page_size; i++) {
+        data[i] = test_value;
+    }
+
+    // the one before the last page in the system
+    uint32_t address = (flash_device.get_flash_start() + flash_device.get_flash_size()) - (sector_size);
+    TEST_ASSERT_TRUE(address != 0UL);
+
+    // unaligned address
+    TEST_SKIP_UNLESS_MESSAGE(address >= FLASHIAP_ROM_END, "Test skipped. Test region overlaps code.");
+    ret = flash_device.erase(address + 1, sector_size);
+    TEST_ASSERT_EQUAL_INT32(-1, ret);
+    if (flash_device.get_page_size() > 1) {
+        ret = flash_device.program(data, address + 1, page_size);
+        TEST_ASSERT_EQUAL_INT32(-1, ret);
+    }
+
+    delete[] data;
+
+    ret = flash_device.deinit();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+}
+
+void flashiap_timing_test()
+{
+    FlashIAP flash_device;
+    uint32_t ret = flash_device.init();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+    mbed::Timer timer;
+    unsigned int num_write_sizes;
+    unsigned int curr_time, byte_usec_ratio;
+    unsigned int avg_erase_time = 0;
+    unsigned int max_erase_time = 0, min_erase_time = (unsigned int) -1;
+    const unsigned int max_writes = 128;
+    const unsigned int max_write_sizes = 6;
+    const unsigned int max_byte_usec_ratio = 200;
+
+    uint32_t page_size = flash_device.get_page_size();
+    uint32_t write_size = page_size;
+
+    uint32_t end_address = flash_device.get_flash_start() + flash_device.get_flash_size();
+
+    utest_printf("\nFlash timing:\n");
+    uint32_t sector_size = flash_device.get_sector_size(end_address - 1UL);
+    uint32_t base_address = end_address - sector_size;
+    timer.start();
+    for (num_write_sizes = 0; num_write_sizes < max_write_sizes; num_write_sizes++) {
+        if (write_size > sector_size) {
+            break;
+        }
+        uint8_t *buf = new (std::nothrow) uint8_t[write_size];
+        if (!buf) {
+            // Don't fail the test on lack of heap memory for the buffer
+            break;
+        }
+        memset(buf, 0x5A, write_size);
+        timer.reset();
+        ret = flash_device.erase(base_address, sector_size);
+        curr_time = timer.read_us();
+        avg_erase_time += curr_time;
+        TEST_ASSERT_EQUAL_INT32(0, ret);
+        max_erase_time = std::max(max_erase_time, curr_time);
+        min_erase_time = std::min(min_erase_time, curr_time);
+        uint32_t address = base_address;
+        unsigned int avg_write_time = 0;
+        unsigned int max_write_time = 0, min_write_time = (unsigned int) -1;
+        unsigned int num_writes;
+        for (num_writes = 0; num_writes < max_writes; num_writes++) {
+            if ((address + write_size) > end_address) {
+                break;
+            }
+            timer.reset();
+            ret = flash_device.program(buf, address, write_size);
+            curr_time = timer.read_us();
+            avg_write_time += curr_time;
+            TEST_ASSERT_EQUAL_INT32(0, ret);
+            max_write_time = std::max(max_write_time, curr_time);
+            min_write_time = std::min(min_write_time, curr_time);
+            address += write_size;
+        }
+        delete[] buf;
+        avg_write_time /= num_writes;
+        utest_printf("Write size %6u bytes: avg %10u, min %10u, max %10u (usec)\n",
+                     write_size, avg_write_time, min_write_time, max_write_time);
+        byte_usec_ratio = write_size / avg_write_time;
+        TEST_ASSERT(byte_usec_ratio < max_byte_usec_ratio);
+        write_size *= 4;
+    }
+
+    if (num_write_sizes) {
+        avg_erase_time /= num_write_sizes;
+        utest_printf("\nErase size %6u bytes: avg %10u, min %10u, max %10u (usec)\n\n",
+                     sector_size, avg_erase_time, min_erase_time, max_erase_time);
+        byte_usec_ratio = sector_size / avg_erase_time;
+        TEST_ASSERT(byte_usec_ratio < max_byte_usec_ratio);
+    }
+
+    ret = flash_device.deinit();
+    TEST_ASSERT_EQUAL_INT32(0, ret);
+}
+
+
+Case cases[] = {
+    Case("FlashIAP - init", flashiap_init_test),
+    Case("FlashIAP - program", flashiap_program_test),
+    Case("FlashIAP - program across sectors", flashiap_cross_sector_program_test),
+    Case("FlashIAP - program errors", flashiap_program_error_test),
+    Case("FlashIAP - timing", flashiap_timing_test),
+};
+
+utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(120, "default_auto");
+    return greentea_test_setup_handler(number_of_cases);
+}
+
+Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
+
+int main()
+{
+    Harness::run(specification);
+}