cancel
Showing results for 
Search instead for 
Did you mean: 

W25X20CL FLASH bring up with STM32H743 issue

aahsan
Associate III

Seeing issue while brining-up Winbond W25X20L FLASH with STM32, Write and read a byte in a loop does not work.

Tried to see the signal's using the scope and seems like clock has some issue, appreciate any help. Please let mw know if more information is needed here.

aahsan_1-1694645378744.png

CubeMx Settings and code I am using is provided below

STM32CubeMX Settings for SPI1 after going through blog post like this Getting Started with STM32 - How to Use SPI (digikey.com) 

aahsan_0-1694644447709.png

Basically updated.
1. data_size from 4 to 8, 2. baud_rate to 1.5Mbps using 64 as Prescaler, 3. Disabled NSSP Mode

Here is the Code i am using to read/write a byte in a loop

  1. #include "main.h"
  2. #include "stm32h7xx_hal.h"
  3. // Define the SPI handle
  4. extern SPI_HandleTypeDef hspi1;
  5. #define TEST_BYTE0  0xAB
  6. #define SPI_ADDRESS 0x0005
  7. #define SPI1_CS     GPIO_PIN_0
  8. // W25X20CL instructions
  9. const uint8_t EEPROM_READ  = 0b00000011;
  10. const uint8_t EEPROM_WRITE = 0b00000010;
  11. const uint8_t EEPROM_WRDI  = 0b00000100;
  12. const uint8_t EEPROM_WREN  = 0b00000110;
  13. const uint8_t EEPROM_RDSR  = 0b00000101;
  14. const uint8_t EEPROM_WRSR  = 0b00000001;
  15. // Function prototypes
  16. void SPI_NOR_WriteByte(uint8_t data, uint32_t address);
  17. uint8_t SPI_NOR_ReadByte(uint32_t address);
  18. void EEPROM_test(void) {
  19.     // Initialize the SPI peripheral
  20.     printf("W25X20CL NOR FLASH - SPI1 Test\r\n"); // going to serial port
  21.     // Read and write data to SPI NOR flash
  22.     uint32_t address   = SPI_ADDRESS;  // Address in the flash memory
  23.     uint8_t write_data = TEST_BYTE0;
  24.     uint8_t read_data;
  25.   // CS pin should default high
  26.   while(1) {   // Writing forever same pattern all the time
  27.       SPI_NOR_WriteByte(write_data, address); // Write data to SPI NOR flash
  28.       read_data = SPI_NOR_ReadByte(address); // Read data from SPI NOR flash
  29.       if(read_data != TEST_BYTE0) {
  30.         printf("SPI Test FAILED\r\n");
  31.         printf("0x%x!=0x%x \r\n", read_data, TEST_BYTE0);
  32.        } 
  33.       else {
  34.          printf("SPI Test PASSED\r\n");
  35.          printf("0x%x \r\n", read_data);
  36.        }
  37.      HAL_Delay (50);  // Write cycle delay (5ms)
  38.   }
  39. }
  40. void SPI_NOR_WriteByte(uint8_t data, uint32_t address) {
  41.   // Send the Write Enable (WREN) command
  42.     // This command is specific to the flash memory manufacturer (Winbond)
  43.     // Refer to the flash memory datasheet for the correct command code
  44.     uint8_t cmd_wren = EEPROM_WREN;
  45.   // Enable the chip select (CS) for the SPI NOR flash
  46.     HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);
  47.     HAL_SPI_Transmit(&hspi1, &cmd_wren, 1, HAL_MAX_DELAY);
  48.  
  49.     // Send the Write (WRITE) command
  50.     // Also, send the 3-byte address
  51.     uint8_t cmd_write = EEPROM_WRITE;
  52.     HAL_SPI_Transmit(&hspi1, &cmd_write, 1, HAL_MAX_DELAY);
  53.     HAL_SPI_Transmit(&hspi1, (uint8_t*)&address, 3, HAL_MAX_DELAY);
  54.     HAL_SPI_Transmit(&hspi1, &data, 1, HAL_MAX_DELAY);  // Send the data byte to be written
  55.     HAL_Delay (3);  // Write cycle delay (3ms)
  56.     HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);  // Disable the chip select (CS)
  57. }
  58. uint8_t SPI_NOR_ReadByte(uint32_t address) {
  59.     // Enable the chip select (CS) for the SPI NOR flash
  60.     HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);
  61.     // Send the Read (READ) command
  62.     // Also, send the 3-byte address
  63.     uint8_t cmd_read = EEPROM_READ;
  64.     HAL_SPI_Transmit(&hspi1, &cmd_read, 1, HAL_MAX_DELAY);
  65.     HAL_SPI_Transmit(&hspi1, (uint8_t*)&address, 3, HAL_MAX_DELAY);
  66.     // Receive the data byte
  67.     uint8_t read_data;
  68.     HAL_SPI_Receive(&hspi1, &read_data, 1, HAL_MAX_DELAY);
  69.     HAL_Delay (3);  // Write cycle delay (3ms)
  70.     HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);  // Disable the chip select (CS)
  71.     return read_data;
  72. }

static void MX_SPI1_Init(void) {

/* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x0;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK) {
    Error_Handler();
  }
}

int main(void){
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* Configure the system clock */
  SystemClock_Config();
  ..
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
 ...
  MX_SPI1_Init();
 ...
  while (1)  {
    /* USER CODE END WHILE */
  }
}
 
1 ACCEPTED SOLUTION

Accepted Solutions
aahsan
Associate III

Finally, it is working for me, tried to put up reference and instructions in the attached .pdf file.

View solution in original post

7 REPLIES 7
aahsan
Associate III

Simplified the program to just read the Manufacturer ID instead of write/read using 0x92 command

Code to Read the ID

  while(1) {

    HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);  // CS LOW

    // Write command 0x92 followed by 3 zeros    
    masterToSlave = HAL_SPI_Transmit(&hspi1, (uint8_t *)&EEPROM_MRID, 1, 100);
    masterToSlave = HAL_SPI_Transmit(&hspi1, (uint8_t *)&zero, 1, 100);
    masterToSlave = HAL_SPI_Transmit(&hspi1, (uint8_t *)&zero, 1, 100);
    masterToSlave = HAL_SPI_Transmit(&hspi1, (uint8_t *)&zero, 1, 100);
 while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY)  // wait for HAL Active

    // read ID
    slaveToMaster = HAL_SPI_Receive(&hspi1, (uint8_t *)&manufactureID, 1, 100);
    slaveToMaster = HAL_SPI_Receive(&hspi1, (uint8_t *)&deviceId, 1, 100);

    HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);      // CS HIGH
    printf("mID: 0x%x %x\r\n",manufactureID, deviceId);   // print ids
  HAL_Delay(10);
  }

0x64 and 0xF0 is read back as manufactureID and deviceID

aahsan_2-1694811951847.pngaahsan_3-1694811993588.png

Here is what I see on the Scope.

aahsan_4-1694812050760.png

Please let me know if there is anything, I am missing.

Use the HAL_SPI_TransmitReceive(), Identify traces, don't be using DUAL mode for single bit SPI, would explain the wrong levels on the Purple trace as both ST and WINBOND are trying to drive the same pin.

Use the 0x9F command (JEDEC ID). send 0x9F, then recover responses to sending 3 zeros.

Bus is symmetrical, the write clocks, data goes out on one edge, read back on the other.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
aahsan
Associate III

Thanks! I tried 

  1. 0x90 --> Read Manufacturer ID
  2. 0x4B --> Read Unique Id
  3. 0x9F --> JEDEC Read (Device ID, Capacity and Memory Type)
    These seems to work, here is the response i am getting back
    aahsan_0-1694887883616.png

    Still having issue reading back Status Register and Write/Read command, really appreciate the response, here is the code I am using


     //0x05 --> Read STATUS Register
     HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);
     HAL_SPI_Transmit(&hspi1, &FLASH_RDSR, 1, 1000);
     HAL_SPI_Receive(&hspi1, (uint8_t *)&statusReg[0], 1, 100);
    HAL_SPI_Receive(&hspi1, (uint8_t *)&statusReg[1], 1, 100);
    HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);
    printf("Status Register: 0x%x%x\r\n",statusReg[0], statusReg[1]);

    // Write Data
    HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET); // Enable chip select (CS) for SPI FLASH
    spi_buf[0] = 0x02; // Write command
    spi_buf[1] = 0x00; // address
    spi_buf[2] = 0x00; // address
    spi_buf[3] = 0x04; // address
    spi_buf[4] = 0x55; // data
    spi_buf[5] = 0x55; // data
    HAL_SPI_Transmit(&hspi1, &FLASH_WREN, 1, HAL_MAX_DELAY);
    HAL_SPI_Transmit(&hspi1, spi_buf, 6, HAL_MAX_DELAY);       // Send the Write (WRITE) command
    HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);        // Disable the chip select (CS)
     
    // Read Back Data
    HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);   // Enable chip select (CS) for SPI FLASH
     uint8_t read_data[2];
     spi_buf[0] = 0x03;  // write command
     HAL_SPI_Transmit(&hspi1, spi_buf, 4, HAL_MAX_DELAY);          // Send the Read (READ) command
     HAL_SPI_Receive(&hspi1, read_data, 2, HAL_MAX_DELAY);      // Receive the data byte
     HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);             // Disable the chip select (CS)
     printf("Data Read %x %x from %x Address\r\n",read_data[0],read_data[1], address);
    Please let me know if you see some issue here, Thanks in advance

I would make sure the SPI register has been sent before raising SPI1_CS

I would raise SPI1_CS after sending WREN command is sent. With some delay between it going high before going low again.

Print the two SR1 / SR2 values with separation or %02X %02X forms. When writing check for completion. WREN bit should reflect in SR1.WEL

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
aahsan
Associate III

I will update it as below and try it on Monday, Hope this will work,
Please let me know if you see some issue here

// Write Data
HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET); // Enable chip select (CS) for SPI FLASH
HAL_SPI_Transmit(&hspi1, &FLASH_WREN, 1, HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);  // Disable the chip select (CS)
spi_buf[0] = 0x02; // Write command
spi_buf[1] = 0x00; // address
spi_buf[2] = 0x00; // address
spi_buf[3] = 0x04; // address
spi_buf[4] = 0x55; // data
spi_buf[5] = 0x55; // data
HAL_Delay_us(1); // 1usec delay
HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET); // Enable chip select (CS) for SPI FLASH
HAL_SPI_Transmit(&hspi1, spi_buf, 6, HAL_MAX_DELAY);       // Send the Write (WRITE) command
HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);        // Disable the chip select (CS)
 
// Read Back Data
HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);   // Enable chip select (CS) for SPI FLASH
 uint8_t read_data[2];
 spi_buf[0] = 0x03;  // write command
 HAL_SPI_Transmit(&hspi1, spi_buf, 4, HAL_MAX_DELAY);          // Send the Read (READ) command
 HAL_SPI_Receive(&hspi1, read_data, 2, HAL_MAX_DELAY);      // Receive the data byte
 HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);             // Disable the chip select (CS)
 printf("Data Read %08X %08X from %08X Address\r\n",read_data[0],read_data[1], address);

 //0x05 --> Read STATUS Register
 HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_RESET);
 HAL_SPI_Transmit(&hspi1, &FLASH_RDSR, 1, 1000);
 HAL_SPI_Receive(&hspi1, (uint8_t *)&statusReg[0], 1, 100);
HAL_SPI_Receive(&hspi1, (uint8_t *)&statusReg[1], 1, 100);
HAL_GPIO_WritePin(GPIOB, SPI1_CS, GPIO_PIN_SET);
printf("Status Register: 0x%02X %02X\r\n",statusReg[0], statusReg[1]);

I would suggest using subroutines. Pass and decompose the address into the command bytes buffer.

You should spin after the WRITE (0x02) command, reading SR1 until SR1.BUSY goes back to zero, then do the READ (0x03).

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
aahsan
Associate III

Finally, it is working for me, tried to put up reference and instructions in the attached .pdf file.