diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | projects/cli-test/cli-test.c | 59 | ||||
-rw-r--r-- | spiflash_n25q128.c | 336 | ||||
-rw-r--r-- | spiflash_n25q128.h | 75 | ||||
-rw-r--r-- | stm-fpgacfg.c | 267 | ||||
-rw-r--r-- | stm-fpgacfg.h | 52 | ||||
-rw-r--r-- | stm-init.c | 2 |
7 files changed, 475 insertions, 317 deletions
@@ -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; @@ -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 |