spi_mem_tools.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include <furi_hal.h>
  2. #include <furi_hal_spi_config.h>
  3. #include "spi_mem_chip_i.h"
  4. #include "spi_mem_tools.h"
  5. static uint8_t spi_mem_tools_addr_to_byte_arr(uint32_t addr, uint8_t* cmd) {
  6. uint8_t len = 3; // TODO(add support of 4 bytes address mode)
  7. for(uint8_t i = 0; i < len; i++) {
  8. cmd[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
  9. }
  10. return len;
  11. }
  12. static bool spi_mem_tools_trx(
  13. SPIMemChipCMD cmd,
  14. uint8_t* tx_buf,
  15. size_t tx_size,
  16. uint8_t* rx_buf,
  17. size_t rx_size) {
  18. bool success = false;
  19. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_external);
  20. do {
  21. if(!furi_hal_spi_bus_tx(
  22. &furi_hal_spi_bus_handle_external, (uint8_t*)&cmd, 1, SPI_MEM_SPI_TIMEOUT))
  23. break;
  24. if(tx_buf) {
  25. if(!furi_hal_spi_bus_tx(
  26. &furi_hal_spi_bus_handle_external, tx_buf, tx_size, SPI_MEM_SPI_TIMEOUT))
  27. break;
  28. }
  29. if(rx_buf) {
  30. if(!furi_hal_spi_bus_rx(
  31. &furi_hal_spi_bus_handle_external, rx_buf, rx_size, SPI_MEM_SPI_TIMEOUT))
  32. break;
  33. }
  34. success = true;
  35. } while(0);
  36. furi_hal_spi_release(&furi_hal_spi_bus_handle_external);
  37. return success;
  38. }
  39. static bool spi_mem_tools_write_buffer(uint8_t* data, size_t size, size_t offset) {
  40. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_external);
  41. uint8_t cmd = (uint8_t)SPIMemChipCMDWriteData;
  42. uint8_t address[4];
  43. uint8_t address_size = spi_mem_tools_addr_to_byte_arr(offset, address);
  44. bool success = false;
  45. do {
  46. if(!furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_external, &cmd, 1, SPI_MEM_SPI_TIMEOUT))
  47. break;
  48. if(!furi_hal_spi_bus_tx(
  49. &furi_hal_spi_bus_handle_external, address, address_size, SPI_MEM_SPI_TIMEOUT))
  50. break;
  51. if(!furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_external, data, size, SPI_MEM_SPI_TIMEOUT))
  52. break;
  53. success = true;
  54. } while(0);
  55. furi_hal_spi_release(&furi_hal_spi_bus_handle_external);
  56. return success;
  57. }
  58. bool spi_mem_tools_read_chip_info(SPIMemChip* chip) {
  59. uint8_t rx_buf[3] = {0, 0, 0};
  60. do {
  61. if(!spi_mem_tools_trx(SPIMemChipCMDReadJEDECChipID, NULL, 0, rx_buf, 3)) break;
  62. if(rx_buf[0] == 0 || rx_buf[0] == 255) break;
  63. chip->vendor_id = rx_buf[0];
  64. chip->type_id = rx_buf[1];
  65. chip->capacity_id = rx_buf[2];
  66. return true;
  67. } while(0);
  68. return false;
  69. }
  70. bool spi_mem_tools_check_chip_info(SPIMemChip* chip) {
  71. SPIMemChip new_chip_info;
  72. spi_mem_tools_read_chip_info(&new_chip_info);
  73. do {
  74. if(chip->vendor_id != new_chip_info.vendor_id) break;
  75. if(chip->type_id != new_chip_info.type_id) break;
  76. if(chip->capacity_id != new_chip_info.capacity_id) break;
  77. return true;
  78. } while(0);
  79. return false;
  80. }
  81. bool spi_mem_tools_read_block(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size) {
  82. if(!spi_mem_tools_check_chip_info(chip)) return false;
  83. for(size_t i = 0; i < block_size; i += SPI_MEM_MAX_BLOCK_SIZE) {
  84. uint8_t cmd[4];
  85. if((offset + SPI_MEM_MAX_BLOCK_SIZE) > chip->size) return false;
  86. if(!spi_mem_tools_trx(
  87. SPIMemChipCMDReadData,
  88. cmd,
  89. spi_mem_tools_addr_to_byte_arr(offset, cmd),
  90. data,
  91. SPI_MEM_MAX_BLOCK_SIZE))
  92. return false;
  93. offset += SPI_MEM_MAX_BLOCK_SIZE;
  94. data += SPI_MEM_MAX_BLOCK_SIZE;
  95. }
  96. return true;
  97. }
  98. size_t spi_mem_tools_get_file_max_block_size(SPIMemChip* chip) {
  99. UNUSED(chip);
  100. return (SPI_MEM_FILE_BUFFER_SIZE);
  101. }
  102. SPIMemChipStatus spi_mem_tools_get_chip_status(SPIMemChip* chip) {
  103. UNUSED(chip);
  104. uint8_t status;
  105. if(!spi_mem_tools_trx(SPIMemChipCMDReadStatus, NULL, 0, &status, 1))
  106. return SPIMemChipStatusError;
  107. if(status & SPIMemChipStatusBitBusy) return SPIMemChipStatusBusy;
  108. return SPIMemChipStatusIdle;
  109. }
  110. static bool spi_mem_tools_set_write_enabled(SPIMemChip* chip, bool enable) {
  111. UNUSED(chip);
  112. uint8_t status;
  113. SPIMemChipCMD cmd = SPIMemChipCMDWriteDisable;
  114. if(enable) cmd = SPIMemChipCMDWriteEnable;
  115. do {
  116. if(!spi_mem_tools_trx(cmd, NULL, 0, NULL, 0)) break;
  117. if(!spi_mem_tools_trx(SPIMemChipCMDReadStatus, NULL, 0, &status, 1)) break;
  118. if(!(status & SPIMemChipStatusBitWriteEnabled) && enable) break;
  119. if((status & SPIMemChipStatusBitWriteEnabled) && !enable) break;
  120. return true;
  121. } while(0);
  122. return false;
  123. }
  124. bool spi_mem_tools_erase_chip(SPIMemChip* chip) {
  125. do {
  126. if(!spi_mem_tools_set_write_enabled(chip, true)) break;
  127. if(!spi_mem_tools_trx(SPIMemChipCMDChipErase, NULL, 0, NULL, 0)) break;
  128. return true;
  129. } while(0);
  130. return true;
  131. }
  132. bool spi_mem_tools_write_bytes(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size) {
  133. do {
  134. if(!spi_mem_tools_check_chip_info(chip)) break;
  135. if(!spi_mem_tools_set_write_enabled(chip, true)) break;
  136. if((offset + block_size) > chip->size) break;
  137. if(!spi_mem_tools_write_buffer(data, block_size, offset)) break;
  138. return true;
  139. } while(0);
  140. return false;
  141. }