FSMC_SRAM testhal. Added memtest and membench.

This commit is contained in:
barthess 2015-02-24 00:10:02 +03:00
parent a1822c490d
commit 33f1b2541e
6 changed files with 514 additions and 68 deletions

View File

@ -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
##############################################################################

View File

@ -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
};
/* 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 memtest_t memtest_struct = {
SRAM_START,
SRAM_SIZE,
MEMTEST_WIDTH_16,
mem_error_cb,
42
};
/*
*
*/
static membench_t membench_ext = {
SRAM_START,
SRAM_SIZE,
};
/*
*
*/
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;
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);}
/* 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);
static void mem_error_cb(memtest_t *memp, testtype_t e, size_t address) {
(void)memp;
(void)e;
(void)address;
/* 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);
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.

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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>);
}
}

View File

@ -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_ */