/* ***************************************************
* ロジックアナライザー データ収集・表示
* ***************************************************
* コマンド受信は割込みで処理
* クロックは4MHzXtalをPLLで20倍にし、80MHz(40MIPS)
*
* Target PIC dsPic33FJ128GP802
* MPLAB X , Microchip XC16
* Created on 2014/12/22, 17:45
* 20211116 CXL を RESET命令に変更
* ******************************************************/
#define FCY 40000000UL // 80MHz / 2
#define ch1_pos 6 // Ch1のPortB入力端子位置
//*******************************************************
#include <xc.h>
#include <string.h>
#include <libpic30.h> // 遅延ライブラリ
// コンフィギュレーション ****** XT(3-10MHz)発振 + PLL ******
_FGS(GWRP_OFF & GCP_OFF);
_FOSCSEL(FNOSC_PRIPLL);
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT);
_FWDT(FWDTEN_OFF);
// プロトタイプ *********************************************
void ckCommand(void);
void Aquition(void);
void intl_UART1(void);
void UART_str(char *, char);
void UART_rom(const char *);
void outAqData(int *, int);
// 共通変数 *************************************************
int __attribute__((address(0x800))) AqData[1200]; // 収集データバッファ
int Err_Cmd; // エラー発生フラグ
int freeRun; // フリーランコマンド受信
int MskPtn; // トリガマスクパターン
int PrePtn; // トリガ準備パターン
int TrgPtn; // トリガパターン
int AqSat; // 収集開始
int AqEnd; // 収集終了
int PortData; // 入力ポートデータ
int ChckData; // トリガ検査データ
int AqPtr; // 収集ポインタ
int RcdNo; // 記録データ数
unsigned char RxWptr,RxRptr; // UART Rx文字数
char RxWbuf[20],RxRbuf[20]; // UART Rxバッファ
// メイン ***********************************************************
int main (void){
// -------------- PLLに関連する設定 ----------------------------
PLLFBD = 78; // M = 80 4MHz x80/2/2
CLKDIVbits.PLLPOST=0; // N2 = 2 = 80MHz
CLKDIVbits.PLLPRE=0; // N1 = 2
while (OSCCONbits.LOCK!=1); // PLLの安定(LOCK)を待つ
// ---------------- 初期設定 ------------------------------------
Err_Cmd = 0; // エラー発生フラグ
// -----------------------------------
T1CON = 0x0010; // Timer1 PS 1:8 初期設定
RxWptr = 0; // 受信書込みポインタのリセット
RxRptr = 0; // 受信読込みポインタのリセット
intl_UART1(); // UART設定
_U1RXIP = 4; // Rx割込優先度を4に設定 (既定値)
_U1RXIF = 0; // Rx割込フラッグをクリア
_U1RXIE = 1; // Rx割込を許可
// ---------------- メインループ -------------------------------
while(1){ // ----------コマンド受信----------
while(!RxRptr); // 待ち
ckCommand(); // コマンドの処理
RxRptr = 0; // 受信処理終了を明示
if(Err_Cmd){ // 処理エラーがあった場合
UART_rom("!\r\n"); // 再送要求を送信
continue; // 受信待ちに戻る
}else{ // 正常終了
UART_rom("#\r\n"); // 正常終了を送信
}
// -----------データの収集-----------
Aquition();
// -----------データ送信-------------
outAqData(AqData+AqPtr, 1100-AqPtr); // 収集
outAqData(AqData, AqPtr); // 収集データ送信
UART_rom("##\r\n"); // データ終了を送信
}
return 0;
}
/* ********************************************************************
* PCからのコマンドでトリガ条件を設定する
* #〇〇〇#〇〇
* ||| |└Trigger位置
* ||| └ Sample Rate
* ||└ Ch3 Trigger条件
* |└─ Ch2 Trigger条件
* └── Ch1 Trigger条件
* Err_Cmd 「1」での復帰はエラーを示す
* 使用する共通変数
* Err_Cmd, RxRptr, RxRbuf
* MskPtn, PrePtn, TrgPtn
* PR1
* AqSat, AqEnd
* *******************************************************************/
void ckCommand(void){
int i;
Err_Cmd = 1; // 受信文字列のエラー確認
if(RxRptr != 7)return; // 受信文字数の確認
if(RxRbuf[0] != '#')return; // コマンド分離の確認
if(RxRbuf[4] != '#')return; // コマンド分離の確認
Err_Cmd = 0;
// ----------- 各ChのTrigger条件設定 -------------------------
MskPtn=0;PrePtn=0;TrgPtn=0; // トリガパターン クリア
for(i=3; i>0; i--){ // Ch3 -> Ch1を処理
MskPtn<<=1; PrePtn<<=1; TrgPtn<<=1;
switch(RxRbuf[i]){
case '0':break; // * 任意
case '1':MskPtn++;PrePtn++;TrgPtn++;break; // 1 Hi
case '2':MskPtn++; break; // 0 Low
case '3':MskPtn++; TrgPtn++;break; // / 立上り
case '4':MskPtn++;PrePtn++; break; // \ 立下り
default:Err_Cmd = 1;return; // 指定文字以外
}
}
// Ch位置をボードの接続端子位置に合わせる
MskPtn<<=ch1_pos; PrePtn<<=ch1_pos; TrgPtn<<=ch1_pos;
// ------------------ Sample Rateの設定 ---------------------
switch(RxRbuf[5]){
case '0':PR1 = 4;break; // 1us
case '1':PR1 = 9;break; // 2us
case '2':PR1 = 24;break; // 5us
case '3':PR1 = 49;break; // 10us
case '4':PR1 = 99;break; // 20us
case '5':PR1 = 249;break; // 50us
case '6':PR1 = 499;break; // 100us
case '7':PR1 = 999;break; // 200us
case '8':PR1 = 2499;break; // 500us
case '9':PR1 = 4999;break; // 1ms
case 'A':PR1 = 9999;break; // 2ms
case 'B':PR1 = 24999;break; // 5ms
case 'C':PR1 = 49999;break; // 10ms
default:Err_Cmd = 1;return; // エラー 指定文字以外
}
// ------------------- 収集開始および終了の指定 --------------------
freeRun = 0;
switch(RxRbuf[6]){
case '0':AqSat= 100;AqEnd=1000;break; // トリガは前方
case '1':AqSat= 0;AqEnd=2000;break; // トリガから1ウインド後
case '2':AqSat= 0;AqEnd=3000;break; // トリガから2ウインド後
case '3':AqSat=1100;freeRun= 1;break; // フリーラン
case '4':AqSat= 550;AqEnd= 550;break; // トリガは中央
case '5':AqSat=1000;AqEnd= 100;break; // トリガは後方
default:Err_Cmd = 1;return; // エラー 指定文字以外
}
}
/* ********************************************************************
* 入力データの取り込み処理
* *******************************************************************/
void Aquition(void){
T1CONbits.TON = 1; // Timer1スタート
AqPtr = 0; // 収集ポインタ リセット
RcdNo = 0; // トリガ後データ数 リセット
do{ // -------------- トリガ前保存 および FreeRun --------------
while(!_T1IF); // 取得タイミングを待つ
_T1IF = 0; //
PortData = PORTB; // データを読込
AqData[AqPtr++] = PortData; // 保存
if(AqPtr > 1100) AqPtr = 0; // 保存ポインタを循環
}while(AqPtr < AqSat); // AqSat(取得開始)数まで保存
if(freeRun)return; // FreeRun時は、保存完了
do{ // ---------------- トリガ条件の確認 -------------------------
do{ // -------------- 前条件の確認 ---------------------------
while(!_T1IF); // 取得タイミングを待つ
_T1IF = 0; //
PortData = PORTB; // データ読込
AqData[AqPtr++] = PortData; // 保存
if(AqPtr > 1100) AqPtr = 0; // 保存ポインタを循環
ChckData = PortData & MskPtn; // 条件検査用データ作成
}while(ChckData != PrePtn); // トリガ前条件成立まで待つ
do{ // ----------------トリガ条件の成立待機 ------------------
while(!_T1IF); // 取得タイミングを待つ
_T1IF = 0; //
PortData = PORTB; // データ読込
AqData[AqPtr++] = PortData; // 保存
if(AqPtr > 1100) AqPtr = 0; // 保存ポインタを循環
ChckData = PortData & MskPtn; // 条件検査用データ作成
}while(ChckData ==PrePtn); // トリガ前条件成立なら繰返
}while(ChckData !=TrgPtn); // トリガ条件一致で抜ける
do{ // ------------------- トリガ後保存 ----------------------------
while(!_T1IF); // 取得タイミングを待つ
_T1IF = 0; //
PortData = PORTB; // データ読込
AqData[AqPtr++] = PortData; // 保存
if(AqPtr > 1100) AqPtr = 0; // 保存ポインタを循環
}while(++RcdNo < AqEnd); // AqSat(取得完了)数まで保存
T1CONbits.TON = 0; // Timer1停止
}
/* ********************************************************************
* UARTの初期設定
* 115200bps @ 40MHz
* *******************************************************************/
void intl_UART1(void){
// U1BRG = 259; // 9600bps @ 40MHz
U1BRG = 21; // 115200bps @ 40MHz
U1MODE = 0x8000; // 8bit, No Parity,
U1STA = 0x0400; // No Flow Control
_PCFG4 = 1; // UART Portをデジタル設定
_PCFG5 = 1; // UART Portをデジタル設定
_U1RXR = 2; // UART1 RX を RP2(RB2 AN4)に設定
_RP3R = 3; // UART1 TX を RP3(RB3 AN5)に設定
__delay_ms(200); // UART安定動作を待つ遅延
}
/* ********************************************************************
* UART1 文字列送信
* 文字配列の指定文字数だけ 送信する
* *******************************************************************/
void UART_str(char *str, char ptr){
while(ptr--){ // 指示文字数分繰り返す
while(U1STAbits.UTXBF); // 送信バッファが空なら
U1TXREG = *str++; // 一文字送信 ポインタを進める
}
}
/* ********************************************************************
* UART1 ROM文字列送信
* 指定文字列を送信する
* *******************************************************************/
void UART_rom(const char *str){
while(*str){ // 終端の「0」になるまで繰り返す
while(U1STAbits.UTXBF); // 送信バッファが空なら
U1TXREG = *str++; // 一文字送信 ポインタを進める
}
}
/* ********************************************************************
* Data配列送信
* 配列のデータを送信する 一行50文字+CRLF
* adata:Data配列名 ptr:データ数
* ch1_pos;データのあるbit位置
* *******************************************************************/
void outAqData(int *adata, int ptr){
int i = 0;
char c;
while(ptr--){ // 指示文字数分繰り返す
c = *adata++ >> ch1_pos; // データを取り出しポインタを進める
c = c & 0xF; // 下位4ビットを取り出す
c = c | '@'; // 「@」からの文字コードに変換
while(U1STAbits.UTXBF); // 送信バッファが空なら
U1TXREG = c; // 一文字送信
if((++i >= 50) | (ptr == 0)){ // 50文字毎または
i = 0; // 指定数送信完了で
UART_rom("\r\n"); // CRLFを挿入
}
}
}
/* ********************************************************************
* Uart1 Rx割込み処理
* RxWptr,RxRptr; RxWbuf[20],RxRbuf[20];
* *******************************************************************/
void __attribute__ ((interrupt, no_auto_psv)) _U1RXInterrupt(void) {
char RxData;
_U1RXIF = 0;
if(U1STAbits.OERR){ // 受信エラーなら
U1STAbits.OERR = 0; // エラークリア
RxWptr = 0; // 既存データはすべて廃棄
}else{ // 正常受信なら
RxData = U1RXREG;
switch(RxData){ // CRLFを受信したら、
case 0x0A: // それまでの受信データを
case 0x0D: // RxRbufに転送する
if(RxWptr){ // ただし、CRLFは転送しない
memcpy(RxRbuf, RxWbuf, RxWptr);
RxRptr = RxWptr; // バッファ転送し受信数保存
RxWptr = 0; // ポインタリセット
}
break;
case '!': // トリガ中止コマンド
asm("RESET"); // PICをソフトウエアでリセット
break;
default: // 一般文字なら
RxWbuf[RxWptr++] = RxData; // 受信バッファに保存
if(RxWptr >= 20)RxWptr = 0; // 容量超えはすべて廃棄
break;
}
}
}