2021年09月25日

PIC32マイコンEEPROMエミュレーション

今回はPIC32MX270F256BをターゲットにMPLAB X v5.45+Harmony3+XC32 v2.50を使用して、PIC32マイコンのフラッシュをEEPROMとしてユーザーデータを保存する方法について紹介します。


PICマイコンのシリーズによってはマイコン内にフラッシュ書き込み回路が内蔵されていないため、内蔵のフラッシュに単体で書き込むことができないものが多いです。一方、PIC32マイコンはフラッシュ書き込み回路が内蔵されているため、単体で書き込むことが可能です。この機能を活用することで外付けのEEPROMの代わりとして内蔵フラッシュに簡単な設定データや固定データ等を保存、読み込みすることができます。


なお、EEPROM同様にUSBメモリやSDカードのようにメモリ領域を分散して書き込む機能がないため、毎回同じメモリセルに書き込まれます。そのため、高頻度に書き換える用途ではフラッシュの該当するメモリセルのみ早期に寿命を迎える可能性があります。PIC32MXシリーズでは最低2万回の読み書きできる仕様ですが、RAMのような使い方をすると早期に寿命になり正常に読み書きできなくなります。設定データや固定データ等の書き換え回数が少ないデータ保存に使用するのが適切です。書き込みの回数に制約があるものの、読み込みは高頻度であっても問題はありません。

また、内蔵フラッシュにデータを保存する注意点として内蔵フラッシュの空き領域であることを確認する必要があります。デフォルトではMedia Start Addressは0x9D020000以降に128kbの領域で設定されています。つまり、内蔵フラッシュの半分以降がEEPROMとして使用する領域として設定されています。この場合、プログラムメモリの使用率を内蔵フラッシュの半分以下にする必要があります。プログラムメモリを多く使用する場合や逆にNVMエリアを広くする場合はプログラムメモリと重複しないようにMedia Start Addressの設定に注意してください。

重複の有無はMPLAB Xのファームを書き込む際に表示されるコンソールから領域を確認できます。
The following memory area(s) will be programmed:
@program memory:
start address = 0x1d000000, end address = 0x1d0083ff

Aprogram memory:
start address = 0x1d03f000, end address = 0x1d03f7ff

上記の領域に0x80000000をオフセットされた領域が実際の領域です。
@0x9d000000, end address = 0x9d0083ff
A0x9d03f000, end address = 0x9d03f7ff

つまり、内蔵フラッシュを0x1F000以上書き込むとAの領域と重複することが分かります。今回のテストコードは0x0400(1024)サイズの書き込みのため、問題ないことが分かります。


Harmony3ではNVMコンポーネントとしてライブラリが準備されています。NVMコンポーネントだけでも読み書きできますが、MEMORYコンポーネントと合わせて使用することで他のメモリでも同じ関数で読み書きできるため、汎用性高く実装できます。今回はNVMコンポーネントとMEMORYコンポーネントを合わせて使用して内蔵フラッシュに対して読み書きしてみました。

Harmony3のプロジェクトグラフは下記の通りです。

eeprom_emu1.jpg

実装は下記の通りです。

app.c内に変数定義及び読み書き完了割込み関数を追加します。

#define BUFFER_SIZE 1024
uint8_t writeBuffer[BUFFER_SIZE];
uint8_t readBuffer[BUFFER_SIZE];
uint32_t blockStart = 0x0;
uint32_t nBlock = BUFFER_SIZE;
DRV_MEMORY_COMMAND_HANDLE commandHandle;
bool xfer_done = false;

void appTransferHandler
(
 DRV_MEMORY_EVENT event,
 DRV_MEMORY_COMMAND_HANDLE commandHandle,
 uintptr_t context
)
{
 switch(event)
 {
  case DRV_MEMORY_EVENT_COMMAND_COMPLETE:
  xfer_done = true;
  break;
  case DRV_MEMORY_EVENT_COMMAND_ERROR:
  break;
  default:
 break;
 }
}

app.c内のAPP_Tasks内に読み書きのテストコードを追加します。


 DRV_HANDLE memoryHandle;
 memoryHandle = DRV_MEMORY_Open(DRV_MEMORY_INDEX_0, DRV_IO_INTENT_READWRITE);
 if (DRV_HANDLE_INVALID == memoryHandle)
  {
   SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Open ERR\r\n");
  }
  SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Open OK\r\n");

  DRV_MEMORY_TransferHandlerSet(memoryHandle, appTransferHandler, (uintptr_t)NULL);
  SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "TransferHandlerSet OK\r\n");


  memset(writeBuffer,'\0',sizeof(writeBuffer));
  memset(readBuffer,'\0',sizeof(readBuffer));
  sprintf((char*)writeBuffer, "Hello!! ");
  SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "sprintf OK\r\n");


  //Write Data
  xfer_done = false;
  DRV_MEMORY_AsyncEraseWrite(memoryHandle, &commandHandle, writeBuffer, blockStart, nBlock);
  if(DRV_MEMORY_COMMAND_HANDLE_INVALID == commandHandle)
  {
   SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AsyncWrite ERR\r\n");
  }
  while(!xfer_done)
  {
   DRV_MEMORY_Tasks(sysObj.drvMemory0);
  }
  SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AsyncWrite Complited\r\n");

  //Read Data
  xfer_done = false;
  DRV_MEMORY_AsyncRead(memoryHandle, &commandHandle, readBuffer, blockStart, nBlock);
  if(DRV_MEMORY_COMMAND_HANDLE_INVALID == commandHandle)
  {
   SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AsyncRead ERR\r\n");
  }
   while(!xfer_done)
   {
    DRV_MEMORY_Tasks(sysObj.drvMemory0);
   }
   SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AsyncRead Complited\r\n");
   SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "W:%s\tR:%s\r\n",writeBuffer,readBuffer);


実際に実行した結果は下記の通りです。

eeprom_emu2.jpg


今回は動作テストとして非同期関数を同期関数のように実装しました。注意点として、読み書き完了後の割込み関数appTransferHandlerはDRV_MEMORY_Tasksを実行しないと呼び出されません。main.cのSYS_Tasks内でDRV_MEMORY_Tasksが自動的に追加されているため、非同期として使用する場合には問題ありませんが、ブロックさせて同期関数のように使用する場合はDRV_MEMORY_Tasksを呼び出してメモリ処理を別途実行する必要があります。

今回のプロジェクトファイル一式はこちらにアップ(PIC32MX_EEPROM.zip)しています。Harmony3を使用することでSTM32マイコン同様に簡単に内蔵フラッシュにユーザーデータを読み書きできることが分かりました。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年09月18日

USBカメラ接続

今回は昨年から試行錯誤しながら取り組んでいるプロジェクトを少し紹介します。組込系でカメラ機能を利用する場合、昨今ではOpenMVやM5Camera、ESP32-Cam等を利用することが多いと思いますが、いまいち継続的な入手性や汎用性に欠けます。


そこで汎用的なUSBカメラから取り込むことで汎用性高く実装することを検討しています。ただ、USBカメラはUVC(USB Video Class)という規格があるものの、非常に帯域を要するため、組込系では処理がギリギリです。また、USBカメラの機種やメーカによっても細かい挙動が異なるため、なかなか苦戦中です。

まだ動作に改善の余地がありますが、LCDに表示させてみました。


uvc1.jpeg


uvc2.jpeg

もともとはSTM32マイコンで実装予定でしたが、Isochronous転送が安定しないことと、、昨今の半導体不足で入手困難であるため、断念しました。FTDIのVinculum2ではRTOSのオーバーヘッドが無視できず、SPIの転送速度が遅すぎて断念しました。現状はPIC32マイコンで実装しています。

紆余曲折あって、苦戦していますが、もう少しファームの作りこみや動作確認を継続して、検討中のプロジェクトに組込たいと思います。
posted by Crescent at 00:00| Comment(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする

2021年09月11日

I2C Bus Accelarator検証

以前に紹介したGrove等で使用されるI2Cを延長する方法について、実際に少し検証してみました。

一般的にI2Cはマイコン周辺の機器との通信を想定しているため、数メートルといった距離の通信を想定していません。Grove規格ではハブやケーブルを接続して、数mまでケーブルを延長すると波形が鈍って通信エラーが多発します。このような場合にI2CバスバッファICで差動信号に変換して、延長先で再度、差動信号をI2Cに変換する方法があります。数10m以上延長する場合に非常に有効な方法ですが、数m程度の延長で変換アダプタを使用するのは少し大がかりです。その際に便利な部品、バスアクセラレータLTC4311を紹介します。


バスアクセラレータLTC4311は、400pFのI2C仕様を上回るバス負荷条件で
データ伝送速度と信頼性を向上させるアクティブ・プルアップです。

• I2Cバス立ち上がり遷移時間を改善
• I2Cバス上に複数のデバイスを接続する場合にデータの完全性を保証
• 広い電源電圧範囲:1.6V〜5.5V
• “L”状態のノイズマージンを改善
• 最大400kHz動作

簡単に言えば、配線が長くなってクロックや信号が鈍ってしまうところをHigh、Lowをバシッと決めてくれるデバイスです。

通信ケーブル1m、波形の鈍りが分かりやすいように意図的に大きなプルアップ抵抗20kΩを接続し、HS3001温度湿度センサをI2Cデバイスとして使用した場合の波形を比べてみました。


LTC4311_3.jpg
100kHzクロックでLTC4311未使用の場合です。赤線がデータ、黄線がクロックです。1mなので通信できますが、立ち上がりが少し鈍っています。

LTC4311_4.jpg
100kHzクロックでLTC4311使用の場合です。赤線がデータ、黄線がクロックです。I2CバスラインにLTC4311を挿入するだけで立ち上がりの鈍りが解消されています。

ケーブルが長い場合やケーブルの種類によっては通常、波形の鈍りが大きくなり、正常に0と1を送信できなくなり、通信エラーが多発します。アクティブ・プルアップによって波形の鈍りを解消することでより長いケーブルでの伝送ができるようになります。今回は検証していませんが、I2C駆動電流を大きく流せないようなデバイスやマイコンの場合に波形が鈍って通信できない場合にも有効だと思います。

部品単体では効果を確認できたため、I2Cバスアクセラレータ基板の設計をしてみたいと思います。
posted by Crescent at 00:00| Comment(0) | 電子部品 | このブログの読者になる | 更新情報をチェックする

2021年09月04日

CTセンサアンプ基板

今回は先日、紹介した実効値変換アナログICを応用したCTセンサアンプ基板ついて紹介します。

一般的にはCTセンサをマイコンで取り込む場合、抵抗で中立点の仮想GNDにシャント抵抗とCTセンサを接続した電圧をAD変換器で取り込む回路を実装することが多いです。ただ、ノイズ除去処理、RMS値の計算処理やある程度速いAD変換サンプリングが必要です。また、振幅が小さい場合やAD変換器の入力インピーダンスが大きい場合は増幅回路が必要となり、回路が多くなるため、CTセンサの取り込みはなかなか厄介です。

そこで便利なのが開発中のCTセンサアンプ基板です。CTセンサアンプ基板は交流電流を測定するためのCTセンサの出力を増幅、RMS値に変換する基板です。基板上に選択可能なシャント抵抗があり、交流の電流に応じてRMS値を直流に変換した値を得ることができます。シャント抵抗、RMS値の演算含めて基板に実装しているため、交流負荷の電流や電力を直流値として簡単に得ることが可能です。


csa1.jpg

csa2.jpg

シャント抵抗は49.9Ω、10Ω、1Ω、0.3Ωの4種類から選択できます。ユーザー側でCTセンサを用いて測定したい電流範囲に応じてジャンパーさせることが可能です。電源は3.3V、5Vに対応していますが、5V電源の方がより多くの電流を測定できます。INA181A1によるゲイン20倍、出力段アンプゲイン3倍で60倍の増幅率です。

VOUT=(IxGainxR)/(CT比)=(Ix60x49.9)/3000


目安として、1:3000のCTセンサを用いた場合の各シャント抵抗における最小電流と最大電流をまとめました。最大電流は増幅アンプ飽和電圧です。一方、最小電流は回路内部のオフセット電圧が数10mV生じるため、オフセットの影響を無視できる範囲として設定しました。


 電源3.3V電源5.0V
シャント抵抗最小電流最大電流最小電流最大電流
49.90.130.16
10.00.5150.523
1.051505230
0.31034010500


なお、電流ゼロの場合でも、使用するAD変換器の入力インピーダンスや回路内のオフセット電圧等の影響で数10mV程度オフセット電圧が生じます。そのため、0.1A以下の微小な電流測定には向いていません。また、50Hz/60Hzの商用電源の電流をCTセンサで測定する用途を想定しているため、歪みの大きな電流やインバータ出力電流等では正しく電流実効値を測定できない場合があります。回路上のローパスフィルタで高周波をカットオフしているため、数百Hz以上の電流変化は測定できません。

シャント抵抗が小さい方が大電流を測定できる一方で小さな電流では出力電圧が小さすぎて、出力オフセットやAD変換分解能の影響で測定誤差が大きくなります。測定したい対象の最大電流に応じて、シャント抵抗を選択します。試作基板を製作して問題なく動作を確認することができたため、量産版の製造を開始をしたいと思います。
posted by Crescent at 00:00| Comment(0) | 電子部品 | このブログの読者になる | 更新情報をチェックする