aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2016-05-24 18:13:26 -0400
committerPaul Selkirk <paul@psgd.org>2016-05-24 18:15:07 -0400
commitebe70741a4771698423e4c61939e88d6db66460d (patch)
treebf78c5e845c809e6dff113e0b2e46c94972317f4
parent9bb798876768f702c5940dcf67feffc6d0e9a0a4 (diff)
parent6265025f7cd7f606b6da62c7add13a6008500cf7 (diff)
Merge branch 'master' of git.cryptech.is:sw/stm32
-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--libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c98
-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.c398
-rw-r--r--stm-fmc.h22
-rw-r--r--stm-init.c21
-rw-r--r--stm-init.h19
-rw-r--r--stm-sdram.c267
-rw-r--r--stm-sdram.h66
16 files changed, 1013 insertions, 343 deletions
diff --git a/Makefile b/Makefile
index b51c74d..2c4710f 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/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c
index bf28b4b..bdf38fc 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c
@@ -1413,23 +1413,31 @@ HAL_StatusTypeDef FMC_SDRAM_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_InitTypeDe
}
else /* FMC_Bank2_SDRAM */
{
- tmpr1 = Device->SDCR[FMC_SDRAM_BANK1];
-
- /* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */
- tmpr1 &= ((uint32_t)~(FMC_SDCR1_NC | FMC_SDCR1_NR | FMC_SDCR1_MWID | \
- FMC_SDCR1_NB | FMC_SDCR1_CAS | FMC_SDCR1_WP | \
- FMC_SDCR1_SDCLK | FMC_SDCR1_RBURST | FMC_SDCR1_RPIPE));
-
- tmpr1 |= (uint32_t)(Init->SDClockPeriod |\
- Init->ReadBurst |\
- Init->ReadPipeDelay);
-
- tmpr2 = Device->SDCR[FMC_SDRAM_BANK2];
+///////////////////////////////
+// BEGIN PIECE OF WEIRD CODE //
+///////////////////////////////
+//
+// tmpr1 = Device->SDCR[FMC_SDRAM_BANK1];
+//
+// /* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */
+// tmpr1 &= ((uint32_t)~(FMC_SDCR1_NC | FMC_SDCR1_NR | FMC_SDCR1_MWID | \
+// FMC_SDCR1_NB | FMC_SDCR1_CAS | FMC_SDCR1_WP | \
+// FMC_SDCR1_SDCLK | FMC_SDCR1_RBURST | FMC_SDCR1_RPIPE));
+//
+// tmpr1 |= (uint32_t)(Init->SDClockPeriod |\
+// Init->ReadBurst |\
+// Init->ReadPipeDelay);
+//
+///////////////////////////////
+// END PIECE OF WEIRD CODE //
+///////////////////////////////
+
+ tmpr2 = Device->SDCR[FMC_SDRAM_BANK1];
/* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */
- tmpr2 &= ((uint32_t)~(FMC_SDCR1_NC | FMC_SDCR1_NR | FMC_SDCR1_MWID | \
- FMC_SDCR1_NB | FMC_SDCR1_CAS | FMC_SDCR1_WP | \
- FMC_SDCR1_SDCLK | FMC_SDCR1_RBURST | FMC_SDCR1_RPIPE));
+ tmpr2 &= ((uint32_t)~(FMC_SDCR2_NC | FMC_SDCR2_NR | FMC_SDCR2_MWID | \
+ FMC_SDCR2_NB | FMC_SDCR2_CAS | FMC_SDCR2_WP | \
+ FMC_SDCR2_SDCLK | FMC_SDCR2_RBURST | FMC_SDCR2_RPIPE));
tmpr2 |= (uint32_t)(Init->ColumnBitsNumber |\
Init->RowBitsNumber |\
@@ -1438,7 +1446,9 @@ HAL_StatusTypeDef FMC_SDRAM_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_InitTypeDe
Init->CASLatency |\
Init->WriteProtection);
- Device->SDCR[FMC_SDRAM_BANK1] = tmpr1;
+//
+// Device->SDCR[FMC_SDRAM_BANK1] = tmpr1;
+//
Device->SDCR[FMC_SDRAM_BANK2] = tmpr2;
}
@@ -1490,30 +1500,44 @@ HAL_StatusTypeDef FMC_SDRAM_Timing_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_Tim
}
else /* FMC_Bank2_SDRAM */
{
- tmpr1 = Device->SDTR[FMC_SDRAM_BANK2];
-
- /* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */
- tmpr1 &= ((uint32_t)~(FMC_SDTR1_TMRD | FMC_SDTR1_TXSR | FMC_SDTR1_TRAS | \
- FMC_SDTR1_TRC | FMC_SDTR1_TWR | FMC_SDTR1_TRP | \
- FMC_SDTR1_TRCD));
-
- tmpr1 |= (uint32_t)(((Timing->LoadToActiveDelay)-1) |\
- (((Timing->ExitSelfRefreshDelay)-1) << 4) |\
- (((Timing->SelfRefreshTime)-1) << 8) |\
- (((Timing->WriteRecoveryTime)-1) <<16) |\
- (((Timing->RCDDelay)-1) << 24));
-
+///////////////////////////////
+// BEGIN PIECE OF WEIRD CODE //
+///////////////////////////////
+//
+// tmpr1 = Device->SDTR[FMC_SDRAM_BANK2];
+//
+// /* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */
+// tmpr1 &= ((uint32_t)~(FMC_SDTR1_TMRD | FMC_SDTR1_TXSR | FMC_SDTR1_TRAS | \
+// FMC_SDTR1_TRC | FMC_SDTR1_TWR | FMC_SDTR1_TRP | \
+// FMC_SDTR1_TRCD));
+//
+// tmpr1 |= (uint32_t)(((Timing->LoadToActiveDelay)-1) |\
+// (((Timing->ExitSelfRefreshDelay)-1) << 4) |\
+// (((Timing->SelfRefreshTime)-1) << 8) |\
+// (((Timing->WriteRecoveryTime)-1) <<16) |\
+// (((Timing->RCDDelay)-1) << 24));
+//
+///////////////////////////////
+// END PIECE OF WEIRD CODE //
+///////////////////////////////
+
tmpr2 = Device->SDTR[FMC_SDRAM_BANK1];
/* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */
- tmpr2 &= ((uint32_t)~(FMC_SDTR1_TMRD | FMC_SDTR1_TXSR | FMC_SDTR1_TRAS | \
- FMC_SDTR1_TRC | FMC_SDTR1_TWR | FMC_SDTR1_TRP | \
- FMC_SDTR1_TRCD));
- tmpr2 |= (uint32_t)((((Timing->RowCycleDelay)-1) << 12) |\
- (((Timing->RPDelay)-1) << 20));
-
- Device->SDTR[FMC_SDRAM_BANK2] = tmpr1;
- Device->SDTR[FMC_SDRAM_BANK1] = tmpr2;
+ tmpr2 &= ((uint32_t)~(FMC_SDTR2_TMRD | FMC_SDTR2_TXSR | FMC_SDTR2_TRAS | \
+ FMC_SDTR2_TRC | FMC_SDTR2_TWR | FMC_SDTR2_TRP | \
+ FMC_SDTR2_TRCD));
+
+ tmpr2 |= (uint32_t)(((Timing->LoadToActiveDelay)-1U) |\
+ (((Timing->ExitSelfRefreshDelay)-1U) << 4U) |\
+ (((Timing->SelfRefreshTime)-1U) << 8U) |\
+ (((Timing->WriteRecoveryTime)-1U) <<16U) |\
+ (((Timing->RCDDelay)-1U) << 24U));
+
+//
+// Device->SDTR[FMC_SDRAM_BANK2] = tmpr1;
+//
+ Device->SDTR[FMC_SDRAM_BANK2] = tmpr2;
}
return HAL_OK;
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 eca4b38..698f7af 100644
--- a/stm-fmc.c
+++ b/stm-fmc.c
@@ -31,325 +31,231 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
-
-//------------------------------------------------------------------------------
-// Headers
-//------------------------------------------------------------------------------
-#include "stm-fmc.h"
#include "stm32f4xx_hal.h"
+#include "stm-init.h"
+#include "stm-fmc.h"
-//------------------------------------------------------------------------------
-// Defined Values
-//------------------------------------------------------------------------------
-#define FMC_FPGA_BASE_ADDR 0x60000000
-#define FMC_FPGA_ADDR_MASK 0x03FFFFFC // there are 26 physical lines, but "only" 24 usable for now
-#define FMC_FPGA_NWAIT_MAX_POLL_TICKS 10
-
-#define FMC_GPIO_PORT_NWAIT GPIOD
-#define FMC_GPIO_PIN_NWAIT GPIO_PIN_6
-
-#define FMC_NWAIT_IDLE GPIO_PIN_SET
-
-
-//------------------------------------------------------------------------------
-// Variables
-//------------------------------------------------------------------------------
static SRAM_HandleTypeDef _fmc_fpga_inst;
-
-//------------------------------------------------------------------------------
-// Prototypes
-//------------------------------------------------------------------------------
-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)
{
- // configure fmc pins
- _fmc_init_gpio();
+ static int initialized = 0;
+
+ if (initialized) {
+ return HAL_OK;
+ }
+ initialized = 1;
+
+ // configure fmc pins
+ fmc_init_gpio();
- // configure fmc registers
- _fmc_init_params();
+ // configure fmc registers
+ return _fmc_init_params();
}
-//------------------------------------------------------------------------------
int fmc_write_32(uint32_t addr, uint32_t *data)
-//------------------------------------------------------------------------------
{
- // calculate target fpga address
- uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK);
+ // calculate target fpga address
+ uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK);
- // write data to fpga
- HAL_StatusTypeDef ok = HAL_SRAM_Write_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);
+ // write data to fpga
+ HAL_StatusTypeDef ok = HAL_SRAM_Write_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);
- // check for error
- if (ok != HAL_OK) return -1;
+ // check for error
+ if (ok != HAL_OK) return -1;
- // wait for transaction to complete
- int wait = _fmc_nwait_idle();
+ // wait for transaction to complete
+ int wait = _fmc_nwait_idle();
- // check for timeout
- if (wait != 0) return -1;
+ // check for timeout
+ if (wait != 0) return -1;
- // everything went ok
- return 0;
+ // everything went ok
+ return 0;
}
-//------------------------------------------------------------------------------
int fmc_read_32(uint32_t addr, uint32_t *data)
-//------------------------------------------------------------------------------
{
- // calculate target fpga address
- uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK);
+ // calculate target fpga address
+ uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK);
- // perform dummy read transaction
- HAL_StatusTypeDef ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);
+ // perform dummy read transaction
+ HAL_StatusTypeDef ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);
- // check for error
- if (ok != HAL_OK) return -1;
+ // check for error
+ if (ok != HAL_OK) return -1;
- // wait for dummy transaction to complete
- int wait = _fmc_nwait_idle();
+ // wait for dummy transaction to complete
+ int wait = _fmc_nwait_idle();
- // check for timeout
- if (wait != 0) return -1;
+ // check for timeout
+ if (wait != 0) return -1;
- // read data from fpga
- ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);
+ // read data from fpga
+ ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);
- // check for error
- if (ok != HAL_OK) return -1;
+ // check for error
+ if (ok != HAL_OK) return -1;
- // wait for read transaction to complete
- wait = _fmc_nwait_idle();
+ // wait for read transaction to complete
+ wait = _fmc_nwait_idle();
- // check for timeout
- if (wait != 0) return -1;
+ // check for timeout
+ if (wait != 0) return -1;
- // everything went ok
- return 0;
+ // everything went ok
+ return 0;
}
-//------------------------------------------------------------------------------
static int _fmc_nwait_idle()
-//------------------------------------------------------------------------------
{
- int cnt; // counter
+ int cnt; // counter
- // poll NWAIT (number of iterations is limited)
- for (cnt=0; cnt<FMC_FPGA_NWAIT_MAX_POLL_TICKS; cnt++)
- {
- // read pin state
- GPIO_PinState nwait = HAL_GPIO_ReadPin(FMC_GPIO_PORT_NWAIT, FMC_GPIO_PIN_NWAIT);
+ // poll NWAIT (number of iterations is limited)
+ for (cnt=0; cnt<FMC_FPGA_NWAIT_MAX_POLL_TICKS; cnt++)
+ {
+ // read pin state
+ GPIO_PinState nwait = HAL_GPIO_ReadPin(FMC_GPIO_PORT_NWAIT, FMC_GPIO_PIN_NWAIT);
- // stop waiting if fpga is ready
- if (nwait == FMC_NWAIT_IDLE) break;
- }
+ // stop waiting if fpga is ready
+ if (nwait == FMC_NWAIT_IDLE) break;
+ }
- // check for timeout
- if (cnt >= FMC_FPGA_NWAIT_MAX_POLL_TICKS) return -1;
+ // check for timeout
+ if (cnt >= FMC_FPGA_NWAIT_MAX_POLL_TICKS) return -1;
- // ok
- return 0;
+ // ok
+ 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();
-
- // enable fmc clock
- __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);
-
- /*
- * When FMC is working with fixed latency, NWAIT pin 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);
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ // enable fmc clock
+ __HAL_RCC_FMC_CLK_ENABLE();
+
+ 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 (PD6) must not be
+ * configured in AF mode, according to STM32F429 errata.
+ */
+ GPIO_InitStruct.Pin = GPIO_PIN_6;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ HAL_GPIO_Init(GPIOD, &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
- */
- _fmc_fpga_inst.Instance = FMC_NORSRAM_DEVICE;
- _fmc_fpga_inst.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
+ /*
+ * fill internal fields
+ */
+ _fmc_fpga_inst.Instance = FMC_NORSRAM_DEVICE;
+ _fmc_fpga_inst.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
- /*
- * configure fmc interface settings
- */
+ /*
+ * configure fmc interface settings
+ */
- // use the first bank and corresponding chip select
- _fmc_fpga_inst.Init.NSBank = FMC_NORSRAM_BANK1;
+ // use the first bank and corresponding chip select
+ _fmc_fpga_inst.Init.NSBank = FMC_NORSRAM_BANK1;
- // data and address buses are separate
- _fmc_fpga_inst.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
+ // data and address buses are separate
+ _fmc_fpga_inst.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
- // fpga mimics psram-type memory
- _fmc_fpga_inst.Init.MemoryType = FMC_MEMORY_TYPE_PSRAM;
+ // fpga mimics psram-type memory
+ _fmc_fpga_inst.Init.MemoryType = FMC_MEMORY_TYPE_PSRAM;
- // data bus is 32-bit
- _fmc_fpga_inst.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32;
+ // data bus is 32-bit
+ _fmc_fpga_inst.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32;
- // read transaction is sync
- _fmc_fpga_inst.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_ENABLE;
+ // read transaction is sync
+ _fmc_fpga_inst.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_ENABLE;
- // this _must_ be configured to high, according to errata, otherwise
- // the processor may hang after trying to access fpga via fmc
- _fmc_fpga_inst.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_HIGH;
+ // this _must_ be configured to high, according to errata, otherwise
+ // the processor may hang after trying to access fpga via fmc
+ _fmc_fpga_inst.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_HIGH;
- // wrap mode is not supported
- _fmc_fpga_inst.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
+ // wrap mode is not supported
+ _fmc_fpga_inst.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
- // don't care in fixed latency mode
- _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_DURING_WS;
+ // don't care in fixed latency mode
+ _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_DURING_WS;
- // allow write access to fpga
- _fmc_fpga_inst.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
+ // allow write access to fpga
+ _fmc_fpga_inst.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
- // use fixed latency mode (ignore wait signal)
- _fmc_fpga_inst.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
+ // use fixed latency mode (ignore wait signal)
+ _fmc_fpga_inst.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
- // write and read have same timing
- _fmc_fpga_inst.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+ // write and read have same timing
+ _fmc_fpga_inst.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
- // don't care in sync mode
- _fmc_fpga_inst.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
+ // don't care in sync mode
+ _fmc_fpga_inst.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
- // write transaction is sync
- _fmc_fpga_inst.Init.WriteBurst = FMC_WRITE_BURST_ENABLE;
+ // write transaction is sync
+ _fmc_fpga_inst.Init.WriteBurst = FMC_WRITE_BURST_ENABLE;
- // keep clock always active
- _fmc_fpga_inst.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ASYNC;
+ // keep clock always active
+ _fmc_fpga_inst.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ASYNC;
- /*
- * configure fmc timing parameters
- */
- FMC_NORSRAM_TimingTypeDef fmc_timing;
+ /*
+ * configure fmc timing parameters
+ */
+ FMC_NORSRAM_TimingTypeDef fmc_timing;
- // don't care in sync mode
- fmc_timing.AddressSetupTime = 15;
+ // don't care in sync mode
+ fmc_timing.AddressSetupTime = 15;
- // don't care in sync mode
- fmc_timing.AddressHoldTime = 15;
+ // don't care in sync mode
+ fmc_timing.AddressHoldTime = 15;
- // don't care in sync mode
- fmc_timing.DataSetupTime = 255;
+ // don't care in sync mode
+ fmc_timing.DataSetupTime = 255;
- // not needed, since nwait will be polled manually
- fmc_timing.BusTurnAroundDuration = 0;
+ // not needed, since nwait will be polled manually
+ fmc_timing.BusTurnAroundDuration = 0;
- // use smallest allowed divisor for best performance
- fmc_timing.CLKDivision = 2;
+ // use smallest allowed divisor for best performance
+ fmc_timing.CLKDivision = 2;
- // stm is too slow to work with min allowed 2-cycle latency
- fmc_timing.DataLatency = 3;
+ // stm is too slow to work with min allowed 2-cycle latency
+ fmc_timing.DataLatency = 3;
- // don't care in sync mode
- fmc_timing.AccessMode = FMC_ACCESS_MODE_A;
+ // don't care in sync mode
+ fmc_timing.AccessMode = FMC_ACCESS_MODE_A;
- // initialize fmc
- HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL);
+ // initialize fmc
+ return HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL);
}
-
-
-//------------------------------------------------------------------------------
-// EOF
-//------------------------------------------------------------------------------
diff --git a/stm-fmc.h b/stm-fmc.h
index 9e34d32..1e6a670 100644
--- a/stm-fmc.h
+++ b/stm-fmc.h
@@ -35,9 +35,27 @@
#ifndef __STM_FMC_H
#define __STM_FMC_H
-#include <stdint.h>
+#define FMC_FPGA_BASE_ADDR 0x60000000
+#define FMC_FPGA_ADDR_MASK 0x03FFFFFC // there are 26 physical lines, but "only" 24 usable for now
+#define FMC_FPGA_NWAIT_MAX_POLL_TICKS 10
-extern void fmc_init(void);
+#define FMC_GPIO_PORT_NWAIT GPIOD
+#define FMC_GPIO_PIN_NWAIT GPIO_PIN_6
+
+#define FMC_NWAIT_IDLE GPIO_PIN_SET
+
+#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