Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- ******************************************************************************
- * @file : W25Q128JV.c
- * @brief : W25Q128JV library
- ******************************************************************************
- * @attention
- *
- *
- * All rights reserved.
- *
- *
- *
- * If no LICENSE file comes with this software, it is provided AS-IS.
- *
- ******************************************************************************
- */
- /*
- | Sector # | Start Addr | End Addr |
- | -------- | ---------- | -------- |
- | 0 | 0x000000 | 0x000FFF |
- | 1 | 0x001000 | 0x001FFF |
- | 2 | 0x002000 | 0x002FFF |
- | 3 | 0x003000 | 0x003FFF |
- | ... | ... | ... |
- | 4093 | 0xFFD000 | 0xFFDFFF |
- | 4094 | 0xFFE000 | 0xFFEFFF |
- | 4095 | 0xFFF000 | 0xFFFFFF |
- flow region spans:
- 0x000000 ... 0xFFDFFF
- sector fill log region:
- 0xFFE000 ... 0xFFFFF9
- reserved to be in erased state, necessary for function "W25Q_sector_scan":
- 0xFFFFFA - 0xFFFFFB
- reserved for erase chip count:
- 0xFFFFFC - 0xFFFFFF
- */
- /* Includes ------------------------------------------------------------------*/
- #include "W25Q128JV.h"
- #include "main.h" // for SPI and UART handles
- #include <stdint.h> // for uint8_t, uint16_t, uint32_t
- #include <string.h> // for strlen()
- #include <stdio.h> // for snprintf
- /* USER CODE BEGIN */
- uint8_t write_e_cmd = 0x06; // Write Enable, sets the Write Enable Latch (WEL) bit in the Status Register-1
- uint8_t spi_t_result, e_spi_r;
- uint8_t read_st_r1_cmd = 0x05; // Read Status Register-1
- uint8_t read_st_r2_cmd = 0x35; // Read Status Register-2
- uint8_t read_st_r3_cmd = 0x15; // Read Status Register-3
- uint8_t sr1 = 0, sr2 = 0, sr3 = 0; // for holding status registers' values
- uint8_t W25Q_ChipErase_flag = 0; // set to 1 inside function W25Q_PageProgram_flow(), will allow to erase chip when flow region is full
- uint32_t last_saved_flow_value = 0; // to store in W25Q
- uint32_t next_flow_addr = 0x000000; // this variable tells "W25Q_PageProgram_flow" at which address to write new flow value
- uint16_t last_sector_num_written = 0; // used in function "W25Q_PageProgram_flow"
- uint16_t last_valid_sector = 0;
- uint8_t W25Q_WaitBusyWithTimeout(uint32_t timeout_ms) {
- uint8_t read_st_r1_cmd = 0x05;
- uint8_t w25_busy_status = 0xFF;
- uint32_t start_tick = HAL_GetTick(); // Get current time (ms)
- do {
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &read_st_r1_cmd, 1, HAL_MAX_DELAY);
- HAL_SPI_Receive(&hspi1, &w25_busy_status, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- if ((HAL_GetTick() - start_tick) > timeout_ms) {
- const char* msg_busy = "[E_W25_X]Timeout waiting for W25Q busy bit to clear.\r\n";
- log_error(msg_busy);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg_busy, strlen(msg_busy), HAL_MAX_DELAY);
- return 0;
- }
- } while (w25_busy_status & 0x01); // While BUSY/WIP (Write In Progress) bit is 1
- return 1;
- }
- void W25Q_Reset(void) {
- uint8_t tData[2];
- tData[0] = 0x66; // enable Reset
- tData[1] = 0x99; // Reset
- if (HAL_GPIO_ReadPin(SPI1_CS_GPIO_Port, SPI1_CS_Pin) != GPIO_PIN_RESET) {
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- }
- // --- Send Reset Enable (0x66) ---
- HAL_SPI_Transmit(&hspi1, &tData[0], 1, HAL_MAX_DELAY); // write to secondary W25Q device via SPI
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // pull CS pin HIGH
- HAL_Delay(1);
- // --- Send Reset Device (0x99) ---
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- HAL_SPI_Transmit(&hspi1, &tData[1], 1, HAL_MAX_DELAY); // write to secondary W25Q device via SPI
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // pull CS pin HIGH
- HAL_Delay(100);
- }
- // Resets Status Registers' settings that are necessary for the project
- // Checks Status Registers' settings
- uint8_t W25Q_SR_Reset(void) {
- // Read SR1
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- HAL_SPI_Transmit(&hspi1, &read_st_r1_cmd, 1, HAL_MAX_DELAY); // send instruction to read SR-1
- HAL_SPI_Receive (&hspi1, &sr1, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- snprintf(msg, sizeof(msg), "SR-1 is: %hu\n", sr1); // Result in decimal
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- if (W25Q_WaitBusyWithTimeout(10000) == 0) { // means timed out
- snprintf(msg, sizeof(msg), "[EX]W25Q_SR_Reset wait timeout\n"); // Result in decimal
- log_error(msg);
- #ifdef DEBUG
- HAL_UART_Transmit(&huart3, (uint8_t*)"W25Q_SR_Reset wait timeout\n", strlen("W25Q_SR_Reset wait timeout\n"), HAL_MAX_DELAY);
- #endif
- return 0; // can't proceed if busy bit hasn't been cleared
- }
- if (sr1 & 0x01) {
- snprintf(msg, sizeof(msg), "r1 BUSY bit is: %hu\n", sr1 & 0x01); // Reading BUSY bit
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- }
- 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
- // Read Status Register 2
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &read_st_r2_cmd, 1, HAL_MAX_DELAY);
- HAL_SPI_Receive(&hspi1, &sr2, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- snprintf(msg, sizeof(msg), "SR-2: %hu\n", sr2);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- if ( (sr2 >> 7) & 0x01) {
- 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);
- uint8_t cmd_resume = 0x7A; // Erase/Program Resume (7Ah) op code
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &cmd_resume, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- W25Q_WaitBusyWithTimeout(5000);
- // Read Status Register 2 again
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &read_st_r2_cmd, 1, HAL_MAX_DELAY);
- HAL_SPI_Receive(&hspi1, &sr2, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- if ( (sr2 >> 7) & 0x1) {
- 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);
- return 0;
- }
- }
- else if (sr2 == 0x02 || sr2 == 0x00) { // either only QE is set or entire SR-2 is clear
- // Read Status Register 3
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &read_st_r3_cmd, 1, HAL_MAX_DELAY);
- HAL_SPI_Receive(&hspi1, &sr3, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- snprintf(msg, sizeof(msg), "SR-3 now: %hu\n", sr3);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- snprintf(msg, sizeof(msg), "SR3's WPS bit is: %hu\n", (sr3 >> 2) & 0x01);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- if ( (((sr3 >> 2) & 0x01) == 1) || sr3 != 96 ){ // checking WPS bit or DRV1 and DRV2 bits
- // Modify SR3 bits
- sr3 = (1 << 6) | (1 << 5); // set s5, s6 bits only, range s0 ... s7, should be 96 in decimal (0x60) or 01100000 in binary
- // Enable write
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- // Write Status Register-3: 0x11 + SR3
- uint8_t tx_r3[2] = { 0x11, sr3 };
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, tx_r3, 2, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- // Read Status Register 3
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &read_st_r3_cmd, 1, HAL_MAX_DELAY);
- HAL_SPI_Receive(&hspi1, &sr3, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- if (sr3 != 96) {
- return 0; // means couldn't set SR-3 to 96 in decimal
- }
- }
- else if (sr3 == 96) {
- return 1;
- }
- }
- }
- return 0; // not quite successful return
- }
- uint32_t W25Q_ReadJedecID(void) {
- uint8_t tData[4] = { 0x9F, 0x00, 0x00, 0x00 }; // Read JEDEC ID
- uint8_t rData[4];
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // set CS pin low
- // Send [0]=0x9F, while simultaneously reading rData[0] (garbage).
- // Then send tData[1..3]=0x00, while reading the 3 ID bytes into rData[1..3].
- HAL_SPI_TransmitReceive(&hspi1, tData, rData, 4, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // pull CS pin HIGH
- 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;
- }
- // stores 64-bit unique ID in the passed array
- uint8_t W25Q_ReadUniqueID(uint8_t *arr) {
- // only pass an array with 8 elements to this function
- uint8_t read_uid_cmd[5] = { 0x4B, 0x00, 0x00, 0x00, 0x00 }; // 0x4B + 4 dummy bytes
- // Begin SPI transaction
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- // Send command + dummy bytes
- HAL_SPI_Transmit(&hspi1, read_uid_cmd, 5, HAL_MAX_DELAY);
- // Read 8-byte unique ID
- e_spi_r = HAL_SPI_Receive(&hspi1, arr, 8, HAL_MAX_DELAY);
- // End SPI transaction
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- if (e_spi_r != HAL_OK) {
- snprintf(msg, sizeof(msg), "[EX]e_spi_r %hu\n", e_spi_r);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return 0;
- }
- // Optional: Print result
- /*
- char msg[64];
- snprintf(msg, sizeof(msg),
- "Unique ID: %02X%02X%02X%02X %02X%02X%02X%02X\n",
- arr[0], arr[1], arr[2], arr[3],
- arr[4], arr[5], arr[6], arr[7]);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- */
- return 1;
- }
- // function to find sector # where last flow value is written in
- // works only for W25Q128JV
- uint16_t W25Q_sector_scan(void){
- uint8_t W25Q_sector_value[2] = { 0 }; // buffer to receive and store 2-byte value
- uint16_t sector_fill_value = 0; // this variable's value will be returned by the function
- // start at 0xFFE000, which is start of sector #4094
- // 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.
- // addresses 0xFFFFFA and 0xFFFFFB are reserved because they need to stay in erased state for the code below to work
- for (uint32_t WT25Q_sector_addr = 0xFFE000; WT25Q_sector_addr <= 0xFFFFFB;WT25Q_sector_addr += 2) {
- uint8_t cmd_s_s[4] = {
- 0x03, // Read data
- (WT25Q_sector_addr >> 16) & 0xFF,
- (WT25Q_sector_addr >> 8) & 0xFF,
- WT25Q_sector_addr & 0xFF
- };
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_s_s, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_sector_value, 2, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[EX]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
- log_error(msg); // logging error
- #ifdef DEBUG
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- return 0;
- }
- //snprintf(msg, sizeof(msg), "WT25Q_sector_addr: %lu\n", WT25Q_sector_addr); //temp
- //HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- if (W25Q_sector_value[0] == 0xFF && W25Q_sector_value[1] == 0xFF) {
- if (WT25Q_sector_addr == 0xFFE000) {
- #ifdef DEBUG
- 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);
- #endif
- break;
- }
- WT25Q_sector_addr -= 2; // minus 2 from current memory address
- uint8_t cmd_s_s2[4] = {
- 0x03, // Read data
- (WT25Q_sector_addr >> 16) & 0xFF,
- (WT25Q_sector_addr >> 8) & 0xFF,
- WT25Q_sector_addr & 0xFF
- };
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_s_s2, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_sector_value, 2, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E_W25_1]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return 0;
- }
- sector_fill_value = ((uint16_t)W25Q_sector_value[0] << 8) | W25Q_sector_value[1];
- 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);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- break; // reached end of valid sector fill log
- }
- }
- if (sector_fill_value > 4093) { // ensuring the sector # value doesn't go beyond maximum possible sector # in this NOR flash memory
- //log error
- snprintf(msg, sizeof(msg), "[E_W25_X]sector_fill_value is %u, beyond #4093", sector_fill_value);
- log_error(msg);
- sector_fill_value = 0;
- #ifdef DEBUG
- 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);
- #endif
- }
- return sector_fill_value;
- }
- // begin search from given sector # to extract last written flow value, then return it
- // and set valid memory address at where new flow value can be written i.e. "next_flow_addr"
- // works only for W25Q128JV
- uint32_t W25Q_get_flow(uint16_t valid_sector_num){
- uint32_t sector_base_addr = (uint32_t)valid_sector_num * 0x1000; // to get 24-bit address where this sector begins
- uint8_t get_flow_value_buf[4] = {0};
- uint32_t get_flow_value;
- uint32_t W25Q_flow_counter;
- 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
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- // 0xFFD000 start of sector 4093
- if (sector_base_addr == 0xFFD000) {
- // checking if the end of flow region is already filled
- // 0xFFDFFC, 0xFFDFFD, 0xFFDFFE, 0xFFDFFF last addresses of flow region, end of sector 4093
- uint8_t cmd_g_f0[4] = {
- 0x03, // Read data
- (0xFFDFFC >> 16) & 0xFF,
- (0xFFDFFC >> 8) & 0xFF,
- 0xFFDFFC & 0xFF
- };
- // Write enable
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f0, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E3]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- }
- 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) {
- // last 4-bytes of sector 4093 are filled
- 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]);
- next_flow_addr = 0xFFE000; // 0xFFE000 is start of sector 4094, should trigger chip erase when passed to "W25Q_PageProgram_flow"
- return get_flow_value;
- }
- }
- else if (sector_base_addr >=0xFFE000) {
- // 0xFFE000 is start of sector #4094, means sector value passed to this function is beyond allowed value (4093 is max)
- 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);
- log_error(msg);
- #ifdef DEBUG
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- return 0;
- }
- else if (sector_base_addr == 0x000000){
- // checking if beginning of flow region hasn't yet been filled (first time start)
- uint8_t cmd_g_f1[4] = {
- 0x03, // Read data
- (0x000000 >> 16) & 0xFF,
- (0x000000 >> 8) & 0xFF,
- 0x000000 & 0xFF
- };
- // Write enable
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f1, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E3]spi_t_result: %hu, e_spi_r %hu\n", spi_t_result, e_spi_r);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- }
- 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) {
- // first 4-bytes of sector 0 are not filled
- get_flow_value = 0;
- next_flow_addr = 0x000000;
- return get_flow_value;
- }
- }
- for (W25Q_flow_counter = sector_base_addr; W25Q_flow_counter < (sector_base_addr + 0x1000); W25Q_flow_counter += 4) { // search within this particular sector only
- uint8_t cmd_g_f2[4] = {
- 0x03, // Read data
- (W25Q_flow_counter >> 16) & 0xFF,
- (W25Q_flow_counter >> 8) & 0xFF,
- W25Q_flow_counter & 0xFF
- };
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f2, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %u, e_spi_r %u\n", spi_t_result, e_spi_r);
- log_error(msg);
- #ifdef DEBUG
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- return 0;
- }
- 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){
- uint32_t W25Q_flow_counter2 = W25Q_flow_counter - 4;
- next_flow_addr = W25Q_flow_counter;
- uint8_t cmd_g_f3[4] = {
- 0x03, // Read data
- (W25Q_flow_counter2 >> 16) & 0xFF,
- (W25Q_flow_counter2 >> 8) & 0xFF,
- W25Q_flow_counter2 & 0xFF
- };
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_g_f3, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, get_flow_value_buf, 4, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[EX]spi_t_result: %u, e_spi_r %u\n", spi_t_result, e_spi_r);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return 0;
- }
- 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]);
- 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
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- if (get_flow_value >= 4294967295) {
- snprintf(msg, sizeof(msg), "[E_W25_X]overflow, get_flow_value: %lu", get_flow_value);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)"get_flow_value >= 4294967295\n", strlen("get_flow_value >= 4294967295\n"), HAL_MAX_DELAY);
- return 429496; // return 429496, easier to catch if there's an issue here
- }
- return get_flow_value;
- }
- }
- return 0;
- }
- /*
- | Sector # | Start Addr | End Addr |
- | -------- | ---------- | -------- |
- | 0 | 0x000000 | 0x000FFF |
- | 1 | 0x001000 | 0x001FFF |
- | 2 | 0x002000 | 0x002FFF |
- | 3 | 0x003000 | 0x003FFF |
- | ... | ... | ... |
- | 4093 | 0xFFD000 | 0xFFDFFF |
- | 4094 | 0xFFE000 | 0xFFEFFF |
- | 4095 | 0xFFF000 | 0xFFFFFF |
- flow region spans:
- 0x000000 ... 0xFFDFFF
- sector fill log region:
- 0xFFE000 ... 0xFFFFF9
- reserved for function "W25Q_sector_scan":
- 0xFFFFFA - 0xFFFFFB
- reserved for erase chip count:
- 0xFFFFFC - 0xFFFFFF
- */
- // only for writing 4-byte flow values
- // 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
- // works only for W25Q128JV
- void W25Q_PageProgram_flow(uint32_t address, uint32_t flow_value) {
- uint32_t page_offset = address & 0xFF;
- // 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
- // can 4 bytes be written in this page without exceeding max memory range in this page
- if (page_offset + 4 > 256) {
- snprintf(msg, sizeof(msg), "[E_W25_X]Page boundary issue, passed address:%lu", address);
- log_error(msg);
- return;
- }
- // checking that passed address is 4-byte aligned, since flow_value is written as 4-bytes
- if (address & 0x3) {
- // error, last 2-bytes in 3-byte address must be one of the following: 0x00, 0x04, 0x08, 0x0C
- snprintf(msg, sizeof(msg), "[E_W25_X]4-byte alignment issue, passed address:%lu", address);
- log_error(msg);
- return;
- }
- else if (address == 0xFFE000) { // 0xFFE000 is start of sector 4094
- //flow region is filled, time to erase chip
- //0xFFDFFC, 0xFFDFFD, 0xFFDFFE, 0xFFDFFF last addresses of flow region, end of sector 4093
- uint8_t cmd_p_f0[4] = {
- 0x03, // Read data
- (0xFFDFFC >> 16) & 0xFF,
- (0xFFDFFC >> 8) & 0xFF,
- 0xFFDFFC & 0xFF
- };
- uint8_t W25Q_flow_value0[4] = {0};
- // Write enable
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_p_f0, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_flow_value0, 4, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %hu, e_spi_r %hu", spi_t_result, e_spi_r);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return;
- }
- if (W25Q_flow_value0[0] == 0xFF && W25Q_flow_value0[1] == 0xFF && W25Q_flow_value0[2] == 0xFF && W25Q_flow_value0[3] == 0xFF) {
- //last 4-bytes of sector 4093 aren't filled, something's wrong
- snprintf(msg, sizeof(msg), "[E_W25_X]last 4 bytes in sector 4093 are in erased state");
- log_error(msg);
- 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);
- return;
- }
- if (W25Q_WaitBusyWithTimeout(10000) != 1) { // something's wrong if busy bit hasn't been cleared
- snprintf(msg, sizeof(msg), "[E_W25_X]busy bit hasn't been cleared");
- log_error(msg);
- return;
- }
- // at addresses 0xFFFFF8-0xFFFFF9 should be the two-byte value 4093, corresponding to the last possible sector of filled flow region
- uint8_t cmd_p_f1[4] = {
- 0x03, // Read data
- (0xFFFFF8 >> 16) & 0xFF,
- (0xFFFFF8 >> 8) & 0xFF,
- 0xFFFFF8 & 0xFF
- };
- uint8_t W25Q_sector_value0[2] = {0};
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_p_f1, 4, HAL_MAX_DELAY);
- e_spi_r = HAL_SPI_Receive(&hspi1, W25Q_sector_value0, 2, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %hu, e_spi_r %hu", spi_t_result, e_spi_r);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return;
- }
- #ifdef DEBUG
- snprintf(msg, sizeof(msg), "W25Q_sector_value0[0]: %u, W25Q_sector_value0[1]: %u\n", W25Q_sector_value0[0], W25Q_sector_value0[1]);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- if (W25Q_sector_value0[0] != 15 && W25Q_sector_value0[1] != 253) { // these two together are 4093 in decimal
- 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]);
- log_error(msg);
- 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);
- return;
- }
- // read last four bytes in memory, check current erase chip count
- uint8_t read_address_last4b[4] = { 0x03, 0xFF, 0xFF, 0xFC }; // Read from an address
- uint8_t read_erase_chip_count[4] = {0};
- uint32_t read_erase_chip_decimal = 0;
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- spi_t_result = HAL_SPI_Transmit(&hspi1, read_address_last4b, 4, HAL_MAX_DELAY); // send instruction to read data
- e_spi_r = HAL_SPI_Receive (&hspi1, read_erase_chip_count, 4, HAL_MAX_DELAY); // store bytes
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- if ( (spi_t_result != HAL_OK) | (e_spi_r != HAL_OK) ) {
- snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %hu, e_spi_r %hu", spi_t_result, e_spi_r);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return;
- }
- #ifdef DEBUG
- 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]);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- 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){
- 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]);
- #ifdef DEBUG
- snprintf(msg, sizeof(msg), "read_erase_chip_decimal: %lu\n", read_erase_chip_decimal);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- }
- else { // seems to be the first erase cycle
- read_erase_chip_decimal += 1;
- }
- // erase chip
- W25Q_ChipErase_flag = 1;
- if (W25Q_ChipErase() == 0) {
- snprintf(msg, sizeof(msg), "[E_W25_X]W25Q_ChipErase unsuccessful");
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)"[E_W25_X]W25Q_ChipErase unsuccessful\n", strlen("[E_W25_X]W25Q_ChipErase unsuccessful\n"), HAL_MAX_DELAY);
- return; // means chip erase wasn't successful
- }
- // write new erase count value
- // Build a single 8-byte buffer: 1-byte opcode + 3-byte address + 4-byte chip erase count value
- // 0xFFFFFC - 0xFFFFFF are the last memory addresses, they hold uint32_t erase chip count value
- uint8_t cmd_erase_chip_count[8] = {
- 0x02, // Page Program opcode
- (uint8_t)(0xFFFFFC >> 16), // A23–A16, casting to uint8_t just keeps the lowest 8 bits
- (uint8_t)(0xFFFFFC >> 8), // A15–A8
- (uint8_t)(0xFFFFFC), // A7–A0
- (uint8_t)(read_erase_chip_decimal >> 24), // Data[0] = MSB
- (uint8_t)(read_erase_chip_decimal >> 16), // Data[1]
- (uint8_t)(read_erase_chip_decimal >> 8), // Data[2]
- (uint8_t)(read_erase_chip_decimal) // Data[3] = LSB
- };
- // Write enable
- // Send the entire Page Program packet at once
- // checking if erase chip is successful
- // check 0xFFDFFC, 0xFFDFFD, 0xFFDFFE, 0xFFDFFF last addresses of flow region, end of sector 4093
- // checking beginning of sector 4094 (0xFFE000), ought to be in erased state
- // read last 4 bytes in memory, check erase count
- return; // successful return
- }
- else if (address > 0xFFDFFC) { //end of sector 4093 (0xFFDFFF), 0xFFDFFF − 3 = 0xFFDFFC;
- snprintf(msg, sizeof(msg), "[E_W25_X]passed address:%lu, which is > 0xFFDFFC", address);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)"address > 0xFFDFFC\n", strlen("address > 0xFFDFFC\n"), HAL_MAX_DELAY);
- return;
- }
- // main write of flow value
- // Build a single 8-byte buffer: 1-byte opcode + 3-byte address + 4-byte flow value
- uint8_t cmd_txBuf[8] = {
- 0x02, // Page Program opcode
- (uint8_t)(address >> 16), // A23–A16, casting to uint8_t just keeps the lowest 8 bits
- (uint8_t)(address >> 8), // A15–A8
- (uint8_t)(address), // A7–A0
- (uint8_t)(flow_value >> 24), // Data[0] = MSB
- (uint8_t)(flow_value >> 16), // Data[1]
- (uint8_t)(flow_value >> 8), // Data[2]
- (uint8_t)(flow_value) // Data[3] = LSB
- };
- // ---- Sector fill tracking ----
- // Determine which sector this address belongs to
- uint16_t sector_num = address / 0x1000;
- #ifdef DEBUG
- snprintf(msg, sizeof(msg), "Inside W25Q_PageProgram_flow, sector_num: %u\n", sector_num); // temp debug
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- // Compute write address in reserved metadata sector (start at 0xFFE000, which is start of sector #4094)
- // Will write sector_num values 1 ... 4093 until address 0xFFFFF9, then addresses 0xFFFFFA…0xFFFFFF are free to be used elsewhere
- if (sector_num >= 1 && sector_num <= 4093 && sector_num != last_sector_num_written) {
- uint32_t meta_addr = 0xFFE000 + (sector_num - 1) * 2; // sector_num is a two-byte value
- uint8_t meta_result[2] = {0};
- uint8_t meta_cmd_read[4] = {
- 0x03, // Read opcode
- (meta_addr >> 16) & 0xFF,
- (meta_addr >> 8 ) & 0xFF,
- (meta_addr ) & 0xFF
- };
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); // pull CS pin low
- HAL_SPI_Transmit(&hspi1, meta_cmd_read, 4, HAL_MAX_DELAY);
- HAL_SPI_Receive(&hspi1, meta_result, 2, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); // set CS pin HIGH
- if (meta_result[0] == 0xFF && meta_result[1] == 0xFF) { // check to see if this sector # has already been written, if not, proceed
- uint8_t meta_cmd[6] = {
- 0x02, // Page Program opcode
- (meta_addr >> 16) & 0xFF,
- (meta_addr >> 8 ) & 0xFF,
- (meta_addr ) & 0xFF,
- (sector_num >> 8) & 0xFF, // MSB of 2-byte sector_num value
- sector_num & 0xFF // LSB
- };
- // Write enable
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- spi_t_result = HAL_SPI_Transmit(&hspi1, meta_cmd, 6, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- W25Q_WaitBusyWithTimeout(5000);
- if (spi_t_result != HAL_OK){
- snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %u\n", spi_t_result);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- }
- last_sector_num_written = sector_num;
- 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
- log_error(msg);
- #ifdef DEBUG
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- #endif
- }
- }
- }
- // ————————————————————————————————————————————————
- // This function erases entire memory in W25Q
- // ————————————————————————————————————————————————
- uint8_t W25Q_ChipErase(void) {
- uint8_t W25Q_SR_Reset_result = W25Q_SR_Reset();
- if (W25Q_SR_Reset_result != 1){
- snprintf(msg, sizeof(msg), "[E_W25_X]W25Q_SR_Reset() != 1\n");
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return 0;
- }
- else if (W25Q_SR_Reset_result == 1 && W25Q_ChipErase_flag == 1) {
- W25Q_ChipErase_flag = 0;
- #ifdef DEBUG
- HAL_UART_Transmit(&huart3, (uint8_t*)"[IX], W25Q_SR_Reset() == 1\n", strlen("[EX], W25Q_SR_Reset() == 1\n"), HAL_MAX_DELAY);
- #endif
- uint8_t cmd_chip_erase[1] = {0xC7}; // 0xC7 chip erase opcode
- // Write enable
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- HAL_SPI_Transmit(&hspi1, &write_e_cmd, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- spi_t_result = HAL_SPI_Transmit(&hspi1, cmd_chip_erase, 1, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- if (W25Q_WaitBusyWithTimeout(60000) == 0) {
- snprintf(msg, sizeof(msg), "[E_W25_X]chip erase timeout");
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)"[E_W25_X]chip erase timeout\n", strlen("[E_W25_X]chip erase timeout\n"), HAL_MAX_DELAY);
- return 0;
- }
- if (spi_t_result != HAL_OK){
- snprintf(msg, sizeof(msg), "[E_W25_X]spi_t_result: %u\n", spi_t_result);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return 0;
- }
- return 1;
- }
- return 0;
- }
- // read 4bytes starting at a given address
- uint32_t W25Q_ReadData_4B(uint32_t address) {
- // Validate address range (W25Q128 has 16MB = 0xFFFFFF max address)
- if (address > 0xFFFFFF) {
- return 0xE000000E; // Invalid address, return error value
- }
- uint8_t cmd[4];
- uint8_t buffer[4] = {0};
- cmd[0] = 0x03; // Read Data command
- cmd[1] = (address >> 16) & 0xFF; // 24-bit address
- cmd[2] = (address >> 8) & 0xFF;
- cmd[3] = address & 0xFF;
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
- // Send command + 24-bit address
- HAL_SPI_Transmit(&hspi1, cmd, 4, HAL_MAX_DELAY);
- // Read actual data into buffer
- HAL_SPI_Receive(&hspi1, buffer, 4, HAL_MAX_DELAY); // read 4 bytes
- HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
- uint32_t value = ((uint32_t)buffer[0] << 24) |
- ((uint32_t)buffer[1] << 16) |
- ((uint32_t)buffer[2] << 8) |
- ((uint32_t)buffer[3]);
- /* Example of bitwise OR masking
- | Buffer Index | Decimal | Shift | Result (Hex) |
- | ------------ | ------- | --------- | ------------ |
- | `buffer[0]` | 1 | `1 << 24` | `0x01000000` |
- | `buffer[1]` | 2 | `2 << 16` | `0x00020000` |
- | `buffer[2]` | 3 | `3 << 8` | `0x00000300` |
- | `buffer[3]` | 10 | no shift | `0x0000000A` |
- final Result = 0x0102030A
- */
- snprintf(msg, sizeof(msg), "starting at address: %08X, 4-byte value is %08X\n", (unsigned int)address, (unsigned int)value);
- log_error(msg);
- HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
- return value;
- }
- /* USER CODE END */
Advertisement
Add Comment
Please, Sign In to add comment