diff options
author | barthess <barthess@yandex.ru> | 2015-02-24 00:10:02 +0300 |
---|---|---|
committer | barthess <barthess@yandex.ru> | 2015-02-24 00:10:02 +0300 |
commit | 33f1b2541ef3a15b4ed5875f741d71a19e773217 (patch) | |
tree | 7539444eeae1f9fc15986901a8ac37fec041d3e0 /testhal | |
parent | a1822c490d9eff67917a8cca2defeff3487b627d (diff) | |
download | ChibiOS-Contrib-33f1b2541ef3a15b4ed5875f741d71a19e773217.tar.gz ChibiOS-Contrib-33f1b2541ef3a15b4ed5875f741d71a19e773217.tar.bz2 ChibiOS-Contrib-33f1b2541ef3a15b4ed5875f741d71a19e773217.zip |
FSMC_SRAM testhal. Added memtest and membench.
Diffstat (limited to 'testhal')
-rw-r--r-- | testhal/STM32/STM32F4xx/FSMC_SRAM/Makefile | 13 | ||||
-rw-r--r-- | testhal/STM32/STM32F4xx/FSMC_SRAM/main.c | 150 | ||||
-rw-r--r-- | testhal/STM32/STM32F4xx/FSMC_SRAM/membench.c | 112 | ||||
-rw-r--r-- | testhal/STM32/STM32F4xx/FSMC_SRAM/membench.h | 32 | ||||
-rw-r--r-- | testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.cpp | 226 | ||||
-rw-r--r-- | testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.hpp | 55 |
6 files changed, 517 insertions, 71 deletions
diff --git a/testhal/STM32/STM32F4xx/FSMC_SRAM/Makefile b/testhal/STM32/STM32F4xx/FSMC_SRAM/Makefile index c70636b..7ae1c80 100644 --- a/testhal/STM32/STM32F4xx/FSMC_SRAM/Makefile +++ b/testhal/STM32/STM32F4xx/FSMC_SRAM/Makefile @@ -87,8 +87,7 @@ include $(CHIBIOS)/community/os/hal/ports/STM32/STM32F4xx/platform.mk include $(CHIBIOS)/os/hal/osal/rt/osal.mk include $(CHIBIOS)/os/rt/rt.mk include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_stm32f4xx.mk -include $(CHIBIOS)/test/rt/test.mk - +include $(CHIBIOS)/os/various/cpp_wrappers/chcpp.mk # Define linker script file here LDSCRIPT= $(PORTLD)/STM32F407xG.ld @@ -97,15 +96,17 @@ LDSCRIPT= $(PORTLD)/STM32F407xG.ld # setting. CSRC = $(PORTSRC) \ $(KERNSRC) \ - $(TESTSRC) \ $(HALSRC) \ + $(OSALSRC) \ $(PLATFORMSRC) \ $(BOARDSRC) \ - main.c + main.c \ + membench.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. -CPPSRC = +CPPSRC = $(CHCPPSRC) \ + memtest.cpp # C sources to be compiled in ARM mode regardless of the global setting. # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler @@ -132,9 +133,9 @@ ASMSRC = $(PORTASM) INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \ $(HALINC) $(OSALINC) $(PLATFORMINC) $(BOARDINC) \ + $(CHIBIOS)/os/various/cpp_wrappers \ $(CHIBIOS)/os/various - # # Project, sources and paths ############################################################################## diff --git a/testhal/STM32/STM32F4xx/FSMC_SRAM/main.c b/testhal/STM32/STM32F4xx/FSMC_SRAM/main.c index ac8f04d..c661d14 100644 --- a/testhal/STM32/STM32F4xx/FSMC_SRAM/main.c +++ b/testhal/STM32/STM32F4xx/FSMC_SRAM/main.c @@ -14,24 +14,20 @@ limitations under the License. */ -/* -TODO: -write memtest function using ideas from http://www.memtest86.com/technical.htm -*/ - #include "ch.h" #include "hal.h" -#include "string.h" - #include "fsmc_sram.h" +#include "membench.h" +#include "memtest.hpp" /* ****************************************************************************** * DEFINES ****************************************************************************** */ -#define USE_INFINITE_MEMTEST FALSE +#define SRAM_START ((void *)FSMC_Bank1_4_MAP) +#define SRAM_SIZE (512 * 1024) /* ****************************************************************************** @@ -45,27 +41,58 @@ write memtest function using ideas from http://www.memtest86.com/technical.htm ****************************************************************************** */ +static void mem_error_cb(memtest_t *memp, testtype_t e, size_t address); + /* ****************************************************************************** * GLOBAL VARIABLES ****************************************************************************** */ -static uint32_t sram_check_buf[16 * 1024]; -static uint32_t *sram_start = (uint32_t *)FSMC_Bank1_4_MAP; -static const size_t sram_size = 524288; /* * SRAM driver configuration structure. */ static const SRAMConfig sram_cfg = { - .btr = 2 << 8 + 2 << 8 +}; + +/* + * + */ +static memtest_t memtest_struct = { + SRAM_START, + SRAM_SIZE, + MEMTEST_WIDTH_16, + mem_error_cb, + 42 +}; + +/* + * + */ +static membench_t membench_ext = { + SRAM_START, + SRAM_SIZE, }; -/* benchmarking results in MiB/S */ -volatile double memset_speed_ext; -volatile double memset_speed_int; -volatile double memcpy_speed_ext2int; -volatile double memcpy_speed_int2ext; +/* + * + */ +static uint8_t int_buf[64*1024]; + +/* + * + */ +static membench_t membench_int = { + int_buf, + sizeof(int_buf), +}; + +/* + * + */ +static membench_result_t membench_result_ext2int; +static membench_result_t membench_result_int2ext; /* ****************************************************************************** @@ -74,58 +101,53 @@ volatile double memcpy_speed_int2ext; ****************************************************************************** ****************************************************************************** */ -/** - * - */ -static void sram_benchmark(void){ - - size_t i=0; - time_measurement_t mem_tmu; - - /* memset speed ext */ - chTMObjectInit(&mem_tmu); - chTMStartMeasurementX(&mem_tmu); - memset(sram_start, 0x55, sram_size); - memset(sram_start, 0x00, sram_size); - chTMStopMeasurementX(&mem_tmu); - memset_speed_ext = 1 / (mem_tmu.cumulative / (double)STM32_SYSCLK); - - /* memset speed int */ - chTMObjectInit(&mem_tmu); - chTMStartMeasurementX(&mem_tmu); - for (i=0; i<16; i++) - memset(sram_check_buf, i, sizeof(sram_check_buf)); - chTMStopMeasurementX(&mem_tmu); - memset_speed_int = 1 / (mem_tmu.cumulative / (double)STM32_SYSCLK); - - /* memcpy ext2int */ - chTMObjectInit(&mem_tmu); - chTMStartMeasurementX(&mem_tmu); - for (i=0; i<16; i++) - memcpy(sram_check_buf, sram_start+ i * sizeof(sram_check_buf), sizeof(sram_check_buf)); - chTMStopMeasurementX(&mem_tmu); - memcpy_speed_ext2int = 1 / (mem_tmu.cumulative / (double)STM32_SYSCLK); - - /* memcpy int2ext */ - chTMObjectInit(&mem_tmu); - memset(sram_check_buf, 0xAA, sizeof(sram_check_buf)); - chTMStartMeasurementX(&mem_tmu); - for (i=0; i<16; i++) - memcpy(sram_start + i * sizeof(sram_check_buf), sram_check_buf, sizeof(sram_check_buf)); - chTMStopMeasurementX(&mem_tmu); - memcpy_speed_int2ext = 1 / (mem_tmu.cumulative / (double)STM32_SYSCLK); + +static inline void red_led_on(void) {palSetPad(GPIOI, GPIOI_LED_R);} +static inline void red_led_off(void) {palClearPad(GPIOI, GPIOI_LED_R);} +static inline void green_led_on(void) {palSetPad(GPIOI, GPIOI_LED_G);} +static inline void green_led_off(void) {palClearPad(GPIOI, GPIOI_LED_G);} +static inline void green_led_toggle(void) {palTogglePad(GPIOI, GPIOI_LED_G);} + +static void mem_error_cb(memtest_t *memp, testtype_t e, size_t address) { + (void)memp; + (void)e; + (void)address; + + green_led_off(); + red_led_on(); + osalSysHalt("Memory broken"); } -/** +/* * */ -#if USE_INFINITE_MEMTEST -static void memstest(void){ +static void memtest(void) { + + red_led_off(); + while (true) { - ; + memtest_struct.width = MEMTEST_WIDTH_16; + memtest_struct.rand_seed = chSysGetRealtimeCounterX(); + memtest_run(&memtest_struct, MEMTEST_RUN_ALL); + + memtest_struct.width = MEMTEST_WIDTH_8; + memtest_struct.rand_seed = chSysGetRealtimeCounterX(); + memtest_run(&memtest_struct, MEMTEST_RUN_ALL); + + green_led_toggle(); } + + green_led_on(); + green_led_off(); +} + +/* + * + */ +static void membench(void) { + membench_run(&membench_ext, &membench_int, &membench_result_int2ext); + membench_run(&membench_int, &membench_ext, &membench_result_ext2int); } -#endif /* USE_INFINITE_MEMTEST */ /* ****************************************************************************** @@ -150,11 +172,9 @@ int main(void) { fsmcSramInit(); fsmcSramStart(&SRAMD4, &sram_cfg); - sram_benchmark(); -#if USE_INFINITE_MEMTEST + membench(); memtest(); -#endif /* * Normal main() thread activity, in this demo it does nothing. diff --git a/testhal/STM32/STM32F4xx/FSMC_SRAM/membench.c b/testhal/STM32/STM32F4xx/FSMC_SRAM/membench.c new file mode 100644 index 0000000..4e9dfcb --- /dev/null +++ b/testhal/STM32/STM32F4xx/FSMC_SRAM/membench.c @@ -0,0 +1,112 @@ +/* + ChibiOS/RT - Copyright (C) 2013-2014 Uladzimir Pylinsky aka barthess + + 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 <string.h> + +#include "ch.h" +#include "hal.h" + +#include "membench.h" + +/* + ****************************************************************************** + * DEFINES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * EXTERNS + ****************************************************************************** + */ + +/* + ****************************************************************************** + * PROTOTYPES + ****************************************************************************** + */ + +/* + ****************************************************************************** + * GLOBAL VARIABLES + ****************************************************************************** + */ +volatile int warning_suppressor; + +/* + ****************************************************************************** + ****************************************************************************** + * LOCAL FUNCTIONS + ****************************************************************************** + ****************************************************************************** + */ +/* + * Calculates memory access time in MiB. + */ +double speed(const time_measurement_t *tmu, size_t len) { + double size; // MiB + double time; // sec + + size = len; + size /= 1024 * 1024; + + time = tmu->last; + time /= STM32_SYSCLK; + + return size / time; +} + +/* + ****************************************************************************** + * EXPORTED FUNCTIONS + ****************************************************************************** + */ + +/* + * + */ +void membench_run(membench_t *dest, const membench_t *src, + membench_result_t *result) { + time_measurement_t mem_tmu; + size_t len; + + if (src->size < dest->size) + len = src->size; + else + len = dest->size; + + /* memset */ + chTMObjectInit(&mem_tmu); + chTMStartMeasurementX(&mem_tmu); + memset(dest->start, 0x55, dest->size); + chTMStopMeasurementX(&mem_tmu); + result->memset_spd = speed(&mem_tmu, dest->size); + + /* memcpy */ + chTMObjectInit(&mem_tmu); + chTMStartMeasurementX(&mem_tmu); + memcpy(dest->start, src->start, len); + chTMStopMeasurementX(&mem_tmu); + result->memcpy_spd = speed(&mem_tmu, len); + + /* memcmp */ + chTMObjectInit(&mem_tmu); + chTMStartMeasurementX(&mem_tmu); + warning_suppressor = memcmp(dest->start, src->start, len); + chTMStopMeasurementX(&mem_tmu); + result->memcmp_spd = speed(&mem_tmu, len); +} + diff --git a/testhal/STM32/STM32F4xx/FSMC_SRAM/membench.h b/testhal/STM32/STM32F4xx/FSMC_SRAM/membench.h new file mode 100644 index 0000000..76ef46c --- /dev/null +++ b/testhal/STM32/STM32F4xx/FSMC_SRAM/membench.h @@ -0,0 +1,32 @@ +#ifndef MEMBENCH_H_ +#define MEMBENCH_H_ + +/* + * + */ +typedef struct { + void *start; + size_t size; +} membench_t; + +/* + * + */ +typedef struct { + double memset_spd; + double memcpy_spd; + double memcmp_spd; +} membench_result_t; + +/* + * + */ +#ifdef __cplusplus +extern "C" { +#endif + void membench_run(membench_t *dest, const membench_t *src, membench_result_t *ret); +#ifdef __cplusplus +} +#endif + +#endif /* MEMBENCH_H_ */ diff --git a/testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.cpp b/testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.cpp new file mode 100644 index 0000000..c12e952 --- /dev/null +++ b/testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.cpp @@ -0,0 +1,226 @@ +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> + +#include "memtest.hpp" + +/* + * + */ +template <typename T> +class Generator { +public: + Generator(void) : pattern(0) {;} + virtual T get(void) = 0; + virtual void init(T seed) { + pattern = seed; + } +protected: + T pattern; +}; + +/* + * + */ +template <typename T> +class GeneratorWalkingOne : public Generator<T> { + T get(void) { + T ret = this->pattern; + + this->pattern <<= 1; + if (0 == this->pattern) + this->pattern = 1; + + return ret; + } +}; + +/* + * + */ +template <typename T> +class GeneratorWalkingZero : public Generator<T> { + T get(void) { + T ret = ~this->pattern; + + this->pattern <<= 1; + if (0 == this->pattern) + this->pattern = 1; + + return ret; + } +}; + +/* + * + */ +template <typename T> +class GeneratorOwnAddress : public Generator<T> { + T get(void) { + T ret = this->pattern; + this->pattern++; + return ret; + } +}; + +/* + * + */ +template <typename T> +class GeneratorMovingInv : public Generator<T> { + T get(void) { + T ret = this->pattern; + this->pattern = ~this->pattern; + return ret; + } +}; + +/* + * + */ +template <typename T> +class GeneratorMovingInvRand : public Generator<T> { +public: + GeneratorMovingInvRand(void) : step(0), prev(0){;} + void init(size_t seed) { + srand(seed); + } + + T get(void) { + T ret; + if ((step & 1) == 0) { + ret = rand(); + prev = ret; + } + else { + ret = ~prev; + } + step++; + + return ret; + } + +private: + size_t step; + T prev; +}; + +/* + * + */ +template <typename T> +static void memtest_sequential(memtest_t *memp, Generator<T> &generator, T seed) { + const size_t steps = memp->size / sizeof(T); + size_t i; + T *mem = static_cast<T *>(memp->start); + + /* fill ram */ + generator.init(seed); + for (i=0; i<steps; i++) { + mem[i] = generator.get(); + } + + /* read back and compare */ + generator.init(seed); + for (i=0; i<steps; i++) { + if (mem[i] != generator.get()) { + memp->ecb(memp, MEMTEST_WALKING_ONE, i*sizeof(T)); + return; + } + } +} + +template <typename T> +static void walking_one(memtest_t *memp) { + GeneratorWalkingOne<T> generator; + memtest_sequential<T>(memp, generator, 1); +} + +template <typename T> +static void walking_zero(memtest_t *memp) { + GeneratorWalkingZero<T> generator; + memtest_sequential<T>(memp, generator, 1); +} + +template <typename T> +static void own_address(memtest_t *memp) { + GeneratorOwnAddress<T> generator; + memtest_sequential<T>(memp, generator, 0); +} + +template <typename T> +static void moving_inversion(memtest_t *memp) { + GeneratorMovingInv<T> generator; + memtest_sequential<T>(memp, generator, 0); +} + +template <typename T> +static void moving_inversion_rand(memtest_t *memp) { + GeneratorMovingInvRand<T> generator; + memtest_sequential<T>(memp, generator, memp->rand_seed); +} + +/* + * + */ +static void memtest_wrapper(memtest_t *memp, + void (*p_u8)(memtest_t *memp), + void (*p_u16)(memtest_t *memp), + void (*p_u32)(memtest_t *memp)) { + switch(memp->width){ + case MEMTEST_WIDTH_32: + p_u32(memp); + p_u16(memp); + p_u8(memp); + break; + case MEMTEST_WIDTH_16: + p_u16(memp); + p_u8(memp); + break; + case MEMTEST_WIDTH_8: + p_u8(memp); + break; + } +} + +/* + * + */ +void memtest_run(memtest_t *memp, uint32_t testmask) { + + if ((testmask & MEMTEST_WALKING_ONE) == MEMTEST_WALKING_ONE) { + memtest_wrapper(memp, + walking_one<uint32_t>, + walking_one<uint16_t>, + walking_one<uint8_t>); + } + + if ((testmask & MEMTEST_WALKING_ZERO) == MEMTEST_WALKING_ZERO) { + memtest_wrapper(memp, + walking_zero<uint32_t>, + walking_zero<uint16_t>, + walking_zero<uint8_t>); + } + + if ((testmask & MEMTEST_OWN_ADDRESS) == MEMTEST_OWN_ADDRESS) { + memtest_wrapper(memp, + own_address<uint32_t>, + own_address<uint16_t>, + own_address<uint8_t>); + } + + if ((testmask & MEMTEST_MOVING_INVERSION) == MEMTEST_MOVING_INVERSION) { + memtest_wrapper(memp, + moving_inversion<uint32_t>, + moving_inversion<uint16_t>, + moving_inversion<uint8_t>); + } + + if ((testmask & MEMTEST_MOVING_INVERSION_RAND) == MEMTEST_MOVING_INVERSION_RAND) { + memtest_wrapper(memp, + moving_inversion_rand<uint32_t>, + moving_inversion_rand<uint16_t>, + moving_inversion_rand<uint8_t>); + } +} + diff --git a/testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.hpp b/testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.hpp new file mode 100644 index 0000000..8b21e94 --- /dev/null +++ b/testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.hpp @@ -0,0 +1,55 @@ +#ifndef MEMTEST_HPP_ +#define MEMTEST_HPP_ + +#define MEMTEST_WALKING_ONE (1 << 0) +#define MEMTEST_WALKING_ZERO (1 << 1) +#define MEMTEST_OWN_ADDRESS (1 << 2) +#define MEMTEST_MOVING_INVERSION (1 << 3) +#define MEMTEST_MOVING_INVERSION_RAND (1 << 4) + +#define MEMTEST_RUN_ALL (MEMTEST_WALKING_ONE | \ + MEMTEST_WALKING_ZERO | \ + MEMTEST_OWN_ADDRESS | \ + MEMTEST_MOVING_INVERSION | \ + MEMTEST_MOVING_INVERSION_RAND) + +typedef struct memtest_t memtest_t; +typedef uint32_t testtype_t; + +/* + * Error call back. + */ +typedef void (*memtestecb_t)(memtest_t *memp, testtype_t e, size_t address); + +/* + * + */ +typedef enum { + MEMTEST_WIDTH_8, + MEMTEST_WIDTH_16, + MEMTEST_WIDTH_32 +} memtest_bus_width_t; + +/* + * + */ +struct memtest_t { + void *start; + size_t size; + memtest_bus_width_t width; + memtestecb_t ecb; + unsigned int rand_seed; +}; + +/* + * + */ +#ifdef __cplusplus +extern "C" { +#endif + void memtest_run(memtest_t *memp, uint32_t testmask); +#ifdef __cplusplus +} +#endif + +#endif /* MEMTEST_HPP_ */ |