平成27年 5月 30日
割り込み関連のフラグ操作を共通化する(2) 必要な情報は?
USARTやSPIなどの周辺機能をCH番号を引数としてアクセスするライブラリを作成します。これはこれらの機能をライブラリとして活用するためには比較的重要度の高い要求です。
まず最初は、割り込み部分のみを共通化します。各周辺機能には幾つかのIRQ番号が割り振られています。例えばUSARTには送信終了・受信完了・受信エラー発生の3つのIRQが割り当てられています。この個々のIRQに対して対応する割り込みフラグIFSと割り込み許可フラグIECのアドレスおよビット位置を定義します。ヘッダーファイルの先頭でIFS,
IEC, IPCレジスタの先頭アドレスを定義しています。これらはデバイスの規模によらず同じ値のようですが、念のためXC32コンパイラが定義してあるマクロ変数_INT_BASE_ADDRESSからの相対指定としてあります。次のマクロ(IFS_ADDR,
IEC_ADDR, INT_MASK, IPC_ADDRの4つ)がIRQ番号およびベクタ番号から、各々の値を計算します。
//pic32int.h
//割り込みフラグのベースアドレス(デバイスによらず固定)
#define IFS_BASE_ADDR (_INT_BASE_ADDRESS +0x30)
#define IEC_BASE_ADDR (IFS_BASE_ADDR +0x30)
#define IPC_BASE_ADDR (IEC_BASE_ADDR +0x30)
#define INT_ADDR_PITCH 0x10
/* これらはIFSn, IECn, IPCnは一定間隔で配置されていることを前提にしている。
*/
#define IFS_ADDR(irq) ((uint32_t*)(IFS_BASE_ADDR+((irq)/32*INT_ADDR_PITCH)))
#define IEC_ADDR(irq) ((uint32_t*)(IEC_BASE_ADDR+((irq)/32*INT_ADDR_PITCH)))
#define INT_MASK(irq) ((uint32_t)1<<((irq)%32))
#define IPC_ADDR(vec) ((INT_PRI_t*)(IPC_BASE_ADDR+((vec)/4*INT_ADDR_PITCH)+(vec)%4))
#define INT_REGDEF(irq) \
{IFS_ADDR(irq), IEC_ADDR(irq), INT_MASK(irq)}
typedef struct {
volatile uint8_t is:2;
volatile uint8_t ip:3;
} INT_PRI_t;
typedef struct {
volatile uint32_t *IFS;
volatile uint32_t *IEC;
uint32_t mask;
}INT_REGDEF__t;
#define INT_REGDEF_t const INT_REGDEF__t
uint8_t INT_getIF(INT_REGDEF_t *def);
bool INT_setIF(INT_REGDEF_t *def, uint8_t flag);
uint8_t INT_getIE(INT_REGDEF_t *def);
bool INT_setIE(INT_REGDEF_t *def, uint8_t flag);
bool INT_getIP(INT_PRI_t *def, uint8_t *ip, uint8_t *is);
bool INT_setIP(INT_PRI_t *def, uint8_t ip, uint8_t is);
割り込み関連はIRQ番号ごとに、それに対応するIFS, IECのアドレスとビット位置を保持する構造体を使ってフラグ操作を行います。ビット位置はIFSとIECで共通なので一つだけになっています。割り込み優先度も同じようにベクタ番号から該当する優先度設定アドレス(バイト単位)を引き出して、それを元に設定、読み出しを行います。
プログラムは下記になります。
//interrupt,c
uint8_t INT_getIF(INT_REGDEF_t *def)
{
uint32_t ret = *def->IFS & def->mask;
return ret ? 1 : 0;
}
bool INT_setIF(INT_REGDEF_t *def, uint8_t flag)
{
if(flag) *def->IFS |= def->mask;
else *def->IFS &= (~def->mask);
return true;
}
uint8_t INT_getIE(INT_REGDEF_t *def)
{
uint32_t ret = *def->IEC & def->mask;
return ret ? 1 : 0;
}
bool INT_setIE(INT_REGDEF_t *def, uint8_t flag)
{
if(flag) *def->IEC |= def->mask;
else *def->IEC &= (~def->mask);
return true;
}
bool INT_getIP(INT_PRI_t *def, uint8_t *ip, uint8_t *is)
{
*ip = def->ip;
*is = def->is;
return true;
}
bool INT_setIP(INT_PRI_t *def, uint8_t ip, uint8_t is)
{
def->ip = ip;
def->is = is;
return true;
}