From 5a77d196ea548e702c61adaad257189e60620045 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Nov 2014 17:38:43 -0800 Subject: [PATCH] W25Q80BV: Separate structures into algorithm and hardware access layers. Also extract #define constants for W25Q80BV into driver structure. Driver could eventually extend to other devices. --- firmware/common/hackrf_core.h | 2 +- firmware/common/w25q80bv.c | 84 ++++++++++++++------------ firmware/common/w25q80bv.h | 13 ++-- firmware/common/w25q80bv_drv.c | 16 ++--- firmware/common/w25q80bv_drv.h | 10 +-- firmware/hackrf_usb/usb_api_spiflash.c | 19 +++--- 6 files changed, 77 insertions(+), 67 deletions(-) diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index 35fa1225..67f1d720 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -34,7 +34,7 @@ extern "C" #include "max2837_drv.h" #include "rffc5071_drv.h" -#include "w25q80bv_drv.h" +#include "w25q80bv.h" /* hardware identification number */ #define BOARD_ID_JELLYBEAN 0 diff --git a/firmware/common/w25q80bv.c b/firmware/common/w25q80bv.c index b9c54616..fe64b957 100644 --- a/firmware/common/w25q80bv.c +++ b/firmware/common/w25q80bv.c @@ -51,7 +51,11 @@ void w25q80bv_setup(w25q80bv_driver_t* const drv) { uint8_t device_id; - w25q80bv_spi_init(drv); + drv->page_len = 256U; + drv->num_pages = 4096U; + drv->num_bytes = 1048576U; + + w25q80bv_spi_init(drv->hw); device_id = 0; while(device_id != W25Q80BV_DEVICE_ID_RES) @@ -64,10 +68,10 @@ uint8_t w25q80bv_get_status(w25q80bv_driver_t* const drv) { uint8_t value; - w25q80bv_spi_select(drv); - w25q80bv_spi_transfer(drv, W25Q80BV_READ_STATUS1); - value = w25q80bv_spi_transfer(drv, 0xFF); - w25q80bv_spi_unselect(drv); + w25q80bv_spi_select(drv->hw); + w25q80bv_spi_transfer(drv->hw, W25Q80BV_READ_STATUS1); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); + w25q80bv_spi_unselect(drv->hw); return value; } @@ -77,17 +81,17 @@ uint8_t w25q80bv_get_device_id(w25q80bv_driver_t* const drv) { uint8_t value; - w25q80bv_spi_select(drv); - w25q80bv_spi_transfer(drv, W25Q80BV_DEVICE_ID); + w25q80bv_spi_select(drv->hw); + w25q80bv_spi_transfer(drv->hw, W25Q80BV_DEVICE_ID); /* Read 3 dummy bytes */ - value = w25q80bv_spi_transfer(drv, 0xFF); - value = w25q80bv_spi_transfer(drv, 0xFF); - value = w25q80bv_spi_transfer(drv, 0xFF); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); /* Read Device ID shall return 0x13 for W25Q80BV */ - value = w25q80bv_spi_transfer(drv, 0xFF); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); - w25q80bv_spi_unselect(drv); + w25q80bv_spi_unselect(drv->hw); return value; } @@ -97,21 +101,21 @@ void w25q80bv_get_unique_id(w25q80bv_driver_t* const drv, w25q80bv_unique_id_t* int i; uint8_t value; - w25q80bv_spi_select(drv); - w25q80bv_spi_transfer(drv, W25Q80BV_UNIQUE_ID); + w25q80bv_spi_select(drv->hw); + w25q80bv_spi_transfer(drv->hw, W25Q80BV_UNIQUE_ID); /* Read 4 dummy bytes */ for(i=0; i<4; i++) - value = w25q80bv_spi_transfer(drv, 0xFF); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); /* Read Unique ID 64bits (8*8) */ for(i=0; i<8; i++) { - value = w25q80bv_spi_transfer(drv, 0xFF); + value = w25q80bv_spi_transfer(drv->hw, 0xFF); unique_id->id_8b[i] = value; } - w25q80bv_spi_unselect(drv); + w25q80bv_spi_unselect(drv->hw); } void w25q80bv_wait_while_busy(w25q80bv_driver_t* const drv) @@ -122,9 +126,9 @@ void w25q80bv_wait_while_busy(w25q80bv_driver_t* const drv) void w25q80bv_write_enable(w25q80bv_driver_t* const drv) { w25q80bv_wait_while_busy(drv); - w25q80bv_spi_select(drv); - w25q80bv_spi_transfer(drv, W25Q80BV_WRITE_ENABLE); - w25q80bv_spi_unselect(drv); + w25q80bv_spi_select(drv->hw); + w25q80bv_spi_transfer(drv->hw, W25Q80BV_WRITE_ENABLE); + w25q80bv_spi_unselect(drv->hw); } void w25q80bv_chip_erase(w25q80bv_driver_t* const drv) @@ -139,9 +143,9 @@ void w25q80bv_chip_erase(w25q80bv_driver_t* const drv) w25q80bv_write_enable(drv); w25q80bv_wait_while_busy(drv); - w25q80bv_spi_select(drv); - w25q80bv_spi_transfer(drv, W25Q80BV_CHIP_ERASE); - w25q80bv_spi_unselect(drv); + w25q80bv_spi_select(drv->hw); + w25q80bv_spi_transfer(drv->hw, W25Q80BV_CHIP_ERASE); + w25q80bv_spi_unselect(drv->hw); } /* write up a 256 byte page or partial page */ @@ -150,24 +154,24 @@ void w25q80bv_page_program(w25q80bv_driver_t* const drv, const uint32_t addr, co int i; /* do nothing if asked to write beyond a page boundary */ - if (((addr & 0xFF) + len) > W25Q80BV_PAGE_LEN) + if (((addr & 0xFF) + len) > drv->page_len) return; /* do nothing if we would overflow the flash */ - if (addr > (W25Q80BV_NUM_BYTES - len)) + if (addr > (drv->num_bytes - len)) return; w25q80bv_write_enable(drv); w25q80bv_wait_while_busy(drv); - w25q80bv_spi_select(drv); - w25q80bv_spi_transfer(drv, W25Q80BV_PAGE_PROGRAM); - w25q80bv_spi_transfer(drv, (addr & 0xFF0000) >> 16); - w25q80bv_spi_transfer(drv, (addr & 0xFF00) >> 8); - w25q80bv_spi_transfer(drv, addr & 0xFF); + w25q80bv_spi_select(drv->hw); + w25q80bv_spi_transfer(drv->hw, W25Q80BV_PAGE_PROGRAM); + w25q80bv_spi_transfer(drv->hw, (addr & 0xFF0000) >> 16); + w25q80bv_spi_transfer(drv->hw, (addr & 0xFF00) >> 8); + w25q80bv_spi_transfer(drv->hw, addr & 0xFF); for (i = 0; i < len; i++) - w25q80bv_spi_transfer(drv, data[i]); - w25q80bv_spi_unselect(drv); + w25q80bv_spi_transfer(drv->hw, data[i]); + w25q80bv_spi_unselect(drv->hw); } /* write an arbitrary number of bytes */ @@ -183,12 +187,12 @@ void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, } /* do nothing if we would overflow the flash */ - if ((len > W25Q80BV_NUM_BYTES) || (addr > W25Q80BV_NUM_BYTES) - || ((addr + len) > W25Q80BV_NUM_BYTES)) + if ((len > drv->num_bytes) || (addr > drv->num_bytes) + || ((addr + len) > drv->num_bytes)) return; /* handle start not at page boundary */ - first_block_len = W25Q80BV_PAGE_LEN - (addr % W25Q80BV_PAGE_LEN); + first_block_len = drv->page_len - (addr % drv->page_len); if (len < first_block_len) first_block_len = len; if (first_block_len) { @@ -199,11 +203,11 @@ void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, } /* one page at a time on boundaries */ - while (len >= W25Q80BV_PAGE_LEN) { - w25q80bv_page_program(drv, addr, W25Q80BV_PAGE_LEN, data); - addr += W25Q80BV_PAGE_LEN; - data += W25Q80BV_PAGE_LEN; - len -= W25Q80BV_PAGE_LEN; + while (len >= drv->page_len) { + w25q80bv_page_program(drv, addr, drv->page_len, data); + addr += drv->page_len; + data += drv->page_len; + len -= drv->page_len; } /* handle end not at page boundary */ diff --git a/firmware/common/w25q80bv.h b/firmware/common/w25q80bv.h index 0bcf6bf7..cab8d686 100644 --- a/firmware/common/w25q80bv.h +++ b/firmware/common/w25q80bv.h @@ -24,11 +24,9 @@ #ifndef __W25Q80BV_H__ #define __W25Q80BV_H__ -#include "w25q80bv_drv.h" +#include -#define W25Q80BV_PAGE_LEN 256U -#define W25Q80BV_NUM_PAGES 4096U -#define W25Q80BV_NUM_BYTES 1048576U +#include "w25q80bv_drv.h" typedef union { @@ -37,6 +35,13 @@ typedef union uint8_t id_8b[8]; /* 8*8bits 64bits Unique ID */ } w25q80bv_unique_id_t; +typedef struct { + w25q80bv_hw_t* hw; + size_t page_len; + size_t num_pages; + size_t num_bytes; +} w25q80bv_driver_t; + void w25q80bv_setup(w25q80bv_driver_t* const drv); void w25q80bv_chip_erase(w25q80bv_driver_t* const drv); void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, const uint8_t* data); diff --git a/firmware/common/w25q80bv_drv.c b/firmware/common/w25q80bv_drv.c index 3639f391..d0500b5d 100644 --- a/firmware/common/w25q80bv_drv.c +++ b/firmware/common/w25q80bv_drv.c @@ -30,7 +30,7 @@ #include #include -void w25q80bv_spi_init(w25q80bv_driver_t* const drv) { +void w25q80bv_spi_init(w25q80bv_hw_t* const hw) { const uint8_t serial_clock_rate = 2; const uint8_t clock_prescale_rate = 2; @@ -57,7 +57,7 @@ void w25q80bv_spi_init(w25q80bv_driver_t* const drv) { /* drive SSEL, HOLD, and WP pins high */ gpio_set(PORT_FLASH, (PIN_FLASH_HOLD | PIN_FLASH_WP)); - w25q80bv_spi_unselect(drv); + w25q80bv_spi_unselect(hw); /* Set GPIO pins as outputs. */ GPIO1_DIR |= (PIN_FLASH_HOLD | PIN_FLASH_WP); @@ -75,17 +75,17 @@ void w25q80bv_spi_init(w25q80bv_driver_t* const drv) { SSP_SLAVE_OUT_ENABLE); } -void w25q80bv_spi_select(w25q80bv_driver_t* const drv) { - (void)drv; +void w25q80bv_spi_select(w25q80bv_hw_t* const hw) { + (void)hw; gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL); } -void w25q80bv_spi_unselect(w25q80bv_driver_t* const drv) { - (void)drv; +void w25q80bv_spi_unselect(w25q80bv_hw_t* const hw) { + (void)hw; gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL); } -uint16_t w25q80bv_spi_transfer(w25q80bv_driver_t* const drv, const uint16_t tx_data) { - (void)drv; +uint16_t w25q80bv_spi_transfer(w25q80bv_hw_t* const hw, const uint16_t tx_data) { + (void)hw; return ssp_transfer(SSP0_NUM, tx_data); } diff --git a/firmware/common/w25q80bv_drv.h b/firmware/common/w25q80bv_drv.h index 2d7e843e..619e14ef 100644 --- a/firmware/common/w25q80bv_drv.h +++ b/firmware/common/w25q80bv_drv.h @@ -28,12 +28,12 @@ typedef struct { /* Empty for now */ -} w25q80bv_driver_t; +} w25q80bv_hw_t; -void w25q80bv_spi_init(w25q80bv_driver_t* const drv); +void w25q80bv_spi_init(w25q80bv_hw_t* const hw); -void w25q80bv_spi_select(w25q80bv_driver_t* const drv); -uint16_t w25q80bv_spi_transfer(w25q80bv_driver_t* const drv, const uint16_t tx_data); -void w25q80bv_spi_unselect(w25q80bv_driver_t* const drv); +void w25q80bv_spi_select(w25q80bv_hw_t* const hw); +uint16_t w25q80bv_spi_transfer(w25q80bv_hw_t* const hw, const uint16_t tx_data); +void w25q80bv_spi_unselect(w25q80bv_hw_t* const hw); #endif//__W25Q80BV_DRV_H__ diff --git a/firmware/hackrf_usb/usb_api_spiflash.c b/firmware/hackrf_usb/usb_api_spiflash.c index 97b1771b..a2368a91 100644 --- a/firmware/hackrf_usb/usb_api_spiflash.c +++ b/firmware/hackrf_usb/usb_api_spiflash.c @@ -30,7 +30,8 @@ #include -uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN]; +/* Buffer size == spi_flash.page_len */ +uint8_t spiflash_buffer[256U]; usb_request_status_t usb_vendor_request_erase_spiflash( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) @@ -58,8 +59,8 @@ usb_request_status_t usb_vendor_request_write_spiflash( if (stage == USB_TRANSFER_STAGE_SETUP) { addr = (endpoint->setup.value << 16) | endpoint->setup.index; len = endpoint->setup.length; - if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) - || ((addr + len) > W25Q80BV_NUM_BYTES)) { + if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes) + || ((addr + len) > spi_flash.num_bytes)) { return USB_REQUEST_STATUS_STALL; } else { usb_transfer_schedule_block(endpoint->out, &spiflash_buffer[0], len, @@ -71,8 +72,8 @@ usb_request_status_t usb_vendor_request_write_spiflash( addr = (endpoint->setup.value << 16) | endpoint->setup.index; len = endpoint->setup.length; /* This check is redundant but makes me feel better. */ - if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) - || ((addr + len) > W25Q80BV_NUM_BYTES)) { + if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes) + || ((addr + len) > spi_flash.num_bytes)) { return USB_REQUEST_STATUS_STALL; } else { w25q80bv_program(&spi_flash, addr, len, &spiflash_buffer[0]); @@ -97,8 +98,8 @@ usb_request_status_t usb_vendor_request_read_spiflash( { addr = (endpoint->setup.value << 16) | endpoint->setup.index; len = endpoint->setup.length; - if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) - || ((addr + len) > W25Q80BV_NUM_BYTES)) { + if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes) + || ((addr + len) > spi_flash.num_bytes)) { return USB_REQUEST_STATUS_STALL; } else { /* TODO flush SPIFI "cache" before to read the SPIFI memory */ @@ -116,8 +117,8 @@ usb_request_status_t usb_vendor_request_read_spiflash( addr = (endpoint->setup.value << 16) | endpoint->setup.index; len = endpoint->setup.length; /* This check is redundant but makes me feel better. */ - if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) - || ((addr + len) > W25Q80BV_NUM_BYTES)) + if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes) + || ((addr + len) > spi_flash.num_bytes)) { return USB_REQUEST_STATUS_STALL; } else