平成27年 5月 30日
USARTをCH番号を引数にして簡単に切り替える
割り込み関連のフラグ操作が片付いたので次はUSARTです。
USARTに関連するレジスタのアドレスと割り込み関連のフラグ操作を行いやすくします。
構造体SCI_REGDEF_tにUSARTに関連した情報を集めてあります。この中にIRQ番号があるのは、DMA機能を合わせて使用するときにこの番号が必要になるので入れてあります。
後は、この構造体から関連するレジスタへのアクセス方法を定義してあります。
//usart.h
typedef struct {
volatile uint32_t *base;
uint8_t errIRQ;
uint8_t rxIRQ;
uint8_t txIRQ;
INT_REGDEF_t err;
INT_REGDEF_t rx;
INT_REGDEF_t tx;
INT_PRI_t *pri;
} SCI_REGDEF__t;
#define SCI_REGDEF_t const SCI_REGDEF__t
extern SCI_REGDEF_t cgSCI_RegDef[];
typedef __U1MODEbits_t UxMODEbits_t;
typedef __U1STAbits_t UxSTAbits_t;
#define pUxMODE(ch) (cgSCI_RegDef[ch].base)
#define UxMODE(ch) (*pUxMODE(ch))
#define UxMODECLR(ch) (*(pUxMODE(ch) +1))
#define UxMODESET(ch) (*(pUxMODE(ch) +2))
#define UxMODEINV(ch) (*(pUxMODE(ch) +3))
#define UxMODEbits(ch) (*(volatile UxMODEbits_t*)pUxMODE(ch))
#define pUxSTA(ch) (cgSCI_RegDef[ch].base +4)
#define UxSTA(ch) (*pUxSTA(ch))
#define UxSTACLR(ch) (*(pUxSTA(ch) +1))
#define UxSTASET(ch) (*(pUxSTA(ch) +2))
#define UxSTAINV(ch) (*(pUxSTA(ch) +3))
#define UxSTAbits(ch) (*(volatile UxSTAbits_t*)pUxSTA(ch))
#define pUxTXREG(ch) (cgSCI_RegDef[ch].base +8)
#define UxTXREG(ch) (*pUxTXREG(ch))
#define UxTXREGCLR(ch) (*(pUxTXREG(ch) +1))
#define UxTXREGSET(ch) (*(pUxTXREG(ch) +2))
#define UxTXREGINV(ch) (*(pUxTXREG(ch) +3))
#define pUxRXREG(ch) (cgSCI_RegDef[ch].base +12)
#define UxRXREG(ch) (*pUxRXREG(ch))
#define UxRXREGCLR(ch) (*(pUxRXREG(ch) +1))
#define UxRXREGSET(ch) (*(pUxRXREG(ch) +2))
#define UxRXREGINV(ch) (*(pUxRXREG(ch) +3))
#define pUxBRG(ch) (cgSCI_RegDef[ch].base +16)
#define UxBRG(ch) (*pUxBRG(ch))
#define UxBRGCLR(ch) (*(pUxBRG(ch) +1))
#define UxBRGSET(ch) (*(pUxBRG(ch) +2))
#define UxBRGINV(ch) (*(pUxBRG(ch) +3))
#define SCI_getTxIF(ch) INT_getIF(&cgSCI_RegDef[ch].tx)
#define SCI_setTxIF(ch, val) INT_setIF(&cgSCI_RegDef[ch].tx, val)
#define SCI_getRxIF(ch) INT_getIF(&cgSCI_RegDef[ch].rx)
#define SCI_setRxIF(ch, val) INT_setIF(&cgSCI_RegDef[ch].rx, val)
#define SCI_getEIF(ch) INT_getIF(&cgSCI_RegDef[ch].err)
#define SCI_setEIF(ch, val) INT_setIF(&cgSCI_RegDef[ch].err, val)
#define SCI_getTxIE(ch) INT_getIE(&cgSCI_RegDef[ch].tx)
#define SCI_setTxIE(ch, val) INT_setIE(&cgSCI_RegDef[ch].tx, val)
#define SCI_getRxIE(ch) INT_getIE(&cgSCI_RegDef[ch].rx)
#define SCI_setRxIE(ch, val) INT_setIE(&cgSCI_RegDef[ch].rx, val)
#define SCI_getEIE(ch) INT_getIE(&cgSCI_RegDef[ch].err)
#define SCI_setEIE(ch, val) INT_setIE(&cgSCI_RegDef[ch].err, val)
#define SCI_getIP(ch, ip, is) INT_getIP(cgSCI_RegDef[ch].pri, ip, is)
#define SCI_setIP(ch, ip, is) INT_setIP(cgSCI_RegDef[ch].pri, ip, is)
構造体SCI_REGDEF_tの定義部分を以下に示します。
IRQ番号とベクタ番号はPIC32のデバイスファミリーによって変わるので、直接数値を指定するのではなくXCコンパイラが定義しているマクロ名を参照します。
USARTのCH番号は0からではなく1から始まっているのでCH番号として0を指定した場合に暴走しないように処置してあります。
マクロINT_REGDEF()は昨日のpic32int.hに記述されています。
マクロの名前としてIRQ()とIRQ_()のように紛らわしいのがあります。あまり良くないですね。これは、このファイルのみで使用されるので良しとしますが、本来は名前を変えるべきでしょう。
//usart,c
#define IRQ(ch, intr) _UART##ch##_##intr##_IRQ
#define TXIRQ(ch) IRQ(ch, TX)
#define RXIRQ(ch) IRQ(ch, RX)
#define ERRIRQ(ch) IRQ(ch, ERR)
#define VEC(ch) _UART_##ch##_VECTOR
#define BASE(ch) (uint32_t*)_UART##ch##_BASE_ADDRESS
#define IRQ_(ch) ERRIRQ(ch), RXIRQ(ch), TXIRQ(ch)
#define REGDEF_(ch) INT_REGDEF(ERRIRQ(ch)), INT_REGDEF(RXIRQ(ch)), \
INT_REGDEF(TXIRQ(ch))
#define SCI_REGDEF_(ch) BASE(ch), IRQ_(ch), REGDEF_(ch), IPC_ADDR(VEC(ch))
SCI_REGDEF_t cgSCI_RegDef[] = {
//配列の0番目は事実上のダミー
{NULL, INT_NUM_ERR, INT_NUM_ERR, INT_NUM_ERR, INT_REGDEF(INT_NUM_ERR),
INT_REGDEF(INT_NUM_ERR),INT_REGDEF(INT_NUM_ERR),
IPC_ADDR(INT_NUM_ERR)},
{SCI_REGDEF_(1)},
{SCI_REGDEF_(2)},
#ifdef _UART3
{SCI_REGDEF_(3)},
#endif //_UART3
#ifdef _UART4
{SCI_REGDEF_(4)},
#endif //_UART4
#ifdef _UART5
{SCI_REGDEF_(5)},
#endif //_UART5
#ifdef _UART6
{SCI_REGDEF_(6)}
#endif //_UART6
};