Graeme Winter

Clocks on the SAMD51 with µPython

It’s all about the clocks it would seem, for anything nontrivial. Need to first understand the default configuration for micropython to prevent locking up the MCU as soon as you touch it. In this case working on the ItsyBitsy M4 as an exemplar of the platform.

General Clock

Code to probe the Generic Clock Controller registers which control the clocks and peripheral links:

from machine import mem32

GCLK_BASE = 0x40001C00

# clock configuration - § 14.8.3

def print_clock_register(register):
    div = register >> 16
    conf = (register & 0xff00) >> 8
    src = register & 0xf
    en = bool(register & (1<<8))
    print(f"Divider: {div}\nConf: {conf:08b}\nSrc: {src}\nEnabled: {en}")
    
for j in range(12):
    reg = mem32[GCLK_BASE + 0x20 + 4 * j]
    print(f"Clock {j}")
    print_clock_register(reg)
    print()

# peripheral configuration - §14.8.4

for j in range(48):
    reg = mem32[GCLK_BASE + 0x80 + 4 * j] & 0xff
    wrtlock = bool(reg & (1<<7))
    en = bool(reg & (1<<6))
    gen = reg & 0xf
    print(f"Peripheral {j}")
    print(f"Write lock / enable: {wrtlock} / {en}")
    print(f"Generator: {gen}")
    print()

Default config looks like:

Clock 0
Divider: 0
Conf: 00100001
Src: 7
Enabled: True

Clock 1
Divider: 1465
Conf: 00000001
Src: 6
Enabled: True

Clock 2
Divider: 1
Conf: 00100001
Src: 6
Enabled: True

Clock 3
Divider: 3
Conf: 00100001
Src: 6
Enabled: True

Clock 4
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Clock 5
Divider: 1
Conf: 00100001
Src: 6
Enabled: True

Clock 6
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Clock 7
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Clock 8
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Clock 9
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Clock 10
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Clock 11
Divider: 0
Conf: 00000000
Src: 0
Enabled: False

Peripheral 0
Write lock / enable: False / False
Generator: 0

Peripheral 1
Write lock / enable: False / True
Generator: 1

Peripheral 2
Write lock / enable: False / False
Generator: 0

Peripheral 3
Write lock / enable: False / False
Generator: 0

Peripheral 4
Write lock / enable: False / False
Generator: 0

Peripheral 5
Write lock / enable: False / False
Generator: 0

Peripheral 6
Write lock / enable: False / False
Generator: 0

Peripheral 7
Write lock / enable: False / False
Generator: 0

Peripheral 8
Write lock / enable: False / False
Generator: 0

Peripheral 9
Write lock / enable: False / True
Generator: 3

Peripheral 10
Write lock / enable: False / True
Generator: 5

Peripheral 11
Write lock / enable: False / False
Generator: 0

Peripheral 12
Write lock / enable: False / False
Generator: 0

Peripheral 13
Write lock / enable: False / False
Generator: 0

Peripheral 14
Write lock / enable: False / False
Generator: 0

Peripheral 15
Write lock / enable: False / False
Generator: 0

Peripheral 16
Write lock / enable: False / False
Generator: 0

Peripheral 17
Write lock / enable: False / False
Generator: 0

Peripheral 18
Write lock / enable: False / False
Generator: 0

Peripheral 19
Write lock / enable: False / False
Generator: 0

Peripheral 20
Write lock / enable: False / False
Generator: 0

Peripheral 21
Write lock / enable: False / False
Generator: 0

Peripheral 22
Write lock / enable: False / False
Generator: 0

Peripheral 23
Write lock / enable: False / False
Generator: 0

Peripheral 24
Write lock / enable: False / False
Generator: 0

Peripheral 25
Write lock / enable: False / False
Generator: 0

Peripheral 26
Write lock / enable: False / False
Generator: 0

Peripheral 27
Write lock / enable: False / False
Generator: 0

Peripheral 28
Write lock / enable: False / False
Generator: 0

Peripheral 29
Write lock / enable: False / False
Generator: 0

Peripheral 30
Write lock / enable: False / False
Generator: 0

Peripheral 31
Write lock / enable: False / False
Generator: 0

Peripheral 32
Write lock / enable: False / False
Generator: 0

Peripheral 33
Write lock / enable: False / False
Generator: 0

Peripheral 34
Write lock / enable: False / False
Generator: 0

Peripheral 35
Write lock / enable: False / False
Generator: 0

Peripheral 36
Write lock / enable: False / False
Generator: 0

Peripheral 37
Write lock / enable: False / False
Generator: 0

Peripheral 38
Write lock / enable: False / False
Generator: 0

Peripheral 39
Write lock / enable: False / False
Generator: 0

Peripheral 40
Write lock / enable: False / False
Generator: 0

Peripheral 41
Write lock / enable: False / False
Generator: 0

Peripheral 42
Write lock / enable: False / False
Generator: 0

Peripheral 43
Write lock / enable: False / False
Generator: 0

Peripheral 44
Write lock / enable: False / False
Generator: 0

Peripheral 45
Write lock / enable: False / False
Generator: 0

Peripheral 46
Write lock / enable: False / False
Generator: 0

Peripheral 47
Write lock / enable: False / False
Generator: 0

Which is a lot of information (guess should have printed a pretty table?) - link to §14 of the data sheet for details. In this case looks like everyone based on the 48MHz PLL (which is in turn driven by the USB connection?) except that one is disabed so 🤔 -> need to investigate more.

Main Clock

MCLK_BASE=0x40000800

HSDIV = mem8[MCLK_BASE | 0x4]
CPUDIV = mem8[MCLK_BASE | 0x5]

AHBMASK = mem32[MCLK_BASE | 0x10]
APBAMASK = mem32[MCLK_BASE | 0x14]
APBBMASK = mem32[MCLK_BASE | 0x18]
APBCMASK = mem32[MCLK_BASE | 0x1c]
APBDMASK = mem32[MCLK_BASE | 0x20]

def print_LE_bits(value):
    for j in range(0, 32, 8):
        byte = (value >> j) & 0xff
        print(f"{byte:08b}")

print("Main clock")
print(f"HSDIV / CPUDIV: {HSDIV} / {CPUDIV}")
print("AHBMASK")
print_LE_bits(AHBMASK)
print()
print("APBAMASK")
print_LE_bits(APBAMASK)
print()
print("APBBMASK")
print_LE_bits(APBBMASK)
print()
print("APBCMASK")
print_LE_bits(APBCMASK)
print()
print("APBDMASK")
print_LE_bits(APBDMASK)
print()

Output

Main clock
HSDIV / CPUDIV: 1 / 1
AHBMASK
11111111
10111111
11111000
00000000

APBAMASK
11111111
11000111
00000000
00000000

APBBMASK
01010111
10000000
00000001
00000000

APBCMASK
00000000
00100000
00000000
00000000

APBDMASK
00000000
00000000
00000000
00000000