平成27年 4月25日
PIC32の周辺機能(USART)を活用する(その2) USARTの切り替え
(H27/05/30追記)
この内容はPIC325xx/6xx/7xxファミリーでは動作しますが、それ以外の例えばPIC321xx/2xxファミリーでは動作しません。
詳細は
こちら以降を参照してください。この文書は資料の連続性を維持するために、残しておきます。
(追記ここまで)
さて、USARTの実装を始めます。最初は、外部仕様の決定からです。通信プログラムは後回しにして、USARTの初期化と割り込み処理関数を汎用的なライブラリとして作成します。
初期化関数では、指定されたUSARTのCH番号によって初期化するUSARTを切り替える必要があるので、最初にCH番号を元に各USARTへアクセスする手段を用意します。
USARTに関連するレジスタはそれ程多くは無く下記に示すものが全てです。
・基本的な設定レジスタ : MODEレジスタ、STAレジスタ、BRGレジスタ、TXレジスタ、RXレジスタ
・割り込みに関連したビット : 割り込み優先度(正・副)、割り込み許可(TXIE、RXIE, EIE)、割り込みフラグ(TXIF, RXIF,
EIF)
これらを指定されたCH番号に応じて切り替えます。レジスタに関してはアドレスを返すようにすれば問題ないのですが、ビットに関しては個々の配置に規則性が少ないので、読み出しと書き込みの関数を用意します。
最初はレジスタからです。
typedef __U1MODEbits_t MODEbits_t;
typedef __U1STAbits_t STAbits_t;
typedef struct {
volatile MODEbits_t *MODEbits;
volatile STAbits_t *STAbits;
volatile uint_t *BRG;
volatile uint_t *TXREG;
volatile uint_t *RXREG;
} SCI_REGDEF__t;
#define SCI_REGDEF_t const SCI_REGDEF__t
static SCI_REGDEF_t SCIREG_def[] = {
{(MODEbits_t*)&U1MODEbits, (STAbits_t*)&U1STAbits, &U1BRG, &U1TXREG, &U1RXREG},
{(MODEbits_t*)&U2MODEbits, (STAbits_t*)&U2STAbits, &U2BRG, &U2TXREG, &U2RXREG},
{(MODEbits_t*)&U3MODEbits, (STAbits_t*)&U3STAbits, &U3BRG, &U3TXREG, &U3RXREG},
{(MODEbits_t*)&U4MODEbits, (STAbits_t*)&U4STAbits, &U4BRG, &U4TXREG, &U4RXREG},
{(MODEbits_t*)&U5MODEbits, (STAbits_t*)&U5STAbits, &U5BRG, &U5TXREG, &U5RXREG},
{(MODEbits_t*)&U6MODEbits, (STAbits_t*)&U6STAbits, &U6BRG, &U6TXREG, &U6RXREG}
};
これで必要ならMODEレジスタやSTAレジスタへのビット単位でのアクセスも出来ます。
次は比較的規則性のある割り込み優先度です。割り込み優先度はワード単位で見ると規則性はないように見えるのですが、バイト単位では非常に規則的です。従ってバイト単位でアクセスするようにします。バイト単位でのアドレスをテーブルにします。
(H27/05/04追記訂正)
テーブルのCH5とCH6が逆に定義されていましたので訂正します。
(訂正ここまで)
typedef struct {
volatile uint8_t IS:2;
volatile uint8_t IP:3;
} IPC_BYTE_t;
static IPC_BYTE_t *const IPCbyte[] = {
(IPC_BYTE_t*)&IPC6,
(IPC_BYTE_t*)&IPC8,
(IPC_BYTE_t*)&IPC7 +3,
(IPC_BYTE_t*)&IPC12 +1,
(IPC_BYTE_t*)&IPC12 +2, //H27/05/04訂正
(IPC_BYTE_t*)&IPC12 +3
(IPC_BYTE_t*)&IPC12 +2, //H27/05/04訂正
};
最後は割り込み許可フラグと割り込みフラグです。これらは全く規則性がないので、個々のフラグが置かれているレジスタのアドレスとビット位置を定義して、これを元にして読み出しと書き込みを行います。
typedef struct {
volatile uint32_t *IE;
uint32_t MASK[3];
} SCIIE_t;
#define SCI_TXIE 2
#define SCI_RXIE 1
#define SCI_EIE 0
static const SCIIE_t SCIIE[] = {
{&IEC0, 1<<26, 1<<27, 1<<28},
{&IEC1, 1<<8, 1<<9, 1<<10},
{&IEC1, 1<<5, 1<<6, 1<<7},
{&IEC2, 1<<3, 1<<4, 1<<5},
{&IEC2, 1<<6, 1<<7, 1<<8}, //H27/05/04訂正
{&IEC2, 1<<9, 1<<10, 1<<11},
{&IEC2, 1<<6, 1<<7, 1<<8}, //H27/05/04訂正
};
typedef struct {
volatile uint32_t *IF;
uint32_t MASK[3];
} SCIIF_t;
#define SCI_TXIF 2
#define SCI_RXIF 1
#define SCI_EIF 0
static const SCIIF_t SCIIF[] = {
{&IFS0, 1<<26, 1<<27, 1<<28},
{&IFS1, 1<<8, 1<<9, 1<<10},
{&IFS1, 1<<5, 1<<6, 1<<7},
{&IFS2, 1<<3, 1<<4, 1<<5},
{&IFS2, 1<<6, 1<<7, 1<<8}, //H27/05/04訂正
{&IFS2, 1<<9, 1<<10, 1<<11},
{&IFS2, 1<<6, 1<<7, 1<<8}, //H27/05/04訂正
};
最後に、IF・IEを読み出し書き込む関数を示します。関数は各IF・IEごとに用意されていますが、最終的には4個の関数に集約されます。
これらのマクロは引数に異常があるとマクロの呼び出し側でSE_faltaERR()関数を呼び出します。SE_fatalErr()関数はほぼassert()関数と同じです。
#define setTXIE(ch,val,msg) SCI_setIE(ch, SCI_TXIE, val, msg)
#define setRXIE(ch,val,msg) SCI_setIE(ch, SCI_RXIE, val, msg)
#define setEIE(ch,val,msg) SCI_setIE(ch, SCI_EIE, val, msg)
#define getTXIE(ch,val,msg) SCI_getIE(ch, SCI_TXIE, val, msg)
#define getRXIE(ch,val,msg) SCI_getIE(ch, SCI_RXIE, val, msg)
#define getEIE(ch,val,msg) SCI_getIE(ch, SCI_EIE, val, msg)
#define setTXIF(ch,val,msg) SCI_setIF(ch, SCI_TXIF, val, msg)
#define setRXIF(ch,val,msg) SCI_setIF(ch, SCI_RXIF, val, msg)
#define setEIF(ch,val,msg) SCI_setIF(ch, SCI_EIF, val, msg)
#define getTXIF(ch,val,msg) SCI_getIF(ch, SCI_TXIF, val, msg)
#define getRXIF(ch,val,msg) SCI_getIF(ch, SCI_RXIF, val, msg)
#define getEIF(ch,val,msg) SCI_getIF(ch, SCI_EIF, val, msg)
#define SCI_setIF(ch, type, val, msg) \
if(SCI_setIF_1(ch, type, val) == false) \
SE_fatalErr(msg);
#define SCI_getIF(ch, type, val, msg) \
if(SCI_getIF_1(ch, type, val) == false) \
SE_fatalErr(msg);
#define SCI_setIE(ch, type, val, msg) \
if(SCI_setIE_1(ch, type, val) == false) \
SE_fatalErr(msg);
#define SCI_getIE(ch, type, val, msg) \
if(SCI_getIE_1(ch, type, val) == false) \
SE_fatalErr(msg);
#define SCI_setIP(ch, ip, is, msg) \
if(SCI_setIP_1(ch, ip, is) == false) \
SE_fatalErr(msg);
bool SCI_setIE_1(uint8_t ch, uint8_t type, uint8_t val)
{
if((--ch > 5) || (type > 2)){
return false;
}
if(val) *SCIIE[ch].IE |= SCIIE[ch].MASK[type];
else *SCIIE[ch].IE &= (~SCIIE[ch].MASK[type]);
return true;
}
bool SCI_getIE_1(uint8_t ch, uint8_t type, uint8_t *val)
{
if((--ch > 5) || (type > 2)){
return false;
}
*val = (*SCIIE[ch].IE & SCIIE[ch].MASK[type]) ? 1 : 0;
return true;
}
bool SCI_setIF_1(uint8_t ch, uint8_t type, uint8_t val)
{
if((--ch > 5) || (type > 2)){
return false;
}
if(val) *SCIIF[ch].IF |= SCIIF[ch].MASK[type];
else *SCIIF[ch].IF &= (~SCIIF[ch].MASK[type]);
return true;
}
bool SCI_getIF_1(uint8_t ch, uint8_t type, uint8_t *val)
{
if((--ch > 5) || (type > 2)){
return false;
}
*val = (*SCIIF[ch].IF & SCIIF[ch].MASK[type]) ? 1 : 0;
return true;
}