皆さん こんにちは。
ペリフェラルに対して細かい制御をしようとするとAPIだけでは処理しきれません。
レジスタに値を書いたり読んだりすることで細かい制御が可能になります。
そこで今回はレジスタへのアクセス方法についてお話します。
前回、UARTの送信処理を行いました。次回は少し飛躍して割り込みを使って送信する予定です。
その際にレジスタへアクセスする必要が出てくるので、今予習しておこうというわけです。
RP2040のレジスタ
RP2040データシート の4章にペリフェラルの記述があり、UARTは4.2項に書かれています。
そしてUARTのレジスタは4.2.8項に書かれていますので必要になった時にご覧になってください。
ペリフェラルのレジスタにはあるメモリーの番地が割り当てられています。
各ペリフェラルは構造体として定義されていて、それらはメモリーの番地と紐づけられています。
SDKの中を検索すると以下の定義が見つかります。(見やすくするために、ひとまとめに記述しています)
#define uart0 ((uart_inst_t *)uart0_hw)
#define uart0_hw ((uart_hw_t *)UART0_BASE)
#define UART0_BASE _u(0x40034000)
static inline uart_hw_t *uart_get_hw(uart_inst_t *uart) {
uart_get_index(uart); // check it is a hw uart
return (uart_hw_t *)uart;
}
uart_get_hw()で uart_hw_t* が得られるのでUART0のレジスタにアクセスするには
uart_get_hw(uart0)->レジスタ名
とします。
例えば、UART0のCRレジスタに0を書くには
uart_get_hw(uart0)->cr = 0;
例えばUARTの構造体定義やレジスタ名は
C:\Users\m3925\Documents\Pico\pico-sdk\src\rp2040\hardware_structs\include\hardware\structs\uart.h で確認できます。
またレジスタ内の各フィールドの定義は
C:\Users\m3925\Documents\Pico\pico-sdk\src\rp2040\hardware_regs\include\hardware\regs\uart.h で確認できます。
m3925の部分は皆さんのユーザー名に置き換えてください。
レジスタにアクセスするためのAPI
レジスタにアクセスするためのAPIがありますので紹介しておきます。
hw_set_bits(), hw_clear_bits(), hw_xor_bits(), hw_write_masked() の4つです。
前3つの関数は Atomically と書かれているのでスレッドをまたぐことになっても安全性が保証されますが、
hw_write_masked()だけは unsafe と書かれているので割り込みやマルチスレッド環境においては注意が必要です。
(*addr ^ values) でレジスタの値とvaluesを XOR し、write_mask でマスクした後に書き戻しているので unsafe だろうと想像はできます。
__force_inline static void hw_write_masked(io_rw_32 *addr, uint32_t values, uint32_t write_mask) {
hw_xor_bits(addr, (*addr ^ values) & write_mask);
}
pico-sdk/src の下に rp2040 や rp2_common のディレクトリーがあります。
rp2040 には このマイコンのレジスタや構造体が定義されています。
rp2040 は rp2シリーズの第1作ですが、この先rp2シリーズが増えてくることが予想されます。
rp2_common は pr2シリーズで共通に使えるAPIが主に定義されています。
アクセス例
hw_set_bits() :
1ビットまたは複数ビットに対して 1 を書く場合に使います。
次の例では uart0のIMSCレジスタのTXIMフィールドに 1 を書きます。
hw_set_bits(&uart_get_hw(uart0)->imsc, 1 << UART_UARTIMSC_TXIM_LSB);
hw_clear_bits() :
1ビットまたは複数ビットに対して 0 を書く場合に使います。
次の例では uart0のIMSCレジスタのTXIMフィールドに 0 を書きます。
hw_clear_bits(&uart_get_hw(uart0)->imsc, 1 << UART_UARTIMSC_TXIM_LSB);
hw_xor_bits() :
1ビットまたは複数ビットを XOR する場合に使います。
この関数はあまり使わないと思うので説明を省略します。
hw_write_masked()の中で使われているので、そちらを参考になさってください。
hw_write_masked() :
マスクする範囲の1ビットまたは複数ビットに対して 01 の組み合わせの値を書き込み場合に使います。
次の例では uart0のIFLSレジスタのRXIFLSELフィールドに 5 を書きます。
hw_write_masked(&uart_get_hw(uart)->ifls, 5 << UART_UARTIFLS_RXIFLSEL_LSB,
UART_UARTIFLS_RXIFLSEL_BITS);
細かく確認していませんが他のペリフェラルも同じようなイメージでアクセスできるようです。
値の確認
なお、デバッグを開始するとペリフェラル・レジスタの値を CORTEX PERIPHERALS から確認することができます。
以下の画像では UART0 レジスタ群の値が見えています。
次回は hw_set_bits() , hw_clear_bits() を使いながら UART の送信割り込みを試してみます。
お疲れさまでした。