2021年11月06日

PIC32マイコンSYS_CONSOLE

今回はPIC32MX270F256BをターゲットにMPLAB X v5.45+Harmony3+XC32 v2.50を使用して、SYS_CONSOLEの使用方法について紹介します。

マイコンのデバッグをする場合、デバッガーを使って確認する方法の他にUART等を介してシリアルコンソールに情報を表示させる方法があります。個人的にはデバッガーよりもUARTとシリアルコンソールを使ったデバッグの方が早く、必要な情報を取り出せるため、よく利用しています。PIC32のHarmony3で利用可能なSYS_CONSOLEはシリアル出力のラッパー機能となっています。UARTの関数を直接呼び出してシリアル出力するよりも汎用性高く、利用しやすくなっています。システムに応じてコンソールの出力先のUARTを変更したり、USBCDCの出力に変更することも容易です。また、コンソールのデバッグレベルを使い分けることで、必要なコンソール出力のみに制限したりすることも容易にできます。


Harmony3ではSystem ServiceのConsole、Debugとしてライブラリが準備されています。今回はConsoleをUART2に接続して利用しました。Harmony3のプロジェクトグラフは下記の通りです。

sys_console1.jpg

必要に応じてUART2のボーレートやピンアサインの設定を行います。

出力のレベルはSYS_ERROR_FATAL、SYS_ERROR_ERROR、SYS_ERROR_WARNING、SYS_ERROR_INFO、SYS_ERROR_DEBUG から選択できます。デフォルトはSYS_ERROR_DEBUGとなっており、プロジェクトグラフのDebugから出力レベルを変更できます。コードではconfiguration.h内で下記のように定義が出力されています。

#define SYS_DEBUG_ENABLE
#define SYS_DEBUG_GLOBAL_ERROR_LEVEL SYS_ERROR_DEBUG

例えば、デバッグ時はSYS_ERROR_DEBUGにして、デバッグ終了後はSYS_ERROR_INFOにすると、SYS_ERROR_INFO以下のコンソールが出力されるようになり、SYS_ERROR_DEBUGのコンソール出力は出力されなくなります。コンソール出力をコメントアウトしたりせずに一括で変更できるため、非常に便利です。


コンソール出力の使い方は下記の通りです。
ヘッダのインクルードを追加します。
#include "system/debug/sys_debug.h"

出力関数は下記の通りです。
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "\r\nInitOK\r\n");


コンソール入力を利用する場合は下記の変数をグローバル変数等に定義します。
SYS_CONSOLE_HANDLE consoleHandle;
ssize_t consoleReadSize;
char consoleBuffer[130];

入力関数は下記の通りです。入力がない場合はconsoleReadSizeが0になります。入力があった場合はそのbyte数がconsoleReadSizeに入り、データはconsoleBufferに格納されます。

consoleReadSize = SYS_CONSOLE_Read( consoleHandle, consoleBuffer, sizeof(consoleBuffer) );

UARTのコンソールはPIC32MXではデフォルトでDMA&リングバッファとして設定されているため、マイコンのメイン処理に対してコンソール出力の影響を抑えてデバッグすることが可能です。

これまで毎週更新していましたが、半導体不足でプロジェクトが停滞気味のため、今後のブログ更新はペースを減らして随時記事を投稿する予定です。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年10月23日

PIC32マイコンSDカード読み書き

今回はPIC32MX270F256BをターゲットにMPLAB X v5.45+Harmony3+XC32 v2.50を使用して、PIC32マイコンにSDカードを接続して読み書きする方法について紹介します。

Harmony3を用いることでSPI接続で簡単にSDカードの読み書きを実装することが可能です。Harmony3のプロジェクトグラフは下記の通りです。

sd_spi1.jpg

今回はSPI1をSDカード用に割り当てました。

sd_spi4.jpg

SPI1の設定はデフォルトのままで問題ありません。

sd_spi3.jpg

SD Card設定ではSDカードのチップセレクトをどのポートにするか設定します。他の設定はそのままで問題ありません。



sd_spi2.jpg
FILE SYSTEMの設定はそのままで問題ありませんが、32GB以上のSDカードを使用する場合は「Enable exFAT ~」にチェックを入れます。

sd_spi5.jpg

最後にSPI1のIOとSDのCSのポートを忘れずに設定します。SPI1のIOとCSをGPIO OUTPUTに設定します。なお、SDI1とSDO1をプルダウン有効にしていますが、必須ではありません。

Harmony3の設定完了後、Generate Codeボタンでコードを生成します。コード生成後、app.cのAPP_Tasks内にファイル書き込みのテストコードを追加します。


SYS_FS_HANDLE fileHandle;
char hello[] = "Hello World !!";
int res;
//SDカードマウント
res=SYS_FS_Mount("/dev/mmcblka1", "/mnt/myDrive1", FAT, 0, NULL);
if(res!= 0)
{
  SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Mount ERR\r\n",res);
  return;
}
else
{
 SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Mount OK\r\n");
}


//ファイルオープン
fileHandle = SYS_FS_FileOpen("TestData.txt", (SYS_FS_FILE_OPEN_WRITE));
if(fileHandle == SYS_FS_HANDLE_INVALID)
{
  SYS_DEBUG_PRINT(SYS_ERROR_WARNING, "FileOpen Error\r\n");
  return;
}
//ファイル書き込み
res= SYS_FS_FileWrite(fileHandle, hello, sizeof(hello));
if(res!= -1) //OK
{
  SYS_DEBUG_PRINT(SYS_ERROR_WARNING, "File Write OK\r\n",);
}
else//NG
{
  SYS_DEBUG_PRINT(SYS_ERROR_WARNING, "FileWrite NG\r\n");
  return;
}
//ファイルクローズ
SYS_FS_FileClose(fileHandle);


マウントからファイル操作、ファイルクローズまでの一連の流れは上記の通りです。

ディレクトリを生成する場合は
SYS_FS_DirectoryMake(dirname);
でdirnameに文字列を渡すことでフォルダの生成ができます。

生成したフォルダに移動する場合は
SYS_FS_DirectoryChange(dirname);
でdirnameに文字列を渡すことでそのフォルダに移動します。

逆にルートフォルダに戻る場合は
SYS_FS_DirectoryChange("/");
でルートフォルダに戻ることが可能です。


FILE SYSTEMの設定で「Enable exFAT ~」にチェックを入れることで32GB以上のSDカードに対応できますが、そのままではビルドに失敗します。ff.hで「#error exFAT feature wants C99 or later」のエラーが発生します。XC32コンパイラはexFATで使用するint64等の変数定義に対応していますが、XC32内でstdバージョン定義がされていないようです。

ff.hの37行目に
#define __STDC_VERSION__ 199902L
を追記して強制的に定義を変更します。


ファイルシステムの時刻がデフォルトは固定となっているため、RTC機能等を実装している場合はapp.cやmain.c等のユーザー側で下記の関数を追加することでファイル生成時やフォルダ生成時に日時が反映されます。なお、GetRtcDateTimeは自作の関数で必要に応じて外付けのRTC等から日時を取得する関数を実装してください。

DWORD get_fattime(void)
{
  SYS_FS_TIME time;
  time.packedTime = 0;
  uint8_t year, month, day, hour, min, sec;

  GetRtcDateTime( &year, &month, &day, &hour, &min, &sec);
  // All FAT FS times are calculated based on 0 = 1980
  time.discreteTime.year = (2000+ year - 1980);
  time.discreteTime.month = month;
  time.discreteTime.day = day;
  time.discreteTime.hour = hour;
  time.discreteTime.minute = min;
  time.discreteTime.second = sec;
  return (time.packedTime);
}


設定によってはすんなりビルドが通らない等ありましたが、比較的簡単にPIC32マイコンにSDカードを接続して読み書きすることができました。その他の注意点としてSDカードの読み書きとconsoleを有効にしただけでプログラムメモリ120kB程度(最適化レベル1)が既に使用済となりました。SDカードの読み書きをする場合は256kB以上のプログラムメモリが大きなPIC32マイコンを選択する必要があります。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年10月16日

mTouchライブラリ追加方法

今回はPIC32マイコンではなく、8bitマイコンのPIC12、PIC16系のmTouchライブラリ追加方法について紹介します。PIC12、PIC16系のマイコンの一部にはCapacitive Sensing (CPS) module、mTouch機能があります。mTouchは静電容量式のスイッチやセンサとして利用できる機能です。

MCC(MPLAB Code Configurator)が利用できるようになってから、mTouchを利用していかなったため、利用してみることにしました。調べてみるとデフォルトではmTouchの機能をMCCから利用できるようにはなっておらず、ライブラリの追加が必要であることが分かりました。マイクロチップのサイトではライブラリファイルをダウンロードして追加するという説明ですが、バージョンやサイトの表示が異なっており、試行錯誤しながらmTouchライブラリを追加することができたので、今回はその方法を紹介します。


mTouchライブラリファイルはこちらからダウンロードします。マイクロチップのサイトではmTouchという名前ですが、「MCC - Touch Library - XXX」という名前になっているようです。Application Libraries内の4ページ目に「MCC - Touch Library - XXX」という名前のフ項目を確認することができます。

webpage.jpg

ライブラリファイルがダウンロードできたら、MPLAB Xを起動させ、Tools→Optionsをクリックします。

mTouch1.jpg

マイクロチップのサイトではEmbeddedという項目にImport Libraryボタンがありますが、MPLAB X v5.45の場合はPluginsという項目のMPLAB Code Configurator 4.xのタブ内にImport Libraryボタンがあります。

mTouch2.jpg


Import Libraryボタンから先ほどダウンロードした「MCC - Touch Library - XXX」のファイルを選択してOKボタンを押すと、ライブラリがインポートされ、mTouch機能を利用することができるようになります。mTouch機能についてはまた別の機会に紹介したいと思います。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年10月09日

PIC32 ソフトウェアリセット

今回はPIC32MX270F256BをターゲットにMPLAB X v5.45+Harmony3+XC32 v2.50を使用して、PIC32マイコンのソフトウェアリセット(Soft Reset)を利用する方法について紹介します。

何かしらの異常が発生した場合に電源投入時の状態に初期化する際にソフトウェアリセットを利用します。Harmony3では予めコンポーネントが用意されているため、コンポーネントを追加するだけで簡単にソフトウェアリセットを利用することができます。ただ、名称が分かりづらく、RCONというコンポーネント名称になっているため、注意が必要です。

RCON1.jpg

RCONを追加した状態でコード生成をするとconfig/(ユーザ指定名)/peripheral/rcon/plib_rcon.h内にソフトウェアリセットの関数が定義されています。

条件に応じてRCON_SoftwareReset();を呼び出すだけでソフトウェアリセットを実行することができます。RCON_SoftwareReset()関数内では割込みの無効化、システムレジスタのアンロック、リセットという一連の必要な処理が既に定義されているため、自身でソフトウェアリセットを実装するよりも簡単に使用することができます。

異常が連続して起きた場合に変な挙動にならないようにソフトリセットの使い方には要注意ですが、コンポーネントを追加するだけで比較的簡単に実装することができました。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

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) | 組込ソフト | このブログの読者になる | 更新情報をチェックする