/*******************************(i2c-EEPROM.c)**************
* I2C接続メモリ利用ライブラリ (24FC1025/M24M02)
***********************************************************/
#define ROM_24FC1025 0 // 値を0にするとdefinが無効となる
#define ROM_M24M02 2 // 値を0にするとdefinが無効となる
#define ROM_ADR 0x50
#define MBFSIZE 64 // メモリ操作用バッファーサイズ
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"
#include "i2c_SSD1306.h"
#include "ctype.h" // isxdigit()
#include "stdio.h" // puts(),..
#include "stdlib.h" // atoi()...
#include "string.h" // strtok()...
#include "myProject.h"
//=== グローバル変数 ========================
static char Dlm[] = ","; // 文字列区切りデリミタ
//--- I2Cメモリー用
static uint8_t Device = 0; // デバイス・ブロック番号
static uint32_t CrtAdr = 0; // カレントアドレス
static uint8_t DBuf[MBFSIZE+2]; // ページメモリ用バッファー
static uint8_t SqMode; // 連続モード(=1)か?
static char SBuf[31]; // 表示用(1行最大30文字)
static uint8_t LstCmd; // 現在(最終)のコマンド
static uint16_t LstChr = 0; // 最終表示文字
//static uint8_t fntPtn[32]; // フォントパターン用
/*********************************************
* I2C EEPROM function
**********************************************/
//---- デバイスのアドレス&ブロック計算
uint8_t calcDev(uint32_t adr){
uint8_t dv;
#if ROM_24FC1025
dv = ROM_ADR + (uint8_t)(adr >> 17);
if(adr & 0x10000) dv += 0x04;
#elif ROM_M24M02
dv = ROM_ADR + (uint8_t)(adr >> 16);
dv += 0x04; // E = high
#endif
return dv;
}
//----- アドレスadrから、1バイトを読み出す
uint8_t I2C_Mem_Read(uint32_t adr){
uint8_t bf[2];
if(adr<0x80000){ // 0-7FFFFH: EEPROM
Device = calcDev(adr);
bf[0] = (uint8_t)((adr & 0x1FFFF) >> 8);
bf[1] = (uint8_t)adr; // アドレスセット
I2C1_WriteNBytes(Device, bf, 2); // アドレス送信
I2C1_ReadNBytes(Device, bf, 1); // データ読込み
return bf[0];
}
return 0;
}
//----- アドレスadrに、1バイトdtを書き込む
void I2C_Mem_Write(uint32_t adr, uint8_t dt){
uint8_t bf[3];
if(adr<0x80000){ // 0-7FFFFH: EEPROM
Device = calcDev(adr);
bf[0] = (uint8_t)((adr & 0x1FFFF) >> 8);
bf[1] = (uint8_t)adr; // アドレスセット
bf[2] = dt; // データセット
I2C1_WriteNBytes(Device, bf, 3); //書き込む
__delay_ms(5);
}
}
//----- アドレスadrからnバイトをary[]に読み出す
void I2C_Mem_NRead(uint32_t adr, uint8_t *ary, uint8_t n){
uint8_t bf[2];
if(adr<0x80000){ // 0-7FFFFH: EEPROM
Device = calcDev(adr);
bf[0] = (uint8_t)((adr & 0x1FFFF) >> 8);
bf[1] = (uint8_t)adr; // アドレスセット
if(n > MBFSIZE) n = MBFSIZE;
I2C1_WriteNBytes(Device, bf, 2); // アドレス送信
I2C1_ReadNBytes(Device, ary, n); // nバイト読込み
}
}
//----- アドレスadrからary[]のnバイトを書き込む
void I2C_Mem_NWriteuint32_t adr, uint8_t *ary, uint8_t n){
uint8_t bf[MBFSIZE + 2];
if(adr<0x80000){ // 0-7FFFFH: EEPROM
Device = calcDev(adr);
bf[0] = (uint8_t)((adr & 0x1FFFF) >> 8);
bf[1] = (uint8_t)adr; // ページ境界に注意!
if(n > MBFSIZE) n = MBFSIZE;
memcpy(bf+2,ary,n); // ary[]をbf[]にコピー
I2C1_WriteNBytes(Device, bf, n+2); // nバイト書込み
__delay_ms(5);
}
}
/****** 汎用サブルーチン ********************/
//---- 16進文字列を10進数に変換
int32_t my_xtoi(char *str){
uint32_t dec;
dec = strtoul(str,NULL,16);
// if(errno == ERANGE) return -1; // 変換エラー
return (int32_t)dec;
}
// 16進数文字変換 uint16 -> str(Hex)
uint8_t my_utoa2(uint16_t n){
n &= 0x0F;
if(n < 10) return '0'+ (uint8_t)n;
else return 'A'+ ((uint8_t)n - 10);
}
void my_utoa(uint8_t *str, uint16_t wd, uint8_t dg){
if(dg > 3) *str++ = my_utoa2(wd >> 12);
if(dg > 2) *str++ = my_utoa2(wd >> 8);
if(dg > 1) *str++ = my_utoa2(wd >> 4);
*str++ = my_utoa2(wd);
*str = '\0';
}
//--- 文字列出力関数(標準出力へ)
void my_puts(char *str){ // 文字列のみ出力
while(*str) putch(*str++);
}
void my_putsLf(char *str){ // 次行に移動(LF)付き
my_puts(str);
putch('\r');
}
//---- ページバッファープリント
void prt_PBf(uint8_t *cBf, uint16_t n){
uint16_t i;
for(i = 0; i < n; i++){
if(i % 16 == 0) putch('\r');
my_utoa((uint8_t *)SBuf,cBf[i],2);
putch(SBuf[0]); putch(SBuf[1]); putch(' ');
if(i < 48){
if(i % 8 == 0) i2cOLED_posPX(i2cOLED_LF(),0);
strcat(SBuf," ");
i2cOLED_str(SBuf);
}
}
puts("\r");
}
//---- 20ビットアドレスと8ビットデータを16進数で文字列に格納
void sPrt_AdrDt(char *strP,uint32_t adr, uint8_t dt, char ch){
uint16_t a16;
uint8_t h;
h = (uint8_t)((adr>>16) & 0x0F);
*strP++ = my_utoa2(h);
a16 = (uint16_t)(adr & 0x0FFFF);
my_utoa((uint8_t *)strP,a16,4);
strP += 4;
*strP++ = ' '; *strP++ = ch; *strP++ =' ';
my_utoa((uint8_t *)strP,(uint16_t)dt,2);
strP += 2;
*strP = '\0';
}
//---- 20ビットアドレス1と20ビットアドレス2を16進数で文字列に格納
void sPrt_AdrAdr(char *strP,uint32_t adr1, uint32_t adr2, char ch){
uint16_t a16;
uint8_t h;
h = (uint8_t)((adr1>>16) & 0x0F);
*strP++ = my_utoa2(h);
a16 = (uint16_t)(adr1 & 0x0FFFF);
my_utoa((uint8_t *)strP,a16,4);
strP += 4;
*strP++ = ' '; *strP++ = ch; *strP++ =' ';
h = (uint8_t)((adr2>>16) & 0x0F);
*strP++ = my_utoa2(h);
a16 = (uint16_t)(adr2 & 0x0FFFF);
my_utoa((uint8_t *)strP,a16,4);
strP += 4;
*strP = '\0';
}
/*********************************************
* コマンドアクション
*********************************************/
//----- Wコマンド W[aaaa][,][d0,・・][,]
uint16_t i2cMem_cmd_W(char *str){
char *pt; // 文字列操作用ポインタ
uint8_t last; // 文字列の最後の位置
int32_t res = 0; // Hex文字数値変換結果
uint8_t dt = 0; // 書き込むバイトデータ
uint16_t cnt = 0; // 実際に書き込んだバイト数
LstCmd = str[0];
if(strlen(str)==1){ // 'W'のみなら
SqMode = 1; // 連続書込モードにセット
#ifndef VBA
puts("SqMode ON\n\r");
#endif
return 0; // データは書き込まない
}
last = (uint8_t)strlen(str)-1; // 文字列の行末位置を取得
if(str[last] == ','){ // 行末がコンマなら
SqMode = 1; // 連続書込モードにセット
#ifndef VBA
puts("SqMode ON\n\r");
#endif
str[last]='\0'; // 行末のコンマを消す
}
if(str[1]!=','){
pt = strtok(str+1,Dlm); // コマンドの次文字から
if(pt != NULL){ // アドレスデータがある
res = my_xtoi(pt);
// if(res < 0) return cnt; // 文字列変換エラー
CrtAdr = (uint32_t)res;
}
pt = strtok(NULL,Dlm); // 次文字列へ
}else{
pt= strtok(str+1,Dlm); // 文字列取得
}
i2cOLED_Clr(0,7,0);
do{
if(pt != NULL){
res = my_xtoi(pt);
// if(res < 0) return cnt;
dt = (uint8_t)res;
if(LstCmd=='W'){ // コマンドが'W'
I2C_Mem_Write(CrtAdr,dt);
}else if(LstCmd == 'S'){ // コマンドが'S'
DBuf[CrtAdr & 0x3F]= dt; // 64バイトまで
}
sPrt_AdrDt(SBuf,CrtAdr,dt,'<');
my_putsLf(SBuf);
i2cOLED_str(SBuf);
i2cOLED_posPX(i2cOLED_LF(),0);
CrtAdr++; cnt++;
pt = strtok(NULL,Dlm); // 次文字列へ
}
}while(pt != NULL);
return cnt;
}
//---- Rコマンド R[aaaa][,n]
uint16_t i2cMem_cmd_R(char *str){
char *pt; // 文字列操作用ポインタ
uint16_t n = 1; // 指定された読込バイト数
int32_t res = 0; // Hex文字数値変換結果
uint8_t dt; // 読み込んだバイトデータ
uint16_t cnt = 0; // 実際に読み出されたバイト数
uint8_t i; // ループ変数
LstCmd = str[0];
if(strlen(str) > 1){
if(str[1]==','){
pt = strtok(str+2,Dlm);
if(pt != NULL){ // 文字無し?
res = my_xtoi(pt);
// if(res < 0) return cnt;
n = (uint16_t)res;
}
}else{
pt = strtok(str+1,Dlm);
if(pt != NULL){ // addressがある?
res = my_xtoi(pt);
// if(res < 0) return cnt;
CrtAdr = (uint32_t)res;
}
pt = strtok(NULL,Dlm); // 次文字へ
if(pt != NULL){ // 文字無し?
res = my_xtoi(pt);
// if(res < 0) return cnt;
n = (uint16_t)res;
}
}
}
i2cOLED_Clr(0,7,0);
for(i = 0; i < n;i++ ){
dt = I2C_Mem_Read(CrtAdr); // バイトデータを読み出す
sPrt_AdrDt(SBuf,CrtAdr,dt,'<');
my_putsLf(SBuf);
i2cOLED_str(SBuf);
i2cOLED_posPX(i2cOLED_LF(),0);
CrtAdr++; cnt++;
}
SqMode = 0;
return cnt;
}
//---- WSQ コマンド(連続書込モード)
uint16_t i2cMem_cmd_WSQ(char *str){
char *pt; // 文字列操作用ポインタ
uint8_t dt; // 書き込むバイトデータ
int32_t res; // Hex文字数値変換結果
uint16_t cnt = 0; // 実際に読み出されたバイト数
pt = strtok(str,Dlm);
while(pt != NULL){
res = my_xtoi(pt);
// if(res < 0) return cnt;
dt = (uint8_t)res;
I2C_Mem_Write(CrtAdr,dt); // データを書き込む
sPrt_AdrDt(SBuf,CrtAdr,dt,'<');
my_putsLf(SBuf);
i2cOLED_str(SBuf);
CrtAdr++; cnt++;
pt = strtok(NULL,Dlm); // 次文字へ
}
return cnt;
}
//---- Qコマンド(連続書込モードの解除) Q
void i2cMem_cmd_Q(char *str){
SqMode = 0;
#ifndef VBA
puts("SqMode OFF\r");
#endif
}
//---- U(dump)コマンド(64バイトのデータをDBuf[]に読み出す)
int i2cMem_cmd_U(char *str){
char *pt; // 文字列操作用ポインタ
int32_t res; // Hex文字数値変換結果
uint32_t ad; // 指定アドレス
uint8_t i; // ループカウンタ用
LstCmd = str[0];
pt = strtok(str+1,Dlm);
if(pt != NULL){ // アドレス有り?
res = my_xtoi(pt);
// if(res < 0) return -1;
CrtAdr = (uint32_t)res;
}
ad = CrtAdr & 0xFFFE0; // 32バイト単位に
I2C_Mem_NRead(ad,DBuf,64); // 64バイトをDBuf[]に読出し
sPrt_AdrAdr(SBuf,ad,ad + MBFSIZE - 1,'-');
my_puts(SBuf);
i2cOLED_Clr(0,7,0);
i2cOLED_str(SBuf);
i2cOLED_posPX(i2cOLED_LF(),0);
prt_PBf(DBuf,MBFSIZE);
SqMode = 0;
return 0;
}
void prt_MemDat(uint32_t adr){
if(LstCmd == 'H'){ // 第2文字がHか?
I2C_Mem_NRead(adr, DBuf, 16); // 16バイトをDBuf[]に
i2cOLED_Ptn(0,0,2,8,(char *)DBuf);
i2cOLED_posPX(2,0);
prt_PBf(DBuf,16);
}else{
I2C_Mem_NRead(adr, DBuf, 32); // 32バイトをDBuf[]に
i2cOLED_Ptn(0,0,2,16,(char *)DBuf);
i2cOLED_posPX(2,0);
prt_PBf(DBuf,32);
}
}
//-- フォントパターンデータの表示
int i2cMem_cmd_u(char *str){
char *pt; // 文字列操作用ポインタ
uint32_t res; // Hex文字数値変換結果
uint32_t ad; // 指定アドレス
pt = strtok(str+1,Dlm);
if(pt != NULL){ // アドレス有り?
res = (uint32_t)my_xtoi(pt);
CrtAdr = res;
}
ad = CrtAdr & 0xFFFFF0; // 16バイト単位に
prt_MemDat(ad);
SqMode = 0;
return 0;
}
//---- P(Page)コマンド PW[aaaa]
int i2cMem_cmd_P(char *str){
char *pt; // 文字列操作用ポインタ
uint32_t res; // Hex文字数値変換結果
uint32_t ad; // 指定アドレス
static char msgP[] = "PageBuffer";
LstCmd = str[0];
if(strlen(str)==1){ // コマンドが'P'のみ
puts(msgP); // ページ内データ表示
i2cOLED_Clr(0,7,0);
i2cOLED_str(msgP);
i2cOLED_posPX(i2cOLED_LF(),0);
prt_PBf(DBuf,MBFSIZE);
return 0;
}
if(str[1]=='R'){ // 第2文字='R'
i2cMem_cmd_U(str+1); // Uコマンドと同じ
return 0;
}
if(str[1] != 'W') return -1; // 第2文字が'W'?
pt = strtok(str+2,Dlm);
if(pt != NULL){ // アドレス有り?
res = (uint32_t)my_xtoi(pt);
CrtAdr = (uint32_t)res;
}
ad = CrtAdr & 0xFFFC0; // 64バイト単位に
I2C_Mem_NWrite(ad,DBuf,64); // DBuf[]の64バイト書込
sPrt_AdrAdr(SBuf,ad,ad + MBFSIZE - 1,'-');
my_putsLf(SBuf);
i2cOLED_Clr(0,7,0);
i2cOLED_str(SBuf);
SqMode = 0;
return 0;
}
//---- シーケンスモードの確認
uint8_t i2cMem_SqMode(void){
return SqMode;
}
//---- K(漢字)表示コマンド K[H][aaaa]
int i2cMem_cmd_K(char *str){
char *sp;
uint8_t cn; // コラムドット数
uint8_t ofs; // 文字列解読オフセット
uint8_t i,n; // ループ変数
int32_t res; // 取得アドレス
LstCmd = str[0];
if((strlen(str)>1)&(str[1]=='H')){
ofs = 2; cn = 8;
}else{
ofs = 1; cn = 16;
}
sp = strtok(str+ofs,Dlm);
if(sp != NULL){
res = my_xtoi(sp) & 0xFFFF0; // 16バイト単位
if(res>0) CrtAdr = (uint32_t)res;
}
i2cOLED_Clr(0,7,0);
sPrt_AdrAdr((char *)SBuf, CrtAdr, CrtAdr+16*cn,'-');
my_putsLf((char *)SBuf);
i2cOLED_str(SBuf);
n = 8 * ofs;
for(i = 0; i < n; i++){
I2C_Mem_NRead(CrtAdr,(uint8_t *)DBuf,2*cn);
i2cOLED_Ptn(2,i*cn,2,cn,(char *)DBuf);
CrtAdr += 2*cn;
}
SqMode = 0;
return i;
}
//---- L(文字)表示コマンド L[code] (文字コード)
void i2cMem_cmd_L(char *str){
char *pt; // 文字列操作用ポインタ
uint32_t res; // Hex文字数値変換結果
uint16_t ftCd = 0; // フォントコード
LstCmd = str[0];
if(strlen(str)==1){ // アドレス無し
LstChr += 1; // 次文字
}else{
pt = strtok(str+1,Dlm);
if(pt != NULL){ // アドレス有り?
res = (uint32_t)my_xtoi(pt);
if(res>0) LstChr = (uint16_t)res;
}
}
i2cOLED_Clr(0,7,0);
my_utoa((uint8_t *)SBuf,LstChr,4); my_putsLf(SBuf);
i2cOLED_str(SBuf);
if(LstChr < 256){
i2cOLED_HchrX(32,0,(uint8_t)LstChr);
I2C_Mem_NRead(HfntAdr((uint8_t)LstChr),DBuf,16);
i2cOLED_posPX(2,0);
prt_PBf(DBuf,16);
}else{
i2cOLED_ZchrX(32,0,LstChr,2);
I2C_Mem_NRead(KfntAdr(LstChr),DBuf,32);
i2cOLED_posPX(2,0);
prt_PBf(DBuf,32);
}
SqMode = 0;
}
|