Merge pull request #434 from dominicgs/flash-investigation
Allow users to interact with the flash status register
This commit is contained in:
@ -38,12 +38,15 @@
|
|||||||
#define W25Q80BV_FAST_READ 0x0b
|
#define W25Q80BV_FAST_READ 0x0b
|
||||||
#define W25Q80BV_WRITE_ENABLE 0x06
|
#define W25Q80BV_WRITE_ENABLE 0x06
|
||||||
#define W25Q80BV_CHIP_ERASE 0xC7
|
#define W25Q80BV_CHIP_ERASE 0xC7
|
||||||
|
#define W25Q80BV_WRITE_STATUS 0x01
|
||||||
#define W25Q80BV_READ_STATUS1 0x05
|
#define W25Q80BV_READ_STATUS1 0x05
|
||||||
|
#define W25Q80BV_READ_STATUS2 0x35
|
||||||
#define W25Q80BV_PAGE_PROGRAM 0x02
|
#define W25Q80BV_PAGE_PROGRAM 0x02
|
||||||
#define W25Q80BV_DEVICE_ID 0xAB
|
#define W25Q80BV_DEVICE_ID 0xAB
|
||||||
#define W25Q80BV_UNIQUE_ID 0x4B
|
#define W25Q80BV_UNIQUE_ID 0x4B
|
||||||
|
|
||||||
#define W25Q80BV_STATUS_BUSY 0x01
|
#define W25Q80BV_STATUS_BUSY 0x01
|
||||||
|
#define W25Q80BV_STATUS_WEL 0x02
|
||||||
|
|
||||||
#define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */
|
#define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */
|
||||||
|
|
||||||
@ -110,6 +113,7 @@ void w25q80bv_write_enable(w25q80bv_driver_t* const drv)
|
|||||||
|
|
||||||
uint8_t data[] = { W25Q80BV_WRITE_ENABLE };
|
uint8_t data[] = { W25Q80BV_WRITE_ENABLE };
|
||||||
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
|
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
|
||||||
|
while (w25q80bv_get_status(drv) ^ W25Q80BV_STATUS_WEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void w25q80bv_chip_erase(w25q80bv_driver_t* const drv)
|
void w25q80bv_chip_erase(w25q80bv_driver_t* const drv)
|
||||||
@ -223,3 +227,22 @@ void w25q80bv_read(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, ui
|
|||||||
|
|
||||||
spi_bus_transfer_gather(drv->bus, transfers, ARRAY_SIZE(transfers));
|
spi_bus_transfer_gather(drv->bus, transfers, ARRAY_SIZE(transfers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void w25q80bv_clear_status(w25q80bv_driver_t* const drv)
|
||||||
|
{
|
||||||
|
w25q80bv_write_enable(drv);
|
||||||
|
w25q80bv_wait_while_busy(drv);
|
||||||
|
uint8_t data[] = { W25Q80BV_WRITE_STATUS, 0x00, 0x00 };
|
||||||
|
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void w25q80bv_get_full_status(w25q80bv_driver_t* const drv, uint8_t* data)
|
||||||
|
{
|
||||||
|
uint8_t cmd[] = { W25Q80BV_READ_STATUS1, 0xFF };
|
||||||
|
spi_bus_transfer(drv->bus, cmd, ARRAY_SIZE(cmd));
|
||||||
|
data[0] = cmd[1];
|
||||||
|
cmd[0] =W25Q80BV_READ_STATUS2;
|
||||||
|
cmd[1] = 0xFF;
|
||||||
|
spi_bus_transfer(drv->bus, cmd, ARRAY_SIZE(cmd));
|
||||||
|
data[1] = cmd[1];
|
||||||
|
}
|
||||||
|
@ -53,10 +53,12 @@ struct w25q80bv_driver_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void w25q80bv_setup(w25q80bv_driver_t* const drv);
|
void w25q80bv_setup(w25q80bv_driver_t* const drv);
|
||||||
|
void w25q80bv_get_full_status(w25q80bv_driver_t* const drv, uint8_t* data);
|
||||||
void w25q80bv_chip_erase(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, uint8_t* data);
|
void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint8_t* data);
|
||||||
uint8_t w25q80bv_get_device_id(w25q80bv_driver_t* const drv);
|
uint8_t w25q80bv_get_device_id(w25q80bv_driver_t* const drv);
|
||||||
void w25q80bv_get_unique_id(w25q80bv_driver_t* const drv, w25q80bv_unique_id_t* unique_id);
|
void w25q80bv_get_unique_id(w25q80bv_driver_t* const drv, w25q80bv_unique_id_t* unique_id);
|
||||||
void w25q80bv_read(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint8_t* const data);
|
void w25q80bv_read(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint8_t* const data);
|
||||||
|
void w25q80bv_clear_status(w25q80bv_driver_t* const drv);
|
||||||
|
|
||||||
#endif//__W25Q80BV_H__
|
#endif//__W25Q80BV_H__
|
||||||
|
@ -90,7 +90,9 @@ static const usb_request_handler_fn vendor_request_handler[] = {
|
|||||||
usb_vendor_request_set_hw_sync_mode,
|
usb_vendor_request_set_hw_sync_mode,
|
||||||
usb_vendor_request_reset,
|
usb_vendor_request_reset,
|
||||||
usb_vendor_request_operacake_set_ranges,
|
usb_vendor_request_operacake_set_ranges,
|
||||||
usb_vendor_request_set_clkout_enable
|
usb_vendor_request_set_clkout_enable,
|
||||||
|
usb_vendor_request_spiflash_status,
|
||||||
|
usb_vendor_request_spiflash_clear_status
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t vendor_request_handler_count =
|
static const uint32_t vendor_request_handler_count =
|
||||||
|
@ -121,3 +121,28 @@ usb_request_status_t usb_vendor_request_read_spiflash(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usb_request_status_t usb_vendor_request_spiflash_status(
|
||||||
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
|
||||||
|
{
|
||||||
|
uint8_t data[2];
|
||||||
|
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||||
|
w25q80bv_get_full_status(&spi_flash, data);
|
||||||
|
usb_transfer_schedule_block(endpoint->in, &data, 2, NULL, NULL);
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||||
|
usb_transfer_schedule_ack(endpoint->out);
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
} else {
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_request_status_t usb_vendor_request_spiflash_clear_status(
|
||||||
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
|
||||||
|
{
|
||||||
|
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||||
|
w25q80bv_clear_status(&spi_flash);
|
||||||
|
usb_transfer_schedule_ack(endpoint->in);
|
||||||
|
}
|
||||||
|
return USB_REQUEST_STATUS_OK;
|
||||||
|
}
|
@ -32,5 +32,9 @@ usb_request_status_t usb_vendor_request_write_spiflash(
|
|||||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||||
usb_request_status_t usb_vendor_request_read_spiflash(
|
usb_request_status_t usb_vendor_request_read_spiflash(
|
||||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||||
|
usb_request_status_t usb_vendor_request_spiflash_status(
|
||||||
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||||
|
usb_request_status_t usb_vendor_request_spiflash_clear_status(
|
||||||
|
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||||
|
|
||||||
#endif /* end of include guard: __USB_API_SPIFLASH_H__ */
|
#endif /* end of include guard: __USB_API_SPIFLASH_H__ */
|
||||||
|
Submodule firmware/libopencm3 updated: d3d6f3e74b...c9f40aae0b
@ -54,6 +54,8 @@ static struct option long_options[] = {
|
|||||||
{ "compatibility", no_argument, 0, 'c' },
|
{ "compatibility", no_argument, 0, 'c' },
|
||||||
{ "device", required_argument, 0, 'd' },
|
{ "device", required_argument, 0, 'd' },
|
||||||
{ "reset", no_argument, 0, 'R' },
|
{ "reset", no_argument, 0, 'R' },
|
||||||
|
{ "status", no_argument, 0, 's' },
|
||||||
|
{ "clear", no_argument, 0, 'c' },
|
||||||
{ "verbose", no_argument, 0, 'v' },
|
{ "verbose", no_argument, 0, 'v' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ 0, 0, 0, 0 },
|
{ 0, 0, 0, 0 },
|
||||||
@ -145,6 +147,8 @@ static void usage()
|
|||||||
printf("\t-w, --write <filename>: Write data from file.\n");
|
printf("\t-w, --write <filename>: Write data from file.\n");
|
||||||
printf("\t-i, --no-check: Skip check for firmware compatibility with target device.\n");
|
printf("\t-i, --no-check: Skip check for firmware compatibility with target device.\n");
|
||||||
printf("\t-d, --device <serialnumber>: Serial number of device, if multiple devices\n");
|
printf("\t-d, --device <serialnumber>: Serial number of device, if multiple devices\n");
|
||||||
|
printf("\t-s, --status: Read SPI flash status registers before other operations.\n");
|
||||||
|
printf("\t-c, --clear: Clear SPI flash status registers before other operations.\n");
|
||||||
printf("\t-R, --reset: Reset HackRF after other operations.\n");
|
printf("\t-R, --reset: Reset HackRF after other operations.\n");
|
||||||
printf("\t-v, --verbose: Verbose output.\n");
|
printf("\t-v, --verbose: Verbose output.\n");
|
||||||
}
|
}
|
||||||
@ -152,6 +156,7 @@ static void usage()
|
|||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
|
uint8_t status[2];
|
||||||
uint32_t address = 0;
|
uint32_t address = 0;
|
||||||
uint32_t length = MAX_LENGTH;
|
uint32_t length = MAX_LENGTH;
|
||||||
uint32_t tmp_length;
|
uint32_t tmp_length;
|
||||||
@ -169,9 +174,11 @@ int main(int argc, char** argv)
|
|||||||
bool ignore_compat_check = false;
|
bool ignore_compat_check = false;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool reset = false;
|
bool reset = false;
|
||||||
|
bool read_status = false;
|
||||||
|
bool clear_status = false;
|
||||||
uint16_t usb_api;
|
uint16_t usb_api;
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "a:l:r:w:id:vRh?", long_options,
|
while ((opt = getopt_long(argc, argv, "a:l:r:w:id:scvRh?", long_options,
|
||||||
&option_index)) != EOF) {
|
&option_index)) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'a':
|
case 'a':
|
||||||
@ -200,6 +207,14 @@ int main(int argc, char** argv)
|
|||||||
serial_number = optarg;
|
serial_number = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
read_status = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
clear_status = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
@ -233,7 +248,7 @@ int main(int argc, char** argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(write || read || reset)) {
|
if(!(write || read || reset || read_status || clear_status)) {
|
||||||
fprintf(stderr, "Specify either read, write, or reset option.\n");
|
fprintf(stderr, "Specify either read, write, or reset option.\n");
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -295,6 +310,42 @@ int main(int argc, char** argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(read_status) {
|
||||||
|
result = hackrf_spiflash_status(device, status);
|
||||||
|
if (result != HACKRF_SUCCESS) {
|
||||||
|
fprintf(stderr, "hackrf_spiflash_status() failed: %s (%d)\n",
|
||||||
|
hackrf_error_name(result), result);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if(!verbose) {
|
||||||
|
printf("Status: 0x%02x %02x\n", status[0], status[1]);
|
||||||
|
} else {
|
||||||
|
printf("SRP0\t%x\nSEC\t%x\nTB\t%x\nBP\t%x\nWEL\t%x\nBusy\t%x\n",
|
||||||
|
(status[0] & 0x80) >> 7,
|
||||||
|
(status[0] & 0x40) >> 6,
|
||||||
|
(status[0] & 0x20) >> 5,
|
||||||
|
(status[0] & 0x1C) >> 2,
|
||||||
|
(status[0] & 0x02) >> 1,
|
||||||
|
status[0] & 0x01);
|
||||||
|
printf("SUS\t%x\nCMP\t%x\nLB\t%x\nRes\t%x\nQE\t%x\nSRP1\t%x\n",
|
||||||
|
(status[1] & 0x80) >> 7,
|
||||||
|
(status[1] & 0x40) >> 6,
|
||||||
|
(status[1] & 0x38) >> 3,
|
||||||
|
(status[1] & 0x04) >> 2,
|
||||||
|
(status[1] & 0x02) >> 1,
|
||||||
|
status[1] & 0x01);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(clear_status) {
|
||||||
|
result = hackrf_spiflash_clear_status(device);
|
||||||
|
if (result != HACKRF_SUCCESS) {
|
||||||
|
fprintf(stderr, "hackrf_spiflash_clear_status() failed: %s (%d)\n",
|
||||||
|
hackrf_error_name(result), result);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(read) {
|
if(read) {
|
||||||
ssize_t bytes_written;
|
ssize_t bytes_written;
|
||||||
tmp_length = length;
|
tmp_length = length;
|
||||||
|
@ -80,6 +80,8 @@ typedef enum {
|
|||||||
HACKRF_VENDOR_REQUEST_RESET = 30,
|
HACKRF_VENDOR_REQUEST_RESET = 30,
|
||||||
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES = 31,
|
HACKRF_VENDOR_REQUEST_OPERACAKE_SET_RANGES = 31,
|
||||||
HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE = 32,
|
HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE = 32,
|
||||||
|
HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS = 33,
|
||||||
|
HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS = 34,
|
||||||
} hackrf_vendor_request;
|
} hackrf_vendor_request;
|
||||||
|
|
||||||
#define USB_CONFIG_STANDARD 0x1
|
#define USB_CONFIG_STANDARD 0x1
|
||||||
@ -136,6 +138,12 @@ static const max2837_ft_t max2837_ft[] = {
|
|||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define USB_API_REQUIRED(device, version) \
|
||||||
|
uint16_t usb_version = 0; \
|
||||||
|
hackrf_usb_api_version_read(device, &usb_version); \
|
||||||
|
if(usb_version < version) \
|
||||||
|
return HACKRF_ERROR_USB_API_VERSION;
|
||||||
|
|
||||||
static volatile bool do_exit = false;
|
static volatile bool do_exit = false;
|
||||||
|
|
||||||
static const uint16_t hackrf_usb_vid = 0x1d50;
|
static const uint16_t hackrf_usb_vid = 0x1d50;
|
||||||
@ -958,6 +966,55 @@ int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ADDCALL hackrf_spiflash_status(hackrf_device* device, uint8_t* data)
|
||||||
|
{
|
||||||
|
USB_API_REQUIRED(device, 0x0103)
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = libusb_control_transfer(
|
||||||
|
device->usb_device,
|
||||||
|
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||||
|
HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
data,
|
||||||
|
2,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result < 1)
|
||||||
|
{
|
||||||
|
last_libusb_error = result;
|
||||||
|
return HACKRF_ERROR_LIBUSB;
|
||||||
|
} else {
|
||||||
|
return HACKRF_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ADDCALL hackrf_spiflash_clear_status(hackrf_device* device)
|
||||||
|
{
|
||||||
|
USB_API_REQUIRED(device, 0x0103)
|
||||||
|
int result;
|
||||||
|
result = libusb_control_transfer(
|
||||||
|
device->usb_device,
|
||||||
|
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||||
|
HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if( result != 0 )
|
||||||
|
{
|
||||||
|
last_libusb_error = result;
|
||||||
|
return HACKRF_ERROR_LIBUSB;
|
||||||
|
} else {
|
||||||
|
return HACKRF_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ADDCALL hackrf_cpld_write(hackrf_device* device,
|
int ADDCALL hackrf_cpld_write(hackrf_device* device,
|
||||||
unsigned char* const data, const unsigned int total_length)
|
unsigned char* const data, const unsigned int total_length)
|
||||||
{
|
{
|
||||||
@ -1054,12 +1111,6 @@ extern ADDAPI int ADDCALL hackrf_usb_api_version_read(hackrf_device* device,
|
|||||||
return HACKRF_SUCCESS;
|
return HACKRF_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define USB_API_REQUIRED(device, version) \
|
|
||||||
uint16_t usb_version = 0; \
|
|
||||||
hackrf_usb_api_version_read(device, &usb_version); \
|
|
||||||
if(usb_version < version) \
|
|
||||||
return HACKRF_ERROR_USB_API_VERSION;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t freq_mhz; /* From 0 to 6000+MHz */
|
uint32_t freq_mhz; /* From 0 to 6000+MHz */
|
||||||
uint32_t freq_hz; /* From 0 to 999999Hz */
|
uint32_t freq_hz; /* From 0 to 999999Hz */
|
||||||
|
@ -176,6 +176,8 @@ extern ADDAPI int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t r
|
|||||||
extern ADDAPI int ADDCALL hackrf_spiflash_erase(hackrf_device* device);
|
extern ADDAPI int ADDCALL hackrf_spiflash_erase(hackrf_device* device);
|
||||||
extern ADDAPI int ADDCALL hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data);
|
extern ADDAPI int ADDCALL hackrf_spiflash_write(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* const data);
|
||||||
extern ADDAPI int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data);
|
extern ADDAPI int ADDCALL hackrf_spiflash_read(hackrf_device* device, const uint32_t address, const uint16_t length, unsigned char* data);
|
||||||
|
extern ADDAPI int ADDCALL hackrf_spiflash_status(hackrf_device* device, uint8_t* data);
|
||||||
|
extern ADDAPI int ADDCALL hackrf_spiflash_clear_status(hackrf_device* device);
|
||||||
|
|
||||||
/* device will need to be reset after hackrf_cpld_write */
|
/* device will need to be reset after hackrf_cpld_write */
|
||||||
extern ADDAPI int ADDCALL hackrf_cpld_write(hackrf_device* device,
|
extern ADDAPI int ADDCALL hackrf_cpld_write(hackrf_device* device,
|
||||||
|
Reference in New Issue
Block a user