aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Thulin <fredrik@thulin.net>2016-05-19 14:23:13 +0200
committerFredrik Thulin <fredrik@thulin.net>2016-05-19 14:23:13 +0200
commitbfcbe2a78f709417c2f41de32a8d6b61842a0abd (patch)
tree265a26c833a0c8339ad9c28df3bc8e81ddc7e0ca
parent67837a0d3cc661d250ecb2c57c22171f312e073a (diff)
Refactor FPGA bitstream upload code.
Move the N25Q128 code to it's own file in order to be able to reuse it for the keystore memory code.
-rw-r--r--Makefile1
-rw-r--r--projects/cli-test/cli-test.c59
-rw-r--r--spiflash_n25q128.c336
-rw-r--r--spiflash_n25q128.h75
-rw-r--r--stm-fpgacfg.c267
-rw-r--r--stm-fpgacfg.h52
-rw-r--r--stm-init.c2
7 files changed, 475 insertions, 317 deletions
diff --git a/Makefile b/Makefile
index f43bac4..2409723 100644
--- a/Makefile
+++ b/Makefile
@@ -54,6 +54,7 @@ export BOARD_OBJS = \
$(TOPLEVEL)/stm-fmc.o \
$(TOPLEVEL)/stm-uart.o \
$(TOPLEVEL)/stm-rtc.o \
+ $(TOPLEVEL)/spiflash_n25q128.o \
$(TOPLEVEL)/stm-fpgacfg.o \
$(TOPLEVEL)/syscalls.o \
$(BOARD_DIR)/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.o \
diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c
index 922fcba..e7d49a7 100644
--- a/projects/cli-test/cli-test.c
+++ b/projects/cli-test/cli-test.c
@@ -92,28 +92,35 @@ int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int
return CLI_OK;
}
+/* The chunk size have to be a multiple of the SPI flash page size (256 bytes),
+ and it has to match the chunk size in the program sending the bitstream over the UART.
+*/
+#define BITSTREAM_UPLOAD_CHUNK_SIZE 4096
+
int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc)
{
- uint32_t filesize = 0, crc = 0, my_crc = 0, n = 4096, counter = 0;
- uint8_t buf[4096];
+ uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0, i;
+ uint32_t offset = 0, n = BITSTREAM_UPLOAD_CHUNK_SIZE;
+ uint8_t buf[BITSTREAM_UPLOAD_CHUNK_SIZE];
- fpgacfg_give_access_to_stm32();
+ fpgacfg_access_control(ALLOW_ARM);
cli_print(cli, "Checking if FPGA config memory is accessible");
- if (n25q128_check_id() != 1) {
+ if (fpgacfg_check_id() != 1) {
cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed.");
return CLI_ERROR;
}
cli_print(cli, "OK, write FPGA bitstream file size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)");
+ /* Read file size (4 bytes) */
uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000);
cli_print(cli, "File size %li", filesize);
while (filesize) {
- uint32_t page, offset;
- uint8_t *ptr;
-
+ /* By initializing buf to the same value that erased flash has (0xff), we don't
+ * have to try and be smart when writing the last page of data to the memory.
+ */
memset(buf, 0xff, 4096);
if (filesize < n) {
@@ -125,38 +132,25 @@ int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *ar
return CLI_ERROR;
}
filesize -= n;
+
+ /* After reception of 4 KB but before ACKing we have "all" the time in the world to
+ * calculate CRC and write it to flash.
+ */
my_crc = update_crc(my_crc, buf, n);
- if ((counter % (N25Q128_SECTOR_SIZE / 4096)) == 0) {
- /* first page in sector, need to erase sector */
- offset = (counter * 4096) / N25Q128_SECTOR_SIZE;
- if (! n25q128_erase_sector(offset)) {
- cli_print(cli, "Failed erasing sector at offset %li (counter = %li)", offset, counter);
- return CLI_ERROR;
- }
- /* XXX add timeout and check for < 0 */
- while (n25q128_get_wip_flag()) { HAL_Delay(10); };
+ if ((i = fpgacfg_write_data(offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE)) != 1) {
+ cli_print(cli, "Failed writing data at offset %li (counter = %li): %li", offset, counter, i);
+ return CLI_ERROR;
}
- ptr = buf;
- for (page = 0; page < 4096 / N25Q128_PAGE_SIZE; page++) {
- offset = counter * (4096 / N25Q128_PAGE_SIZE) + page;
- if (! n25q128_write_page(offset, ptr)) {
- cli_print(cli, "Failed writing page %li at offset %li (counter = %li)", page, offset, counter);
- return CLI_ERROR;
- }
- ptr += N25Q128_PAGE_SIZE;
-
- /* XXX add timeout and check for < 0 */
- while (n25q128_get_wip_flag()) { HAL_Delay(10); };
-
- /* XXX read back data and verify it */
- }
+ offset += BITSTREAM_UPLOAD_CHUNK_SIZE;
+ /* ACK this chunk by sending the current chunk counter (4 bytes) */
counter++;
uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4);
}
+ /* The sending side will now send it's calculated CRC-32 */
cli_print(cli, "Send CRC-32");
uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000);
cli_print(cli, "CRC-32 %li", crc);
@@ -166,7 +160,7 @@ int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *ar
cli_print(cli, "CRC checksum did NOT match");
}
- fpgacfg_give_access_to_fpga();
+ fpgacfg_access_control(ALLOW_FPGA);
return CLI_OK;
}
@@ -190,7 +184,6 @@ int check_auth(const char *username, const char *password)
int
main()
{
- int i;
static struct cli_def cli;
struct cli_command cmd_show_s = {(char *) "show", NULL, 0, NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL};
struct cli_command cmd_show_cpuspeed_s = {(char *) "cpuspeed", cmd_show_cpuspeed, 0,
@@ -233,7 +226,7 @@ main()
embedded_cli_loop(&cli);
- cli_print(&cli, "Rebooting in 3 seconds");
+ cli_print(&cli, "Rebooting in 4 seconds");
HAL_Delay(3000);
HAL_NVIC_SystemReset();
diff --git a/spiflash_n25q128.c b/spiflash_n25q128.c
new file mode 100644
index 0000000..10f5954
--- /dev/null
+++ b/spiflash_n25q128.c
@@ -0,0 +1,336 @@
+/*
+ * spiflash_n25q128.c
+ * ------------------
+ * Functions and defines for accessing SPI flash with part number n25q128.
+ *
+ * The Alpha board has two of these SPI flash memorys, the FPGA config memory
+ * and the keystore 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-fpgacfg.h"
+#include "stm-init.h"
+
+#define _n25q128_select(ctx) HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_RESET);
+#define _n25q128_deselect(ctx) HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_SET);
+
+
+int _n25q128_get_wel_flag(struct spiflash_ctx *ctx);
+
+
+int n25q128_check_id(struct spiflash_ctx *ctx)
+{
+ // tx, rx buffers
+ uint8_t spi_tx[4];
+ uint8_t spi_rx[4];
+
+ // result
+ HAL_StatusTypeDef ok;
+
+ // send READ ID command
+ spi_tx[0] = N25Q128_COMMAND_READ_ID;
+
+ // select, send command & read response, deselect
+ _n25q128_select(ctx);
+ ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 4, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return 0;
+
+ // parse response (note, that the very first byte was received during the
+ // transfer of the command byte, so it contains garbage and should
+ // be ignored here)
+ if (spi_rx[1] != N25Q128_ID_MANUFACTURER) return 0;
+ if (spi_rx[2] != N25Q128_ID_DEVICE_TYPE) return 0;
+ if (spi_rx[3] != N25Q128_ID_DEVICE_CAPACITY) return 0;
+
+ // done
+ return 1;
+}
+
+
+int n25q128_read_page(struct spiflash_ctx *ctx, uint32_t page_offset, uint8_t *page_buffer)
+{
+ // tx buffer
+ uint8_t spi_tx[4];
+
+ // result
+ HAL_StatusTypeDef ok;
+
+ // check offset
+ if (page_offset >= N25Q128_NUM_PAGES) return 0;
+
+ // calculate byte address
+ page_offset *= N25Q128_PAGE_SIZE;
+
+ // prepare READ command
+ spi_tx[0] = N25Q128_COMMAND_READ_PAGE;
+ spi_tx[1] = (uint8_t)(page_offset >> 16);
+ spi_tx[2] = (uint8_t)(page_offset >> 8);
+ spi_tx[3] = (uint8_t)(page_offset >> 0);
+
+ // activate, send command
+ _n25q128_select(ctx);
+ ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+
+ // check
+ if (ok != HAL_OK) {
+ _n25q128_deselect(ctx);
+ return 0;
+ }
+
+ // read response, deselect
+ ok = HAL_SPI_Receive(ctx->hspi, page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return 0;
+
+ // done
+ return 1;
+}
+
+
+int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer)
+{
+ // tx buffer
+ uint8_t spi_tx[4];
+
+ // result
+ HAL_StatusTypeDef ok;
+
+ // check offset
+ if (page_offset >= N25Q128_NUM_PAGES) return 0;
+
+ // enable writing
+ spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
+
+ // activate, send command, deselect
+ _n25q128_select(ctx);
+ ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return 0;
+
+ // make sure, that write enable did the job
+ int wel = _n25q128_get_wel_flag(ctx);
+ if (wel != 1) return 0;
+
+ // calculate byte address
+ page_offset *= N25Q128_PAGE_SIZE;
+
+ // prepare PROGRAM PAGE command
+ spi_tx[0] = N25Q128_COMMAND_PAGE_PROGRAM;
+ spi_tx[1] = (uint8_t)(page_offset >> 16);
+ spi_tx[2] = (uint8_t)(page_offset >> 8);
+ spi_tx[3] = (uint8_t)(page_offset >> 0);
+
+ // activate, send command
+ _n25q128_select(ctx);
+ ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+
+ // check
+ if (ok != HAL_OK) {
+ _n25q128_deselect(ctx);
+ return 0;
+ }
+
+ // send data, deselect
+ ok = HAL_SPI_Transmit(ctx->hspi, (uint8_t *) page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return 0;
+
+ // done
+ return 1;
+}
+
+
+int n25q128_get_wip_flag(struct spiflash_ctx *ctx)
+{
+ // tx, rx buffers
+ uint8_t spi_tx[2];
+ uint8_t spi_rx[2];
+
+ // result
+ HAL_StatusTypeDef ok;
+
+ // send READ STATUS command
+ spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
+
+ // send command, read response, deselect
+ _n25q128_select(ctx);
+ ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return -1;
+
+ // done
+ return (spi_rx[1] & 1);
+}
+
+
+int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset)
+{
+ // tx buffer
+ uint8_t spi_tx[4];
+
+ // result
+ HAL_StatusTypeDef ok;
+
+ // check offset
+ if (sector_offset >= N25Q128_NUM_SECTORS) return 0;
+
+ // enable writing
+ spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
+
+ // select, send command, deselect
+ _n25q128_select(ctx);
+ ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return 0;
+
+ // make sure, that write enable did the job
+ int wel = _n25q128_get_wel_flag(ctx);
+ if (wel != 1) return 0;
+
+ // calculate byte address
+ sector_offset *= N25Q128_SECTOR_SIZE;
+
+ // send ERASE SUBSECTOR command
+ spi_tx[0] = N25Q128_COMMAND_ERASE_SECTOR;
+ spi_tx[1] = (uint8_t)(sector_offset >> 16);
+ spi_tx[2] = (uint8_t)(sector_offset >> 8);
+ spi_tx[3] = (uint8_t)(sector_offset >> 0);
+
+ // activate, send command, deselect
+ _n25q128_select(ctx);
+ ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return 0;
+
+ // done
+ return 1;
+}
+
+
+int _n25q128_get_wel_flag(struct spiflash_ctx *ctx)
+{
+ // tx, rx buffers
+ uint8_t spi_tx[2];
+ uint8_t spi_rx[2];
+
+ // result
+ HAL_StatusTypeDef ok;
+
+ // send READ STATUS command
+ spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
+
+ // send command, read response, deselect
+ _n25q128_select(ctx);
+ ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
+ HAL_Delay(1);
+ _n25q128_deselect(ctx);
+
+ // check
+ if (ok != HAL_OK) return -1;
+
+ // done
+ return ((spi_rx[1] >> 1) & 1);
+}
+
+/* Wait until the flash memory is done writing (wip = Write In Progress) */
+inline int _wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout)
+{
+ int i;
+ while (timeout--) {
+ i = n25q128_get_wip_flag(ctx);
+ if (i < 0) return 0;
+ if (! i) break;
+ HAL_Delay(10);
+ }
+ return 1;
+}
+
+/* This function performs erasure if needed, and then writing of a number of pages to the flash memory */
+int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len)
+{
+ uint32_t page;
+
+ /* Ensure alignment */
+ if ((offset % N25Q128_PAGE_SIZE) != 0) return -1;
+ if ((len % N25Q128_PAGE_SIZE) != 0) return -2;
+
+ if ((offset % N25Q128_SECTOR_SIZE) == 0) {
+ /* first page in sector, need to erase sector */
+
+ if (! _wait_while_wip(ctx, 1000)) return -3;
+
+ if (! n25q128_erase_sector(ctx, offset / N25Q128_SECTOR_SIZE)) {
+ return -4;
+ }
+ }
+
+ for (page = 0; page < len / N25Q128_PAGE_SIZE; page++) {
+ /* Wait until the flash memory is done writing (wip = Write In Progress) */
+ if (! _wait_while_wip(ctx, 1000)) return -5;
+
+ if (! n25q128_write_page(ctx, offset / N25Q128_PAGE_SIZE, buf)) {
+ return -6;
+ }
+ buf += N25Q128_PAGE_SIZE;
+ offset += N25Q128_PAGE_SIZE;
+
+ /* XXX read back data and verify it, or maybe just verify ability to write
+ * to memory by verifying the contents of one page after erase?
+ */
+ }
+
+ return 1;
+}
+
diff --git a/spiflash_n25q128.h b/spiflash_n25q128.h
new file mode 100644
index 0000000..6802e22
--- /dev/null
+++ b/spiflash_n25q128.h
@@ -0,0 +1,75 @@
+/*
+ * spiflash_n25q128.h
+ * ------------------
+ * Functions and defines for accessing SPI flash with part number n25q128.
+ *
+ * The Alpha board has two of these SPI flash memorys, the FPGA config memory
+ * and the keystore 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_SPIFLASH_N25Q128_H
+#define __STM32_SPIFLASH_N25Q128_H
+
+#include "stm32f4xx_hal.h"
+
+#define N25Q128_COMMAND_READ_ID 0x9E
+#define N25Q128_COMMAND_READ_PAGE 0x03
+#define N25Q128_COMMAND_READ_STATUS 0x05
+#define N25Q128_COMMAND_WRITE_ENABLE 0x06
+#define N25Q128_COMMAND_ERASE_SECTOR 0xD8
+#define N25Q128_COMMAND_PAGE_PROGRAM 0x02
+
+#define N25Q128_PAGE_SIZE 0x100 // 256
+#define N25Q128_NUM_PAGES 0x10000 // 65536
+
+#define N25Q128_SECTOR_SIZE 0x10000 // 65536
+#define N25Q128_NUM_SECTORS 0x100 // 256
+
+#define N25Q128_SPI_TIMEOUT 1000
+
+#define N25Q128_ID_MANUFACTURER 0x20
+#define N25Q128_ID_DEVICE_TYPE 0xBA
+#define N25Q128_ID_DEVICE_CAPACITY 0x18
+
+struct spiflash_ctx {
+ SPI_HandleTypeDef *hspi;
+ GPIO_TypeDef *cs_n_port;
+ uint16_t cs_n_pin;
+};
+
+extern int n25q128_check_id(struct spiflash_ctx *ctx);
+extern int n25q128_get_wip_flag(struct spiflash_ctx *ctx);
+extern int n25q128_read_page(struct spiflash_ctx *ctx, uint32_t page_offset, uint8_t *page_buffer);
+extern int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer);
+extern int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset);
+
+extern int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len);
+#endif /* __STM32_SPIFLASH_N25Q128_H */
diff --git a/stm-fpgacfg.c b/stm-fpgacfg.c
index 0d255e5..f8ff6fa 100644
--- a/stm-fpgacfg.c
+++ b/stm-fpgacfg.c
@@ -38,259 +38,34 @@
SPI_HandleTypeDef hspi_fpgacfg;
-int _n25q128_get_wel_flag(void);
+struct spiflash_ctx fpgacfg_ctx = {&hspi_fpgacfg, PROM_CS_N_GPIO_Port, PROM_CS_N_Pin};
-
-int n25q128_check_id()
+int fpgacfg_check_id()
{
- // tx, rx buffers
- uint8_t spi_tx[4];
- uint8_t spi_rx[4];
-
- // result
- HAL_StatusTypeDef ok;
-
- // send READ ID command
- spi_tx[0] = N25Q128_COMMAND_READ_ID;
-
- // select, send command & read response, deselect
- _n25q128_select();
- ok = HAL_SPI_TransmitReceive(N25Q128_SPI_HANDLE, spi_tx, spi_rx, 4, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return 0;
-
- // parse response (note, that the very first byte was received during the
- // transfer of the command byte, so it contains garbage and should
- // be ignored here)
- if (spi_rx[1] != N25Q128_ID_MANUFACTURER) return 0;
- if (spi_rx[2] != N25Q128_ID_DEVICE_TYPE) return 0;
- if (spi_rx[3] != N25Q128_ID_DEVICE_CAPACITY) return 0;
-
- // done
- return 1;
+ return n25q128_check_id(&fpgacfg_ctx);
}
-
-int n25q128_read_page(uint32_t page_offset, uint8_t *page_buffer)
+int fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len)
{
- // tx buffer
- uint8_t spi_tx[4];
-
- // result
- HAL_StatusTypeDef ok;
-
- // check offset
- if (page_offset >= N25Q128_NUM_PAGES) return 0;
-
- // calculate byte address
- page_offset *= N25Q128_PAGE_SIZE;
-
- // prepare READ command
- spi_tx[0] = N25Q128_COMMAND_READ_PAGE;
- spi_tx[1] = (uint8_t)(page_offset >> 16);
- spi_tx[2] = (uint8_t)(page_offset >> 8);
- spi_tx[3] = (uint8_t)(page_offset >> 0);
-
- // activate, send command
- _n25q128_select();
- ok = HAL_SPI_Transmit(N25Q128_SPI_HANDLE, spi_tx, 4, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
-
- // check
- if (ok != HAL_OK) {
- _n25q128_deselect();
- return 0;
- }
-
- // read response, deselect
- ok = HAL_SPI_Receive(N25Q128_SPI_HANDLE, page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return 0;
-
- // done
- return 1;
+ return n25q128_write_data(&fpgacfg_ctx, offset, buf, len);
}
-
-int n25q128_write_page(uint32_t page_offset, uint8_t *page_buffer)
+void fpgacfg_access_control(enum fpgacfg_access_ctrl access)
{
- // tx buffer
- uint8_t spi_tx[4];
-
- // result
- HAL_StatusTypeDef ok;
-
- // check offset
- if (page_offset >= N25Q128_NUM_PAGES) return 0;
-
- // enable writing
- spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
-
- // activate, send command, deselect
- _n25q128_select();
- ok = HAL_SPI_Transmit(N25Q128_SPI_HANDLE, spi_tx, 1, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return 0;
-
- // make sure, that write enable did the job
- int wel = _n25q128_get_wel_flag();
- if (wel != 1) return 0;
-
- // calculate byte address
- page_offset *= N25Q128_PAGE_SIZE;
-
- // prepare PROGRAM PAGE command
- spi_tx[0] = N25Q128_COMMAND_PAGE_PROGRAM;
- spi_tx[1] = (uint8_t)(page_offset >> 16);
- spi_tx[2] = (uint8_t)(page_offset >> 8);
- spi_tx[3] = (uint8_t)(page_offset >> 0);
-
- // activate, send command
- _n25q128_select();
- ok = HAL_SPI_Transmit(N25Q128_SPI_HANDLE, spi_tx, 4, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
-
- // check
- if (ok != HAL_OK) {
- _n25q128_deselect();
- return 0;
+ if (access == ALLOW_ARM) {
+ // fpga disable = 1
+ HAL_GPIO_WritePin(PROM_FPGA_DIS_GPIO_Port, PROM_FPGA_DIS_Pin, GPIO_PIN_SET);
+ // arm enable = 0
+ HAL_GPIO_WritePin(GPIOF, PROM_ARM_ENA_Pin, GPIO_PIN_RESET);
+ } else if (access == ALLOW_FPGA) {
+ // fpga disable = 0
+ HAL_GPIO_WritePin(PROM_FPGA_DIS_GPIO_Port, PROM_FPGA_DIS_Pin, GPIO_PIN_RESET);
+ // arm enable = 1
+ HAL_GPIO_WritePin(GPIOF, PROM_ARM_ENA_Pin, GPIO_PIN_SET);
+ } else {
+ // fpga disable = 1
+ HAL_GPIO_WritePin(PROM_FPGA_DIS_GPIO_Port, PROM_FPGA_DIS_Pin, GPIO_PIN_SET);
+ // arm enable = 1
+ HAL_GPIO_WritePin(GPIOF, PROM_ARM_ENA_Pin, GPIO_PIN_SET);
}
-
- // send data, deselect
- ok = HAL_SPI_Transmit(N25Q128_SPI_HANDLE, page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return 0;
-
- // done
- return 1;
-}
-
-
-int n25q128_get_wip_flag(void)
-{
- // tx, rx buffers
- uint8_t spi_tx[2];
- uint8_t spi_rx[2];
-
- // result
- HAL_StatusTypeDef ok;
-
- // send READ STATUS command
- spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
-
- // send command, read response, deselect
- _n25q128_select();
- ok = HAL_SPI_TransmitReceive(N25Q128_SPI_HANDLE, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return -1;
-
- // done
- return (spi_rx[1] & 1);
-}
-
-
-int n25q128_erase_sector(uint32_t sector_offset)
-{
- // tx buffer
- uint8_t spi_tx[4];
-
- // result
- HAL_StatusTypeDef ok;
-
- // check offset
- if (sector_offset >= N25Q128_NUM_SECTORS) return 0;
-
- // enable writing
- spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
-
- // select, send command, deselect
- _n25q128_select();
- ok = HAL_SPI_Transmit(N25Q128_SPI_HANDLE, spi_tx, 1, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return 0;
-
- // make sure, that write enable did the job
- int wel = _n25q128_get_wel_flag();
- if (wel != 1) return 0;
-
- // calculate byte address
- sector_offset *= N25Q128_SECTOR_SIZE;
-
- // send ERASE SUBSECTOR command
- spi_tx[0] = N25Q128_COMMAND_ERASE_SECTOR;
- spi_tx[1] = (uint8_t)(sector_offset >> 16);
- spi_tx[2] = (uint8_t)(sector_offset >> 8);
- spi_tx[3] = (uint8_t)(sector_offset >> 0);
-
- // activate, send command, deselect
- _n25q128_select();
- ok = HAL_SPI_Transmit(N25Q128_SPI_HANDLE, spi_tx, 4, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return 0;
-
- // done
- return 1;
-}
-
-
-int _n25q128_get_wel_flag(void)
-{
- // tx, rx buffers
- uint8_t spi_tx[2];
- uint8_t spi_rx[2];
-
- // result
- HAL_StatusTypeDef ok;
-
- // send READ STATUS command
- spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
-
- // send command, read response, deselect
- _n25q128_select();
- ok = HAL_SPI_TransmitReceive(N25Q128_SPI_HANDLE, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
- HAL_Delay(1);
- _n25q128_deselect();
-
- // check
- if (ok != HAL_OK) return -1;
-
- // done
- return ((spi_rx[1] >> 1) & 1);
-}
-
-void fpgacfg_give_access_to_stm32()
-{
- // fpga disable = 1
- HAL_GPIO_WritePin(GPIOI, GPIO_PIN_14, GPIO_PIN_SET);
- // arm enable = 0
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);
-}
-
-void fpgacfg_give_access_to_fpga()
-{
- // fpga disable = 0
- HAL_GPIO_WritePin(GPIOI, GPIO_PIN_14, GPIO_PIN_RESET);
- // arm enable = 1
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET);
}
diff --git a/stm-fpgacfg.h b/stm-fpgacfg.h
index fa5c4ef..ad86a89 100644
--- a/stm-fpgacfg.h
+++ b/stm-fpgacfg.h
@@ -36,47 +36,25 @@
#define __STM32_FPGACFG_H
#include "stm32f4xx_hal.h"
+#include "spiflash_n25q128.h"
-#define N25Q128_SPI_HANDLE (&hspi_fpgacfg)
+#define PROM_FPGA_DIS_Pin GPIO_PIN_14
+#define PROM_FPGA_DIS_GPIO_Port GPIOI
+#define PROM_ARM_ENA_Pin GPIO_PIN_6
+#define PROM_ARM_ENA_GPIO_Port GPIOF
+#define PROM_CS_N_Pin GPIO_PIN_12
+#define PROM_CS_N_GPIO_Port GPIOB
-#define N25Q128_COMMAND_READ_ID 0x9E
-#define N25Q128_COMMAND_READ_PAGE 0x03
-#define N25Q128_COMMAND_READ_STATUS 0x05
-#define N25Q128_COMMAND_WRITE_ENABLE 0x06
-#define N25Q128_COMMAND_ERASE_SECTOR 0xD8
-#define N25Q128_COMMAND_PAGE_PROGRAM 0x02
-#define N25Q128_PAGE_SIZE 0x100 // 256
-#define N25Q128_NUM_PAGES 0x10000 // 65536
+enum fpgacfg_access_ctrl {
+ ALLOW_NONE,
+ ALLOW_FPGA,
+ ALLOW_ARM,
+};
-#define N25Q128_SECTOR_SIZE 0x10000 // 65536
-#define N25Q128_NUM_SECTORS 0x100 // 256
-
-#define N25Q128_SPI_TIMEOUT 1000
-
-#define N25Q128_ID_MANUFACTURER 0x20
-#define N25Q128_ID_DEVICE_TYPE 0xBA
-#define N25Q128_ID_DEVICE_CAPACITY 0x18
-
-#define PROM_FPGA_DIS_Pin GPIO_PIN_14
-#define PROM_FPGA_DIS_GPIO_Port GPIOI
-#define PROM_ARM_ENA_Pin GPIO_PIN_6
-#define PROM_ARM_ENA_GPIO_Port GPIOF
-#define PROM_CS_N_Pin GPIO_PIN_12
-#define PROM_CS_N_GPIO_Port GPIOB
-
-
-#define _n25q128_select() HAL_GPIO_WritePin(PROM_CS_N_GPIO_Port, PROM_CS_N_Pin, GPIO_PIN_RESET);
-#define _n25q128_deselect() HAL_GPIO_WritePin(PROM_CS_N_GPIO_Port, PROM_CS_N_Pin, GPIO_PIN_SET);
-
-extern int n25q128_check_id(void);
-extern int n25q128_get_wip_flag(void);
-extern int n25q128_read_page(uint32_t page_offset, uint8_t *page_buffer);
-extern int n25q128_write_page(uint32_t page_offset, uint8_t *page_buffer);
-extern int n25q128_erase_sector(uint32_t sector_offset);
-
-extern void fpgacfg_give_access_to_stm32(void);
-extern void fpgacfg_give_access_to_fpga(void);
+extern int fpgacfg_check_id();
+extern int fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len);
+extern void fpgacfg_access_control(enum fpgacfg_access_ctrl access);
extern SPI_HandleTypeDef hspi_fpgacfg;
diff --git a/stm-init.c b/stm-init.c
index 9b86a30..2c19d58 100644
--- a/stm-init.c
+++ b/stm-init.c
@@ -85,7 +85,7 @@ void stm_init(void)
/* Give the FPGA access to it's bitstream ASAP (maybe this should actually
* be done in the application, before calling stm_init()).
*/
- fpgacfg_give_access_to_fpga();
+ fpgacfg_access_control(ALLOW_FPGA);
#endif
#endif
#ifdef HAL_UART_MODULE_ENABLED