• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Esp32 + fatfs + external flash

in_text

New member
Привет всем кто забрёл поинтересоваться
:)

Задача на первый взгляд достаточно проста, мне нужно читать/создавать/удалять файлы которые находятся на внешней флеш памяти на которой стоит файловая система ФАТ. Сразу скажу что использование внутренней флеш памяти мне не подходит - у меня требование именно к использованию внешней памяти.
Искал и находил много библиотек, но ни одна из них не была заточена конкретно под ESP32, мне кажется что проблема с инициализацией SPI. Не важно какой именно использовать, железный или софтовый, главное чтобы флешка читалась и было видно файлы.
Может у кто-то сталкивался с подобной задачей и может подсказать?
P.S. флеш-память W25Q64

Всем спасибо кто откликнется
:)
 

ewogs30

New member
Значит для этого придётся писать свой драйвер флешки, но я делал подобное для STM32, но там общение с флешкой шло через spiflash_execute, которое и работало с SPI.
Вот код, который содержит функцию spiflash_execute, и фуннкции fatfs для доступа к накопителю

C:
void spiflash_execute(uint8_t cmd, uint8_t *idata, int idatalen, uint8_t *odata, int odatalen) {
    // flash_cs = low
    
    // spi_write (cmd)
    
    while (idatalen--) {
        // spi_write (*idata++)
    }
    
    while (odatalen--) {
        // *odata++ = spi_read()
    }
    
    // flash_cs = high
}

DRESULT disk_read(BYTE drv, BYTE *buff, LBA_t lba, UINT count) {
    switch (drv) {
        case 0:
        {
            BYTE adr[3];
            
            adr[0] = ((lba*4096)>>16)&255;
            adr[1] = ((lba*4096)>>8 )&255;
            adr[2] = ((lba*4096)>>0 )&255;
            
            spiflash_execute(0x03, adr, 3, buff, count * 4096);
        return RES_OK;}
    }
    return RES_PARERR;
}

DRESULT disk_write(BYTE drv, const BYTE *dat, LBA_t lba, UINT cnt) {
    switch (drv) {
        case 0:
        {
            uint8_t bpos[259];
            int i;
            // erase
            for (i = 0; i < cnt; i++){
                bpos[2] = ((lba+i)*4096);
                bpos[1] = ((lba+i)*4096)>>8;
                bpos[0] = ((lba+i)*4096)>>16;
                
                spiflash_execute(0x06, 0, 0, 0, 0); // writeenable
                spiflash_execute(0x20, &bpos, 3, 0, 0); // erase sector
                while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1);
            }
            
            for (i = 0; i < (cnt * 16); i++){
                bpos[2] = (lba*4096)+(i*256);
                bpos[1] = ((lba*4096)+(i*256))>>8;
                bpos[0] = ((lba*4096)+(i*256))>>16;
                
                memcpy(&bpos[3], &dat[i*256], 256);
                spiflash_execute(0x06, 0, 0, 0, 0); // writeenable
                spiflash_execute(0x02, (void*)&bpos, 259, 0, 0); // write data
                while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1);
            }
            
            return RES_OK;
        }
    }
    return RES_PARERR;
}
Если всё вынести в отдельные функции, то будет
C:
void spiflash_execute(uint8_t cmd, uint8_t *idata, int idatalen, uint8_t *odata, int odatalen) {

    // flash_cs = low  

    // spi_write (cmd)

    while (idatalen--) {

        // spi_write (*idata++)

    }

    while (odatalen--) {

        // *odata++ = spi_read()

    }

    // flash_cs = high

}

void spiflash_read(int lba, int cnt, uint8_t *data) {
  uint8_t adr[3];
  adr[0] = ((lba*4096)>>16)&255; // 23..16
  adr[1] = ((lba*4096)>>8 )&255; // 15..8
  adr[2] = ((lba*4096)>>0 )&255; //  8..0
            
  spiflash_execute(0x03, adr, 3, buff, count * 4096);
}

void spiflash_write(int lba, int cnt, uint8_t *data) {
  uint8_t bpos[259];
  int i;
  // стереть сектора
  for (i = 0; i < cnt; i++){
      bpos[0] = ((lba*4096)>>16)&255; // 23..16
      bpos[1] = ((lba*4096)>>8 )&255; // 15..8
      bpos[2] = ((lba*4096)>>0 )&255; //  8..0

      spiflash_execute(0x06, 0, 0, 0, 0); // разрешить запись
      spiflash_execute(0x20, &bpos, 3, 0, 0); // стереть сектор
      while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1); // ждать пока сектор не сотрётся
    }
    // записать сектора
    for (i = 0; i < (cnt * 16); i++){
        bpos[0] = ((lba*4096)>>16)&255; // 23..16
        bpos[1] = ((lba*4096)>>8 )&255; // 15..8
        bpos[2] = ((lba*4096)>>0 )&255; //  8..0

        memcpy(&bpos[3], &dat[i*256], 256);
        spiflash_execute(0x06, 0, 0, 0, 0); // разрешить запись
        spiflash_execute(0x02, (void*)&bpos, 259, 0, 0); // записать 256 байт
        while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1); // ждать пока не запишется
    }
}
и потом можно их использовать.
Правда мой код заточен под работу с секторами в 4096 байт, так как это минимальный размер, который можно стереть, а выдумывать что-то для работы с секторами в 512 байт было нецелесообразно.
 

in_text

New member
Значит для этого придётся писать свой драйвер флешки, но я делал подобное для STM32, но там общение с флешкой шло через spiflash_execute, которое и работало с SPI.
Вот код, который содержит функцию spiflash_execute, и фуннкции fatfs для доступа к накопителю

C:
void spiflash_execute(uint8_t cmd, uint8_t *idata, int idatalen, uint8_t *odata, int odatalen) {
    // flash_cs = low
   
    // spi_write (cmd)
   
    while (idatalen--) {
        // spi_write (*idata++)
    }
   
    while (odatalen--) {
        // *odata++ = spi_read()
    }
   
    // flash_cs = high
}

DRESULT disk_read(BYTE drv, BYTE *buff, LBA_t lba, UINT count) {
    switch (drv) {
        case 0:
        {
            BYTE adr[3];
           
            adr[0] = ((lba*4096)>>16)&255;
            adr[1] = ((lba*4096)>>8 )&255;
            adr[2] = ((lba*4096)>>0 )&255;
           
            spiflash_execute(0x03, adr, 3, buff, count * 4096);
        return RES_OK;}
    }
    return RES_PARERR;
}

DRESULT disk_write(BYTE drv, const BYTE *dat, LBA_t lba, UINT cnt) {
    switch (drv) {
        case 0:
        {
            uint8_t bpos[259];
            int i;
            // erase
            for (i = 0; i < cnt; i++){
                bpos[2] = ((lba+i)*4096);
                bpos[1] = ((lba+i)*4096)>>8;
                bpos[0] = ((lba+i)*4096)>>16;
               
                spiflash_execute(0x06, 0, 0, 0, 0); // writeenable
                spiflash_execute(0x20, &bpos, 3, 0, 0); // erase sector
                while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1);
            }
           
            for (i = 0; i < (cnt * 16); i++){
                bpos[2] = (lba*4096)+(i*256);
                bpos[1] = ((lba*4096)+(i*256))>>8;
                bpos[0] = ((lba*4096)+(i*256))>>16;
               
                memcpy(&bpos[3], &dat[i*256], 256);
                spiflash_execute(0x06, 0, 0, 0, 0); // writeenable
                spiflash_execute(0x02, (void*)&bpos, 259, 0, 0); // write data
                while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1);
            }
           
            return RES_OK;
        }
    }
    return RES_PARERR;
}
Если всё вынести в отдельные функции, то будет
C:
void spiflash_execute(uint8_t cmd, uint8_t *idata, int idatalen, uint8_t *odata, int odatalen) {

    // flash_cs = low 

    // spi_write (cmd)

    while (idatalen--) {

        // spi_write (*idata++)

    }

    while (odatalen--) {

        // *odata++ = spi_read()

    }

    // flash_cs = high

}

void spiflash_read(int lba, int cnt, uint8_t *data) {
  uint8_t adr[3];
  adr[0] = ((lba*4096)>>16)&255; // 23..16
  adr[1] = ((lba*4096)>>8 )&255; // 15..8
  adr[2] = ((lba*4096)>>0 )&255; //  8..0
           
  spiflash_execute(0x03, adr, 3, buff, count * 4096);
}

void spiflash_write(int lba, int cnt, uint8_t *data) {
  uint8_t bpos[259];
  int i;
  // стереть сектора
  for (i = 0; i < cnt; i++){
      bpos[0] = ((lba*4096)>>16)&255; // 23..16
      bpos[1] = ((lba*4096)>>8 )&255; // 15..8
      bpos[2] = ((lba*4096)>>0 )&255; //  8..0

      spiflash_execute(0x06, 0, 0, 0, 0); // разрешить запись
      spiflash_execute(0x20, &bpos, 3, 0, 0); // стереть сектор
      while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1); // ждать пока сектор не сотрётся
    }
    // записать сектора
    for (i = 0; i < (cnt * 16); i++){
        bpos[0] = ((lba*4096)>>16)&255; // 23..16
        bpos[1] = ((lba*4096)>>8 )&255; // 15..8
        bpos[2] = ((lba*4096)>>0 )&255; //  8..0

        memcpy(&bpos[3], &dat[i*256], 256);
        spiflash_execute(0x06, 0, 0, 0, 0); // разрешить запись
        spiflash_execute(0x02, (void*)&bpos, 259, 0, 0); // записать 256 байт
        while (spiflash_execute(0x05, 0, 0, &bpos, 1), bpos[0]&1); // ждать пока не запишется
    }
}
и потом можно их использовать.
Правда мой код заточен под работу с секторами в 4096 байт, так как это минимальный размер, который можно стереть, а выдумывать что-то для работы с секторами в 512 байт было нецелесообразно.
Спасибо, сектор в моей памяти тоже занимает 4КБ, а одна страница занимает 256 байт. Процесс записи выглядит немного страшно, прочитать весь сектор, обновить данные и записать всё это обратно, но такова структура памяти. За помощь спасибо!
 
Сверху Снизу