diff --git a/CMakeLists.txt b/CMakeLists.txt index ab244025..171d344b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,15 +190,6 @@ add_executable(bus_pirate5_rev10 ) target_compile_definitions(bus_pirate5_rev10 PUBLIC BP5_REV=10) -add_executable(bus_pirate5_rev10_2gbit - ${bp5_common} - ${bp5_rev10} - ) -target_compile_definitions(bus_pirate5_rev10_2gbit PUBLIC BP5_REV=10) -target_compile_definitions(bus_pirate5_rev10_2gbit PUBLIC FLASH_MT29F2G01ABAFDWB) - - - set(stdlibs pico_stdlib hardware_spi @@ -225,7 +216,6 @@ set(stdlibs set(revisions bus_pirate5_rev8 bus_pirate5_rev10 - bus_pirate5_rev10_2gbit ) @@ -272,7 +262,6 @@ set(USE_LGPL3 TRUE CACHE BOOL "indicated if to include LGPL3 protected code") include(cmake/ansi_colours_import.cmake) if(USE_LGPL3) if(LEGACY_ANSI_COLOURS_ENABLED) - target_link_libraries(bus_pirate5_rev10_2gbit lib_ansi_colours) target_link_libraries(bus_pirate5_rev10 lib_ansi_colours) target_link_libraries(bus_pirate5_rev8 lib_ansi_colours) endif() diff --git a/nand/attic/fifo.h b/nand/attic/fifo.h deleted file mode 100644 index 67955d0d..00000000 --- a/nand/attic/fifo.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file fifo.h - * @author Andrew Loebs - * @brief Header file of the FIFO module - * - * Simple inline functions for FIFO buffer interaction - * - */ - -#ifndef __FIFO_H -#define __FIFO_H - -#include -#include - -typedef struct { - uint8_t *_front; - uint8_t *_back; - uint8_t *_read; - uint8_t *_write; -} fifo_t; - -/// @brief Macro for fifo static initializer -/// @param buffer Underlying memory block to be used by the fifo -/// @param len Length of the memory block -#define FIFO_STATIC_INIT(buffer, len) \ - { \ - ._front = (buffer), ._back = &(buffer)[(len)-1], ._read = (buffer), ._write = (buffer), \ - } - -/// @brief Inline function for checking if the fifo is empty -static inline bool fifo_is_empty(fifo_t *fifo) { return fifo->_read == fifo->_write; } - -/// @brief Inline function for checking if the fifo is full -static inline bool fifo_is_full(fifo_t *fifo) -{ - bool normal_case = (fifo->_write + 1) == fifo->_read; - bool edge_case = (fifo->_write == fifo->_back) && (fifo->_read == fifo->_front); - - return normal_case || edge_case; -} - -/// @brief Inline function for enqueueing a byte into the fifo -/// @return true if enqueued successfully, false if full -static inline bool fifo_enqueue(fifo_t *fifo, uint8_t value) -{ - if (fifo_is_full(fifo)) return false; - - *fifo->_write = value; - // circular increment - if (fifo->_write == fifo->_back) - fifo->_write = fifo->_front; - else - fifo->_write++; - - return true; -} - -/// @brief Inline function for dequeueing a byte from the fifo -/// @return true if dequeued successfully, false if empty -static inline bool fifo_try_dequeue(fifo_t *fifo, uint8_t *out) -{ - if (fifo_is_empty(fifo)) return false; - - *out = *fifo->_read; - // circular increment - if (fifo->_read == fifo->_back) - fifo->_read = fifo->_front; - else - fifo->_read++; - - return true; -} - -#endif // __FIFO_H diff --git a/nand/attic/led.c b/nand/attic/led.c deleted file mode 100644 index 04fcfacf..00000000 --- a/nand/attic/led.c +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file led.c - * @author Andrew Loebs - * @brief Implementation file of the LED module - * - */ - -#include "led.h" - -#include "../st/ll/stm32l4xx_ll_bus.h" - -// public function definitions -void led_init(void) -{ - // enable peripheral clock - if (!LL_AHB2_GRP1_IsEnabledClock(LL_AHB2_GRP1_PERIPH_GPIOB)) - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - - // setup pin as output -- default to low (LED off) - led_set_output(false); - LL_GPIO_SetPinMode(LD3_PORT, LD3_PIN, LL_GPIO_MODE_OUTPUT); - LL_GPIO_SetPinOutputType(LD3_PORT, LD3_PIN, LL_GPIO_OUTPUT_PUSHPULL); - LL_GPIO_SetPinSpeed(LD3_PORT, LD3_PIN, LL_GPIO_SPEED_FREQ_LOW); - LL_GPIO_SetPinPull(LD3_PORT, LD3_PIN, LL_GPIO_PULL_NO); -} diff --git a/nand/attic/led.h b/nand/attic/led.h deleted file mode 100644 index d3eeff01..00000000 --- a/nand/attic/led.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file led.h - * @author Andrew Loebs - * @brief Header file of the LED module - * - * Handles interaction with the "LD3" LED on the NUCLEO-L432KC board. - * - */ - -#ifndef __LED_H -#define __LED_H - -#include - -#include "../st/ll/stm32l4xx_ll_gpio.h" - -#define LD3_PORT GPIOB -#define LD3_PIN LL_GPIO_PIN_3 - -/// @brief Enables GPIOB clock and sets up LED pin -void led_init(void); - -/// @brief Sets the LED output -/// @note This function is inlined as it will be called from exception handlers -static inline void led_set_output(bool pin_state) -{ - if (pin_state) { - LL_GPIO_SetOutputPin(LD3_PORT, LD3_PIN); - } - else { - LL_GPIO_ResetOutputPin(LD3_PORT, LD3_PIN); - } -} - -#endif // __LED_H diff --git a/nand/attic/mem.c b/nand/attic/mem.c deleted file mode 100644 index 617946ee..00000000 --- a/nand/attic/mem.c +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file mem.c - * @author Andrew Loebs - * @brief Implementation file of the memory management module - * - */ - -#include "pirate/mem.h" - -#include - -#include "spi_nand.h" - -// private variables -static uint8_t mem_buffer[SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE]; -static bool allocated = false; - -// public function definitions -uint8_t *mem_alloc(size_t size) -{ - if (!allocated && size <= sizeof(mem_buffer)) { - allocated = true; - return mem_buffer; - } - else { - return NULL; - } -} - -void mem_free(uint8_t *ptr) -{ - if (ptr == mem_buffer) { - allocated = false; - } -} \ No newline at end of file diff --git a/nand/attic/mem.h b/nand/attic/mem.h deleted file mode 100644 index e133fda0..00000000 --- a/nand/attic/mem.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file mem.h - * @author Andrew Loebs - * @brief Header file of the memory management module - * - * A simple module to manage allocation of a single nand page buffer. - * - * This was made in response to many modules (shell_command, spi_nand), - * needing temporary access to a page-sized array, and not wanting to - * create that array on the stack or allocate it statically for the lifetime - * of the application. This is not the page buffer used by the flash translation - * layer. - * - * - */ - -#ifndef __MEM_H -#define __MEM_H - -#include -#include - -/// @brief Attempts to allocate a nand page buffer. -/// @return Pointer to the buffer if available, NULL if not available -/// @note Return value should always be checked against null. -/// @note Max size: SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE -uint8_t *mem_alloc(size_t size); - -/// @brief Frees the allocated nand page buffer -/// @param ptr pointer to the nand page buffer -void mem_free(uint8_t *ptr); - -#endif // __MEM_H diff --git a/nand/attic/shell.c b/nand/attic/shell.c deleted file mode 100644 index e5fd99f9..00000000 --- a/nand/attic/shell.c +++ /dev/null @@ -1,192 +0,0 @@ -/** - * @file shell.c - * @author Andrew Loebs - * @brief Implementation file of the shell module - * - */ - -#include "shell.h" - -#include -#include -#include - -#include "shell_cmd.h" - -// defines -#define RECEIVE_BUFFER_LEN 128 // max command + args length supported - -// private function prototypes -static void receive_buffer_reset(void); -static bool receive_buffer_is_full(void); -static size_t receive_buffer_len(void); -static void receive_buffer_push(char c); - -static bool try_get_char(char *out); -static void echo(char c); -static void put_prompt(void); - -// private variables -static char receive_buffer[RECEIVE_BUFFER_LEN]; -static size_t receive_index; - -// public function definitions -void shell_init(void) -{ - receive_buffer_reset(); - // start with welcome message and prompt - shell_put_newline(); - shell_put_newline(); - shell_prints_line("==== shell started! ===="); - shell_put_newline(); - put_prompt(); -} - -void shell_tick(void) -{ - char c; - if (try_get_char(&c)) { - // ignore newline -- we only expect carriage return from the client - if (c != '\n') { - echo(c); - receive_buffer_push(c); - // if carriage return, process command - if ('\r' == c) { - shell_cmd_process(receive_buffer, receive_buffer_len()); - shell_put_newline(); // more readable with the extra newline - put_prompt(); - receive_buffer_reset(); - } - // else, check for rx full - else if (receive_buffer_is_full()) { - shell_printf_line("Receive buffer full (limit %d). Resetting receive buffer.", - RECEIVE_BUFFER_LEN); - receive_buffer_reset(); - } - } - } -} - -void shell_print(const char *buff, size_t len) -{ - for (int i = 0; i < len; i++) { - putchar(buff[i]); - } -} - -void shell_prints(const char *string) -{ - while (*string) { - putchar(*string); - string++; - } -} - -void shell_prints_line(const char *string) -{ - // this gives us control over the newline behavior (over puts()) - while (*string) { - putchar(*string); - string++; - } - shell_put_newline(); -} - -void shell_printf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); -} - -void shell_printf_line(const char *format, ...) -{ - // handle the printf - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); - // newline - shell_put_newline(); -} - -void shell_put_newline(void) -{ - putchar('\r'); - putchar('\n'); -} - -// private function definitions -static void receive_buffer_reset(void) -{ - receive_buffer[0] = 0; - receive_index = 0; -} - -static bool receive_buffer_is_full(void) -{ - return receive_index >= (RECEIVE_BUFFER_LEN - 1); -} - -static size_t receive_buffer_len(void) -{ - return receive_index; -} - -static void receive_buffer_push(char c) -{ - if ('\b' == c) { - if (receive_index != 0) { - receive_index--; - receive_buffer[receive_index] = 0; - } - } - else { - receive_buffer[receive_index] = c; - receive_index++; - } -} - -static bool try_get_char(char *out) -{ - // To get around getchar() blocking, the _read() syscall returns - // EOF for stdin whenever the UART rx is empty. Because of this, - // we must check getchar() for EOF so that we know if we have a new - // character, and rewind stdin when we do not. - char c = getchar(); - if ((char)EOF == c) { - rewind(stdin); - return false; - } - else { - *out = c; - return true; - } -} - -static void echo(char c) -{ - // handle newline - if ('\r' == c) { - shell_put_newline(); - } - // handle backspace - else if ('\b' == c) { - if (receive_index != 0) { // dont backspace prompt - putchar('\b'); - putchar(' '); - putchar('\b'); - } - } - // else, just echo - else { - putchar(c); - } -} - -static void put_prompt(void) -{ - putchar('>'); - putchar(' '); -} diff --git a/nand/attic/shell.h b/nand/attic/shell.h deleted file mode 100644 index 602becda..00000000 --- a/nand/attic/shell.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file shell.h - * @author Andrew Loebs - * @brief Header file of the shell module - * - * Provides functionality for a virtual shell & CLI. - * - */ - -#ifndef __SHELL_H -#define __SHELL_H - -#include // size_t - -/// @brief Initializes the shell -void shell_init(void); - -/// @brief Gives processing time to the shell -void shell_tick(void); - -/// @brief Writes characters to the shell -void shell_print(const char *buff, size_t len); - -/// @brief Writes a string to the shell -void shell_prints(const char *string); - -/// @brief Writes a string + newline to the shell -void shell_prints_line(const char *string); - -/// @brief Writes formatted output to the shell -void shell_printf(const char *format, ...); - -/// @brief Writes formatted output + newline to the shell -void shell_printf_line(const char *format, ...); - -/// @brief Writes a newline character to the shell -/// @note This keeps our newline in a single function in case we decide to use a different line -/// ending in the future -void shell_put_newline(void); - -#endif // __SHELL_H diff --git a/nand/attic/shell_cmd.c b/nand/attic/shell_cmd.c deleted file mode 100644 index 7cc2338a..00000000 --- a/nand/attic/shell_cmd.c +++ /dev/null @@ -1,518 +0,0 @@ -/** - * @file shell_cmd.c - * @author Andrew Loebs - * @brief Implementation file of the shell command module - * - */ - -#include "shell_cmd.h" - -#include -#include - -#include "../fatfs/ff.h" -#include "pirate/mem.h" -#include "shell.h" -#include "spi_nand.h" - -// defines -#define MAX_ARGS 8 -#define NUM_COMMANDS (sizeof(shell_commands) / sizeof(*shell_commands)) -#define PRINT_BYTES_WIDTH 16 - -// private types -typedef void (*shell_cmd_handler_t)(int argc, char *argv[]); -typedef struct { - const char *name; - shell_cmd_handler_t handler; - const char *description; - const char *usage; -} shell_command_t; - -// private function prototypes -static void command_help(int argc, char *argv[]); -static void command_read_page(int argc, char *argv[]); -static void command_write_page(int argc, char *argv[]); -static void command_erase_block(int argc, char *argv[]); -static void command_get_bad_block_table(int argc, char *argv[]); -static void command_mark_bad_block(int argc, char *argv[]); -static void command_page_is_free(int argc, char *argv[]); -static void command_copy_page(int argc, char *argv[]); -static void command_clear_nand(int argc, char *argv[]); -static void command_write_file(int argc, char *argv[]); -static void command_read_file(int argc, char *argv[]); -static void command_list_dir(int argc, char *argv[]); -static void command_file_size(int argc, char *argv[]); - -static const shell_command_t *find_command(const char *name); -static void print_bytes(uint8_t *data, size_t len); - -// private constants -static const shell_command_t shell_commands[] = { - {"help", command_help, "Prints all commands and their associated help text.", "help"}, - {"read_page", command_read_page, "Reads a page from the SPI NAND memory unit.", - "read_page "}, - {"write_page", command_write_page, - "Writes a value (repeated) to a page of the SPI NAND memory unit.", - "write_page "}, - {"erase_block", command_erase_block, "Erases a block of the SPI NAND memory unit.", - "erase_block "}, - {"get_bbt", command_get_bad_block_table, - "Prints a 0 (good) or 1 (bad) representing each block's status.", "get_bbt"}, - {"mark_bb", command_mark_bad_block, "Marks a block of the SPI NAND memory unit as bad.", - "mark_bb "}, - {"page_is_free", command_page_is_free, "Determines whether a page is free.", - "page_is_free "}, - {"copy_page", command_copy_page, "Copies the source page to the destination page.", - "copy_page "}, - {"clear_nand", command_clear_nand, "Erases all good blocks from the SPI NAND memory unit.", - "clear_nand"}, - {"write_file", command_write_file, - "Writes a file with the supplied word repeated *count* times.", - "write_file "}, - {"read_file", command_read_file, "Reads a file out to the prompt.", "read_file "}, - {"list_dir", command_list_dir, "Lists files and subdirectories within a given directory.", - "list_dir "}, - {"file_size", command_file_size, "Prints the size of the given file.", "file_size "}, -}; - -// public function definitions -void shell_cmd_process(char *buff, size_t len) -{ - // parse arguments - char *argv[MAX_ARGS] = {0}; - int argc = 0; - char *next_arg = NULL; - for (size_t i = 0; (i < len) && (argc < MAX_ARGS); i++) { - char *c = &buff[i]; - if ((*c == ' ') || (i == len - 1)) { - *c = '\0'; - if (next_arg) { - argv[argc++] = next_arg; - next_arg = NULL; - } - } - else if (!next_arg) { - next_arg = c; - } - } - - // attempt to find command - if (argc > 0) { - const shell_command_t *command = find_command(argv[0]); - if (command) { - command->handler(argc, argv); - } - else { - shell_printf_line("Unknown command '%s'.", argv[0]); - shell_prints_line("Type 'help' for a list of commands and descriptions."); - } - } -} - -// private function definitions -static void command_help(int argc, char *argv[]) -{ - for (int i = 0; i < NUM_COMMANDS; i++) { - shell_printf_line("%-14s%s", shell_commands[i].name, shell_commands[i].description); - shell_printf_line("%14cUsage: %s", ' ', shell_commands[i].usage); - } -} - -static void command_read_page(int argc, char *argv[]) -{ - if (argc != 4) { - shell_printf_line("read_page requires block, page, and column arguments. Type \"help\" " - "for more info."); - return; - } - - // parse arguments - uint16_t block, page, column; - sscanf(argv[1], "%hu", &block); - sscanf(argv[2], "%hu", &page); - sscanf(argv[3], "%hu", &column); - - // attempt to allocate a page buffer - uint8_t *page_buffer = mem_alloc(SPI_NAND_PAGE_SIZE); - if (!page_buffer) { - shell_printf_line("Unable to allocate nand page buffer."); - return; - } - // attempt to read.. - row_address_t row = {.block = block, .page = page}; - int ret = spi_nand_page_read(row, column, page_buffer, sizeof(page_buffer)); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to read page: %d.", ret); - } - else { - print_bytes(page_buffer, sizeof(page_buffer) - column); - } - - mem_free(page_buffer); -} - -static void command_write_page(int argc, char *argv[]) -{ - if (argc != 5) { - shell_printf_line( - "write_page requires block, page, column, and value arguments. Type \"help\" " - "for more info."); - return; - } - - // parse arguments - uint16_t block, page, column, value; - sscanf(argv[1], "%hu", &block); - sscanf(argv[2], "%hu", &page); - sscanf(argv[3], "%hu", &column); - sscanf(argv[4], "%hu", &value); - - // attempt to allocate a page buffer - uint8_t *page_buffer = mem_alloc(SPI_NAND_PAGE_SIZE); - if (!page_buffer) { - shell_printf_line("Unable to allocate nand page buffer."); - return; - } - // create write data - size_t write_len = sizeof(page_buffer) - column; - memset(page_buffer, value, write_len); - // attempt to write.. - row_address_t row = {.block = block, .page = page}; - int ret = spi_nand_page_program(row, column, page_buffer, write_len); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to write page: %d.", ret); - } - else { - shell_printf_line("Write page successful."); - } - mem_free(page_buffer); -} - -static void command_erase_block(int argc, char *argv[]) -{ - if (argc != 2) { - shell_printf_line("erase_block requires a block number as an argument. Type \"help\" " - "for more info."); - return; - } - - // parse arguments - uint16_t block; - sscanf(argv[1], "%hu", &block); - - // attempt to erase.. - row_address_t row = {.block = block, .page = 0}; - int ret = spi_nand_block_erase(row); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to erase block: %d.", ret); - } - else { - shell_printf_line("Block erase successful."); - } -} - -static void command_get_bad_block_table(int argc, char *argv[]) -{ - // attempt to allocate a page buffer - uint8_t *page_buffer = mem_alloc(SPI_NAND_PAGE_SIZE); - if (!page_buffer) { - shell_printf_line("Unable to allocate nand page buffer."); - return; - } - // read block status into page buffer - bool success = true; - for (int i = 0; i < SPI_NAND_ERASE_BLOCKS_PER_LUN; i++) { - bool is_bad; - row_address_t row = {.block = i, .page = 0}; - int ret = spi_nand_block_is_bad(row, &is_bad); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when checking block %d status: %d.", i, ret); - success = false; - break; - } - else { - page_buffer[i] = is_bad; - } - } - - // print bad block table - if (success) { - print_bytes(page_buffer, SPI_NAND_ERASE_BLOCKS_PER_LUN); - } - mem_free(page_buffer); -} - -static void command_mark_bad_block(int argc, char *argv[]) -{ - if (argc != 2) { - shell_printf_line("mark_bb requires a block number as an argument. Type \"help\" " - "for more info."); - return; - } - - // parse arguments - uint16_t block; - sscanf(argv[1], "%hu", &block); - - // attempt to mark bad block.. - row_address_t row = {.block = block, .page = 0}; - int ret = spi_nand_block_mark_bad(row); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to mark bad block: %d.", ret); - } - else { - shell_printf_line("Mark bad block successful."); - } -} - -static void command_page_is_free(int argc, char *argv[]) -{ - if (argc != 3) { - shell_printf_line("page_is_free requires block and page arguments. Type \"help\" " - "for more info."); - return; - } - - // parse arguments - uint16_t block, page; - sscanf(argv[1], "%hu", &block); - sscanf(argv[2], "%hu", &page); - - // attempt to get is free status.. - bool is_free; - row_address_t row = {.block = block, .page = page}; - int ret = spi_nand_page_is_free(row, &is_free); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to check if page is free: %d.", ret); - } - else { - if (is_free) { - shell_prints_line("True."); - } - else { - shell_prints_line("False."); - } - } -} - -static void command_copy_page(int argc, char *argv[]) -{ - if (argc != 5) { - shell_printf_line("copy_page requires src block, src page, dest block, and dest page " - "arguments. Type \"help\" for more info."); - return; - } - - // parse arguments - uint16_t src_block, src_page, dest_block, dest_page; - sscanf(argv[1], "%hu", &src_block); - sscanf(argv[2], "%hu", &src_page); - sscanf(argv[3], "%hu", &dest_block); - sscanf(argv[4], "%hu", &dest_page); - - // attempt to copy.. - row_address_t src_row = {.block = src_block, .page = src_page}; - row_address_t dest_row = {.block = dest_block, .page = dest_page}; - int ret = spi_nand_page_copy(src_row, dest_row); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to copy page: %d.", ret); - } - else { - shell_printf_line("Copy page successful."); - } -} - -static void command_clear_nand(int argc, char *argv[]) -{ - int ret = spi_nand_clear(); - if (SPI_NAND_RET_OK != ret) { - shell_printf_line("Error when attempting to clear nand: %d.", ret); - } - else { - shell_printf_line("Clear nand successful."); - } -} - -static void command_write_file(int argc, char *argv[]) -{ - if (argc != 4) { - shell_printf_line("write_file requires filename, word, and count arguments. Type \"help\" " - "for more info."); - return; - } - - // parse arguments - char *filename = argv[1]; - char *word = argv[2]; - unsigned int count; - sscanf(argv[3], "%u", &count); - - // attempt to open file - FIL file; - FRESULT res = f_open(&file, filename, FA_CREATE_NEW | FA_WRITE); - if (FR_OK != res) { - shell_printf_line("f_open failed with res: %d.", res); - return; - } - - // attempt to write to file - size_t word_len = strlen(word); - unsigned int bytes_written; - for (int i = 0; i < count; i++) { - res = f_write(&file, word, word_len, &bytes_written); - if (FR_OK != res || word_len != bytes_written) { - shell_printf_line("f_write of len: %d failed with res: %d, bytes_written: %d.", - word_len, res, bytes_written); - f_close(&file); // close and ignore result - return; - } - // put newline.. - res = f_write(&file, "\r\n", 2, &bytes_written); - if (FR_OK != res || 2 != bytes_written) { - shell_printf_line("f_write of len: %d failed with res: %d, bytes_written: %d.", 2, res, - bytes_written); - f_close(&file); // close and ignore result - return; - } - } - - // attempt to close the file - res = f_close(&file); - if (FR_OK != res) { - shell_printf_line("f_close failed with res: %d.", res); - return; - } - - // if we made it here, it was successful - shell_printf_line("write_file to \"%s\" succeeded!", filename); -} - -static void command_read_file(int argc, char *argv[]) -{ - if (argc != 2) { - shell_printf_line("read_file requires filename argument. Type \"help\" for more info."); - return; - } - - // parse arguments - char *filename = argv[1]; - - // attempt to open file - FIL file; - FRESULT res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ); - if (FR_OK != res) { - shell_printf_line("f_open failed with res: %d.", res); - return; - } - - // attempt to read from the file - char read_buffer[16]; - unsigned int bytes_read = 0; - do { - res = f_read(&file, read_buffer, sizeof(read_buffer), &bytes_read); - if (FR_OK != res) { - shell_put_newline(); // put extra newline to separate from read data - shell_printf_line("f_read failed with res: %d.", res); - } - else { - shell_print(read_buffer, bytes_read); - } - } while (sizeof(read_buffer) == bytes_read); - - // attempt to close the file - res = f_close(&file); - if (FR_OK != res) { - shell_put_newline(); // put extra newline to separate from read data - shell_printf_line("f_close failed with res: %d.", res); - return; - } - - // if we made it here, it was successful - shell_put_newline(); // put extra newline to separate from read data - shell_printf_line("read_file from \"%s\" succeeded!", filename); -} - -static void command_list_dir(int argc, char *argv[]) -{ - if (argc != 2) { - shell_printf_line("list_dir requires path argument. Type \"help\" for more info."); - return; - } - - // parse arguments - char *path = argv[1]; - - // open the directory - DIR directory; - FRESULT res = f_opendir(&directory, path); - if (FR_OK != res) { - shell_printf_line("f_opendir failed with res: %d.", res); - } - else { - for (;;) { - FILINFO file_info; - res = f_readdir(&directory, &file_info); - if (FR_OK != res) { - shell_printf_line("f_readdir failed with res: %d.", res); - break; - } - else if (0 == file_info.fname[0]) { - // end of directory - break; - } - else { - shell_prints_line(file_info.fname); - } - } - res = f_closedir(&directory); - if (FR_OK != res) { - shell_printf_line("f_closedir failed with res: %d.", res); - } - } - - shell_put_newline(); // put extra newline for prettiness -} - -static void command_file_size(int argc, char *argv[]) -{ - if (argc != 2) { - shell_printf_line("file_size requires filename argument. Type \"help\" for more info."); - return; - } - - // parse arguments - char *filename = argv[1]; - - // attempt to open file - FIL file; - FRESULT res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ); - if (FR_OK != res) { - shell_printf_line("f_open failed with res: %d.", res); - } - else { - shell_printf_line("File size: %d", f_size(&file)); - } -} - -static const shell_command_t *find_command(const char *name) -{ - for (int i = 0; i < NUM_COMMANDS; i++) { - if (strcmp(shell_commands[i].name, name) == 0) return &shell_commands[i]; - } - // if execution reaches here, we did not find the command - return NULL; -} - -static void print_bytes(uint8_t *data, size_t len) -{ - for (int i = 0; i < len; i++) { - // check if the width has been met - if ((i % PRINT_BYTES_WIDTH) == (PRINT_BYTES_WIDTH - 1)) { - shell_printf_line("%02x", data[i]); // print with newline - } - else { - shell_printf("%02x ", data[i]); // print with trailing space - } - } -} diff --git a/nand/attic/shell_cmd.h b/nand/attic/shell_cmd.h deleted file mode 100644 index 49546382..00000000 --- a/nand/attic/shell_cmd.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @file shell_cmd.h - * @author Andrew Loebs - * @brief Header file of the shell command module - * - * Provides command processing for the shell. - * - */ - -#ifndef __SHELL_CMD_H -#define __SHELL_CMD_H - -#include - -/// @brief Parses the command buffer into argv/argc and calls the relevant handler function -void shell_cmd_process(char *buff, size_t len); - -#endif // __SHELL_CMD_H diff --git a/nand/attic/uart.c b/nand/attic/uart.c deleted file mode 100644 index 264ed3b3..00000000 --- a/nand/attic/uart.c +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @file uart.c - * @author Andrew Loebs - * @brief Implementation file of the UART module - * - */ - -#include "uart.h" - -#include -#include - -#include "../st/ll/stm32l4xx_ll_bus.h" -#include "../st/ll/stm32l4xx_ll_gpio.h" -#include "../st/ll/stm32l4xx_ll_rcc.h" -#include "../st/ll/stm32l4xx_ll_usart.h" -#include "../st/stm32l4xx.h" - -#include "fifo.h" -#include "sys_time.h" - -// defines -#define VCP_TX_PORT GPIOA -#define VCP_TX_PIN LL_GPIO_PIN_2 -#define VCP_RX_PORT GPIOA -#define VCP_RX_PIN LL_GPIO_PIN_15 - -#define VCP_UART USART2 - -#define BAUD_RATE 115200 -#define PUTC_TIMEOUT 10 // ms - -#define UART_PREEMPT_PRIORITY 7 // low -#define UART_SUB_PRIORITY 0 - -#define RX_BUFF_LEN 256 - -// private function prototypes -static uint32_t get_pclk1_hz(void); - -// private variables -static uint8_t rx_fifo_memblock[RX_BUFF_LEN]; -static fifo_t rx_fifo = FIFO_STATIC_INIT(rx_fifo_memblock, sizeof(rx_fifo_memblock)); - -// public function definitions -void uart_init(void) -{ - // enable peripheral clocks - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2); - if (!LL_AHB2_GRP1_IsEnabledClock(LL_AHB2_GRP1_PERIPH_GPIOA)) - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - - // setup pins - LL_GPIO_SetPinMode(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinOutputType(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL); - LL_GPIO_SetPinSpeed(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); - LL_GPIO_SetPinPull(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_PULL_NO); - LL_GPIO_SetAFPin_0_7(VCP_TX_PORT, VCP_TX_PIN, LL_GPIO_AF_7); - - LL_GPIO_SetPinMode(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinOutputType(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL); - LL_GPIO_SetPinSpeed(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); - LL_GPIO_SetPinPull(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_PULL_NO); - LL_GPIO_SetAFPin_8_15(VCP_RX_PORT, VCP_RX_PIN, LL_GPIO_AF_3); - - // configure UART CR1 - LL_USART_SetDataWidth(VCP_UART, LL_USART_DATAWIDTH_8B); - LL_USART_SetParity(VCP_UART, LL_USART_PARITY_NONE); - LL_USART_EnableDirectionTx(VCP_UART); - LL_USART_EnableDirectionRx(VCP_UART); - LL_USART_SetOverSampling(VCP_UART, LL_USART_OVERSAMPLING_16); - - // configure UART CR2 - LL_USART_SetStopBitsLength(VCP_UART, LL_USART_STOPBITS_1); - - // configure UART CR3 - LL_USART_DisableOneBitSamp(VCP_UART); - LL_USART_SetHWFlowCtrl(VCP_UART, LL_USART_HWCONTROL_NONE); - - // config UART BRR - LL_USART_SetBaudRate(VCP_UART, get_pclk1_hz(), LL_USART_OVERSAMPLING_16, BAUD_RATE); - - // enable UART interrupt for rx - LL_USART_EnableIT_RXNE(VCP_UART); - NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), - UART_PREEMPT_PRIORITY, UART_SUB_PRIORITY)); - NVIC_EnableIRQ(USART2_IRQn); - - // enable UART - LL_USART_Enable(VCP_UART); -} - -void _uart_putc(char c) -{ - // Blocking single-byte transmit with timeout - uint32_t start = sys_time_get_ms(); - LL_USART_TransmitData8(VCP_UART, c); - // wait for completion - while (!LL_USART_IsActiveFlag_TC(VCP_UART) && !sys_time_is_elapsed(start, PUTC_TIMEOUT)) - ; -} - -bool _uart_try_getc(char *c) { return fifo_try_dequeue(&rx_fifo, c); } - -void _uart_isr(void) -{ - // if there is an overrun flag, clear it - if (LL_USART_IsActiveFlag_ORE(VCP_UART)) { - LL_USART_ClearFlag_ORE(VCP_UART); - } - // if there is an rxn flag, read byte - if (LL_USART_IsActiveFlag_RXNE(VCP_UART)) { - // TODO: grab the return value from this and log a "uart fifo full" - // status somewhere if false - fifo_enqueue(&rx_fifo, LL_USART_ReceiveData8(VCP_UART)); - } -} - -// private function definitions -static uint32_t get_pclk1_hz(void) -{ - uint32_t pclk1 = SystemCoreClock; - switch (LL_RCC_GetAPB1Prescaler()) { - case LL_RCC_APB1_DIV_1: - // do nothing - break; - case LL_RCC_APB1_DIV_2: - pclk1 /= 2; - break; - case LL_RCC_APB1_DIV_4: - pclk1 /= 4; - break; - case LL_RCC_APB1_DIV_8: - pclk1 /= 8; - break; - case LL_RCC_APB1_DIV_16: - pclk1 /= 16; - break; - default: - break; - } - - return pclk1; -} diff --git a/nand/attic/uart.h b/nand/attic/uart.h deleted file mode 100644 index fd1b670c..00000000 --- a/nand/attic/uart.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file uart.h - * @author Andrew Loebs - * @brief Header file of the UART module - * - * Handles interaction with the UART module. Functions should not be called directly -- - * this module provides functionality for c std lib functions (putc, getc, printf, etc.). - * - * This is not intended to be a high-speed UART driver, it does have blocking functions. - * - */ - -#ifndef __UART_H -#define __UART_H - -#include - -/// @brief Enables GPIOA and USART clocks, sets up pins and USART2 module. -/// @note Called in main() -- cannot be called by __libc_init_array() since -/// system clock is not configured -void uart_init(void); - -/// @brief Writes a character to the UART -/// @note Called by _write sys call -void _uart_putc(char c); - -/// @brief Returns true and writes character to c if present, false if not -/// @note Called by _read sys call -bool _uart_try_getc(char *c); - -/// @brief Handles uart interrupt -/// @note Called by USART2_IRQHandler -void _uart_isr(void); - -#endif // __UART_H diff --git a/nand/nand_ftl_diskio.c b/nand/nand_ftl_diskio.c index f5296c2e..93e4fad4 100644 --- a/nand/nand_ftl_diskio.c +++ b/nand/nand_ftl_diskio.c @@ -23,11 +23,7 @@ static bool initialized = false; static struct dhara_map map; static uint8_t page_buffer[SPI_NAND_PAGE_SIZE]; -static struct dhara_nand nand = { - .log2_page_size = SPI_NAND_LOG2_PAGE_SIZE, - .log2_ppb = SPI_NAND_LOG2_PAGES_PER_ERASE_BLOCK, - .num_blocks = SPI_NAND_ERASE_BLOCKS_PER_LUN, -}; +static struct dhara_nand dhara_nand_parameters = {}; // public function definitions DSTATUS diskio_initialize(BYTE drv) @@ -35,13 +31,13 @@ DSTATUS diskio_initialize(BYTE drv) if (drv) return STA_NOINIT; /* Supports only drive 0 */ // init flash management stack - int ret = spi_nand_init(); + int ret = spi_nand_init(&dhara_nand_parameters); if (SPI_NAND_RET_OK != ret) { //printf("spi_nand_init failed, status: %d.", ret); return STA_NOINIT; } // init flash translation layer - dhara_map_init(&map, &nand, page_buffer, 4); + dhara_map_init(&map, &dhara_nand_parameters, page_buffer, 4); dhara_error_t err = DHARA_E_NONE; ret = dhara_map_resume(&map, &err); //printf("dhara resume return: %d, error: %d", ret, err); @@ -135,7 +131,7 @@ DRESULT diskio_ioctl(BYTE drv, BYTE cmd, void *buff) case GET_BLOCK_SIZE: ; DWORD *block_size_out = (DWORD *)buff; - *block_size_out = SPI_NAND_PAGES_PER_BLOCK; + *block_size_out = SPI_NAND_PAGES_PER_ERASE_BLOCK; break; case CTRL_TRIM: ; diff --git a/nand/spi_nand.c b/nand/spi_nand.c index dccc5a58..616a3fb5 100644 --- a/nand/spi_nand.c +++ b/nand/spi_nand.c @@ -40,27 +40,61 @@ #define READ_ID_DEVICE_INDEX 3 // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv // See also: spi_nand.h, which contains external per-chip guards -#if defined(FLASH_MT29F2G01ABAFDWB) - #define SPI_NAND_MFR_ID 0x2C // Micron - #define SPI_NAND_DEVICE_ID 0x24 // DEVICE_ID_2G_3V3 - -#else // default to MT29F1G01ABAFDWB - - #define SPI_NAND_MFR_ID 0x2C // Micron - #define SPI_NAND_DEVICE_ID 0x14 // DEVICE_ID_1G_3V3 - -#endif +/// @brief Since only support two chips, can differentiate them simply +/// using only the DeviceID. +typedef struct _nand_identity { + uint8_t Manufacturer; + uint8_t DeviceID; +} nand_identity_t; + +/// @brief Only two chips supported. List only the parts that differ for now. +/// Can later make this more dynamic by reading the parameter from the chip, +/// and more thoroughly validating the chip's identity. +typedef struct _supported_nand_device { + nand_identity_t Identity; + /// @brief Log2 of the number of planes in the device + uint8_t Log2_plane_count; + /// @brief Count of planes in the device ( === 2^Log2_plane_count ) + uint8_t Plane_count; + /// @brief Mask to get plane from block ( === (2^Log2_plane_count) - 1 ) + uint8_t Plane_mask; + /// @brief size, in bytes, of extra data per sector / block (typically used for ECC) + uint8_t Oob_size; +} supported_nand_device_t; +static const supported_nand_device_t * g_Actual_Nand_Device = NULL; // stays NULL until set by `spi_nand_init()` +static const supported_nand_device_t bp5_supported_nand[] = { + { .Identity = { .Manufacturer = 0x2C, .DeviceID = 0x14 }, .Log2_plane_count = 0, .Plane_count = 1, .Plane_mask = 0, .Oob_size = 64, }, + { .Identity = { .Manufacturer = 0x2C, .DeviceID = 0x24 }, .Log2_plane_count = 1, .Plane_count = 2, .Plane_mask = 1, .Oob_size = 128, }, +}; + +#define SPI_NAND_LARGEST_OOB_SUPPORTED 128 // so can allocate buffer large enough for any supported NAND chip +#define SPI_NAND_ERASE_BLOCKS_PER_PLANE 1024 // both supported devices have the same count per plane... + +static inline uint8_t SPI_NAND_OOB_SIZE() { + assert(g_Actual_Nand_Device != NULL); + return g_Actual_Nand_Device->Oob_size; +} +static inline uint32_t SPI_NAND_PLANE_COUNT() { + assert(g_Actual_Nand_Device != NULL); + return g_Actual_Nand_Device->Plane_count; +} +static inline uint32_t SPI_NAND_ERASE_BLOCKS_PER_LUN() { + assert(g_Actual_Nand_Device != NULL); + return g_Actual_Nand_Device->Plane_count * SPI_NAND_ERASE_BLOCKS_PER_PLANE; +} +static inline uint32_t SPI_NAND_MAX_BLOCK_ADDRESS() { + return SPI_NAND_ERASE_BLOCKS_PER_LUN() - 1; +} +#define SPI_NAND_MAX_PAGE_ADDRESS (SPI_NAND_PAGES_PER_ERASE_BLOCK - 1) // zero-indexed -inline uint8_t get_plane(row_address_t row) { - if (SPI_NAND_LOG2_PLANE_COUNT == 0) return 0; - return (row.block & (SPI_NAND_PLANE_COUNT -1)); +static inline uint8_t get_plane(row_address_t row) { + assert(g_Actual_Nand_Device != NULL); + return row.block & g_Actual_Nand_Device->Plane_mask; } +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#define SPI_NAND_MAX_PAGE_ADDRESS (SPI_NAND_PAGES_PER_BLOCK - 1) // zero-indexed -#define SPI_NAND_MAX_BLOCK_ADDRESS (SPI_NAND_ERASE_BLOCKS_PER_LUN - 1) // zero-indexed -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #define FEATURE_TRANS_LEN 3 #define FEATURE_REG_INDEX 1 @@ -140,17 +174,17 @@ static void csel_setup(void); static void csel_deselect(void); static void csel_select(void); -static int reset(void); -static int read_id(void); +static int spi_nand_reset(void); +static int read_id(nand_identity_t * identity_out); static int set_feature(uint8_t reg, uint8_t data, uint32_t timeout); static int get_feature(uint8_t reg, uint8_t *data_out, uint32_t timeout); static int write_enable(uint32_t timeout); static int page_read(row_address_t row, uint32_t timeout); -static int read_from_cache(row_address_t row, column_address_t column, uint8_t *data_out, size_t read_len, +static int read_from_cache(row_address_t row, column_address_t column, void *data_out, size_t read_len, uint32_t timeout); -static int program_load(row_address_t row, column_address_t column, const uint8_t *data_in, size_t write_len, +static int program_load(row_address_t row, column_address_t column, const void *data_in, size_t write_len, uint32_t timeout); -static int program_load_random_data(row_address_t row, column_address_t column, uint8_t *data_in, size_t write_len, +static int program_load_random_data(row_address_t row, column_address_t column, void *data_in, size_t write_len, uint32_t timeout); static int program_execute(row_address_t row, uint32_t timeout); @@ -166,11 +200,13 @@ static int get_ret_from_ecc_status(feature_reg_status_t status); // private variables // this buffer is needed for is_free, we don't want to allocate this on the stack -uint8_t page_main_and_oob_buffer[SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE]; +uint8_t page_main_and_largest_oob_buffer[SPI_NAND_PAGE_SIZE + SPI_NAND_LARGEST_OOB_SUPPORTED]; // public function definitions -int spi_nand_init(void) +int spi_nand_init(struct dhara_nand * dhara_parameters_out) { + memset(dhara_parameters_out, 0, sizeof(struct dhara_nand)); + // initialize chip select csel_deselect(); csel_setup(); @@ -178,15 +214,28 @@ int spi_nand_init(void) // reset //sys_time_delay(RESET_DELAY); busy_wait_ms(RESET_DELAY); - int ret = reset(); + int ret = spi_nand_reset(); if (SPI_NAND_RET_OK != ret) return ret; //sys_time_delay(RESET_DELAY); busy_wait_ms(RESET_DELAY); // read id - ret = read_id(); + nand_identity_t chip_id; + ret = read_id(&chip_id); if (SPI_NAND_RET_OK != ret) return ret; + // Check for a supported chip and set the dhara parameters accordingly + for (int i = 0; i < count_of(bp5_supported_nand); ++i) { + if ((bp5_supported_nand[i].Identity.Manufacturer == chip_id.Manufacturer) && + (bp5_supported_nand[i].Identity.DeviceID == chip_id.DeviceID)) { + g_Actual_Nand_Device = &bp5_supported_nand[i]; + break; // out of for loop + } + } + if (g_Actual_Nand_Device == NULL) { + return SPI_NAND_RET_DEVICE_ID; + } + // unlock all blocks ret = unlock_all_blocks(); if (SPI_NAND_RET_OK != ret) return ret; @@ -195,17 +244,22 @@ int spi_nand_init(void) ret = enable_ecc(); if (SPI_NAND_RET_OK != ret) return ret; + // fill in the return structure + dhara_parameters_out->log2_page_size = SPI_NAND_LOG2_PAGE_SIZE; + dhara_parameters_out->log2_ppb = SPI_NAND_LOG2_PAGES_PER_ERASE_BLOCK; + dhara_parameters_out->num_blocks = SPI_NAND_ERASE_BLOCKS_PER_LUN(); + return ret; } -int spi_nand_page_read(row_address_t row, column_address_t column, uint8_t *data_out, +int spi_nand_page_read(row_address_t row, column_address_t column, void *data_out, size_t read_len) { // input validation if (!validate_row_address(row) || !validate_column_address(column)) { return SPI_NAND_RET_BAD_ADDRESS; } - uint16_t max_read_len = (SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE) - column; + uint16_t max_read_len = (SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE()) - column; if (read_len > max_read_len) return SPI_NAND_RET_INVALID_LEN; // setup timeout tracking @@ -220,14 +274,14 @@ int spi_nand_page_read(row_address_t row, column_address_t column, uint8_t *data return read_from_cache(row, column, data_out, read_len, timeout); } -int spi_nand_page_program(row_address_t row, column_address_t column, const uint8_t *data_in, +int spi_nand_page_program(row_address_t row, column_address_t column, const void *data_in, size_t write_len) { // input validation if (!validate_row_address(row) || !validate_column_address(column)) { return SPI_NAND_RET_BAD_ADDRESS; } - uint16_t max_write_len = (SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE) - column; + uint16_t max_write_len = (SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE()) - column; if (write_len > max_write_len) return SPI_NAND_RET_INVALID_LEN; // setup timeout tracking @@ -264,9 +318,13 @@ int spi_nand_page_copy(row_address_t src, row_address_t dest) // // Without this check, data would be corrupted on multi-plane // NAND when the source and destination are on different planes. - int ret = spi_nand_page_read(src, 0, page_main_and_oob_buffer, sizeof(page_main_and_oob_buffer)); + // + // As a result, must read the source sector to a host buffer, and + // then write that host buffer to the destination sector. + size_t page_and_oob_len = SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE(); + int ret = spi_nand_page_read(src, 0, page_main_and_largest_oob_buffer, page_and_oob_len); if (SPI_NAND_RET_OK != ret) return ret; - return spi_nand_page_program(dest, 0, page_main_and_oob_buffer, sizeof(page_main_and_oob_buffer)); + return spi_nand_page_program(dest, 0, page_main_and_largest_oob_buffer, page_and_oob_len); } // setup timeout tracking @@ -348,8 +406,9 @@ int spi_nand_block_mark_bad(row_address_t row) int spi_nand_page_is_free(row_address_t row, bool *is_free) { // page read will validate block & page address - int ret = - spi_nand_page_read(row, 0, page_main_and_oob_buffer, sizeof(page_main_and_oob_buffer)); + size_t page_and_oob_len = SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE(); + + int ret = spi_nand_page_read(row, 0, page_main_and_largest_oob_buffer, page_and_oob_len); if (SPI_NAND_RET_OK != ret) return ret; *is_free = true; // innocent until proven guilty @@ -357,8 +416,8 @@ int spi_nand_page_is_free(row_address_t row, bool *is_free) // TODO: static_assert( sizeof(page_main_and_oob_buffer) % sizeof(uint32_t) == 0, "page_main_and_oob_buffer size must be a multiple of 4" ); uint32_t comp_word = 0xffffffff; - for (int i = 0; i < sizeof(page_main_and_oob_buffer); i += sizeof(comp_word)) { - if (0 != memcmp(&comp_word, &page_main_and_oob_buffer[i], sizeof(comp_word))) { + for (size_t i = 0; i < page_and_oob_len; i += sizeof(comp_word)) { + if (0 != memcmp(&comp_word, &page_main_and_largest_oob_buffer[i], sizeof(comp_word))) { *is_free = false; break; } @@ -370,7 +429,7 @@ int spi_nand_page_is_free(row_address_t row, bool *is_free) int spi_nand_clear(void) { bool is_bad; - for (int i = 0; i < SPI_NAND_ERASE_BLOCKS_PER_LUN; i++) { + for (int i = 0; i < SPI_NAND_ERASE_BLOCKS_PER_LUN(); i++) { // get bad block flag row_address_t row = {.block = i, .page = 0}; int ret = spi_nand_block_is_bad(row, &is_bad); @@ -419,7 +478,7 @@ static void csel_select(void) gpio_put(FLASH_STORAGE_CS, 0); } -static int reset(void) +static int spi_nand_reset(void) { // setup data uint8_t tx_data = CMD_RESET; // this is just a one-byte command @@ -434,8 +493,10 @@ static int reset(void) return poll_for_oip_clear(&status, OP_TIMEOUT); } -static int read_id(void) +static int read_id(nand_identity_t * identity_out) { + memset(identity_out, 0, sizeof(nand_identity_t)); + // setup data uint8_t tx_data[READ_ID_TRANS_LEN] = {0}; uint8_t rx_data[READ_ID_TRANS_LEN] = {0}; @@ -446,21 +507,12 @@ static int read_id(void) csel_deselect(); // check spi return - if (SPI_RET_OK == ret) { - // check mfr & device id - if ((SPI_NAND_MFR_ID == rx_data[READ_ID_MFR_INDEX]) && - (SPI_NAND_DEVICE_ID == rx_data[READ_ID_DEVICE_INDEX])) { - // success - return SPI_NAND_RET_OK; - } - else { - // bad mfr or device id - return SPI_NAND_RET_DEVICE_ID; - } - } - else { + if (SPI_RET_OK != ret) { return SPI_NAND_RET_BAD_SPI; } + identity_out->Manufacturer = rx_data[READ_ID_MFR_INDEX]; + identity_out->DeviceID = rx_data[READ_ID_DEVICE_INDEX]; + return SPI_RET_OK; } static int set_feature(uint8_t reg, uint8_t data, uint32_t timeout) @@ -541,7 +593,7 @@ static int page_read(row_address_t row, uint32_t timeout) } /// @note Input validation is expected to be performed by caller. -static int read_from_cache(row_address_t row, column_address_t column, uint8_t *data_out, size_t read_len, +static int read_from_cache(row_address_t row, column_address_t column, void *data_out, size_t read_len, uint32_t timeout) { // setup timeout tracking for second operation @@ -568,7 +620,7 @@ static int read_from_cache(row_address_t row, column_address_t column, uint8_t * } /// @note Input validation is expected to be performed by caller. -static int program_load(row_address_t row, column_address_t column, const uint8_t *data_in, size_t write_len, +static int program_load(row_address_t row, column_address_t column, const void *data_in, size_t write_len, uint32_t timeout) { // setup timeout tracking for second operation @@ -592,7 +644,7 @@ static int program_load(row_address_t row, column_address_t column, const uint8_ return (SPI_RET_OK == ret) ? SPI_NAND_RET_OK : SPI_NAND_RET_BAD_SPI; } -static int program_load_random_data(row_address_t row, column_address_t column, uint8_t *data_in, size_t write_len, +static int program_load_random_data(row_address_t row, column_address_t column, void *data_in, size_t write_len, uint32_t timeout) { // setup timeout tracking for second operation @@ -696,7 +748,7 @@ static int enable_ecc(void) return set_feature(FEATURE_REG_CONFIGURATION, ecc_enable.whole, OP_TIMEOUT); } -static int poll_for_oip_clear(feature_reg_status_t *status_out, uint32_t timeout) +static int poll_for_oip_clear(feature_reg_status_t *status_out, uint32_t ms_timeout) { uint32_t start_time = sys_time_get_ms(); for (;;) { @@ -711,7 +763,7 @@ static int poll_for_oip_clear(feature_reg_status_t *status_out, uint32_t timeout return SPI_NAND_RET_OK; } // check for timeout - if (sys_time_is_elapsed(start_time, timeout)) { + if (sys_time_is_elapsed(start_time, ms_timeout)) { return SPI_NAND_RET_TIMEOUT; } } @@ -719,7 +771,7 @@ static int poll_for_oip_clear(feature_reg_status_t *status_out, uint32_t timeout static bool validate_row_address(row_address_t row) { - if ((row.block > SPI_NAND_MAX_BLOCK_ADDRESS) || (row.page > SPI_NAND_MAX_PAGE_ADDRESS)) { + if ((row.block > SPI_NAND_MAX_BLOCK_ADDRESS()) || (row.page > SPI_NAND_MAX_PAGE_ADDRESS)) { return false; } else { @@ -729,7 +781,7 @@ static bool validate_row_address(row_address_t row) static bool validate_column_address(column_address_t address) { - if (address >= (SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE)) { + if (address >= (SPI_NAND_PAGE_SIZE + SPI_NAND_OOB_SIZE())) { return false; } else { diff --git a/nand/spi_nand.h b/nand/spi_nand.h index ee140f10..6db36066 100644 --- a/nand/spi_nand.h +++ b/nand/spi_nand.h @@ -13,6 +13,16 @@ #include #include #include +#include "../dhara/nand.h" // for `struct dhara_nand` definition + +#define SPI_NAND_LOG2_PAGE_SIZE ( 11) +#define SPI_NAND_LOG2_PAGES_PER_ERASE_BLOCK ( 6) +#define SPI_NAND_PAGES_PER_ERASE_BLOCK (1 << SPI_NAND_LOG2_PAGES_PER_ERASE_BLOCK) +#define SPI_NAND_PAGE_SIZE (1 << SPI_NAND_LOG2_PAGE_SIZE) + +#if SPI_NAND_PAGE_SIZE != 2048 + #error "Currently only 2048-byte pages are supported" // cannot be static assert (until C23?) +#endif /// @brief SPI return statuses enum { @@ -28,29 +38,6 @@ enum { SPI_NAND_RET_E_FAIL = -9, }; -// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv -// See also: spi_nand.c, which contains internal-only per chip guards -#if defined(FLASH_MT29F2G01ABAFDWB) - #define SPI_NAND_LOG2_PLANE_COUNT 1 - #define SPI_NAND_OOB_SIZE 128 -#else // default to MT29F1G01ABAFDWB - #define SPI_NAND_LOG2_PLANE_COUNT 0 - #define SPI_NAND_OOB_SIZE 64 // extra bytes of data per sector / block - -#endif -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#define SPI_NAND_LOG2_PAGE_SIZE 11 -#define SPI_NAND_LOG2_PAGES_PER_ERASE_BLOCK 6 -#define SPI_NAND_ERASE_BLOCKS_PER_PLANE 1024 - -#define SPI_NAND_PAGES_PER_BLOCK (1 << SPI_NAND_LOG2_PAGES_PER_ERASE_BLOCK) -#define SPI_NAND_PAGE_SIZE (1 << SPI_NAND_LOG2_PAGE_SIZE) -#define SPI_NAND_PLANE_COUNT (1 << SPI_NAND_LOG2_PLANE_COUNT) -#define SPI_NAND_ERASE_BLOCKS_PER_LUN (SPI_NAND_PLANE_COUNT * SPI_NAND_ERASE_BLOCKS_PER_PLANE) - -#if SPI_NAND_PAGE_SIZE != 2048 - #error "Currently only 2048-byte pages are supported" -#endif /// @brief Nand row address typedef union { @@ -64,14 +51,14 @@ typedef union { typedef uint16_t column_address_t; /// @brief Initializes the spi nand driver -int spi_nand_init(void); +int spi_nand_init(struct dhara_nand *dhara_parameters_out); /// @brief Performs a read page operation -int spi_nand_page_read(row_address_t row, column_address_t column, uint8_t *data_out, +int spi_nand_page_read(row_address_t row, column_address_t column, void *data_out, size_t read_len); /// @brief Performs a page program operation -int spi_nand_page_program(row_address_t row, column_address_t column, const uint8_t *data_in, +int spi_nand_page_program(row_address_t row, column_address_t column, const void *data_in, size_t write_len); /// @brief Copies the source page to the destination page using nand's internal cache diff --git a/pirate/mem.c b/pirate/mem.c index 80dedf5a..2eab84e7 100644 --- a/pirate/mem.c +++ b/pirate/mem.c @@ -13,7 +13,7 @@ #include "system_config.h" // private variables -static uint8_t mem_buffer[BIG_BUFFER_SIZE] __attribute__((aligned(32768))); +static uint8_t mem_buffer[BIG_BUFFER_SIZE] __attribute__((aligned(32768))); // 128k ... this is 50% of the total RAM! static bool allocated = false; // public function definitions diff --git a/pirate/mem.h b/pirate/mem.h index 3c6a4a77..5ed90d52 100644 --- a/pirate/mem.h +++ b/pirate/mem.h @@ -24,7 +24,7 @@ enum big_buffer_owners{ BP_BIG_BUFFER_NONE=0, BP_BIG_BUFFER_SCOPE, BP_BIG_BUFFER_LA, - BP_BIG_BUFFER_DISKFORMAT + BP_BIG_BUFFER_DISKFORMAT, }; /// @brief Attempts to allocate a nand page buffer. diff --git a/pirate/storage.c b/pirate/storage.c index 1f7c1380..27624ab7 100644 --- a/pirate/storage.c +++ b/pirate/storage.c @@ -123,6 +123,8 @@ bool storage_detect(void){ } uint8_t storage_format(void){ + static_assert(FF_MAX_SS <= BIG_BUFFER_SIZE, "BIG_BUFFER_SIZE must be at least FF_MAX_SS for this allocation to succeed."); + FRESULT fr; /* FatFs return code */ uint8_t *work_buffer = mem_alloc(FF_MAX_SS, BP_BIG_BUFFER_DISKFORMAT); if (!work_buffer) {