Workshop example
Dependencies: X_NUCLEO_COMMON ST_INTERFACES
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 }
Generated on Tue Jul 12 2022 22:34:14 by 1.7.2