Workshop example

Dependencies:   X_NUCLEO_COMMON ST_INTERFACES

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2018 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "greentea-client/test_env.h"
00017 #include "unity.h"
00018 #include "utest.h"
00019 #include "QSPIFBlockDevice.h"
00020 #include "mbed_trace.h"
00021 #include "rtos/Thread.h"
00022 #include <stdlib.h>
00023 
00024 using namespace utest::v1;
00025 
00026 #define TEST_BLOCK_COUNT 10
00027 #define TEST_ERROR_MASK 16
00028 #define QSPIF_TEST_NUM_OF_THREADS 5
00029 
00030 const struct {
00031     const char *name;
00032     bd_size_t (BlockDevice::*method)() const;
00033 } ATTRS[] = {
00034     {"read size",    &BlockDevice::get_read_size},
00035     {"program size", &BlockDevice::get_program_size},
00036     {"erase size",   &BlockDevice::get_erase_size},
00037     {"total size",   &BlockDevice::size},
00038 };
00039 
00040 static SingletonPtr<PlatformMutex> _mutex;
00041 
00042 
00043 // Mutex is protecting rand() per srand for buffer writing and verification.
00044 // Mutex is also protecting printouts for clear logs.
00045 // Mutex is NOT protecting Block Device actions: erase/program/read - which is the purpose of the multithreaded test!
00046 void basic_erase_program_read_test(QSPIFBlockDevice &blockD, bd_size_t block_size, uint8_t *write_block,
00047                                    uint8_t *read_block, unsigned addrwidth)
00048 {
00049     int err = 0;
00050     _mutex->lock();
00051     // Find a random block
00052     bd_addr_t block = (rand() * block_size) % blockD.size();
00053 
00054     // Use next random number as temporary seed to keep
00055     // the address progressing in the pseudorandom sequence
00056     unsigned seed = rand();
00057 
00058     // Fill with random sequence
00059     srand(seed);
00060     for (bd_size_t i_ind = 0; i_ind < block_size; i_ind++) {
00061         write_block[i_ind] = 0xff & rand();
00062     }
00063     // Write, sync, and read the block
00064     utest_printf("\ntest  %0*llx:%llu...", addrwidth, block, block_size);
00065     _mutex->unlock();
00066 
00067     err = blockD.erase(block, block_size);
00068     TEST_ASSERT_EQUAL(0, err);
00069 
00070     err = blockD.program(write_block, block, block_size);
00071     TEST_ASSERT_EQUAL(0, err);
00072 
00073     err = blockD.read(read_block, block, block_size);
00074     TEST_ASSERT_EQUAL(0, err);
00075 
00076     _mutex->lock();
00077     // Check that the data was unmodified
00078     srand(seed);
00079     int val_rand;
00080     for (bd_size_t i_ind = 0; i_ind < block_size; i_ind++) {
00081         val_rand = rand();
00082         if ((0xff & val_rand) != read_block[i_ind]) {
00083             utest_printf("\n Assert Failed Buf Read - block:size: %llx:%llu \n", block, block_size);
00084             utest_printf("\n pos: %llu, exp: %02x, act: %02x, wrt: %02x \n", i_ind, (0xff & val_rand), read_block[i_ind],
00085                          write_block[i_ind]);
00086         }
00087         TEST_ASSERT_EQUAL(0xff & val_rand, read_block[i_ind]);
00088     }
00089     _mutex->unlock();
00090 }
00091 
00092 void test_qspif_random_program_read_erase()
00093 {
00094     utest_printf("\nTest Random Program Read Erase Starts..\n");
00095 
00096     QSPIFBlockDevice blockD(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
00097                             QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
00098 
00099     int err = blockD.init();
00100     TEST_ASSERT_EQUAL(0, err);
00101 
00102     for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
00103         static const char *prefixes[] = {"", "k", "M", "G"};
00104         for (int i_ind = 3; i_ind >= 0; i_ind--) {
00105             bd_size_t size = (blockD.*ATTRS[atr].method)();
00106             if (size >= (1ULL << 10 * i_ind)) {
00107                 utest_printf("%s: %llu%sbytes (%llubytes)\n",
00108                              ATTRS[atr].name, size >> 10 * i_ind, prefixes[i_ind], size);
00109                 break;
00110             }
00111         }
00112     }
00113 
00114     bd_size_t block_size = blockD.get_erase_size();
00115     unsigned addrwidth = ceil(log(float(blockD.size() - 1)) / log(float(16))) + 1;
00116 
00117     uint8_t *write_block = new (std::nothrow) uint8_t[block_size];
00118     uint8_t *read_block = new (std::nothrow) uint8_t[block_size];
00119     if (!write_block || !read_block) {
00120         utest_printf("\n Not enough memory for test");
00121         goto end;
00122     }
00123 
00124     for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
00125         basic_erase_program_read_test(blockD, block_size, write_block, read_block, addrwidth);
00126     }
00127 
00128     err = blockD.deinit();
00129     TEST_ASSERT_EQUAL(0, err);
00130 
00131 end:
00132     delete[] write_block;
00133     delete[] read_block;
00134 }
00135 
00136 void test_qspif_unaligned_erase()
00137 {
00138 
00139     utest_printf("\nTest Unaligned Erase Starts..\n");
00140 
00141     QSPIFBlockDevice blockD(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
00142                             QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
00143 
00144     int err = blockD.init();
00145     TEST_ASSERT_EQUAL(0, err);
00146 
00147     for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
00148         static const char *prefixes[] = {"", "k", "M", "G"};
00149         for (int i_ind = 3; i_ind >= 0; i_ind--) {
00150             bd_size_t size = (blockD.*ATTRS[atr].method)();
00151             if (size >= (1ULL << 10 * i_ind)) {
00152                 utest_printf("%s: %llu%sbytes (%llubytes)\n",
00153                              ATTRS[atr].name, size >> 10 * i_ind, prefixes[i_ind], size);
00154                 break;
00155             }
00156         }
00157     }
00158 
00159     bd_addr_t addr = 0;
00160     bd_size_t sector_erase_size = blockD.get_erase_size(addr);
00161     unsigned addrwidth = ceil(log(float(blockD.size() - 1)) / log(float(16))) + 1;
00162 
00163     utest_printf("\ntest  %0*llx:%llu...", addrwidth, addr, sector_erase_size);
00164 
00165     //unaligned start address
00166     addr += 1;
00167     err = blockD.erase(addr, sector_erase_size - 1);
00168     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
00169 
00170     err = blockD.erase(addr, sector_erase_size);
00171     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
00172 
00173     err = blockD.erase(addr, 1);
00174     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
00175 
00176     //unaligned end address
00177     addr = 0;
00178 
00179     err = blockD.erase(addr, 1);
00180     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
00181 
00182     err = blockD.erase(addr, sector_erase_size + 1);
00183     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
00184 
00185     //erase size exceeds flash device size
00186     err = blockD.erase(addr, blockD.size() + 1);
00187     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
00188 
00189     // Valid erase
00190     err = blockD.erase(addr, sector_erase_size);
00191     TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_OK, err);
00192 
00193     err = blockD.deinit();
00194     TEST_ASSERT_EQUAL(0, err);
00195 }
00196 
00197 
00198 
00199 static void test_qspif_thread_job(void *vBlockD/*, int thread_num*/)
00200 {
00201     static int thread_num = 0;
00202     thread_num++;
00203     QSPIFBlockDevice *blockD = (QSPIFBlockDevice *)vBlockD;
00204     utest_printf("\n Thread %d Started \n", thread_num);
00205 
00206     bd_size_t block_size = blockD->get_erase_size();
00207     unsigned addrwidth = ceil(log(float(blockD->size() - 1)) / log(float(16))) + 1;
00208 
00209     uint8_t *write_block = new (std::nothrow) uint8_t[block_size];
00210     uint8_t *read_block = new (std::nothrow) uint8_t[block_size];
00211     if (!write_block || !read_block) {
00212         utest_printf("\n Not enough memory for test");
00213         goto end;
00214     }
00215 
00216     for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
00217         basic_erase_program_read_test((*blockD), block_size, write_block, read_block, addrwidth);
00218     }
00219 
00220 end:
00221     delete[] write_block;
00222     delete[] read_block;
00223 }
00224 
00225 void test_qspif_multi_threads()
00226 {
00227 
00228     utest_printf("\nTest Multi Threaded Erase/Program/Read Starts..\n");
00229 
00230     QSPIFBlockDevice blockD(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
00231                             QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
00232 
00233     int err = blockD.init();
00234     TEST_ASSERT_EQUAL(0, err);
00235 
00236     for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
00237         static const char *prefixes[] = {"", "k", "M", "G"};
00238         for (int i_ind = 3; i_ind >= 0; i_ind--) {
00239             bd_size_t size = (blockD.*ATTRS[atr].method)();
00240             if (size >= (1ULL << 10 * i_ind)) {
00241                 utest_printf("%s: %llu%sbytes (%llubytes)\n",
00242                              ATTRS[atr].name, size >> 10 * i_ind, prefixes[i_ind], size);
00243                 break;
00244             }
00245         }
00246     }
00247 
00248     rtos::Thread qspif_bd_thread[QSPIF_TEST_NUM_OF_THREADS];
00249 
00250     osStatus threadStatus;
00251     int i_ind;
00252 
00253     for (i_ind = 0; i_ind < QSPIF_TEST_NUM_OF_THREADS; i_ind++) {
00254         threadStatus = qspif_bd_thread[i_ind].start(test_qspif_thread_job, (void *)&blockD);
00255         if (threadStatus != 0) {
00256             utest_printf("\n Thread %d Start Failed!", i_ind + 1);
00257         }
00258     }
00259 
00260     for (i_ind = 0; i_ind < QSPIF_TEST_NUM_OF_THREADS; i_ind++) {
00261         qspif_bd_thread[i_ind].join();
00262     }
00263 
00264     err = blockD.deinit();
00265     TEST_ASSERT_EQUAL(0, err);
00266 }
00267 
00268 
00269 
00270 
00271 // Test setup
00272 utest::v1::status_t test_setup(const size_t number_of_cases)
00273 {
00274     GREENTEA_SETUP(60, "default_auto");
00275     return verbose_test_setup_handler(number_of_cases);
00276 }
00277 
00278 Case cases[] = {
00279     Case("Testing unaligned erase blocks", test_qspif_unaligned_erase),
00280     Case("Testing read write random blocks", test_qspif_random_program_read_erase),
00281     Case("Testing Multi Threads Erase Program Read", test_qspif_multi_threads)
00282 };
00283 
00284 Specification specification(test_setup, cases);
00285 
00286 
00287 int main()
00288 {
00289     mbed_trace_init();
00290     utest_printf("MAIN STARTS\n");
00291     return !Harness::run(specification);
00292 }