aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h2
-rw-r--r--libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c9
-rw-r--r--projects/cli-test/Makefile2
-rw-r--r--projects/cli-test/cli-test.c98
-rw-r--r--projects/cli-test/mgmt-cli.c4
-rw-r--r--projects/cli-test/mgmt-cli.h33
-rw-r--r--projects/cli-test/test_sdram.c274
-rw-r--r--projects/cli-test/test_sdram.h42
-rw-r--r--stm-fmc.c124
-rw-r--r--stm-fmc.h14
-rw-r--r--stm-init.c21
-rw-r--r--stm-init.h19
-rw-r--r--stm-sdram.c267
-rw-r--r--stm-sdram.h66
15 files changed, 828 insertions, 148 deletions
diff --git a/Makefile b/Makefile
index 9c0661b..5166b08 100644
--- a/Makefile
+++ b/Makefile
@@ -57,6 +57,7 @@ export BOARD_OBJS = \
$(TOPLEVEL)/spiflash_n25q128.o \
$(TOPLEVEL)/stm-fpgacfg.o \
$(TOPLEVEL)/stm-keystore.o \
+ $(TOPLEVEL)/stm-sdram.o \
$(TOPLEVEL)/syscalls.o \
$(BOARD_DIR)/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.o \
$(BOARD_DIR)/system_stm32f4xx.o \
diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h
index 3844481..8a11b8b 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h
@@ -65,7 +65,7 @@
//#define HAL_NOR_MODULE_ENABLED
//#define HAL_PCCARD_MODULE_ENABLED
#define HAL_SRAM_MODULE_ENABLED
-//#define HAL_SDRAM_MODULE_ENABLED
+#define HAL_SDRAM_MODULE_ENABLED
//#define HAL_HASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
index 6d1d029..2a207b6 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c
@@ -107,6 +107,15 @@ void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* hsram)
{
}
+void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram)
+{
+}
+
+void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* hsdram)
+{
+}
+
+
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
diff --git a/projects/cli-test/Makefile b/projects/cli-test/Makefile
index f3976e4..7737e13 100644
--- a/projects/cli-test/Makefile
+++ b/projects/cli-test/Makefile
@@ -1,6 +1,6 @@
TEST = cli-test
-OBJS = crc32.o mgmt-cli.o
+OBJS = crc32.o mgmt-cli.o test_sdram.o
CFLAGS += -I$(LIBCLI_DIR)
LIBS += $(LIBCLI_DIR)/libcli.a
diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c
index 152c121..dfcf856 100644
--- a/projects/cli-test/cli-test.c
+++ b/projects/cli-test/cli-test.c
@@ -37,38 +37,12 @@
#include "stm-uart.h"
#include "stm-fpgacfg.h"
#include "stm-keystore.h"
+#include "stm-sdram.h"
#include "mgmt-cli.h"
+#include "test_sdram.h"
#include <string.h>
-/* A bunch of defines to make it easier to add/maintain the CLI commands.
- *
- */
-#define _cli_cmd_struct(name, fullname, func, help) \
- static struct cli_command cmd_##fullname##_s = \
- {(char *) #name, func, 0, help, \
- PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL}
-
-/* ROOT is a top-level label with no command */
-#define cli_command_root(name) \
- _cli_cmd_struct(name, name, NULL, NULL); \
- cli_register_command2(cli, &cmd_##name##_s, NULL)
-
-/* BRANCH is a label with a parent, but no command */
-#define cli_command_branch(parent, name) \
- _cli_cmd_struct(name, parent##_##name, NULL, NULL); \
- cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s)
-
-/* NODE is a label with a parent and with a command associated with it */
-#define cli_command_node(parent, name, help) \
- _cli_cmd_struct(name, parent##_##name, cmd_##parent##_##name, (char *) help); \
- cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s)
-
-/* ROOT NODE is a label without a parent, but with a command associated with it */
-#define cli_command_root_node(name, help) \
- _cli_cmd_struct(name, name, NULL, (char *) help); \
- cli_register_command2(cli, &cmd_##name##_s, NULL)
-
extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len);
@@ -306,6 +280,64 @@ int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc)
while (1) {};
}
+int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ // run external memory initialization sequence
+ HAL_StatusTypeDef status;
+ int ok, n = 1, test_completed;
+
+ cli_print(cli, "Initializing SDRAM");
+ status = sdram_init();
+ if (status != HAL_OK) {
+ cli_print(cli, "Failed initializing SDRAM: %i", (int) status);
+ return CLI_OK;
+ }
+
+ /* XXX support number of iterations given as argument like 'test sdram 5' */
+ while (n--) {
+ cli_print(cli, "Starting SDRAM test (n = %i)", n);
+ test_completed = 0;
+ // set LFSRs to some initial value, LFSRs will produce
+ // pseudo-random 32-bit patterns to test our memories
+ lfsr1 = 0xCCAA5533;
+ lfsr2 = 0xCCAA5533;
+
+ cli_print(cli, "Run sequential write-then-read test for the first chip");
+ ok = test_sdram_sequential(SDRAM_BASEADDR_CHIP1);
+ if (!ok) break;
+
+ cli_print(cli, "Run random write-then-read test for the first chip");
+ ok = test_sdram_random(SDRAM_BASEADDR_CHIP1);
+ if (!ok) break;
+
+ cli_print(cli, "Run sequential write-then-read test for the second chip");
+ ok = test_sdram_sequential(SDRAM_BASEADDR_CHIP2);
+ if (!ok) break;
+
+ cli_print(cli, "Run random write-then-read test for the second chip");
+ ok = test_sdram_random(SDRAM_BASEADDR_CHIP2);
+ if (!ok) break;
+
+ // turn blue led on (testing two chips at the same time)
+ led_on(LED_BLUE);
+
+ cli_print(cli, "Run interleaved write-then-read test for both chips at once");
+ ok = test_sdrams_interleaved(SDRAM_BASEADDR_CHIP1, SDRAM_BASEADDR_CHIP2);
+
+ led_off(LED_BLUE);
+ test_completed = 1;
+ cli_print(cli, "SDRAM test (n = %i) completed", n);
+ }
+
+ if (! test_completed) {
+ cli_print(cli, "SDRAM test failed (n = %i)", n);
+ } else {
+ cli_print(cli, "SDRAM test completed successfully");
+ }
+
+ return CLI_OK;
+}
+
int check_auth(const char *username, const char *password)
{
if (strcasecmp(username, "ct") != 0)
@@ -349,6 +381,15 @@ void configure_cli_fpga(struct cli_def *cli)
cli_command_node(fpga_bitstream, erase, "Erase FPGA config memory");
}
+void configure_cli_test(struct cli_def *cli)
+{
+ /* test */
+ cli_command_root(test);
+
+ /* test sdram */
+ cli_command_node(test, sdram, "Run SDRAM tests");
+}
+
void configure_cli_misc(struct cli_def *cli)
{
/* filetransfer */
@@ -371,6 +412,7 @@ main()
configure_cli_show(&cli);
configure_cli_fpga(&cli);
+ configure_cli_test(&cli);
configure_cli_misc(&cli);
led_off(LED_RED);
diff --git a/projects/cli-test/mgmt-cli.c b/projects/cli-test/mgmt-cli.c
index 8d53515..faaafda 100644
--- a/projects/cli-test/mgmt-cli.c
+++ b/projects/cli-test/mgmt-cli.c
@@ -33,7 +33,6 @@
*/
#include "stm32f4xx_hal.h"
#include "stm-init.h"
-#include "stm-led.h"
#include "stm-uart.h"
#include "mgmt-cli.h"
@@ -79,11 +78,8 @@ int embedded_cli_loop(struct cli_def *cli)
while (1) {
cli_loop_start_new_command(cli, &ctx);
- HAL_GPIO_TogglePin(LED_PORT, LED_YELLOW);
while (1) {
- HAL_GPIO_TogglePin(LED_PORT, LED_BLUE);
-
cli_loop_show_prompt(cli, &ctx);
n = cli_loop_read_next_char(cli, &ctx, &c);
diff --git a/projects/cli-test/mgmt-cli.h b/projects/cli-test/mgmt-cli.h
index 2f1f139..e6780a3 100644
--- a/projects/cli-test/mgmt-cli.h
+++ b/projects/cli-test/mgmt-cli.h
@@ -38,13 +38,40 @@
#include "stm32f4xx_hal.h"
#include <libcli.h>
+
+/* A bunch of defines to make it easier to add/maintain the CLI commands.
+ *
+ */
+#define _cli_cmd_struct(name, fullname, func, help) \
+ static struct cli_command cmd_##fullname##_s = \
+ {(char *) #name, func, 0, help, \
+ PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL}
+
+/* ROOT is a top-level label with no command */
+#define cli_command_root(name) \
+ _cli_cmd_struct(name, name, NULL, NULL); \
+ cli_register_command2(cli, &cmd_##name##_s, NULL)
+
+/* BRANCH is a label with a parent, but no command */
+#define cli_command_branch(parent, name) \
+ _cli_cmd_struct(name, parent##_##name, NULL, NULL); \
+ cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s)
+
+/* NODE is a label with a parent and with a command associated with it */
+#define cli_command_node(parent, name, help) \
+ _cli_cmd_struct(name, parent##_##name, cmd_##parent##_##name, (char *) help); \
+ cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s)
+
+/* ROOT NODE is a label without a parent, but with a command associated with it */
+#define cli_command_root_node(name, help) \
+ _cli_cmd_struct(name, name, NULL, (char *) help); \
+ cli_register_command2(cli, &cmd_##name##_s, NULL)
+
+
extern void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf);
extern int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count);
extern int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count);
extern int embedded_cli_loop(struct cli_def *cli);
extern void mgmt_cli_init(struct cli_def *cli);
-extern __IO ITStatus MgmtUartDataReceived;
-extern __IO ITStatus MgmtUartShouldCli;
-
#endif /* __STM32_MGMT_CLI_H */
diff --git a/projects/cli-test/test_sdram.c b/projects/cli-test/test_sdram.c
new file mode 100644
index 0000000..e720667
--- /dev/null
+++ b/projects/cli-test/test_sdram.c
@@ -0,0 +1,274 @@
+/*
+ * test_sdram.c
+ * ------------
+ * Test code for the 2x512 MBit SDRAM working memory.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "stm32f4xx_hal.h"
+#include "stm-led.h"
+#include "stm-sdram.h"
+#include "test_sdram.h"
+
+
+uint32_t lfsr1;
+uint32_t lfsr2;
+
+
+int test_sdram_sequential(uint32_t *base_addr)
+{
+ // memory offset
+ int offset;
+
+ // readback value
+ uint32_t sdram_readback;
+
+
+ /* This test fills entire memory chip with some pseudo-random pattern
+ starting from the very first cell and going in linear fashion. It then
+ reads entire memory and compares read values with what was written. */
+
+
+ // turn on yellow led to indicate, that we're writing
+ led_on(LED_YELLOW);
+
+
+ //
+ // Note, that SDRAM_SIZE is in BYTES, and since we write using
+ // 32-bit words, total number of words is SDRAM_SIZE / 4.
+ //
+
+ // fill entire memory with "random" values
+ for (offset=0; offset<(SDRAM_SIZE >> 2); offset++) {
+ // generate next "random" value to write
+ lfsr1 = lfsr_next_32(lfsr1);
+
+ // write to memory
+ base_addr[offset] = lfsr1;
+ }
+
+
+ // turn off yellow led to indicate, that we're going to read
+ led_off(LED_YELLOW);
+
+
+ // read entire memory and compare values
+ for (offset=0; offset<(SDRAM_SIZE >> 2); offset++) {
+ // generate next "random" value (we use the second LFSR to catch up)
+ lfsr2 = lfsr_next_32(lfsr2);
+
+ // read from memory
+ sdram_readback = base_addr[offset];
+
+ // compare and abort test in case of mismatch
+ if (sdram_readback != lfsr2) return 0;
+ }
+
+ // done
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+int test_sdram_random(uint32_t *base_addr)
+//-----------------------------------------------------------------------------
+{
+ // cell counter, memory offset
+ int counter, offset;
+
+ // readback value
+ uint32_t sdram_readback;
+
+
+ /* This test fills entire memory chip with some pseudo-random pattern
+ starting from the very first cell, but then jumping around in pseudo-
+ random fashion to make sure, that SDRAM controller in STM32 handles
+ bank, row and column switching correctly. It then reads entire memory
+ and compares read values with what was written. */
+
+
+ // turn on yellow led to indicate, that we're writing
+ led_on(LED_YELLOW);
+
+
+ //
+ // Note, that SDRAM_SIZE is in BYTES, and since we write using
+ // 32-bit words, total number of words is SDRAM_SIZE / 4.
+ //
+
+ // start with the first cell
+ for (counter=0, offset=0; counter<(SDRAM_SIZE >> 2); counter++) {
+ // generate next "random" value to write
+ lfsr1 = lfsr_next_32(lfsr1);
+
+ // write to memory
+ base_addr[offset] = lfsr1;
+
+ // generate next "random" address
+
+ //
+ // Note, that for 64 MB memory with 32-bit data bus we need 24 bits
+ // of address, so we use 24-bit LFSR here. Since LFSR has only 2^^24-1
+ // states, i.e. all possible 24-bit values excluding 0, we have to
+ // manually kick it into some arbitrary state during the first iteration.
+ //
+
+ offset = offset ? lfsr_next_24(offset) : 0x00DEC0DE;
+ }
+
+
+ // turn off yellow led to indicate, that we're going to read
+ led_off(LED_YELLOW);
+
+
+ // read entire memory and compare values
+ for (counter=0, offset=0; counter<(SDRAM_SIZE >> 2); counter++) {
+ // generate next "random" value (we use the second LFSR to catch up)
+ lfsr2 = lfsr_next_32(lfsr2);
+
+ // read from memory
+ sdram_readback = base_addr[offset];
+
+ // compare and abort test in case of mismatch
+ if (sdram_readback != lfsr2) return 0;
+
+ // generate next "random" address
+ offset = offset ? lfsr_next_24(offset) : 0x00DEC0DE;
+ }
+
+ //
+ // we should have walked exactly 2**24 iterations and returned
+ // back to the arbitrary starting address...
+ //
+
+ if (offset != 0x00DEC0DE) return 0;
+
+
+ // done
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+int test_sdrams_interleaved(uint32_t *base_addr1, uint32_t *base_addr2)
+//-----------------------------------------------------------------------------
+{
+ // cell counter, memory offsets
+ int counter, offset1, offset2;
+
+ // readback value
+ uint32_t sdram_readback;
+
+
+ /* Basically this is the same as test_sdram_random() except that it
+ tests both memory chips at the same time. */
+
+
+ // turn on yellow led to indicate, that we're writing
+ led_on(LED_YELLOW);
+
+
+ //
+ // Note, that SDRAM_SIZE is in BYTES, and since we write using
+ // 32-bit words, total number of words is SDRAM_SIZE / 4.
+ //
+
+ // start with the first cell
+ for (counter=0, offset1=0, offset2=0; counter<(SDRAM_SIZE >> 2); counter++) {
+ // generate next "random" value to write
+ lfsr1 = lfsr_next_32(lfsr1);
+
+ // write to memory
+ base_addr1[offset1] = lfsr1;
+ base_addr2[offset2] = lfsr1;
+
+ // generate next "random" addresses (use different starting states!)
+
+ offset1 = offset1 ? lfsr_next_24(offset1) : 0x00ABCDEF;
+ offset2 = offset2 ? lfsr_next_24(offset2) : 0x00FEDCBA;
+ }
+
+
+ // turn off yellow led to indicate, that we're going to read
+ led_off(LED_YELLOW);
+
+
+ // read entire memory and compare values
+ for (counter=0, offset1=0, offset2=0; counter<(SDRAM_SIZE >> 2); counter++) {
+ // generate next "random" value (we use the second LFSR to catch up)
+ lfsr2 = lfsr_next_32(lfsr2);
+
+ // read from the first memory and compare
+ sdram_readback = base_addr1[offset1];
+ if (sdram_readback != lfsr2) return 0;
+
+ // read from the second memory and compare
+ sdram_readback = base_addr2[offset2];
+ if (sdram_readback != lfsr2) return 0;
+
+ // generate next "random" addresses
+ offset1 = offset1 ? lfsr_next_24(offset1) : 0x00ABCDEF;
+ offset2 = offset2 ? lfsr_next_24(offset2) : 0x00FEDCBA;
+ }
+
+ //
+ // we should have walked exactly 2**24 iterations and returned
+ // back to the arbitrary starting address...
+ //
+
+ if (offset1 != 0x00ABCDEF) return 0;
+ if (offset2 != 0x00FEDCBA) return 0;
+
+ // done
+ return 1;
+}
+
+uint32_t lfsr_next_32(uint32_t lfsr)
+{
+ uint32_t tap = 0;
+
+ tap ^= (lfsr >> 31);
+ tap ^= (lfsr >> 30);
+ tap ^= (lfsr >> 29);
+ tap ^= (lfsr >> 9);
+
+ return (lfsr << 1) | (tap & 1);
+}
+
+uint32_t lfsr_next_24(uint32_t lfsr)
+{
+ unsigned int tap = 0;
+
+ tap ^= (lfsr >> 23);
+ tap ^= (lfsr >> 22);
+ tap ^= (lfsr >> 21);
+ tap ^= (lfsr >> 16);
+
+ return ((lfsr << 1) | (tap & 1)) & 0x00FFFFFF;
+}
diff --git a/projects/cli-test/test_sdram.h b/projects/cli-test/test_sdram.h
new file mode 100644
index 0000000..b848d18
--- /dev/null
+++ b/projects/cli-test/test_sdram.h
@@ -0,0 +1,42 @@
+/*
+ * test_sdram.h
+ * ------------
+ * Prototypes and defines for testing the 2x512 MBit SDRAM working memory.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+extern uint32_t lfsr1;
+extern uint32_t lfsr2;
+
+extern int test_sdram_sequential(uint32_t *base_addr);
+extern int test_sdram_random(uint32_t *base_addr);
+extern int test_sdrams_interleaved(uint32_t *base_addr1, uint32_t *base_addr2);
+
+extern uint32_t lfsr_next_32(uint32_t lfsr);
+extern uint32_t lfsr_next_24(uint32_t lfsr);
diff --git a/stm-fmc.c b/stm-fmc.c
index 69dfb87..698f7af 100644
--- a/stm-fmc.c
+++ b/stm-fmc.c
@@ -32,23 +32,30 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stm32f4xx_hal.h"
+#include "stm-init.h"
#include "stm-fmc.h"
static SRAM_HandleTypeDef _fmc_fpga_inst;
-static void _fmc_init_gpio(void);
-static void _fmc_init_params(void);
+static HAL_StatusTypeDef _fmc_init_params(void);
static int _fmc_nwait_idle(void);
-void fmc_init(void)
+HAL_StatusTypeDef fmc_init(void)
{
+ static int initialized = 0;
+
+ if (initialized) {
+ return HAL_OK;
+ }
+ initialized = 1;
+
// configure fmc pins
- _fmc_init_gpio();
+ fmc_init_gpio();
// configure fmc registers
- _fmc_init_params();
+ return _fmc_init_params();
}
@@ -129,104 +136,45 @@ static int _fmc_nwait_idle()
return 0;
}
-static void _fmc_init_gpio(void)
+void fmc_init_gpio(void)
{
- // enable gpio clocks
- __GPIOA_CLK_ENABLE();
- __GPIOB_CLK_ENABLE();
- __GPIOD_CLK_ENABLE();
- __GPIOE_CLK_ENABLE();
- __GPIOF_CLK_ENABLE();
- __GPIOG_CLK_ENABLE();
- __GPIOH_CLK_ENABLE();
- __GPIOI_CLK_ENABLE();
+ GPIO_InitTypeDef GPIO_InitStruct;
// enable fmc clock
- __FMC_CLK_ENABLE();
+ __HAL_RCC_FMC_CLK_ENABLE();
- // structure
- GPIO_InitTypeDef GPIO_InitStruct;
-
- // Port B
- GPIO_InitStruct.Pin = GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
-
- // Port D
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
- |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15
- |GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3|GPIO_PIN_4
- |GPIO_PIN_5|GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+ fmc_af_gpio(GPIOB, GPIO_PIN_7);
+ fmc_af_gpio(GPIOD, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4
+ | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9
+ | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13
+ | GPIO_PIN_14 | GPIO_PIN_15);
/*
- * When FMC is working with fixed latency, NWAIT pin must not be
+ * When FMC is working with fixed latency, NWAIT pin (PD6) must not be
* configured in AF mode, according to STM32F429 errata.
*/
-
- // Port D (GPIO!)
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- // Port E
- GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
- |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
- |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
-
- // Port F
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
- |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13
- |GPIO_PIN_14|GPIO_PIN_15;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
-
- // Port G
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
- |GPIO_PIN_4|GPIO_PIN_5;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
-
- // Port H
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
- |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
-
- // Port I
- GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_0|GPIO_PIN_1
- |GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_6|GPIO_PIN_7;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
- HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
+ fmc_af_gpio(GPIOE, GPIO_PIN_2
+ | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7
+ | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11
+ | GPIO_PIN_12 | GPIO_PIN_13 |GPIO_PIN_14 | GPIO_PIN_15);
+ fmc_af_gpio(GPIOF, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
+ | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13
+ | GPIO_PIN_14 | GPIO_PIN_15);
+ fmc_af_gpio(GPIOG, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
+ | GPIO_PIN_4 | GPIO_PIN_5);
+ fmc_af_gpio(GPIOH, GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11
+ | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
+ fmc_af_gpio(GPIOI, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
+ | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10);
}
-static void _fmc_init_params(void)
+static HAL_StatusTypeDef _fmc_init_params(void)
{
/*
* fill internal fields
@@ -309,5 +257,5 @@ static void _fmc_init_params(void)
fmc_timing.AccessMode = FMC_ACCESS_MODE_A;
// initialize fmc
- HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL);
+ return HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL);
}
diff --git a/stm-fmc.h b/stm-fmc.h
index 7b73a94..1e6a670 100644
--- a/stm-fmc.h
+++ b/stm-fmc.h
@@ -44,8 +44,18 @@
#define FMC_NWAIT_IDLE GPIO_PIN_SET
-
-extern void fmc_init(void);
+#define fmc_af_gpio(port, pins) \
+ GPIO_InitStruct.Pin = pins; \
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; \
+ GPIO_InitStruct.Pull = GPIO_NOPULL; \
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; \
+ GPIO_InitStruct.Alternate = GPIO_AF12_FMC; \
+ __HAL_RCC_##port##_CLK_ENABLE(); \
+ HAL_GPIO_Init(port, &GPIO_InitStruct)
+
+
+extern HAL_StatusTypeDef fmc_init(void);
+extern void fmc_init_gpio(void);
extern int fmc_write_32(uint32_t addr, uint32_t *data);
extern int fmc_read_32(uint32_t addr, uint32_t *data);
diff --git a/stm-init.c b/stm-init.c
index 7ded2a6..c8228d8 100644
--- a/stm-init.c
+++ b/stm-init.c
@@ -38,9 +38,6 @@
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm-led.h"
#endif
-#ifdef HAL_SRAM_MODULE_ENABLED
-#include "stm-fmc.h"
-#endif
#ifdef HAL_UART_MODULE_ENABLED
#include "stm-uart.h"
#endif
@@ -143,24 +140,6 @@ static void MX_USART2_UART_Init(void)
#ifdef HAL_GPIO_MODULE_ENABLED
-#define gpio_output(output_port, output_pins, output_level) \
- /* Configure GPIO pin Output Level */ \
- HAL_GPIO_WritePin(output_port, output_pins, output_level); \
- /* Configure pin as output */ \
- GPIO_InitStruct.Pin = output_pins; \
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \
- GPIO_InitStruct.Pull = GPIO_NOPULL; \
- GPIO_InitStruct.Speed = GPIO_SPEED_LOW; \
- HAL_GPIO_Init(output_port, &GPIO_InitStruct)
-
-#define gpio_input(input_port, input_pin, input_pull) \
- GPIO_InitStruct.Pin = input_pin; \
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \
- GPIO_InitStruct.Pull = input_pull; \
- GPIO_InitStruct.Speed = GPIO_SPEED_LOW; \
- HAL_GPIO_Init(input_port, &GPIO_InitStruct)
-
-
/* Configure General Purpose Input/Output pins */
static void MX_GPIO_Init(void)
{
diff --git a/stm-init.h b/stm-init.h
index ed80d01..dd19311 100644
--- a/stm-init.h
+++ b/stm-init.h
@@ -38,6 +38,25 @@
#include "cmsis_os.h"
#include "stm32f4xx_hal.h"
+/* Macros used to make GPIO pin setup (in stm-init.c) easier */
+#define gpio_output(output_port, output_pins, output_level) \
+ /* Configure GPIO pin Output Level */ \
+ HAL_GPIO_WritePin(output_port, output_pins, output_level); \
+ /* Configure pin as output */ \
+ GPIO_InitStruct.Pin = output_pins; \
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \
+ GPIO_InitStruct.Pull = GPIO_NOPULL; \
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW; \
+ HAL_GPIO_Init(output_port, &GPIO_InitStruct)
+
+#define gpio_input(input_port, input_pin, input_pull) \
+ GPIO_InitStruct.Pin = input_pin; \
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \
+ GPIO_InitStruct.Pull = input_pull; \
+ GPIO_InitStruct.Speed = GPIO_SPEED_LOW; \
+ HAL_GPIO_Init(input_port, &GPIO_InitStruct)
+
+
extern void stm_init(void);
extern void Error_Handler(void);
diff --git a/stm-sdram.c b/stm-sdram.c
new file mode 100644
index 0000000..0ec8065
--- /dev/null
+++ b/stm-sdram.c
@@ -0,0 +1,267 @@
+/*
+ * stm-sdram.c
+ * -----------
+ * Functions concerning the 2x512 Mbit SDRAM working memory.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-sdram.h"
+#include "stm-fmc.h"
+#include "stm-led.h"
+
+SDRAM_HandleTypeDef hsdram1;
+SDRAM_HandleTypeDef hsdram2;
+
+void _sdram_init_gpio(void);
+HAL_StatusTypeDef _sdram_init_fmc(void);
+HAL_StatusTypeDef _sdram_init_params(SDRAM_HandleTypeDef *sdram1, SDRAM_HandleTypeDef *sdram2);
+
+
+HAL_StatusTypeDef sdram_init(void)
+{
+ HAL_StatusTypeDef status;
+ static int initialized = 0;
+
+ if (initialized) {
+ return;
+ }
+ initialized = 1;
+
+ /* We rely on several things being set up by fmc_init() instead of duplicating all
+ * that code here for independent FPGA/SDRAM FMC setup. This means the FPGA<->STM32
+ * FMC bus can be used without the SDRAMs initialized, but the SDRAMs can't be
+ * initialized withouth the FPGA<->STM32 FMC bus being set up too.
+ */
+ fmc_init();
+
+ // configure FMC
+ _sdram_init_gpio();
+ status = _sdram_init_fmc();
+ if (status != HAL_OK) return status;
+
+ // configure SDRAM registers
+ status = _sdram_init_params(&hsdram1, &hsdram2);
+ if (status != HAL_OK) return status;
+
+ return HAL_OK;
+}
+
+void _sdram_init_gpio(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* The bulk of the FMC GPIO pins are set up in fmc_init_gpio().
+ * This function just needs to enable the additional ones used
+ * with the SDRAMs.
+ */
+ fmc_af_gpio(GPIOB, GPIO_PIN_5 | GPIO_PIN_6);
+ fmc_af_gpio(GPIOC, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);
+ fmc_af_gpio(GPIOE, GPIO_PIN_0 | GPIO_PIN_1);
+ fmc_af_gpio(GPIOF, GPIO_PIN_11);
+ fmc_af_gpio(GPIOG, GPIO_PIN_8 | GPIO_PIN_15);
+ fmc_af_gpio(GPIOI, GPIO_PIN_4 | GPIO_PIN_5);
+}
+
+HAL_StatusTypeDef _sdram_init_fmc()
+{
+ HAL_StatusTypeDef status;
+ FMC_SDRAM_TimingTypeDef SdramTiming;
+
+ /*
+ * following settings are for -75E speed grade memory chip
+ * clocked at only 90 MHz instead of the rated 133 MHz
+ *
+ * ExitSelfRefreshDelay: 67 ns @ 90 MHz is 6.03 cycles, so in theory
+ * 6 can be used here, but let's be on the safe side
+ *
+ * WriteRecoveryTime: must be >= tRAS - tRCD (5 - 2 = 3 cycles),
+ * and >= tRC - tRCD - tRP (8 - 2 - 2 = 4 cycles)
+ */
+ SdramTiming.LoadToActiveDelay = 2; // tMRD
+ SdramTiming.ExitSelfRefreshDelay = 7; // (see above)
+ SdramTiming.SelfRefreshTime = 5; // should be >= tRAS (5 cycles)
+ SdramTiming.RowCycleDelay = 8; // tRC
+ SdramTiming.WriteRecoveryTime = 4; // (see above)
+ SdramTiming.RPDelay = 2; // tRP
+ SdramTiming.RCDDelay = 2; // tRCD
+
+ /*
+ * configure the first bank
+ */
+
+ // memory type
+ hsdram1.Instance = FMC_SDRAM_DEVICE;
+
+ // bank
+ hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
+
+ // settings for IS42S32160F
+ hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
+ hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
+ hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
+ hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
+ hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
+
+ // write protection not needed
+ hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
+
+ // memory clock is 90 MHz (HCLK / 2)
+ hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
+
+ // read burst not needed
+ hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
+
+ // additional pipeline stages not neeed
+ hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
+
+ // call HAL layer
+ status = HAL_SDRAM_Init(&hsdram1, &SdramTiming);
+ if (status != HAL_OK) return status;
+
+ /*
+ * configure the second bank
+ */
+
+ // memory type
+ hsdram2.Instance = FMC_SDRAM_DEVICE;
+
+ // bank number
+ hsdram2.Init.SDBank = FMC_SDRAM_BANK2;
+
+ // settings for IS42S32160F
+ hsdram2.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
+ hsdram2.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
+ hsdram2.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
+ hsdram2.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
+ hsdram2.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
+
+ // write protection not needed
+ hsdram2.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
+
+ // memory clock is 90 MHz (HCLK / 2)
+ hsdram2.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
+
+ // read burst not needed
+ hsdram2.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
+
+ // additional pipeline stages not neeed
+ hsdram2.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
+
+ // call HAL layer
+ return HAL_SDRAM_Init(&hsdram2, &SdramTiming);
+}
+
+HAL_StatusTypeDef _sdram_init_params(SDRAM_HandleTypeDef *sdram1, SDRAM_HandleTypeDef *sdram2)
+{
+ HAL_StatusTypeDef ok; // status
+ FMC_SDRAM_CommandTypeDef cmd; // command
+
+ /*
+ * enable clocking
+ */
+ cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
+ cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
+ cmd.AutoRefreshNumber = 1;
+ cmd.ModeRegisterDefinition = 0;
+
+ HAL_Delay(1);
+ ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
+ if (ok != HAL_OK) return ok;
+
+ /*
+ * precharge all banks
+ */
+ cmd.CommandMode = FMC_SDRAM_CMD_PALL;
+ cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
+ cmd.AutoRefreshNumber = 1;
+ cmd.ModeRegisterDefinition = 0;
+
+ HAL_Delay(1);
+ ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
+ if (ok != HAL_OK) return ok;
+
+
+ /*
+ * send two auto-refresh commands in a row
+ */
+ cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
+ cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
+ cmd.AutoRefreshNumber = 1;
+ cmd.ModeRegisterDefinition = 0;
+
+ ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
+ if (ok != HAL_OK) return ok;
+
+ ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
+ if (ok != HAL_OK) return ok;
+
+
+ /*
+ * load mode register
+ */
+ cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
+ cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
+ cmd.AutoRefreshNumber = 1;
+ cmd.ModeRegisterDefinition =
+ SDRAM_MODEREG_BURST_LENGTH_1 |
+ SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
+ SDRAM_MODEREG_CAS_LATENCY_2 |
+ SDRAM_MODEREG_OPERATING_MODE_STANDARD |
+ SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ;
+
+ ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
+ if (ok != HAL_OK) return ok;
+
+
+ /*
+ * set number of consequtive auto-refresh commands
+ * and program refresh rate
+ *
+ * RefreshRate = 64 ms / 8192 cyc = 7.8125 us/cyc
+ *
+ * RefreshCycles = 7.8125 us * 90 MHz = 703
+ *
+ * According to the formula on p.1665 of the reference manual,
+ * we also need to subtract 20 from the value, so the target
+ * refresh rate is 703 - 20 = 683.
+ */
+
+ ok = HAL_SDRAM_SetAutoRefreshNumber(sdram1, 8);
+ if (ok != HAL_OK) return ok;
+
+ HAL_SDRAM_ProgramRefreshRate(sdram1, 683);
+ if (ok != HAL_OK) return ok;
+
+ /*
+ * done
+ */
+ return HAL_OK;
+}
diff --git a/stm-sdram.h b/stm-sdram.h
new file mode 100644
index 0000000..8f58b34
--- /dev/null
+++ b/stm-sdram.h
@@ -0,0 +1,66 @@
+/*
+ * stm-sdram.h
+ * -----------
+ * Functions and defines concerning the 2x512 Mbit SDRAM working memory.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __STM32_SDRAM_H
+#define __STM32_SDRAM_H
+
+/* Base Addresses */
+#define SDRAM_BASEADDR_CHIP1 ((uint32_t *)0xC0000000)
+#define SDRAM_BASEADDR_CHIP2 ((uint32_t *)0xD0000000)
+
+/* Memory Size, 64 MBytes (512 Mbits) */
+#define SDRAM_SIZE 0x4000000
+
+/* Mode Register Bits */
+#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
+#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
+#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
+#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
+
+#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
+#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
+
+#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
+#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
+
+#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
+
+#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
+#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
+
+extern SDRAM_HandleTypeDef hsdram1;
+extern SDRAM_HandleTypeDef hsdram2;
+
+extern HAL_StatusTypeDef sdram_init(void);
+
+#endif