wiringPi_Blueberry/wiringPi/w25q64.c

363 lines
9.4 KiB
C
Raw Normal View History

2023-08-11 15:53:17 +08:00
//
// Flash Memory W25Q64 Access Library for RaspberryPi
//
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include "w25q64.h"
#define SPI_SLAVE_SEL_PIN 10 // チップセレクトピン番号
#define MAX_BLOCKSIZE 128 // ブロック総数
#define MAX_SECTORSIZE 2048 // 総セクタ数
#define CMD_WRIRE_ENABLE 0x06
#define CMD_WRITE_DISABLE 0x04
#define CMD_READ_STATUS_R1 0x05
#define CMD_READ_STATUS_R2 0x35
#define CMD_WRITE_STATUS_R 0x01 // 未実装
#define CMD_PAGE_PROGRAM 0x02
#define CMD_QUAD_PAGE_PROGRAM 0x32 // 未実装
#define CMD_BLOCK_ERASE64KB 0xd8
#define CMD_BLOCK_ERASE32KB 0x52
#define CMD_SECTOR_ERASE 0x20
#define CMD_CHIP_ERASE 0xC7
#define CMD_ERASE_SUPPEND 0x75 // 未実装
#define CMD_ERASE_RESUME 0x7A // 未実装
#define CMD_POWER_DOWN 0xB9
#define CMD_HIGH_PERFORM_MODE 0xA3 // 未実装
#define CMD_CNT_READ_MODE_RST 0xFF // 未実装
#define CMD_RELEASE_PDOWN_ID 0xAB // 未実装
#define CMD_MANUFACURER_ID 0x90
#define CMD_READ_UNIQUE_ID 0x4B
#define CMD_JEDEC_ID 0x9f
#define CMD_READ_DATA 0x03
#define CMD_FAST_READ 0x0B
#define CMD_READ_DUAL_OUTPUT 0x3B // 未実装
#define CMD_READ_DUAL_IO 0xBB // 未実装
#define CMD_READ_QUAD_OUTPUT 0x6B // 未実装
#define CMD_READ_QUAD_IO 0xEB // 未実装
#define CMD_WORD_READ 0xE3 // 未実装
#define SR1_BUSY_MASK 0x01
#define SR1_WEN_MASK 0x02
//#define SPI_CHANNEL 0 // /dev/spidev0.0
#define SPI_CHANNEL 1 // /dev/spidev0.1
//static uint8_t cspin ;
static uint8_t _spich;
void spcDump(char *id,int rc, uint8_t *data,int len) {
int i;
printf("[%s] = %d\n",id,rc);
for(i=0;i<len;i++) {
printf("%0x ",data[i]);
if ( (i % 10) == 9) printf("\n");
}
printf("\n");
}
//
// フラッシュメモリ W25Q64の利用開始
//
//void W25Q64_begin(uint8_t cs) {
void W25Q64_begin(uint8_t spich) {
_spich = spich;
}
//
// ステータスレジスタ1の値取得
// 戻り値: ステータスレジスタ1の値
//
uint8_t W25Q64_readStatusReg1(void) {
uint8_t data[2];
int rc;
data[0] = CMD_READ_STATUS_R1;
data[1] = 0xff;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("readStatusReg1",rc,data,2);
return data[1];
}
//
// ステータスレジスタ2の値取得
// 戻り値: ステータスレジスタ2の値
//
uint8_t W25Q64_readStatusReg2(void) {
uint8_t data[2];
int rc;
data[0] = CMD_READ_STATUS_R2;
data[1] = 0xff;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("readStatusReg2",rc,data,2);
return data[1];
}
//
// JEDEC ID(Manufacture, Memory Type,Capacity)の取得
// d(out) :Manufacture, Memory Type,Capacityのバイトを格納する
//
void W25Q64_readManufacturer(uint8_t* d) {
uint8_t data[4];
int rc;
memset(data,0,sizeof(data));
data[0] = CMD_JEDEC_ID;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("readManufacturer",rc,data,4);
memcpy(d,&data[1],3);
}
//
// Unique IDの取得
// d(out): Unique ID 7バイトを返す
//
void W25Q64_readUniqieID(uint8_t* d) {
uint8_t data[12];
int rc;
memset(data,0,sizeof(data));
data[0] = CMD_READ_UNIQUE_ID;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("readUniqieID",rc,data,12);
memcpy(d,&data[5],7);
}
//
// 書込み等の処理中チェック
// 戻り値: true:作業 、false:アイドル中
//
bool W25Q64_IsBusy() {
uint8_t data[2];
int rc;
data[0] = CMD_READ_STATUS_R1;
data[1] = 0xff;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("IsBusy",rc,data,2);
uint8_t r1;
r1 = data[1];
if(r1 & SR1_BUSY_MASK)
return true;
return false;
}
//
// パワーダウン指定
//
void W25Q64_powerDown(void) {
uint8_t data[1];
int rc;
data[0] = CMD_POWER_DOWN;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("powerDown",rc,data,1);
}
//
// 書込み許可設定
//
void W25Q64_WriteEnable(void) {
uint8_t data[1];
int rc;
data[0] = CMD_WRIRE_ENABLE;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("WriteEnable",rc,data,1);
}
//
// 書込み禁止設定
//
void W25Q64_WriteDisable(void) {
uint8_t data[1];
int rc;
data[0] = CMD_WRITE_DISABLE;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// spcDump("WriteDisable",rc,data,1);
}
//
// データの読み込み
// addr(in): 読込開始アドレス (24ビット 0x000000 - 0xFFFFFF)
// n(in):読込データ数
//
uint16_t W25Q64_read(uint32_t addr,uint8_t *buf,uint16_t n){
uint8_t *data;
int rc;
data = (char*)malloc(n+4);
data[0] = CMD_READ_DATA;
data[1] = (addr>>16) & 0xFF; // A23-A16
data[2] = (addr>>8) & 0xFF; // A15-A08
data[3] = addr & 0xFF; // A07-A00
rc = wiringPiSPIDataRW (_spich,data,n+4);
// spcDump("read",rc,data,rc);
memcpy(buf,&data[4],n);
free(data);
return rc-4;
}
//
// 高速データの読み込み
// addr(in): 読込開始アドレス (24ビット 0x00000 - 0xFFFFF)
// n(in):読込データ数
//
uint16_t W25Q64_fastread(uint32_t addr,uint8_t *buf,uint16_t n) {
uint8_t *data;
int rc;
data = (char*)malloc(n+5);
data[0] = CMD_FAST_READ;
data[1] = (addr>>16) & 0xFF; // A23-A16
data[2] = (addr>>8) & 0xFF; // A15-A08
data[3] = addr & 0xFF; // A07-A00
data[4] = 0;
rc = wiringPiSPIDataRW (_spich,data,n+5);
// spcDump("fastread",rc,data,rc);
memcpy(buf,&data[5],n);
return rc-5;
}
//
// セクタ単位消去(4kb空間単位でデータの消去を行う)
// sect_no(in) セクタ番号(0 - 2048)
// flgwait(in) true:処理待ちを行う false:待ち無し
// 戻り値: true:正常終了 false:失敗
// 補足: データシートでは消去に通常 30ms 、最大400msかかると記載されている
// アドレス23ビットのうち上位 11ビットがセクタ番号の相当する。下位12ビットはセクタ内アドレスとなる。
//
bool W25Q64_eraseSector(uint16_t sect_no, bool flgwait) {
uint8_t data[4];
int rc;
uint32_t addr = sect_no;
addr<<=12;
W25Q64_WriteEnable();
data[0] = CMD_SECTOR_ERASE;
data[1] = (addr>>16) & 0xff;
data[2] = (addr>>8) & 0xff;
data[3] = addr & 0xff;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// 処理待ち
while(W25Q64_IsBusy() & flgwait) {
delay(10);
}
return true;
}
//
// 64KBブロック単位消去(64kb空間単位でデータの消去を行う)
// blk_no(in) ブロック番号(0 - 127)
// flgwait(in) true:処理待ちを行う false:待ち無し
// 戻り値: true:正常終了 false:失敗
// 補足: データシートでは消去に通常 150ms 、最大1000msかかると記載されている
// アドレス23ビットのうち上位 7ビットがブロックの相当する。下位16ビットはブロック内アドレスとなる。
//
bool W25Q64_erase64Block(uint16_t blk_no, bool flgwait) {
uint8_t data[4];
int rc;
uint32_t addr = blk_no;
addr<<=16;
W25Q64_WriteEnable();
data[0] = CMD_BLOCK_ERASE64KB;
data[1] = (addr>>16) & 0xff;
data[2] = (addr>>8) & 0xff;
data[3] = addr & 0xff;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// 処理待ち
while(W25Q64_IsBusy() & flgwait) {
delay(50);
}
return true;
}
//
// 32KBブロック単位消去(32kb空間単位でデータの消去を行う)
// blk_no(in) ブロック番号(0 - 255)
// flgwait(in) true:処理待ちを行う false:待ち無し
// 戻り値: true:正常終了 false:失敗
// 補足: データシートでは消去に通常 120ms 、最大800msかかると記載されている
// アドレス23ビットのうち上位 8ビットがブロックの相当する。下位15ビットはブロック内アドレスとなる。
//
bool W25Q64_erase32Block(uint16_t blk_no, bool flgwait) {
uint8_t data[4];
int rc;
uint32_t addr = blk_no;
addr<<=15;
W25Q64_WriteEnable();
data[0] = CMD_BLOCK_ERASE32KB;
data[1] = (addr>>16) & 0xff;
data[2] = (addr>>8) & 0xff;
data[3] = addr & 0xff;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// 処理待ち
while(W25Q64_IsBusy() & flgwait) {
delay(50);
}
return true;
}
//
// 全領域の消去
// flgwait(in) true:処理待ちを行う false:待ち無し
// 戻り値: true:正常終了 false:失敗
// 補足: データシートでは消去に通常 15s 、最大30sかかると記載されている
//
bool W25Q64_eraseAll(bool flgwait) {
uint8_t data[1];
int rc;
W25Q64_WriteEnable();
data[0] = CMD_CHIP_ERASE;
rc = wiringPiSPIDataRW (_spich,data,sizeof(data));
// 処理待ち
while(W25Q64_IsBusy() & flgwait) {
delay(500);
}
return true;
}
// データの書き込み
// sect_no(in) : セクタ番号(0x00 - 0x7FF)
// inaddr(in) : セクタ内アドレス(0x00-0xFFF)
// data(in) : 書込みデータ格納アドレス
// n(in) : 書込みバイト数(0256)
//
uint16_t W25Q64_pageWrite(uint16_t sect_no, uint16_t inaddr, uint8_t* buf, uint8_t n) {
// uint8_t data[4];
uint8_t *data;
int rc;
uint32_t addr = sect_no;
int i;
addr<<=12;
addr += inaddr;
W25Q64_WriteEnable();
if (W25Q64_IsBusy()) {
return 0;
}
data = (char*)malloc(n+4);
data[0] = CMD_PAGE_PROGRAM;
data[1] = (addr>>16) & 0xff;
data[2] = (addr>>8) & 0xff;
data[3] = addr & 0xFF;
memcpy(&data[4],buf,n);
rc = wiringPiSPIDataRW (_spich,data,n+4);
// spcDump("pageWrite",rc,buf,n);
while(W25Q64_IsBusy()) ;
free(data);
return rc;
}