目次: OpenOCD
いよいよ、正常に動かないSPI Flashの消去を見ます。消去は書き込みと違い大量にデータを書く必要がなく、ヘルパープログラムを使った実装はありません。前回紹介したJTAGでSPIを直接制御する方法(簡易版)と似た処理です。
SPI Flashの消去には3種類あります。ブロック消去に対応していないデバイスもあるようです。ややこしいことに統一された名前がないらしくて、メーカーによっては大きな消去単位をセクタと呼んでいます(Micronがそうだった)。なんじゃそりゃ、訳がわからんから統一してくれ〜。
細かい名前は覚えても意味がない(メーカーによって違うのでどうでも良い)ので、全部消す、大サイズで消す、小サイズで消す、くらいの理解で十分だと思います。
前置きはこれくらいにして、消去処理のコードを見ましょう。
// openocd/src/flash/nor/fespi.c
static int fespi_erase_sector(struct flash_bank *bank, int sector)
{
struct fespi_flash_bank *fespi_info = bank->driver_priv;
int retval;
retval = fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
if (retval != ERROR_OK)
return retval;
retval = fespi_txwm_wait(bank);
if (retval != ERROR_OK)
return retval;
if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK) //★CE# 信号をLowにする(負論理、処理の開始を示す)
return ERROR_FAIL;
retval = fespi_tx(bank, fespi_info->dev->erase_cmd); //★ブロック64K消去コマンド
if (retval != ERROR_OK)
return retval;
sector = bank->sectors[sector].offset;
retval = fespi_tx(bank, sector >> 16); //★アドレス
if (retval != ERROR_OK)
return retval;
retval = fespi_tx(bank, sector >> 8);
if (retval != ERROR_OK)
return retval;
retval = fespi_tx(bank, sector);
if (retval != ERROR_OK)
return retval;
retval = fespi_txwm_wait(bank); //★送信し終わるまで待つ
if (retval != ERROR_OK)
return retval;
if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK) //★CE# 信号をHighにする(負論理、処理の終了を示す)
return ERROR_FAIL;
retval = fespi_wip(bank, FESPI_MAX_TIMEOUT);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
ページ書き込みのときはコマンドが決め打ちでしたが、セクター消去ではコマンドが変数になっています。この変数が持つ値は、前回も紹介したSPI Flashのパラメータリストに載っています。もう一度掲載します。
// openocd/src/flash/nor/spi.c
const struct flash_device flash_devices[] = {
/* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id,
* pagesize, sectorsize, size_in_bytes */
FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000),
...
//★HiFive1が搭載しているFlash
FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
FLASH_ID("issi is25wp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018709d, 0x100, 0x10000, 0x1000000),
FLASH_ID("issi is25lp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019609d, 0x100, 0x10000, 0x2000000),
//★HiFive Unleashedが搭載しているFlash
FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),
...
HiFive Unleashedが搭載しているSPI Flashの品番はISSI IS25WP256Dですから、erase_cmdは0xdcです。SPI Flashのデータシートを見ると0xdcはBLOCK ERASE OPERATIONの4BER64Kコマンドです。
コードを見たときにお気づきかもしれませんが、SPI Flashの書き込みや消去で渡しているアドレスは3バイトしかなく、最大で16MBまでしか扱えません。一方HiFive Unleashedが搭載しているSPI Flashの容量は256Mbit = 32MBです。
足りないですね?どうやって16MB以降の消去や書き込みを行うのでしょうか?方法は3つあるようです。
OpenOCDは3番目を期待しているようです。なぜかというと4BER64Kコマンドは4バイトアドレスを期待するコマンドだからです。
データシートから抜粋したコマンドの仕様は上記の通りです。アドレスを4バイト送ってくることを期待しています。しかし実装は3バイトしかアドレスを送っていません。うーん、何かおかしいですね?
< | 2021 | > | ||||
<< | < | 07 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日: