Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 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 
00017 #if !DEVICE_FLASH
00018     #error [NOT_SUPPORTED] Flash API not supported for this target
00019 #endif
00020 
00021 #include "utest/utest.h"
00022 #include "unity/unity.h"
00023 #include "greentea-client/test_env.h"
00024 
00025 #include "mbed.h"
00026 #include "flash_api.h"
00027 
00028 using namespace utest::v1;
00029 
00030 #define TEST_CYCLES         1000000
00031 #define ALLOWED_DRIFT_PPM   1000         //0.1%
00032 
00033 /*
00034     return values to be checked are documented at:
00035         http://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html#Verify
00036 */
00037 
00038 #ifndef ALIGN_DOWN
00039 #define ALIGN_DOWN(x, a) ((x)& ~((a) - 1))
00040 #endif
00041 
00042 static int timer_diff_start;
00043 
00044 static void erase_range(flash_t *flash, uint32_t addr, uint32_t size)
00045 {
00046     while (size > 0) {
00047         uint32_t sector_size = flash_get_sector_size(flash, addr);
00048         TEST_ASSERT_NOT_EQUAL(0, sector_size);
00049         int32_t ret = flash_erase_sector(flash, addr);
00050         TEST_ASSERT_EQUAL_INT32(0, ret);
00051         addr += sector_size;
00052         size = size > sector_size ? size - sector_size : 0;
00053     }
00054 }
00055 #ifdef __CC_ARM
00056 MBED_NOINLINE
00057 __asm static void delay_loop(uint32_t count)
00058 {
00059 1
00060   SUBS a1, a1, #1
00061   BCS  %BT1
00062   BX   lr
00063 }
00064 #elif defined (__ICCARM__)
00065 MBED_NOINLINE
00066 static void delay_loop(uint32_t count)
00067 {
00068   __asm volatile(
00069     "loop: \n"
00070     " SUBS %0, %0, #1 \n"
00071     " BCS.n  loop\n"
00072     : "+r" (count)
00073     :
00074     : "cc"
00075   );
00076 }
00077 #elif  defined ( __GNUC__ ) ||  (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
00078 MBED_NOINLINE
00079 static void delay_loop(uint32_t count)
00080 {
00081   __asm__ volatile (
00082     "%=:\n\t"
00083 #if defined(__thumb__) && !defined(__thumb2__) && !defined(__ARMCC_VERSION)
00084     "SUB  %0, #1\n\t"
00085 #else
00086     "SUBS %0, %0, #1\n\t"
00087 #endif
00088     "BCS  %=b\n\t"
00089     : "+l" (count)
00090     :
00091     : "cc"
00092   );
00093 }
00094 #endif
00095 
00096 MBED_NOINLINE
00097 static int time_cpu_cycles(uint32_t cycles)
00098 {
00099     Timer timer;
00100     timer.start();
00101 
00102     int timer_start = timer.read_us();
00103 
00104     uint32_t delay = cycles;
00105     delay_loop(delay);
00106     int timer_end = timer.read_us();
00107 
00108     timer.stop();
00109     return timer_end - timer_start;
00110 }
00111 
00112 void flash_init_test()
00113 {
00114     timer_diff_start = time_cpu_cycles(TEST_CYCLES);
00115 
00116     flash_t test_flash;
00117     int32_t ret = flash_init(&test_flash);
00118     TEST_ASSERT_EQUAL_INT32(0, ret);
00119     ret = flash_free(&test_flash);
00120     TEST_ASSERT_EQUAL_INT32(0, ret);
00121 }
00122 
00123 void flash_mapping_alignment_test()
00124 {
00125     flash_t test_flash;
00126     int32_t ret = flash_init(&test_flash);
00127     TEST_ASSERT_EQUAL_INT32(0, ret);
00128 
00129     const uint32_t page_size = flash_get_page_size(&test_flash);
00130     const uint32_t flash_start = flash_get_start_address(&test_flash);
00131     const uint32_t flash_size = flash_get_size(&test_flash);
00132     TEST_ASSERT_TRUE(page_size != 0UL);
00133 
00134     uint32_t sector_size = flash_get_sector_size(&test_flash, flash_start);
00135     for (uint32_t offset = 0; offset < flash_size;  offset += sector_size) {
00136         const uint32_t sector_start = flash_start + offset;
00137         sector_size = flash_get_sector_size(&test_flash, sector_start);
00138         const uint32_t sector_end = sector_start + sector_size - 1;
00139         const uint32_t end_sector_size = flash_get_sector_size(&test_flash, sector_end);
00140 
00141         // Sector size must be a valid value
00142         TEST_ASSERT_NOT_EQUAL(MBED_FLASH_INVALID_SIZE, sector_size);
00143         // Sector size must be greater than zero
00144         TEST_ASSERT_NOT_EQUAL(0, sector_size);
00145         // All flash sectors must be a multiple of page size
00146         TEST_ASSERT_EQUAL(0, sector_size % page_size);
00147         // Sector address must be a multiple of sector size
00148         TEST_ASSERT_EQUAL(0, sector_start % sector_size);
00149         // All address in a sector must return the same sector size
00150         TEST_ASSERT_EQUAL(sector_size, end_sector_size);
00151     }
00152 
00153     // Make sure unmapped flash is reported correctly
00154     TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start - 1));
00155     TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start + flash_size));
00156 
00157     ret = flash_free(&test_flash);
00158     TEST_ASSERT_EQUAL_INT32(0, ret);
00159 }
00160 
00161 void flash_erase_sector_test()
00162 {
00163     flash_t test_flash;
00164     int32_t ret = flash_init(&test_flash);
00165     TEST_ASSERT_EQUAL_INT32(0, ret);
00166 
00167     uint32_t addr_after_last = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
00168     uint32_t last_sector_size = flash_get_sector_size(&test_flash, addr_after_last - 1);
00169     uint32_t last_sector = addr_after_last - last_sector_size;
00170     TEST_ASSERT_EQUAL_INT32(0, last_sector % last_sector_size);
00171     ret = flash_erase_sector(&test_flash, last_sector);
00172     TEST_ASSERT_EQUAL_INT32(0, ret);
00173 
00174     ret = flash_free(&test_flash);
00175     TEST_ASSERT_EQUAL_INT32(0, ret);
00176 }
00177 
00178 // Erase sector, write one page, erase sector and write new data
00179 void flash_program_page_test()
00180 {
00181     flash_t test_flash;
00182     int32_t ret = flash_init(&test_flash);
00183     TEST_ASSERT_EQUAL_INT32(0, ret);
00184 
00185     uint32_t test_size = flash_get_page_size(&test_flash);
00186     uint8_t *data = new uint8_t[test_size];
00187     uint8_t *data_flashed = new uint8_t[test_size];
00188     for (uint32_t i = 0; i < test_size; i++) {
00189         data[i] = 0xCE;
00190     }
00191 
00192     // the one before the last page in the system
00193     uint32_t address = flash_get_start_address(&test_flash) + flash_get_size(&test_flash) - (2*test_size);
00194 
00195     // sector size might not be same as page size
00196     uint32_t erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
00197     ret = flash_erase_sector(&test_flash, erase_sector_boundary);
00198     TEST_ASSERT_EQUAL_INT32(0, ret);
00199 
00200     ret = flash_program_page(&test_flash, address, data, test_size);
00201     TEST_ASSERT_EQUAL_INT32(0, ret);
00202 
00203     ret = flash_read(&test_flash, address, data_flashed, test_size);
00204     TEST_ASSERT_EQUAL_INT32(0, ret);
00205     TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);
00206 
00207     // sector size might not be same as page size
00208     erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
00209     ret = flash_erase_sector(&test_flash, erase_sector_boundary);
00210     TEST_ASSERT_EQUAL_INT32(0, ret);
00211 
00212     // write another data to be certain we are re-flashing
00213     for (uint32_t i = 0; i < test_size; i++) {
00214         data[i] = 0xAC;
00215     }
00216     ret = flash_program_page(&test_flash, address, data, test_size);
00217     TEST_ASSERT_EQUAL_INT32(0, ret);
00218 
00219     ret = flash_read(&test_flash, address, data_flashed, test_size);
00220     TEST_ASSERT_EQUAL_INT32(0, ret);
00221     TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);
00222 
00223     ret = flash_free(&test_flash);
00224     TEST_ASSERT_EQUAL_INT32(0, ret);
00225     delete[] data;
00226     delete[] data_flashed;
00227 }
00228 
00229 // make sure programming works with an unaligned data buffer
00230 void flash_buffer_alignment_test()
00231 {
00232     flash_t test_flash;
00233     int32_t ret = flash_init(&test_flash);
00234     TEST_ASSERT_EQUAL_INT32(0, ret);
00235 
00236     const uint32_t page_size = flash_get_page_size(&test_flash);
00237     const uint32_t buf_size = page_size + 4;
00238     uint8_t *data = new uint8_t[buf_size];
00239     uint8_t *data_flashed = new uint8_t[buf_size];
00240     for (uint32_t i = 0; i < buf_size; i++) {
00241         data[i] = i & 0xFF;
00242     }
00243 
00244     // use the last four pages for the alignment test
00245     const uint32_t flash_end = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
00246     const uint32_t test_addr = flash_end - page_size * 4;
00247     const uint32_t erase_sector_boundary = ALIGN_DOWN(test_addr, flash_get_sector_size(&test_flash, test_addr));
00248     erase_range(&test_flash, erase_sector_boundary, flash_end - erase_sector_boundary);
00249 
00250     // make sure page program works with an unaligned data buffer
00251     for (uint32_t i = 0; i < 4; i++) {
00252         const uint32_t addr = test_addr + i * page_size;
00253         ret = flash_program_page(&test_flash, addr, data + i, page_size);
00254         TEST_ASSERT_EQUAL_INT32(0, ret);
00255 
00256         ret = flash_read(&test_flash, addr, data_flashed, page_size);
00257         TEST_ASSERT_EQUAL_INT32(0, ret);
00258         TEST_ASSERT_EQUAL_UINT8_ARRAY(data + i, data_flashed, page_size);
00259     }
00260 
00261     ret = flash_free(&test_flash);
00262     TEST_ASSERT_EQUAL_INT32(0, ret);
00263     delete[] data;
00264     delete[] data_flashed;
00265 }
00266 
00267 // check the execution speed at the start and end of the test to make sure
00268 // cache settings weren't changed
00269 void flash_clock_and_cache_test()
00270 {
00271     const int timer_diff_end = time_cpu_cycles(TEST_CYCLES);
00272     const int acceptable_range = timer_diff_start / (1000000 / ALLOWED_DRIFT_PPM);
00273     TEST_ASSERT_UINT32_WITHIN(acceptable_range, timer_diff_start, timer_diff_end);
00274 }
00275 
00276 Case cases[] = {
00277     Case("Flash - init", flash_init_test),
00278     Case("Flash - mapping alignment", flash_mapping_alignment_test),
00279     Case("Flash - erase sector", flash_erase_sector_test),
00280     Case("Flash - program page", flash_program_page_test),
00281     Case("Flash - buffer alignment test", flash_buffer_alignment_test),
00282     Case("Flash - clock and cache test", flash_clock_and_cache_test),
00283 };
00284 
00285 utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
00286     GREENTEA_SETUP(20, "default_auto");
00287     return greentea_test_setup_handler(number_of_cases);
00288 }
00289 
00290 Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
00291 
00292 int main() {
00293     Harness::run(specification);
00294 }