data.txtに設定した文字列をUSB-Serialに出力し続けるプログラムです。 text dataを出力する装置の模擬装置として使用します。 data.txtはmbedのlocalに保管しておきます。
Dependencies: mbed BufferedSerial
<mbed側の準備>
serial_dummyはmbedのlocalに保管した data.txt のtext dataをUSB-serialから出力し続けるプログラムです。 text data を出力する装置の模擬として使用します。
data.txtの例は次のところにあります。 /media/uploads/suupen/data.txt
data.txt には出力する文字列のほかに、 1.USB-serial のbaudrate 9600[bps]の例
B9600
2.送信文字列の送信時間間隔 1000[ms]の例
T1000
を設定できます。 '>B','>T' のコマンドは、設定した次の行の文字列から有効になります。
<パソコン側の準備>
windowsの場合パソコンにUSB-serialのdriverをインストールする必要があります。 driver は次のページからダウンロードして下さい。 https://mbed.org/handbook/Windows-serial-configuration
main.cpp
- Committer:
- suupen
- Date:
- 21 months ago
- Revision:
- 3:327bb0fcdf45
- Parent:
- 2:52002844d0c6
File content as of revision 3:327bb0fcdf45:
/** GreenPak HEX file Writer <Green Pak Hex file structure> HEX fileのコードは以下を参照 https://ja.wikipedia.org/wiki/Intel_HEX start code | byte count | | address | | | recode type | | | | data checksum ↓ ↓ ↓ ↓ ↓ ↓ : 10 0000 00 9F07003D0F0000000000000000000000 FE ↓ data : 10 0010 00 00000000000000000000000000000000 E0 :100020000000000000000000000000E0FB000000F5 :10003000000000000000000000000000CFEFFC0006 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :1000600000303000303030300000303030000000E0 :1000700030303030000000000000000000000000C0 :10008000FA00FA663B1422300C0000000000000069 :10009000000000000000000000000300000000005D :1000A0000000002000010000000201000002000129 :1000B0000000020100000200010000020100000235 :1000C000000100000200010000000101000000002A :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F000000000000000000000000000000000A55B ↑ data :00000001FF ← end code 0x0000 ~ 0x00ff の256byteになる <使い方> <USB-Serialの通信設定値> baudrate : PC_BOUDで変更可能(初期値=9600[bps] bits : 8bit parity : none stopbit : 1bit */ //#define DEBUG #include "ctype.h" #include "mbed.h" #include <cstdint> #include <stdio.h> //#include <string.h> #include "BufferedSerial.h" //#include "mbed2/233/i2c_api.h" //#include "mbed2/233/I2C.h" // mbed内部のfilesystem LocalFileSystem local("local"); // local file systemの設定 #define Z_bufferNumber \ (100) // HEX fileは1行44byteなのでこれ以上のbyte数があればよい(file // systemは1行づつ読み込まれる) char buffer[Z_bufferNumber]; // 読みだしたデータの保管先 // PCからのコマンド入力用USB-Uart // 参考コードは DELICIA_BLE_CommDummy BufferedSerial pc(USBTX, USBRX); #define PC_BOUD (115200) #define Z_pcBuffer (100) // PCからのコマンド保管用 char B_pcRx[Z_pcBuffer] __attribute__(( section("AHBSRAM0"))); // RAMが足りないのでEthernet用エリアを使用 // (0x2007c000) (コピー元をそのまま転記した) Timeout txSend; // 送信間隔作成用 // mbedボード上の動作モニタLED DigitalOut ledopen(LED1); // 1:file open 0:file close DigitalOut ledout(LED2); // 1: serial out // DigitalOut lederror(LED4); //*************************************************************************** // 新規のコマンド受信用 //*************************************************************************** //============================================================================= // PC 側処理 (command & data 送受信) // main()から呼び出す。戻り値が"1"ならコマンド解析する。 //============================================================================= /** * pc rx data * @@para ans 0:受信中 1:受信完了 */ int pcRecive(void) { static char *p = B_pcRx; char data; int ans = 0; #define Z_00 (0x00) #define Z_CR (0x0d) // buffer オーバーフロー対策 if ((p - B_pcRx) >= Z_pcBuffer) { p = B_pcRx; *p = Z_00; } // 1文字受信処理 while ((pc.readable() == 1) && ans == 0) { // 受信データあり data = pc.getc(); switch (data) { case Z_CR: *p = Z_00; p = B_pcRx; ans = 1; break; case ' ': case ',': // nothing break; default: // 小文字のアルファベットを大文字に差し替える if (('a' <= data) && (data <= 'z')) { data -= ('a' - 'A'); } *p++ = data; *p = Z_00; break; } } return (ans); } //*************************************************************************** // ベースのPC送信割り込み //*************************************************************************** int D_start_wait_us = 100; // 送信開始時の待ち時間 (1/1 [us]/bit) min = 100[us] int D_char_wait_us = 100; // キャラクタ間の送信間隔 ( 1/1 [ms]/bit) min = 100[us] // 送信処理状態遷移 typedef enum { Z_txIdle, Z_txStart, Z_txSend } txSend_t; txSend_t M_txSend = Z_txIdle; // 0:受信完了(STX送信待ち) 1:STX以降CRまでの送信中 /** * 割り込み処理 * 送信データ送信処理 * 受信完了から送信開始の20[ms]の遅延 * 送信データ1byte毎に2[ms]の遅延 * を入れて送信する */ void txDataSend(void) { static char *p; switch (M_txSend) { case Z_txStart: // STX ~ CR 送信 p = buffer; M_txSend = Z_txSend; // brak; case Z_txSend: if (*p != 0x00) { pc.putc(*p++); wait(0.01); txSend.attach_us( &txDataSend, D_char_wait_us); // 次回送信開始まで2[us]セット(時間は可変設定にする) } else { // 送信完了 M_txSend = Z_txIdle; txSend.detach(); } break; case Z_txIdle: // defaultと同じ処理 default: // nothing break; } } /** * main処理 * 受信終了から送信開始までの20[ms]遅延設定 * */ void txDataWait(void) { txSend.attach_us(&txDataSend, D_start_wait_us); // 受信完了からx[ms]経過待ち M_txSend = Z_txStart; } /** * 送信終了判定 * @@para int 戻り値 送信処理状況 1:送信完了 0:送信中 */ int txSendEndCheck(void) { int ans; if (M_txSend == Z_txIdle) { ans = 1; } else { ans = 0; } return (ans); } /** asciiコード1文字をhexに変換 * 引数: char* p : 文字の入った変数のポインタ * 戻り値: 0 ~ 0x0f, 0xff:変換不能 */ uint8_t atoh1(char *p) { char a = *p; uint8_t ans = 0xff; if (('0' <= a) && (a <= '9')) { ans = a - '0'; } else if (('a' <= a) && (a <= 'f')) { ans = a - 'a' + 0x0a; } else if (('A' <= a) && (a <= 'F')) { ans = a - 'A' + 0x0a; } else { ans = 0xff; } return (ans); } /** asciiコード2文字をhexに変換 * 引数: char* p: 文字の入った変数ポインタ * 戻り値: 0x00 ~ 0xff (変換不能の場合は0xffにしている) */ uint8_t atoh2(char *p) { uint8_t ans; uint8_t up = atoh1(p); uint8_t dn = atoh1(p + 1); if ((up != 0xff) && (dn != 0xff)) { ans = (up << 4) | dn; } else { // 変換不能 ans = 0xff; } return (ans); } uint8_t byteCount; uint8_t address; // 上位8bitは必ず0x00になるので省略 uint8_t recodeType; uint8_t NVMData[16][16]; // NVM書き込み用データバッファ uint8_t EEPROMData[16][16]; // EEPROM用書き込みデータバッファ uint8_t NVMFile = 0; // NVMファイルの読み込み結果 0:NG, 1:OK uint8_t EEPROMFile = 0; // EEPROMファイルの読み込み結果 0:NG, 1:OK /** NVM fileを読み出す * 対象ファイルは"NVM.hex"の決め打ち * 戻り値: 0:データなし n:読み込み桁数(正常なら16になる) */ uint8_t NVMFileRead(void) { uint8_t ans = 0; FILE *fp; char *p; pc.printf("NVM file read\n"); fp = fopen("/local/NVM.hex", "r"); while (fgets(buffer, Z_bufferNumber, fp) != NULL) { p = buffer; while (*p != 0x00) { switch (*p++) { case ':': byteCount = atoh2(p); p += 2; p += 2; address = atoh2(p) >> 4; // 2byte addressの下位1byteを取得 p += 2; recodeType = atoh2(p); p += 2; pc.printf("byte=%02x address=%02x type=%02x : ", byteCount, address, recodeType); wait(.1); if (byteCount != 0x10) { pc.printf("end of data\n"); break; } ans++; for (uint8_t i = 0; i < 16; i++) { NVMData[address][i] = atoh2(p); p += 2; pc.printf("%02x", NVMData[address][i]); } pc.printf("\n"); } } } fclose(fp); return (ans); } //***************************************************************************** // GreenPak のI2C処理 //***************************************************************************** I2C Wire(p9, p10); // sda, sci //@ss+ Block Address (Control Byte A10-8) // A10 // |A9 // ||A8 // xxxx 098xb // xxxx 001xb :resster // xxxx 010xb :NVM // xxxx 110xb :EEPROM #define RESISTER_CONFIG 0x02 // 0x01 << 1 //@ss+ #define NVM_CONFIG 0x04 // 0x02 << 1 #define EEPROM_CONFIG 0x06 // 0x03 << 1 #define MASK_CONTROLCODE \ (0xf0) // I2Cアドレス部の ControlCode(上位4bit)を残すためのマスク int count = 0; uint8_t slave_address = 0x00; bool device_present[16] = {false}; uint8_t data_array[16][16] = {}; typedef enum { NVM, EEPROM, RESISTER } greenPakMemory_t; greenPakMemory_t NVMorEEPROM = NVM; // 読み書き対象 char i2cBuffer[10]; // I2C送受信用バッファ //////////////////////////////////////////////////////////////////////////////// // power cycle //////////////////////////////////////////////////////////////////////////////// void powercycle(int code) { pc.printf("Power Cycling!\n"); // Software reset // レジスタアドレス=0xc8 bit1を1にすると I2C resetをしてNVMのデータをレジスタに転送することができる i2cBuffer[0] = 0xC8; i2cBuffer[1] = 0x02; Wire.write(code & MASK_CONTROLCODE, i2cBuffer, 2); //@ss MASK_CONTROLCODEは Control Code:slave // addressを残しresisterアクセスにするためのマスク // pc.printf("Done Power Cycling!\n"); } //////////////////////////////////////////////////////////////////////////////// // ack polling //////////////////////////////////////////////////////////////////////////////// int ackPolling(int addressForAckPolling) { int ans; int nack_count = 0; while (1) { ans = Wire.read(addressForAckPolling, i2cBuffer, 0); if (ans == 0) { return 0; } if (nack_count >= 1000) { pc.printf("Geez! Something went wrong while programming!\n"); return -1; } nack_count++; wait(1); } } //////////////////////////////////////////////////////////////////////////////// // ping //////////////////////////////////////////////////////////////////////////////// void ping(void) { int ans; for (int i = 0; i < 16; i++) { ans = Wire.read(i << 4, i2cBuffer, 0); // ICに影響を与えないようにreadコマンドで確認する if (ans == 0) { pc.printf("device 0x%02x", i); pc.printf(" is present\n"); device_present[i] = true; } else { pc.printf("device 0x%02x", i); pc.printf(" is not present\n"); device_present[i] = false; } } wait(0.1); } //////////////////////////////////////////////////////////////////////////////// // resister un protect //////////////////////////////////////////////////////////////////////////////// void resister_unprotect(uint8_t control_code) //@ss+ { // resisiterのプロテクトをクリアする // レジスタアドレス: 0xE1 にNVMのプロテクト領域がある (HM p.171) // 下位2bit 00: read/write/erase 可能 // 01: read禁止 // 10: write/erase 禁止 // 11: read/write/erase 禁止 i2cBuffer[0] = 0xE1; i2cBuffer[1] = 0x00; Wire.write(control_code & MASK_CONTROLCODE, i2cBuffer, 2); //@ss MASK_CONTROLCODEは Control Code:slave // addressを残しresisterアクセスにするためのマスク i2cBuffer[0] = 0xE1; Wire.write(control_code & MASK_CONTROLCODE, i2cBuffer, 1); Wire.read(control_code & MASK_CONTROLCODE, i2cBuffer, 1); uint8_t val = i2cBuffer[0]; pc.printf("0xE1 = %02x\n", val); // 0x00ならプロテクト解除されている } //////////////////////////////////////////////////////////////////////////////// // writeChip //////////////////////////////////////////////////////////////////////////////// #if 0 // NVM書き込み試験用 int writeChip(greenPakMemory_t NVMorEEPROM) { i2cBuffer[0] = 0x00; i2cBuffer[1] = 0x01; i2cBuffer[2] = 0x02; i2cBuffer[3] = 0x03; i2cBuffer[4] = 0x04; i2cBuffer[5] = 0x05; i2cBuffer[6] = 0x06; i2cBuffer[7] = 0x07; i2cBuffer[8] = 0x08; i2cBuffer[9] = 0x09; i2cBuffer[10] = 0x0a; i2cBuffer[11] = 0x0b; i2cBuffer[12] = 0x0c; i2cBuffer[13] = 0x0d; i2cBuffer[14] = 0x0e; i2cBuffer[15] = 0x0f; i2cBuffer[16] = 0x10; Wire.write(0x04, i2cBuffer, 17); } #endif #if 1 int writeChip(greenPakMemory_t NVMorEEPROM) { int control_code = 0x00; int addressForAckPolling = 0x00; bool RESISTER_selected = false; bool NVM_selected = false; bool EEPROM_selected = false; int ans; if (NVMorEEPROM == NVM) { control_code = slave_address << 4; resister_unprotect(uint8_t(control_code)); //@ss+ // Serial.println(F("Writing NVM")); // Set the slave address to 0x00 since the chip has just been erased slave_address = 0x00; // Set the control code to 0x00 since the chip has just been erased control_code = 0x00; control_code |= NVM_CONFIG; NVM_selected = true; addressForAckPolling = 0x00; } else if (NVMorEEPROM == EEPROM) { // pc.printf("Writing EEPROM\n"); control_code = slave_address << 4; control_code |= EEPROM_CONFIG; EEPROM_selected = true; addressForAckPolling = slave_address << 4; } else if (NVMorEEPROM == RESISTER) //@ss+↓ { // Serial.println(F("Writing RESISTER")); control_code = slave_address << 4; control_code |= RESISTER_CONFIG; RESISTER_selected = true; addressForAckPolling = slave_address << 4; } //@ss+↑ pc.printf("Control Code: 0x%02x\n", control_code); // Assign each byte to data_array[][] array; // http://www.gammon.com.au/progmem // pc.printf("New NVM or EEPROM data:"); if (NVM_selected) { for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { data_array[i][j] = NVMData[i][j]; } } } else if (EEPROM_selected) { for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { data_array[i][j] = EEPROMData[i][j]; } } } if (NVM_selected || RESISTER_selected) { // slave_addressに設定されている値に差し替える // レジスタアドレス=0xcaのbit3-0 にI2C slave address を設定する // bit7-4: 0にすると下位4bitのアドレスが有効になる(1にするとIO2,3,4,5の端子状態がアドレスになる) data_array[0xC][0xA] = (data_array[0xC][0xA] & 0xF0) | slave_address; } // Write each byte of data_array[][] array to the chip for (int i = 0; i < 16; i++) { i2cBuffer[0] = i << 4; pc.printf("%02x: ", i); for (int j = 0; j < 16; j++) { i2cBuffer[j+1] = data_array[i][j]; pc.printf("%02x ", data_array[i][j]); } ans = Wire.write(control_code, i2cBuffer, 17); wait(0.01); if (ans != 0) { pc.printf(" nack\n"); pc.printf("Oh No! Something went wrong while programming!\n"); Wire.stop(); return -1; } pc.printf(" ack "); if (ackPolling(addressForAckPolling) == -1) { return -1; } else { pc.printf("ready\n"); wait(0.1); } } Wire.stop(); if (RESISTER_selected == false) { //@ss+ powercycle(control_code); } //@ss+ return 0; } #endif //////////////////////////////////////////////////////////////////////////////// // eraseChip // 230105OK //////////////////////////////////////////////////////////////////////////////// int eraseChip(greenPakMemory_t NVMorEEPROM) { int control_code = (slave_address << 4) | RESISTER_CONFIG; //@ss ControlCode(A14-11)=slaveAddress(4bit) + // BlockAddress(A10-8)=000b int addressForAckPolling = control_code; if (NVMorEEPROM == RESISTER) { //@ss+↓ pc.printf("RESISTER don't erase area\n"); return (0); } //@ss+↑ resister_unprotect(uint8_t(control_code)); //@ss+ for (uint8_t i = 0; i < 16; i++) { pc.printf("Erasing page: 0x%02x ", i); i2cBuffer[0] = 0xE3; // I2C Word Address //@ss Page Erase Register //@ss bit7: ERSE 1 //@ss bit4: ERSEB4 0: NVM, 1:EEPROM //@ss bit3-0: ERSEB3-0: page address if (NVMorEEPROM == NVM) { pc.printf("NVM \n"); i2cBuffer[1] = (0x80 | i); } else if (NVMorEEPROM == EEPROM) { pc.printf("EEPROM \n"); i2cBuffer[1] = (0x90 | i); } Wire.write(control_code, i2cBuffer, 2); //@ss Control BYte = ControlCode + Block Address wait(0.1); //@ss+ /* To accommodate for the non-I2C compliant ACK behavior of the Page Erase * Byte, we've removed the software check for an I2C ACK and added the * "Wire.endTransmission();" line to generate a stop condition. * - Please reference "Issue 2: Non-I2C Compliant ACK Behavior for the NVM * and EEPROM Page Erase Byte" in the SLG46824/6 (XC revision) errata * document for more information. * * 要約: たまにNACKを返すことがあるので、無条件に終了させればよい。 * //@ss220717+ * https://medium.com/dialog-semiconductor/slg46824-6-arduino-programming-example-1459917da8b * //@ss220717+ */ //@ss tER(20ms)の処理終了待ち if (ackPolling(addressForAckPolling) == -1) { pc.printf("NG\n"); return -1; } else { pc.printf("ready \n"); wait(0.1); } } powercycle(control_code); return 0; } //////////////////////////////////////////////////////////////////////////////// // readChip 230105OK //////////////////////////////////////////////////////////////////////////////// void readChip(greenPakMemory_t NVMorEEPROM) { //@ss220717+ //@ssint readChip(String NVMorEEPROM) { //@ss220717- // int control_code = slave_address << 4; uint8_t control_code = slave_address << 4; //@ss I2C Block Addressの設定 //@ss A9=1, A8=0: NVM (0x02) //@ss A9=1, A8=1: EEPROM (0x03) if (NVMorEEPROM == NVM) { control_code |= NVM_CONFIG; pc.printf("memory = NVM\n"); } else if (NVMorEEPROM == EEPROM) { control_code |= EEPROM_CONFIG; pc.printf("memory = EEPROM\n"); } else if (NVMorEEPROM == RESISTER) //@ss+↓ { control_code |= RESISTER_CONFIG; pc.printf("memory = RESISTER\n"); } //@ss+↑ // pc.printf("memory = %02x\n",control_code); for (int i = 0; i < 16; i++) { pc.printf("%02x :", i); //@ss+ i2cBuffer[0] = i << 4; Wire.write(control_code, i2cBuffer, 1, true); wait(0.01); Wire.read(control_code, i2cBuffer, 16, true); for (int j = 0; j < 16; j++) { pc.printf("%02x ", i2cBuffer[j]); } pc.printf("\n"); } Wire.stop(); } //***************************************************************************** // main //***************************************************************************** #if 1 int main() { // pc.format(8,Serial::Even,1); pc.baud(PC_BOUD); Wire.frequency(10000); NVMFile = NVMFileRead(); pc.printf("ans = %d", NVMFile); while (1) { // typedef enum { NVM, EEPROM, RESISTER } greenPakMemory_t; // greenPakMemory_t NVMorEEPROM = NVM; // 読み書き対象 if (pcRecive() == 1) { char *p = B_pcRx; switch (*p++) { case 'A': // スレーブアドレス変更 uint8_t address; address = atoh1(p); if ((0 <= address) && (address <= 0xf)) { pc.printf("old address = %02x\n", slave_address); slave_address = address; pc.printf("new address = %02x\n", slave_address); } else { pc.printf("now address = %02x\n", slave_address); } break; case 'C': pc.printf("slave address = %02x\n", slave_address); pc.printf("Memory = "); switch (NVMorEEPROM) { case NVM: pc.printf("NVM\n"); break; case EEPROM: pc.printf("EEPROM\n"); break; case RESISTER: pc.printf("RESISTER"); break; default: pc.printf("unkown\n"); break; } break; case 'E': pc.printf("erase start\n"); if (eraseChip(NVMorEEPROM) == 0) { pc.printf("erase OK\n"); } else { pc.printf("erase NG\n"); } break; case 'S': // 操作対象変更 switch (*p++) { case 'N': NVMorEEPROM = NVM; pc.printf("new select = NVM set\n"); break; case 'E': NVMorEEPROM = EEPROM; pc.printf("new select = EEPROM set\n"); break; case 'R': NVMorEEPROM = RESISTER; pc.printf("new select = RESISTER set\n"); break; default: switch (NVMorEEPROM) { case NVM: pc.printf("now select = NVM\n"); break; case EEPROM: pc.printf("now select = EEPROM\n"); break; case RESISTER: pc.printf("now select = RESISTER"); break; default: pc.printf("now select = unkown\n"); break; } break; } break; case 'P': ping(); break; case 'R': pc.printf("Reading chip!\n"); readChip(NVMorEEPROM); break; case 'W': // erase pc.printf("erase start\n"); if (eraseChip(NVMorEEPROM) == 0) { pc.printf("erase OK\n"); } else { pc.printf("erase NG\n"); } // write if (writeChip(NVMorEEPROM) == 0) { pc.printf("write OK\n"); } else { pc.printf("write NG\n"); } break; case 'D': pc.printf("D input\n"); break; } } } } #endif #if 0 int main() { pc.baud(115200); FILE *fp; // int ans; char *p; int timer; // serial送信時間間隔 ( 1/1 [ms]/bit) int baud; // usb-serialのbaudrate ( 1/1 [bps]/bit) NVMFile = NVMFileRead(); pc.printf("main main\n"); fp = fopen("/local/NVM.hex", "r"); ledopen = 1; while (1) { if (fgets(buffer, Z_bufferNumber, fp) != NULL) { // ans = fscanf(fp,"%s",buffer); // if(ans != -1) { p = buffer; for(uint8_t i = 0; i < 255; i++){ pc.printf("*p(%d) = %02x\n",i, *(p+i)); wait(0.1); } // 文字列 or 制御コマンド while (*p != 0x00) { pc.printf("*p = %02x\n",*p); switch (*p++) { case ':': byteCount = atoh2(p); p += 2; p += 2; address = atoh2(p) >> 4; // 2byte addressの下位1byteを取得 p += 2; recodeType = atoh2(p); p += 2; pc.printf("byte=%02x address=%02x type=%02x\n", byteCount, address, recodeType); wait(1); if (byteCount != 0x10) { wait(1); break; } for (uint8_t i = 0; i < 16; i++) { NVMData[address][i] = atoh2(p); p += 2; pc.printf("%02x", NVMData[address][i]); } pc.printf("\n"); } } #if 0 switch (*p++) { default: // 出力文字列として処理する txDataWait(); while (txSendEndCheck() == 0) { // 割り込みで送信中 ledout = !ledout; // この行がないとwhile文から抜けなくなる。原因不明 } wait_ms(timer); //ここ break; } #endif } else { // 読みだすデータがなくなったら、先頭に戻す pc.printf("\nend end end\n"); // ファイルの最後の"LF"の代わりに出力する fclose(fp); ledopen = 0; // wait_ms(timer); fp = fopen("/local/NVM.hex", "r"); ledopen = 1; } } } #endif