I²S Left/Right Clock (or Word Select clock) runs too fast when selecting the Audio Oscillator

Environment info:

Tested on own integrated product, and nRF5340 Audio DK.

Firmware built on Fedora Linux 42,

Using the Rust programming language, using embassy-nrf & cortex-m crates.

Problem summary:

Intention: Master devices I²S, Sending Left channel data to single speaker.

- When using the Audio Oscillator as clock source for I²S peripheral, the Left/Right Clock AKA Word Select runs on 41,67 kHz instead of the expected 16kHz (measured using oscilloscope)

- When rerunning it with the internal clock, using the suggested parameters as mentioned on the I²S page it works with the 0.8% increased speed as advertised. (again, verified using oscilloscope)

Since the embassy-nrf crate does not yet implement an 'ready to use' peripheral, I've used the embassy-nrf::pac (peripheral access crate) to directly set the registers, just as is done in low-level C.

Set up all the registers and executed tests with following values and in written order.

1. Pin Configurations registers set:

PSEL.MCK = Disconnected, 0x10000000
PSEL.LRCK = Pin number & port configured, Connected, thus starting 0x0..... (works, could measure signals)
PSEL.SDIN = Disconnected, 0x10000000
PSEL.SDOUT = Pin number & port configured, Connected, thus starting 0x0..... (works, could measure signals)

2. Configuration registers set:

CONFIG.CLKCONFIG= CLKSRC depends on test case, BYPASS = false, so either 0x00 or 0x01
CONFIG.MODE = Master, 0x00
CONFIG.RXEN = Disabled, 0x00
CONFIG.TXEN = Enabled, 0x01
CONFIG.MCKEN = Enabled. 0x01
CONFIG.MCKFREQ: in ACLK: 175304704 (0xA72F000), in PCLK32M 135274496 (0x8102000) (see Configuration Examples)
CONFIG.RATIO: in ACLK: _32X (0x00) in PCLK32M _64X (0x02)
CONFIG.SWIDTH = 16Bit (0x01)
CONFIG.FORMAT = I2S (0x00)
CONFIG.ALIGN = Left (0x00)
CONFIG.CHANNELS = Left (0x01)
TXD.PTR = raw pointer
RXTXD.MAXCNT = size of buffer in 32-bit word: 1600 byte buffer, so 400 value. (0x190)

3. Bind interrupts
- Bind interrupt to ISR
- During interrupt:
    - TXD.PTR = set to new pointer
    - EVENTS_TXTRUP = NotGenerated (0x00)
    - <Wait with nop until EVENTS_TXRUP is truely 0x00>

4. (Only when testing ACLK)
HFCLKAUDIO.FREQUENY = 39846 (0x9BA6), (see Audio oscillator example table)
HFCLKAUDIOALWAYSRUN = AlwaysRun (0x01)
TASKS_HFCLKAUDIOSTART = Trigger (0x01)
<Wait until HFAUDIOSTAT = state.running (0b00000000000000010000000000010000)>

5. start I²S
EVENTS_TXTRUP = NotGenerated (0x00)
INTENSET = txtrupd, set, (0b00000000000000000000000000100000)
ENABLE = Enabled (0x01)
TASK_START = Trigger (0x01)

6. Measure

Noticed wrong pitch of sine tone, and that interrupts were triggered more than twice fast in case of ACLK use. Therefore, I started debugging and measuring.
Since we were working on own hardware, I switched to nRF5340 Audio DK, running the exact same program. Still same issue.

Therefore I grabbed an oscilloscope, and measured the LRCLK signal since that determines my sample rate, and measured 41,67 kHz instead of the expected clean 16 kHz.
When I set the clock source to PCLK32M and change the CONFIG.MCLKFREQ and CONFIG.RATIO accordingly, it runs nicely on the on the 16,128 kHz as described in the documentation

All measuring has been done on the nRF5340 Audio DK, Did I miss anything switching to using the ACLK?

Related