Guest User

W25Q128JV.c

a guest
Aug 11th, 2025
14
0
13 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 37.36 KB | Source Code | 0 0
  1. /**
  2.   ******************************************************************************
  3.   * @file           : W25Q128JV.c
  4.   * @brief          : W25Q128JV library
  5.   ******************************************************************************
  6.   * @attention
  7.   *
  8.   *
  9.   * All rights reserved.
  10.   *
  11.   *
  12.   *
  13.   * If no LICENSE file comes with this software, it is provided AS-IS.
  14.   *
  15.   ******************************************************************************
  16. */
  17.   /*
  18.     | Sector # | Start Addr | End Addr |
  19.     | -------- | ---------- | -------- |
  20.     | 0        | 0x000000   | 0x000FFF |
  21.     | 1        | 0x001000   | 0x001FFF |
  22.     | 2        | 0x002000   | 0x002FFF |
  23.     | 3        | 0x003000   | 0x003FFF |
  24.     | ...      | ...        | ...      |
  25.     | 4093     | 0xFFD000   | 0xFFDFFF |
  26.     | 4094     | 0xFFE000   | 0xFFEFFF |
  27.     | 4095     | 0xFFF000   | 0xFFFFFF |
  28.  
  29.  
  30.     flow region spans:
  31.     0x000000 ... 0xFFDFFF
  32.  
  33.     sector fill log region:
  34.     0xFFE000 ... 0xFFFFF9
  35.  
  36.     reserved to be in erased state, necessary for function "W25Q_sector_scan":
  37.     0xFFFFFA - 0xFFFFFB
  38.  
  39.     reserved for erase chip count:
  40.     0xFFFFFC - 0xFFFFFF
  41.  */
  42. /* Includes ------------------------------------------------------------------*/
  43. #include "W25Q128JV.h"
  44. #include "main.h"      // for SPI and UART handles
  45. #include <stdint.h>    // for uint8_t, uint16_t, uint32_t
  46. #include <string.h>    // for strlen()
  47. #include <stdio.h>     // for snprintf
  48.  
  49. /* USER CODE BEGIN */
  50. uint8_t write_e_cmd = 0x06; // Write Enable, sets the Write Enable Latch (WEL) bit in the Status Register-1
  51. uint8_t spi_t_result, e_spi_r;
  52.  
  53. uint8_t read_st_r1_cmd = 0x05; // Read Status Register-1
  54. uint8_t read_st_r2_cmd = 0x35; // Read Status Register-2
  55. uint8_t read_st_r3_cmd = 0x15; // Read Status Register-3
  56.  
  57. uint8_t sr1 = 0, sr2 = 0, sr3 = 0; // for holding status registers' values
  58.  
  59. uint8_t W25Q_ChipErase_flag = 0; // set to 1 inside function W25Q_PageProgram_flow(), will allow to erase chip when flow region is full
  60.  
  61. uint32_t last_saved_flow_value = 0; // to store in W25Q
  62. uint32_t next_flow_addr = 0x000000;    // this variable tells "W25Q_PageProgram_flow" at which address to write new flow value
  63. uint16_t last_sector_num_written = 0; // used in function "W25Q_PageProgram_flow"
  64. uint16_t last_valid_sector  = 0;
  65.  
  66.  
  67. uint8_t W25Q_WaitBusyWithTimeout(uint32_t timeout_ms) {
  68.     uint8_t read_st_r1_cmd = 0x05;
  69.     uint8_t w25_busy_status = 0xFF;
  70.     uint32_t start_tick = HAL_GetTick();  // Get current time (ms)
  71.  
  72.     do {
  73.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  74.         HAL_SPI_Transmit(&hspi1, &read_st_r1_cmd, 1, HAL_MAX_DELAY);
  75.         HAL_SPI_Receive(&hspi1, &w25_busy_status, 1, HAL_MAX_DELAY);
  76.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  77.  
  78.         if ((HAL_GetTick() - start_tick) > timeout_ms) {
  79.             const char* msg_busy = "[E_W25_X]Timeout waiting for W25Q busy bit to clear.\r\n";
  80.             log_error(msg_busy);
  81.             HAL_UART_Transmit(&huart3, (uint8_t*)msg_busy, strlen(msg_busy), HAL_MAX_DELAY);
  82.             return 0;
  83.         }
  84.  
  85.     } while (w25_busy_status & 0x01);  // While BUSY/WIP (Write In Progress) bit is 1
  86. return 1;
  87. }
  88.  
  89.  
  90. void W25Q_Reset(void) {
  91.     uint8_t tData[2];
  92.  
  93.     tData[0] = 0x66;  // enable Reset
  94.     tData[1] = 0x99;  // Reset
  95.  
  96.     if (HAL_GPIO_ReadPin(SPI1_CS_GPIO_Port, SPI1_CS_Pin) != GPIO_PIN_RESET) {
  97.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  98.     }
  99.     // --- Send Reset Enable (0x66) ---
  100.     HAL_SPI_Transmit(&hspi1, &tData[0], 1, HAL_MAX_DELAY); // write to secondary W25Q device via SPI
  101.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // pull CS pin HIGH
  102.     HAL_Delay(1);
  103.  
  104.     // --- Send Reset Device (0x99) ---
  105.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  106.     HAL_SPI_Transmit(&hspi1, &tData[1], 1, HAL_MAX_DELAY); // write to secondary W25Q device via SPI
  107.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // pull CS pin HIGH
  108.  
  109.     HAL_Delay(100);
  110. }
  111.  
  112. // Resets Status Registers' settings that are necessary for the project
  113. // Checks Status Registers' settings
  114. uint8_t W25Q_SR_Reset(void) {
  115.     // Read SR1
  116.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  117.     HAL_SPI_Transmit(&hspi1, &read_st_r1_cmd, 1, HAL_MAX_DELAY); // send instruction to read SR-1
  118.     HAL_SPI_Receive (&hspi1, &sr1, 1, HAL_MAX_DELAY);
  119.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  120.  
  121.     snprintf(msg, sizeof(msg), "SR-1 is: %hu\n", sr1); // Result in decimal
  122.     HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  123.  
  124.     if (W25Q_WaitBusyWithTimeout(10000) == 0) { // means timed out
  125.         snprintf(msg, sizeof(msg), "[EX]W25Q_SR_Reset wait timeout\n"); // Result in decimal
  126.         log_error(msg);
  127. #ifdef DEBUG
  128.         HAL_UART_Transmit(&huart3, (uint8_t*)"W25Q_SR_Reset wait timeout\n", strlen("W25Q_SR_Reset wait timeout\n"), HAL_MAX_DELAY);
  129. #endif
  130.         return 0; // can't proceed if busy bit hasn't been cleared
  131.     }
  132.  
  133.     if (sr1 & 0x01) {
  134.         snprintf(msg, sizeof(msg), "r1 BUSY bit is: %hu\n", sr1 & 0x01); // Reading BUSY bit
  135.         HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  136.     }
  137.     else if (sr1 == 0x00 || 0x02) { // ensuring either everything as well as Block Protect Bits S6-S2 are clear, or only WEL bit (0x02) is set
  138.             // Read Status Register 2
  139.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  140.             HAL_SPI_Transmit(&hspi1, &read_st_r2_cmd, 1, HAL_MAX_DELAY);
  141.             HAL_SPI_Receive(&hspi1, &sr2, 1, HAL_MAX_DELAY);
  142.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  143.  
  144.             snprintf(msg, sizeof(msg), "SR-2: %hu\n", sr2);
  145.             HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  146.  
  147.             if ( (sr2 >> 7) & 0x01) {
  148.                 HAL_UART_Transmit(&huart3, (uint8_t*)"SR-2's bit 7 (suspend) is high\n", strlen("SR-2's bit 7 (suspend) is high\n"), HAL_MAX_DELAY);
  149.  
  150.                 uint8_t cmd_resume = 0x7A; // Erase/Program Resume (7Ah) op code
  151.                 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  152.                 HAL_SPI_Transmit(&hspi1, &cmd_resume, 1, HAL_MAX_DELAY);
  153.                 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  154.                 W25Q_WaitBusyWithTimeout(5000);
  155.  
  156.                 // Read Status Register 2 again
  157.                 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  158.                 HAL_SPI_Transmit(&hspi1, &read_st_r2_cmd, 1, HAL_MAX_DELAY);
  159.                 HAL_SPI_Receive(&hspi1, &sr2, 1, HAL_MAX_DELAY);
  160.                 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  161.  
  162.                 if ( (sr2 >> 7) & 0x1) {
  163.                     HAL_UART_Transmit(&huart3, (uint8_t*)"[EX]Couldn't clear 7th bit in SR-2\n", strlen("[EX]Couldn't clear 7th bit in SR-2\n"), HAL_MAX_DELAY);
  164.                     return 0;
  165.                 }
  166.             }
  167.             else if (sr2 == 0x02 || sr2 == 0x00) { // either only QE is set or entire SR-2 is clear
  168.                 // Read Status Register 3
  169.                 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  170.                 HAL_SPI_Transmit(&hspi1, &read_st_r3_cmd, 1, HAL_MAX_DELAY);
  171.                 HAL_SPI_Receive(&hspi1, &sr3, 1, HAL_MAX_DELAY);
  172.                 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  173.  
  174.  
  175.                 snprintf(msg, sizeof(msg), "SR-3 now: %hu\n", sr3);
  176.                 HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  177.  
  178.                 snprintf(msg, sizeof(msg), "SR3's WPS bit is: %hu\n", (sr3 >> 2) & 0x01);
  179.                 HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  180.  
  181.                 if ( (((sr3 >> 2) & 0x01) == 1) || sr3 != 96 ){ // checking WPS bit or DRV1 and DRV2 bits
  182.                     // Modify SR3 bits
  183.                     sr3 = (1 << 6) | (1 << 5); // set s5, s6 bits only, range s0 ... s7, should be 96 in decimal (0x60) or 01100000 in binary
  184.                     // Enable write
  185.                     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  186.                     HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
  187.                     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  188.  
  189.                     // Write Status Register-3: 0x11 + SR3
  190.                     uint8_t tx_r3[2] = { 0x11, sr3 };
  191.                     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  192.                     HAL_SPI_Transmit(&hspi1, tx_r3, 2, HAL_MAX_DELAY);
  193.                     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  194.  
  195.                     // Read Status Register 3
  196.                     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  197.                     HAL_SPI_Transmit(&hspi1, &read_st_r3_cmd, 1, HAL_MAX_DELAY);
  198.                     HAL_SPI_Receive(&hspi1, &sr3, 1, HAL_MAX_DELAY);
  199.                     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  200.  
  201.                     if (sr3 != 96) {
  202.                         return 0; // means couldn't set SR-3 to 96 in decimal
  203.                     }
  204.                 }
  205.                 else if (sr3 == 96) {
  206.                     return 1;
  207.                 }
  208.             }
  209.     }
  210.  
  211. return 0; // not quite successful return
  212. }
  213.  
  214.  
  215.  
  216. uint32_t W25Q_ReadJedecID(void) {
  217.     uint8_t tData[4] = { 0x9F, 0x00, 0x00, 0x00 };  // Read JEDEC ID
  218.     uint8_t rData[4];
  219.  
  220.  
  221.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // set CS pin low
  222.     // Send [0]=0x9F, while simultaneously reading rData[0] (garbage).
  223.     // Then send tData[1..3]=0x00, while reading the 3 ID bytes into rData[1..3].
  224.     HAL_SPI_TransmitReceive(&hspi1, tData, rData, 4, HAL_MAX_DELAY);
  225.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // pull CS pin HIGH
  226.  
  227.     return ((rData[1]<<16)|(rData[2]<<8)|rData[3]); // MFN ID : MEM ID : CAPACITY ID, also Integer promotion at <<16; return_value = (Manufacturer_ID << 16) | (Memory_Type << 8) | Capacity_ID;
  228. }
  229.  
  230.  
  231. // stores 64-bit unique ID in the passed array
  232. uint8_t W25Q_ReadUniqueID(uint8_t *arr) {
  233.     // only pass an array with 8 elements to this function
  234.     uint8_t read_uid_cmd[5] = { 0x4B, 0x00, 0x00, 0x00, 0x00 };  // 0x4B + 4 dummy bytes
  235.  
  236.     // Begin SPI transaction
  237.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  238.     // Send command + dummy bytes
  239.     HAL_SPI_Transmit(&hspi1, read_uid_cmd, 5, HAL_MAX_DELAY);
  240.     // Read 8-byte unique ID
  241.     e_spi_r = HAL_SPI_Receive(&hspi1, arr, 8, HAL_MAX_DELAY);
  242.     // End SPI transaction
  243.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  244.  
  245.     if (e_spi_r != HAL_OK) {
  246.       snprintf(msg, sizeof(msg), "[EX]e_spi_r %hu\n", e_spi_r);
  247.       HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  248.       return 0;
  249.     }
  250.  
  251.     // Optional: Print result
  252.     /*
  253.     char msg[64];
  254.     snprintf(msg, sizeof(msg),
  255.         "Unique ID: %02X%02X%02X%02X %02X%02X%02X%02X\n",
  256.         arr[0], arr[1], arr[2], arr[3],
  257.         arr[4], arr[5], arr[6], arr[7]);
  258.     HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  259.     */
  260. return 1;
  261. }
  262.  
  263.  
  264.  
  265. // function to find sector # where last flow value is written in
  266. // works only for W25Q128JV
  267. uint16_t W25Q_sector_scan(void){
  268.     uint8_t W25Q_sector_value[2] =  { 0 }; // buffer to receive and store 2-byte value
  269.  
  270.     uint16_t sector_fill_value = 0; // this variable's value will be returned by the function
  271.     // start at 0xFFE000, which is start of sector #4094
  272.     // sector_num values 1 ... 4093 are written until address 0xFFFFF9, 0xFFFFFA and 0xFFFFFB are reserved, then addresses 0xFFFFFC…0xFFFFFF are free to be used elsewhere.
  273.     // addresses 0xFFFFFA and 0xFFFFFB are reserved because they need to stay in erased state for the code below to work
  274.     for (uint32_t WT25Q_sector_addr = 0xFFE000; WT25Q_sector_addr <= 0xFFFFFB;WT25Q_sector_addr += 2) {
  275.         uint8_t cmd_s_s[4] = {
  276.             0x03, // Read data
  277.             (WT25Q_sector_addr >> 16) & 0xFF,
  278.             (WT25Q_sector_addr >> 8) & 0xFF,
  279.              WT25Q_sector_addr & 0xFF
  280.         };
  281.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  282.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_s_s, 4, HAL_MAX_DELAY);
  283.         e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_sector_value, 2, HAL_MAX_DELAY);
  284.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  285.  
  286.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  287.           snprintf(msg, sizeof(msg), "[EX]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
  288.           log_error(msg); // logging error
  289. #ifdef DEBUG
  290.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  291. #endif
  292.           return 0;
  293.         }
  294.  
  295.         //snprintf(msg, sizeof(msg), "WT25Q_sector_addr: %lu\n", WT25Q_sector_addr); //temp
  296.         //HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  297.  
  298.         if (W25Q_sector_value[0] == 0xFF && W25Q_sector_value[1] == 0xFF) {
  299.             if (WT25Q_sector_addr == 0xFFE000) {
  300. #ifdef DEBUG
  301.                 HAL_UART_Transmit(&huart3, (uint8_t*)"[IX]two erased bytes beginning at 0xFFE000, which is start of sector #4094\n", strlen("[IX]two erased bytes beginning at 0xFFE000, which is start of sector #4094\n"), HAL_MAX_DELAY);
  302. #endif
  303.                 break;
  304.             }
  305.  
  306.             WT25Q_sector_addr -= 2; // minus 2 from current memory address
  307.             uint8_t cmd_s_s2[4] = {
  308.                         0x03, // Read data
  309.                         (WT25Q_sector_addr >> 16) & 0xFF,
  310.                         (WT25Q_sector_addr >> 8) & 0xFF,
  311.                          WT25Q_sector_addr & 0xFF
  312.             };
  313.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  314.             spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_s_s2, 4, HAL_MAX_DELAY);
  315.             e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_sector_value, 2, HAL_MAX_DELAY);
  316.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  317.  
  318.             if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  319.               snprintf(msg, sizeof(msg), "[E_W25_1]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
  320.               HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  321.               return 0;
  322.             }
  323.  
  324.             sector_fill_value = ((uint16_t)W25Q_sector_value[0] << 8) | W25Q_sector_value[1];
  325.             snprintf(msg, sizeof(msg), "[IX]found 2-byte sector_fill_value: %u beginning at 24-bit address: 0x%X\n", sector_fill_value, (unsigned int)WT25Q_sector_addr);
  326.             HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  327.             break; // reached end of valid sector fill log
  328.         }
  329.     }
  330. if (sector_fill_value > 4093) { // ensuring the sector # value doesn't go beyond maximum possible sector # in this NOR flash memory
  331.     //log error
  332.     snprintf(msg, sizeof(msg), "[E_W25_X]sector_fill_value is %u, beyond #4093", sector_fill_value);
  333.     log_error(msg);
  334.     sector_fill_value = 0;
  335. #ifdef DEBUG
  336.     HAL_UART_Transmit(&huart3, (uint8_t*)"[E_W25_X]inside if (sector_fill_value > 4093)\n", strlen("[E_W25_X]inside if (sector_fill_value > 4093)\n"), HAL_MAX_DELAY);
  337. #endif
  338. }
  339.  
  340. return sector_fill_value;
  341. }
  342.  
  343. // begin search from given sector # to extract last written flow value, then return it
  344. // and set valid memory address at where new flow value can be written i.e. "next_flow_addr"
  345. // works only for W25Q128JV
  346. uint32_t W25Q_get_flow(uint16_t valid_sector_num){
  347.     uint32_t sector_base_addr = (uint32_t)valid_sector_num * 0x1000; // to get 24-bit address where this sector begins
  348.     uint8_t  get_flow_value_buf[4] = {0};
  349.     uint32_t get_flow_value;
  350.     uint32_t W25Q_flow_counter;
  351.  
  352.     snprintf(msg, sizeof(msg), "Starting search in sector #%u beginning at address 0x%06X\n", valid_sector_num, (unsigned int)sector_base_addr); //temp debug
  353.     HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  354.  
  355.     // 0xFFD000 start of sector 4093
  356.     if (sector_base_addr == 0xFFD000) {
  357.         // checking if the end of flow region is already filled
  358.         // 0xFFDFFC, 0xFFDFFD, 0xFFDFFE, 0xFFDFFF last addresses of flow region, end of sector 4093
  359.         uint8_t cmd_g_f0[4] = {
  360.                     0x03, // Read data
  361.                     (0xFFDFFC >> 16) & 0xFF,
  362.                     (0xFFDFFC >> 8) & 0xFF,
  363.                      0xFFDFFC & 0xFF
  364.         };
  365.  
  366.         // Write enable
  367.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  368.         HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
  369.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  370.  
  371.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  372.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f0, 4, HAL_MAX_DELAY);
  373.         e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
  374.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  375.  
  376.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  377.           snprintf(msg, sizeof(msg), "[E3]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
  378.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  379.         }
  380.  
  381.         if (get_flow_value_buf[0] != 0xFF && get_flow_value_buf[1] != 0xFF && get_flow_value_buf[2] != 0xFF && get_flow_value_buf[3] != 0xFF) {
  382.             // last 4-bytes of sector 4093 are filled
  383.             get_flow_value = ((uint32_t)get_flow_value_buf[0] << 24) | ((uint32_t)get_flow_value_buf[1] << 16) |  ((uint32_t)get_flow_value_buf[2] << 8) | ((uint32_t)get_flow_value_buf[3]);
  384.             next_flow_addr = 0xFFE000; // 0xFFE000 is start of sector 4094, should trigger chip erase when passed to "W25Q_PageProgram_flow"
  385.             return get_flow_value;
  386.         }
  387.     }
  388.     else if (sector_base_addr >=0xFFE000) {
  389.         // 0xFFE000 is start of sector #4094, means sector value passed to this function is beyond allowed value (4093 is max)
  390.         snprintf(msg, sizeof(msg), "[E_W25_X]valid_sector_num value: %u beginning at address 0x%06X beyond allowed value\n", valid_sector_num, (unsigned int)sector_base_addr);
  391.         log_error(msg);
  392. #ifdef DEBUG
  393.         HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  394. #endif
  395.         return 0;
  396.     }
  397.     else if (sector_base_addr == 0x000000){
  398.         // checking if beginning of flow region hasn't yet been filled (first time start)
  399.         uint8_t cmd_g_f1[4] = {
  400.                     0x03, // Read data
  401.                     (0x000000 >> 16) & 0xFF,
  402.                     (0x000000 >> 8) & 0xFF,
  403.                      0x000000 & 0xFF
  404.         };
  405.  
  406.         // Write enable
  407.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  408.         HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
  409.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  410.  
  411.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  412.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f1, 4, HAL_MAX_DELAY);
  413.         e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
  414.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  415.  
  416.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  417.           snprintf(msg, sizeof(msg), "[E3]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
  418.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  419.         }
  420.  
  421.         if (get_flow_value_buf[0] == 0xFF && get_flow_value_buf[1] == 0xFF && get_flow_value_buf[2] == 0xFF && get_flow_value_buf[3] == 0xFF) {
  422.             // first 4-bytes of sector 0 are not filled
  423.             get_flow_value = 0;
  424.             next_flow_addr = 0x000000;
  425.             return get_flow_value;
  426.         }
  427.  
  428.     }
  429.  
  430.     for (W25Q_flow_counter = sector_base_addr; W25Q_flow_counter < (sector_base_addr + 0x1000); W25Q_flow_counter += 4) { // search within this particular sector only
  431.         uint8_t cmd_g_f2[4] = {
  432.                     0x03, // Read data
  433.                     (W25Q_flow_counter >> 16) & 0xFF,
  434.                     (W25Q_flow_counter >> 8) & 0xFF,
  435.                      W25Q_flow_counter & 0xFF
  436.         };
  437.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  438.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f2, 4, HAL_MAX_DELAY);
  439.         e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
  440.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  441.  
  442.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  443.                   snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %u, e_spi_r %u\n", spi_t_result, e_spi_r);
  444.                   log_error(msg);
  445. #ifdef DEBUG
  446.                   HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  447. #endif
  448.                   return 0;
  449.         }
  450.  
  451.         if (get_flow_value_buf[0] == 0xFF && get_flow_value_buf[1] == 0xFF && get_flow_value_buf[2] == 0xFF && get_flow_value_buf[3] == 0xFF){
  452.             uint32_t W25Q_flow_counter2 = W25Q_flow_counter - 4;
  453.             next_flow_addr = W25Q_flow_counter;
  454.             uint8_t cmd_g_f3[4] = {
  455.                     0x03, // Read data
  456.                     (W25Q_flow_counter2 >> 16) & 0xFF,
  457.                     (W25Q_flow_counter2 >> 8) & 0xFF,
  458.                      W25Q_flow_counter2 & 0xFF
  459.             };
  460.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  461.             spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f3, 4, HAL_MAX_DELAY);
  462.             e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
  463.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  464.  
  465.             if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  466.                   snprintf(msg, sizeof(msg), "[EX]spi_t_result: %u, e_spi_r %u\n", spi_t_result, e_spi_r);
  467.                   HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  468.                   return 0;
  469.             }
  470.             get_flow_value = ((uint32_t)get_flow_value_buf[0] << 24) | ((uint32_t)get_flow_value_buf[1] << 16) |  ((uint32_t)get_flow_value_buf[2] << 8) | ((uint32_t)get_flow_value_buf[3]);
  471.             snprintf(msg, sizeof(msg), "Found 4-byte flow value: %lu beginning at address 0x%X\n", get_flow_value, (unsigned int)W25Q_flow_counter2); // debug
  472.             HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  473.             if (get_flow_value >= 4294967295) {
  474.                 snprintf(msg, sizeof(msg), "[E_W25_X]overflow, get_flow_value: %lu", get_flow_value);
  475.                 log_error(msg);
  476.                 HAL_UART_Transmit(&huart3, (uint8_t*)"get_flow_value >= 4294967295\n", strlen("get_flow_value >= 4294967295\n"), HAL_MAX_DELAY);
  477.                 return 429496; // return 429496, easier to catch if there's an issue here
  478.             }
  479.  
  480.             return get_flow_value;
  481.         }
  482.     }
  483. return 0;
  484. }
  485.  
  486. /*
  487. | Sector # | Start Addr | End Addr |
  488. | -------- | ---------- | -------- |
  489. | 0        | 0x000000   | 0x000FFF |
  490. | 1        | 0x001000   | 0x001FFF |
  491. | 2        | 0x002000   | 0x002FFF |
  492. | 3        | 0x003000   | 0x003FFF |
  493. | ...      | ...        | ...      |
  494. | 4093     | 0xFFD000   | 0xFFDFFF |
  495. | 4094     | 0xFFE000   | 0xFFEFFF |
  496. | 4095     | 0xFFF000   | 0xFFFFFF |
  497.  
  498.  
  499. flow region spans:
  500. 0x000000 ... 0xFFDFFF
  501.  
  502. sector fill log region:
  503. 0xFFE000 ... 0xFFFFF9
  504.  
  505. reserved for function "W25Q_sector_scan":
  506. 0xFFFFFA - 0xFFFFFB
  507.  
  508. reserved for erase chip count:
  509. 0xFFFFFC - 0xFFFFFF
  510.  */
  511.  
  512. // only for writing 4-byte flow values
  513. // remember, at a particular address in memory, 1 byte can be written e.g. at 0x000000, 1 byte is stored, at 0x000001 also 1 byte can be stored
  514. // works only for W25Q128JV
  515. void W25Q_PageProgram_flow(uint32_t address, uint32_t flow_value) {
  516.     uint32_t page_offset = address & 0xFF;
  517.     // guard page boundary, when you add by +4 in decimal, you ensure that if address is incremented by 4, it shouldn't exceed max value of address in a page
  518.     // can 4 bytes be written in this page without exceeding max memory range in this page
  519.     if (page_offset + 4 > 256) {
  520.         snprintf(msg, sizeof(msg), "[E_W25_X]Page boundary issue, passed address:%lu", address);
  521.         log_error(msg);
  522.         return;
  523.     }
  524.  
  525.     // checking that passed address is 4-byte aligned, since flow_value is written as 4-bytes
  526.     if (address & 0x3) {
  527.         // error, last 2-bytes in 3-byte address must be one of the following: 0x00, 0x04, 0x08, 0x0C
  528.         snprintf(msg, sizeof(msg), "[E_W25_X]4-byte alignment issue, passed address:%lu", address);
  529.         log_error(msg);
  530.         return;
  531.     }
  532.     else if (address == 0xFFE000) { // 0xFFE000 is start of sector 4094
  533.         //flow region is filled, time to erase chip
  534.  
  535.          //0xFFDFFC, 0xFFDFFD, 0xFFDFFE, 0xFFDFFF last addresses of flow region, end of sector 4093
  536.         uint8_t cmd_p_f0[4] = {
  537.             0x03, // Read data
  538.             (0xFFDFFC >> 16) & 0xFF,
  539.             (0xFFDFFC >> 8) & 0xFF,
  540.              0xFFDFFC & 0xFF
  541.         };
  542.         uint8_t W25Q_flow_value0[4] = {0};
  543.  
  544.         // Write enable
  545.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  546.         HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
  547.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  548.  
  549.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  550.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_p_f0, 4, HAL_MAX_DELAY);
  551.         e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_flow_value0, 4, HAL_MAX_DELAY);
  552.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  553.  
  554.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  555.           snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %hu, e_spi_r %hu", spi_t_result, e_spi_r);
  556.           log_error(msg);
  557.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  558.           return;
  559.         }
  560.  
  561.         if (W25Q_flow_value0[0] == 0xFF && W25Q_flow_value0[1] == 0xFF && W25Q_flow_value0[2] == 0xFF && W25Q_flow_value0[3] == 0xFF) {
  562.             //last 4-bytes of sector 4093 aren't filled, something's wrong
  563.             snprintf(msg, sizeof(msg), "[E_W25_X]last 4 bytes in sector 4093 are in erased state");
  564.             log_error(msg);
  565.             HAL_UART_Transmit(&huart3, (uint8_t*)"[EX] last 4 bytes in sector 4093 are in erased state\n", strlen("[EX] last 4 bytes in sector 4093 are in erased state\n"), HAL_MAX_DELAY);
  566.             return;
  567.         }
  568.  
  569.         if (W25Q_WaitBusyWithTimeout(10000) != 1) { // something's wrong if busy bit hasn't been cleared
  570.             snprintf(msg, sizeof(msg), "[E_W25_X]busy bit hasn't been cleared");
  571.             log_error(msg);
  572.             return;
  573.         }
  574.         // at addresses 0xFFFFF8-0xFFFFF9 should be the two-byte value 4093, corresponding to the last possible sector of filled flow region
  575.         uint8_t cmd_p_f1[4] = {
  576.             0x03, // Read data
  577.             (0xFFFFF8 >> 16) & 0xFF,
  578.             (0xFFFFF8 >> 8) & 0xFF,
  579.              0xFFFFF8 & 0xFF
  580.         };
  581.  
  582.         uint8_t W25Q_sector_value0[2] = {0};
  583.  
  584.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  585.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_p_f1, 4, HAL_MAX_DELAY);
  586.         e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_sector_value0, 2, HAL_MAX_DELAY);
  587.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  588.  
  589.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  590.           snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %hu, e_spi_r %hu", spi_t_result, e_spi_r);
  591.           log_error(msg);
  592.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  593.           return;
  594.         }
  595. #ifdef DEBUG
  596.         snprintf(msg, sizeof(msg), "W25Q_sector_value0[0]: %u, W25Q_sector_value0[1]: %u\n", W25Q_sector_value0[0], W25Q_sector_value0[1]);
  597.         HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  598. #endif
  599.         if (W25Q_sector_value0[0] != 15 && W25Q_sector_value0[1] != 253) { // these two together are 4093 in decimal
  600.             snprintf(msg, sizeof(msg), "[E_W25_X]0xFFFFF8-0xFFFFF9 is %hu %hu, but must have stored 4093", W25Q_sector_value0[0], W25Q_sector_value0[1]);
  601.             log_error(msg);
  602.             HAL_UART_Transmit(&huart3, (uint8_t*)"[E_W25_X]W25Q_sector_value0[0] != 15\n", strlen("[E_W25_X]W25Q_sector_value0[0] != 15\n"), HAL_MAX_DELAY);
  603.             return;
  604.         }
  605.  
  606.         // read last four bytes in memory, check current erase chip count
  607.         uint8_t read_address_last4b[4] = { 0x03, 0xFF, 0xFF, 0xFC };  // Read from an address
  608.         uint8_t read_erase_chip_count[4] = {0};
  609.         uint32_t read_erase_chip_decimal = 0;
  610.  
  611.  
  612.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  613.         spi_t_result = HAL_SPI_Transmit(&hspi1, read_address_last4b, 4, HAL_MAX_DELAY); // send instruction to read data
  614.         e_spi_r = HAL_SPI_Receive (&hspi1, read_erase_chip_count, 4, HAL_MAX_DELAY); // store bytes
  615.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  616.  
  617.         if ( (spi_t_result != HAL_OK) |  (e_spi_r != HAL_OK) ) {
  618.           snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %hu, e_spi_r %hu", spi_t_result, e_spi_r);
  619.           log_error(msg);
  620.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  621.           return;
  622.         }
  623.  
  624. #ifdef DEBUG
  625.         snprintf(msg, sizeof(msg), "read_erase_chip_count[0]: %u, read_erase_chip_count[1]:%u, read_erase_chip_count[2]:%u, read_erase_chip_count[3]:%u\n", read_erase_chip_count[0], read_erase_chip_count[1], read_erase_chip_count[2], read_erase_chip_count[3]);
  626.         HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  627. #endif
  628.  
  629.         if (read_erase_chip_count[0] != 0xFF && read_erase_chip_count[1] != 0xFF && read_erase_chip_count[2] != 0xFF && read_erase_chip_count[3] != 0xFF){
  630.             read_erase_chip_decimal = ((uint32_t)read_erase_chip_count[0] << 24) | ((uint32_t)read_erase_chip_count[1] << 16) |  ((uint32_t)read_erase_chip_count[2] << 8) | ((uint32_t)read_erase_chip_count[3]);
  631. #ifdef DEBUG
  632.             snprintf(msg, sizeof(msg), "read_erase_chip_decimal: %lu\n", read_erase_chip_decimal);
  633.             HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  634. #endif
  635.         }
  636.         else { // seems to be the first erase cycle
  637.             read_erase_chip_decimal += 1;
  638.         }
  639.  
  640.         // erase chip
  641.         W25Q_ChipErase_flag = 1;
  642.         if (W25Q_ChipErase() == 0) {
  643.             snprintf(msg, sizeof(msg), "[E_W25_X]W25Q_ChipErase unsuccessful");
  644.             log_error(msg);
  645.             HAL_UART_Transmit(&huart3, (uint8_t*)"[E_W25_X]W25Q_ChipErase unsuccessful\n", strlen("[E_W25_X]W25Q_ChipErase unsuccessful\n"), HAL_MAX_DELAY);
  646.             return; // means chip erase wasn't successful
  647.         }
  648.  
  649.         // write new erase count value
  650.         // Build a single 8-byte buffer: 1-byte opcode + 3-byte address + 4-byte chip erase count value
  651.         // 0xFFFFFC - 0xFFFFFF are the last memory addresses, they hold uint32_t erase chip count value
  652.         uint8_t cmd_erase_chip_count[8] = {
  653.             0x02,                                       // Page Program opcode
  654.             (uint8_t)(0xFFFFFC >> 16),                  // A23–A16, casting to uint8_t just keeps the lowest 8 bits
  655.             (uint8_t)(0xFFFFFC >>  8),                  // A15–A8
  656.             (uint8_t)(0xFFFFFC),                        // A7–A0
  657.             (uint8_t)(read_erase_chip_decimal >> 24),   // Data[0] = MSB
  658.             (uint8_t)(read_erase_chip_decimal >> 16),   // Data[1]
  659.             (uint8_t)(read_erase_chip_decimal >>  8),   // Data[2]
  660.             (uint8_t)(read_erase_chip_decimal)          // Data[3] = LSB
  661.         };
  662.  
  663.         // Write enable
  664.  
  665.  
  666.         // Send the entire Page Program packet at once
  667.  
  668.  
  669.         // checking if erase chip is successful
  670.  
  671.         // check 0xFFDFFC, 0xFFDFFD, 0xFFDFFE, 0xFFDFFF last addresses of flow region, end of sector 4093
  672.  
  673.  
  674.         // checking beginning of sector 4094 (0xFFE000), ought to be in erased state
  675.        
  676.  
  677.  
  678.         // read last 4 bytes in memory, check erase count
  679.        
  680.         return; // successful return
  681.  
  682.     }
  683.     else if (address > 0xFFDFFC) { //end of sector 4093 (0xFFDFFF), 0xFFDFFF − 3 = 0xFFDFFC;
  684.         snprintf(msg, sizeof(msg), "[E_W25_X]passed address:%lu, which is > 0xFFDFFC", address);
  685.         log_error(msg);
  686.         HAL_UART_Transmit(&huart3, (uint8_t*)"address > 0xFFDFFC\n", strlen("address > 0xFFDFFC\n"), HAL_MAX_DELAY);
  687.         return;
  688.     }
  689.  
  690.     // main write of flow value
  691.  
  692.     // Build a single 8-byte buffer: 1-byte opcode + 3-byte address + 4-byte flow value
  693.     uint8_t cmd_txBuf[8] = {
  694.         0x02,                               // Page Program opcode
  695.         (uint8_t)(address >> 16),           // A23–A16, casting to uint8_t just keeps the lowest 8 bits
  696.         (uint8_t)(address >>  8),           // A15–A8
  697.         (uint8_t)(address),                 // A7–A0
  698.         (uint8_t)(flow_value >> 24),        // Data[0] = MSB
  699.         (uint8_t)(flow_value >> 16),        // Data[1]
  700.         (uint8_t)(flow_value >>  8),        // Data[2]
  701.         (uint8_t)(flow_value)               // Data[3] = LSB
  702.     };
  703.  
  704.  
  705.     // ---- Sector fill tracking ----
  706.     // Determine which sector this address belongs to
  707.     uint16_t sector_num = address / 0x1000;
  708. #ifdef DEBUG
  709.     snprintf(msg, sizeof(msg), "Inside W25Q_PageProgram_flow, sector_num: %u\n", sector_num); // temp debug
  710.     HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  711. #endif
  712.  
  713.     // Compute write address in reserved metadata sector (start at 0xFFE000, which is start of sector #4094)
  714.     // Will write sector_num values 1 ... 4093 until address 0xFFFFF9, then addresses 0xFFFFFA…0xFFFFFF are free to be used elsewhere
  715.     if (sector_num >= 1 && sector_num <= 4093 && sector_num != last_sector_num_written) {
  716.         uint32_t meta_addr = 0xFFE000 + (sector_num - 1) * 2; // sector_num is a two-byte value
  717.         uint8_t  meta_result[2] = {0};
  718.  
  719.         uint8_t  meta_cmd_read[4] = {
  720.             0x03,                               // Read opcode
  721.             (meta_addr >> 16) & 0xFF,
  722.             (meta_addr >> 8 ) & 0xFF,
  723.             (meta_addr      ) & 0xFF
  724.         };
  725.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
  726.         HAL_SPI_Transmit(&hspi1, meta_cmd_read, 4, HAL_MAX_DELAY);
  727.         HAL_SPI_Receive(&hspi1, meta_result, 2, HAL_MAX_DELAY);
  728.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
  729.         if (meta_result[0] == 0xFF && meta_result[1] == 0xFF) { // check to see if this sector # has already been written, if not, proceed
  730.             uint8_t meta_cmd[6] = {
  731.                 0x02,                               // Page Program opcode
  732.                 (meta_addr >> 16) & 0xFF,
  733.                 (meta_addr >> 8 ) & 0xFF,
  734.                 (meta_addr      ) & 0xFF,
  735.                 (sector_num >> 8) & 0xFF,           // MSB of 2-byte sector_num value
  736.                  sector_num & 0xFF                  // LSB
  737.             };
  738.  
  739.             // Write enable
  740.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  741.             HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
  742.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  743.  
  744.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  745.             spi_t_result = HAL_SPI_Transmit(&hspi1, meta_cmd, 6, HAL_MAX_DELAY);
  746.             HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  747.             W25Q_WaitBusyWithTimeout(5000);
  748.  
  749.             if (spi_t_result != HAL_OK){
  750.               snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %u\n", spi_t_result);
  751.               log_error(msg);
  752.               HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  753.             }
  754.  
  755.             last_sector_num_written = sector_num;
  756.  
  757.             snprintf(msg, sizeof(msg), "[I_W25_X]2-byte sector_num written: %u beginning at address: 0x%08X\n", sector_num, (unsigned int)meta_addr); // debug
  758.             log_error(msg);
  759. #ifdef DEBUG
  760.             HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  761. #endif
  762.         }
  763.     }
  764. }
  765.  
  766.  
  767. // ————————————————————————————————————————————————
  768. // This function erases entire memory in W25Q
  769. // ————————————————————————————————————————————————
  770. uint8_t W25Q_ChipErase(void) {
  771.     uint8_t W25Q_SR_Reset_result = W25Q_SR_Reset();
  772.     if (W25Q_SR_Reset_result != 1){
  773.         snprintf(msg, sizeof(msg), "[E_W25_X]W25Q_SR_Reset() != 1\n");
  774.         log_error(msg);
  775.         HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  776.         return 0;
  777.     }
  778.     else if (W25Q_SR_Reset_result == 1 && W25Q_ChipErase_flag == 1) {
  779.         W25Q_ChipErase_flag = 0;
  780. #ifdef DEBUG
  781.         HAL_UART_Transmit(&huart3, (uint8_t*)"[IX], W25Q_SR_Reset() == 1\n", strlen("[EX], W25Q_SR_Reset() == 1\n"), HAL_MAX_DELAY);
  782. #endif
  783.  
  784.         uint8_t cmd_chip_erase[1] = {0xC7}; // 0xC7 chip erase opcode
  785.  
  786.         // Write enable
  787.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  788.         HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
  789.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  790.  
  791.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  792.         spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_chip_erase, 1, HAL_MAX_DELAY);
  793.         HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  794.  
  795.         if (W25Q_WaitBusyWithTimeout(60000) == 0) {
  796.             snprintf(msg, sizeof(msg), "[E_W25_X]chip erase timeout");
  797.             log_error(msg);
  798.             HAL_UART_Transmit(&huart3, (uint8_t*)"[E_W25_X]chip erase timeout\n", strlen("[E_W25_X]chip erase timeout\n"), HAL_MAX_DELAY);
  799.             return 0;
  800.         }
  801.  
  802.         if (spi_t_result != HAL_OK){
  803.           snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %u\n", spi_t_result);
  804.           log_error(msg);
  805.           HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  806.           return 0;
  807.         }
  808.         return 1;
  809.     }
  810.  
  811. return 0;
  812. }
  813.  
  814. // read 4bytes starting at a given address
  815. uint32_t W25Q_ReadData_4B(uint32_t address) {
  816.     // Validate address range (W25Q128 has 16MB = 0xFFFFFF max address)
  817.     if (address > 0xFFFFFF) {
  818.         return 0xE000000E;  // Invalid address, return error value
  819.     }
  820.  
  821.     uint8_t cmd[4];
  822.     uint8_t buffer[4] = {0};
  823.     cmd[0] = 0x03;  // Read Data command
  824.     cmd[1] = (address >> 16) & 0xFF;  // 24-bit address
  825.     cmd[2] = (address >> 8) & 0xFF;
  826.     cmd[3] = address & 0xFF;
  827.  
  828.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
  829.     // Send command + 24-bit address
  830.     HAL_SPI_Transmit(&hspi1, cmd, 4, HAL_MAX_DELAY);
  831.     // Read actual data into buffer
  832.     HAL_SPI_Receive(&hspi1, buffer, 4, HAL_MAX_DELAY); // read 4 bytes
  833.     HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
  834.  
  835.  
  836.     uint32_t value = ((uint32_t)buffer[0] << 24) |
  837.                      ((uint32_t)buffer[1] << 16) |
  838.                      ((uint32_t)buffer[2] << 8)  |
  839.                      ((uint32_t)buffer[3]);
  840.     /* Example of bitwise OR masking
  841.         | Buffer Index | Decimal | Shift     | Result (Hex) |
  842.         | ------------ | ------- | --------- | ------------ |
  843.         | `buffer[0]`  | 1       | `1 << 24` | `0x01000000` |
  844.         | `buffer[1]`  | 2       | `2 << 16` | `0x00020000` |
  845.         | `buffer[2]`  | 3       | `3 << 8`  | `0x00000300` |
  846.         | `buffer[3]`  | 10      | no shift  | `0x0000000A` |
  847.  
  848.     final Result = 0x0102030A
  849.     */
  850.     snprintf(msg, sizeof(msg), "starting at address: %08X, 4-byte value is %08X\n", (unsigned int)address, (unsigned int)value);
  851.     log_error(msg);
  852.     HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  853.  
  854. return value;
  855. }
  856. /* USER CODE END */
Tags: W25Q
Advertisement
Add Comment
Please, Sign In to add comment