aboutsummaryrefslogtreecommitdiffstats
path: root/testhal/STM32/STM32F4xx/FSMC_SRAM
diff options
context:
space:
mode:
authorbarthess <barthess@yandex.ru>2015-02-24 00:10:02 +0300
committerbarthess <barthess@yandex.ru>2015-02-24 00:10:02 +0300
commit33f1b2541ef3a15b4ed5875f741d71a19e773217 (patch)
tree7539444eeae1f9fc15986901a8ac37fec041d3e0 /testhal/STM32/STM32F4xx/FSMC_SRAM
parenta1822c490d9eff67917a8cca2defeff3487b627d (diff)
downloadChibiOS-Contrib-33f1b2541ef3a15b4ed5875f741d71a19e773217.tar.gz
ChibiOS-Contrib-33f1b2541ef3a15b4ed5875f741d71a19e773217.tar.bz2
ChibiOS-Contrib-33f1b2541ef3a15b4ed5875f741d71a19e773217.zip
FSMC_SRAM testhal. Added memtest and membench.
Diffstat (limited to 'testhal/STM32/STM32F4xx/FSMC_SRAM')
-rw-r--r--testhal/STM32/STM32F4xx/FSMC_SRAM/Makefile13
-rw-r--r--testhal/STM32/STM32F4xx/FSMC_SRAM/main.c150
-rw-r--r--testhal/STM32/STM32F4xx/FSMC_SRAM/membench.c112
-rw-r--r--testhal/STM32/STM32F4xx/FSMC_SRAM/membench.h32
-rw-r--r--testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.cpp226
-rw-r--r--testhal/STM32/STM32F4xx/FSMC_SRAM/memtest.hpp55
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_ */