espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.89k stars 7.33k forks source link

Winbond: esp_flash_read_chip_id reads unaligned CHIP_ID (IDFGH-7993) #9503

Closed KonssnoK closed 1 year ago

KonssnoK commented 2 years ago

Using ESP32S3 Using Winbond W25N01GVZEIG Using ESP-IDF v4.4.2

If we initialize the Flash using esp-idf provided libraries we read the following wrong output:

I (00:02:52.523) spi_flash: trying chip: issi
I (00:02:52.527) spi_flash: trying chip: gd
I (00:02:52.532) spi_flash: trying chip: mxic
I (00:02:52.537) spi_flash: trying chip: winbond
I (00:02:52.542) spi_flash: trying chip: boya
I (00:02:52.547) spi_flash: trying chip: th
I (00:02:52.552) spi_flash: trying chip: mxic (opi)
I (00:02:52.558) spi_flash: trying chip: generic
I (00:02:52.563) spi_flash: detected chip: generic
I (00:02:52.568) spi_flash: flash io: fastrd
I (00:02:52.573) winbond: Chip driver: 'generic', device ID: 0xFFEFAA

Instead of 0xFFEFAA the Chip ID should be 0xEFAA21. If we use custom code and just the SPI bus we are able to read the correct CHIP_ID. We cannot use our custom code because we would like to use the wear leveling implementation from IDF.

We tried changing speed, input_delay, DMA enabled, and to follow the code until the general purpose spi command.

Here is the initialization code we used for using the flash apis:

    esp_err_t r;
    struct {
        uint32_t id;
        esp_flash_t* dev;
        esp_partition_t const* part;
    } flash;

    spi_bus_config_t bus_cfg = {
        .mosi_io_num = CONFIG_NAND_MOSI_GPIO,
        .miso_io_num = CONFIG_NAND_MISO_GPIO,
        .sclk_io_num = CONFIG_NAND_SCK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = NAND_COLUMN_SIZE,
    };

    /* initialize the SPI bus */
    r = spi_bus_initialize(SPI3_HOST, &bus_cfg, SPI_DMA_CH_AUTO);
    if (ESP_OK == r) {
        const esp_flash_spi_device_config_t dev_cfg = {
            .host_id = SPI3_HOST,
            .cs_id = 0,
            .cs_io_num = CONFIG_NAND_CS_GPIO,
            .io_mode = SPI_FLASH_FASTRD,
            .speed = ESP_FLASH_5MHZ,
            .input_delay_ns = 10,
            };

        r = spi_bus_add_flash_device(&flash.dev, &dev_cfg);
        if (ESP_OK == r) {
            r = esp_flash_init(flash.dev);
            if (ESP_OK == r) {
                r = esp_flash_read_id(flash.dev, &flash.id);
            }
        }
    }

    if (ESP_OK == r) {
        ESP_LOGI(
            "winbond",
            "Chip driver: '%s', device ID: 0x%X",
            flash.dev->chip_drv->name,
            flash.id
            );
    } else {
        ESP_LOGE("winbond", "external flash initialization failed (%d)", r);
    }

Here is the extract from our custom code for reading the chip id which works:

error_t nand_spi_init(void)
{
    gpio_set_level(CONFIG_NAND_CS_GPIO, 1);
    gpio_config_t cs_cfg = {
        .pin_bit_mask = BIT64(CONFIG_NAND_CS_GPIO),
        .mode = GPIO_MODE_OUTPUT,
    };
    gpio_config(&cs_cfg);

    error_t err;
    spi_bus_config_t buscfg = {
        .mosi_io_num = CONFIG_NAND_MOSI_GPIO,
        .miso_io_num = CONFIG_NAND_MISO_GPIO,
        .sclk_io_num = CONFIG_NAND_SCK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = NAND_COLUMN_SIZE,
    };

    /* Initialize the SPI bus peripheral */
    err = spi_bus_initialize(NAND_HOST, &buscfg, SPI_DMA_CH_AUTO);
    if (err != SYS_OK) {
        return err;
    }

    spi_device_interface_config_t devcfg = {
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .clock_speed_hz = NAND_FLASH_CLK_FREQ,
        .mode = 0, /* SPI mode 0 */
        .spics_io_num = -1, //not used - handled manually
        .queue_size = 1,
        .flags = 0,
        .cs_ena_pretrans = 1,
        .cs_ena_posttrans = 1,
    };

    /* Attach a device to the SPI bus */
    return spi_bus_add_device(SPI3_HOST, &devcfg, &spi);
}

error_t nand_device_id(uint32_t* id)
{
    error_t r;
    /* read device ID: Manufacturer and Device Identification */
    uint8_t buff[5] = { NAND_JEDEC_ID, 0x00, 0x00, 0x00, 0x00 };
    r = nand_spi_command(buff, sizeof(buff), buff, sizeof(buff), false);
    if (SYS_OK == r) {
        *id = (buff[2] << 16) | (buff[3] << 8) | buff[4];
//        if ((buff[2] != WINBOND_MAN_ID) || (dev_id != W25N01GV_DEV_ID)) {
//            r = SYS_EOBJECT;
//        }
    }

    return r;
}

error_t nand_spi_command(
    const void* txbuf,
    size_t txlen,
    void* rxbuf,
    size_t rxlen,
    bool keep_cs
    )
{
    spi_transaction_t transaction = {
        .length = txlen * 8,    /* length in bits */
        .rxlength = rxlen * 8,  /* should be not greater than .length */
        .tx_buffer = txbuf,
        .rx_buffer = rxbuf,
    };

    if (transaction.length < transaction.rxlength) {
        return SYS_EINVAL;
    }

    gpio_set_level(CONFIG_NAND_CS_GPIO, 0);
    esp_err_t esp_err = spi_device_polling_transmit(spi, &transaction);
    if (!keep_cs) {
        gpio_set_level(CONFIG_NAND_CS_GPIO, 1);
    }
    return translate_error(esp_err);
}
KonssnoK commented 2 years ago

@johnboiles , saw you are using winbond flashes in a PR. Did you manage to use the esp_flash_init correctly? Meaning, do you manage to have idf choose the winbond driver for your flash? Or you see it going to the generic driver as in our case? (If you manage to initialize correctly, could you share the initialization settings?)

Thanks!

KonssnoK commented 2 years ago

Working on this. Apparently the difference between the SPi direct approach and the Flash_SPI driver is in the handling of the MISO pin.

The Flash driver is sending 4 bytes instead of 5 bytes, as requested by the JEDEC ID image

4 BYTES FLASH Driver (reading unaligned FF) image

5 BYTES SPI Driver (working) image

Also the ESP Flash driver MISO is 1 by default (?)

KonssnoK commented 2 years ago

Apparently some other chips do not have the 8 dummy clocks in the middle, some do... Considering winbond itself, which has both approaches

image image image

johnboiles commented 2 years ago

I'm using W25Q512JVEIQ and I have flash detection enabled and auto-detection worked fine for me out of the box (of course with the capacity detection fix in place). Perhaps this is something specific to the 1gbit chips?

Here are the logs I see:

D (1650) FLASH_HAL: extra_dummy: 0
V (1653) memspi: raw_chip_id: 2040EF

V (1656) memspi: chip_id: EF4020

V (1660) memspi: raw_chip_id: 2040EF

V (1664) memspi: chip_id: EF4020

D (1667) spi_flash: trying chip: issi
D (1671) spi_flash: trying chip: gd
D (1674) spi_flash: trying chip: mxic
D (1678) spi_flash: trying chip: winbond
I (1682) spi_flash: detected chip: winbond
I (1687) spi_flash: flash io: dio
KonssnoK commented 2 years ago

yes it's related to newest chips, which usually mean higher capacity. I think it's related to the command addressing line being 16 bits instead of 8, and this made them add 8 dummy bit clocks after the standard chip id command. As you can see above also macronix implements the same procedure.

KonssnoK commented 1 year ago

we detached from espressif flash libraries for these kind of chips.