3. レジスタでペリフェラルに直接アクセスする方法¶
ESP32 のペリフェラルは、レジスタを直接読み書きして制御できます。そのためには、データシートを読んで、どのレジスタを使用するか、どの値を書き込むかを知る必要があります。次の例では、MCPWM0 ペリフェラルのプリスケーラをオンにして変更する方法を示しています。
from micropython import const
from machine import mem32
# 使うレジスタアドレスを定義。
DR_REG_DPORT_BASE = const(0x3FF00000)
DPORT_PERIP_CLK_EN_REG = const(DR_REG_DPORT_BASE + 0x0C0)
DPORT_PERIP_RST_EN_REG = const(DR_REG_DPORT_BASE + 0x0C4)
DPORT_PWM0_CLK_EN = const(1 << 17)
MCPWM0 = const(0x3FF5E000)
MCPWM1 = const(0x3FF6C000)
# CLK の有効化と RST の無効化。
print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff))
print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff))
mem32[DPORT_PERIP_CLK_EN_REG] |= DPORT_PWM0_CLK_EN
mem32[DPORT_PERIP_RST_EN_REG] &= ~DPORT_PWM0_CLK_EN
print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff))
print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff))
# MCPWM0 プリスケーラの変更。
print(hex(mem32[MCPWM0])) # PWM_CLK_CFG_REG (reset value = 0)の読取り
mem32[MCPWM0] = 0x55 # PWM_CLK_PRESCALE の変更
print(hex(mem32[MCPWM0])) # PWM_CLK_CFG_REG の読取り
一部のアドレスは ESP32 モジュールによって異なります。たとえば ESP32-S3 では次の値を使います。
DR_REG_DPORT_BASE = const(0x600C_0000)
DPORT_PERIP_CLK_EN0_REG = const(DR_REG_DPORT_BASE + 0x0018)
DPORT_PERIP_RST_EN0_REG = const(DR_REG_DPORT_BASE + 0x0020)
DPORT_PWM0_CLK_EN = const(1 << 17)
MCPWM0 = const(0x6001_E000 + 0x0004)
...
ペリフェラルを使う前には、そのクロックを有効にし、リセットを解除する必要があります。上記の例では、以下のレジスタがこのために使用されています。
DPORT_PERI_CLK_EN_REG
: ペリフェラルクロックを有効にするために使われていますDPORT_PERI_RST_EN_REG
: ペリフェラルのリセット(またはリセットの無効化)に使われています
MCPWM0 ペリフェラルは上記2つのレジスタの第17ビットすなわち DPORT_PWM0_CLK_EN
の値になります。
3.1. レジスタを介したピンへの直接同期アクセス¶
次のコードは、レジスタを介してピンに直接アクセスする方法を示しています。これは一般的な ESP32 ボードでテストしています。コードは、ピン 16, 17, 32, 33 をレジスタを介して出力モードに設定し、ピンの出力値をレジスタを介して切り替えます。ピン 16 と 17 は同時に切り替わります。
from micropython import const
from machine import mem32, Pin
GPIO_OUT_REG = const(0x3FF44004) # GPIO 0-31 の出力レジスタ
GPIO_OUT1_REG = const(0x3FF44010) # GPIO 32-39 の出力レジスタ
GPIO_ENABLE_REG = const(0x3FF44020) # GPIO 0-31 の出力設定レジスタ
GPIO_ENABLE1_REG = const(0x3FF4402C) # GPIO 32-39 の出力設定レジスタ
M16 = 1 << 16 # Pin(16) のビットマスク
M17 = 1 << 17 # Pin(17) のビットマスク
M32 = 1 << (32-32) # Pin(32) のビットマスク
M33 = 1 << (33-32) # Pin(33) のビットマスク
# 次のような出力モードに設定
# p16 = Pin(16, mode=Pin.OUT)
# p17 = Pin(17, mode=Pin.OUT)
# p32 = Pin(32, mode=Pin.OUT)
# p33 = Pin(33, mode=Pin.OUT)
mem32[GPIO_ENABLE_REG] = mem32[GPIO_ENABLE_REG] | M16 | M17
mem32[GPIO_ENABLE1_REG] = mem32[GPIO_ENABLE1_REG] | M32 | M33
print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG]))
# 次のように 1 を出力
# p16(1)
# p17(1)
# p32(1)
# p33(1)
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33
print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG]))
# 次のように 0 を出力
# p16(0)
# p17(0)
# p32(0)
# p33(0)
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17)
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33)
print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG]))
while True:
# 1 を出力
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33
# 0 を出力
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17)
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33)
以下のような出力が得られます:
0x0 0x0
0x30000 0x3
0x0 0x0
"ピン 16 と 17 は同時に切り替わります:

ピン 32 と 33 も同様です。
ピン 34-36 と 39 は入力専用であることに注意してください。また、ピン 1 と 3 は REPL UART の Tx と Rx であり、ピン 6-11 は内蔵の SPI フラッシュに結線されています。