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?

Parents Reply Children
  • Hi Elving,

    First of all, thank you for taking the time and picking this up.

    Currently we're in the early stages of the firmware development, and are now using the 32MHz clock source as a replacement. For now it is not really a huge problem, but it might come around to haunt us later when we integrate other audio/voice devices in our solution. So take your time.

    Don't worry, about Rust, you can write code in C for me, as long as it is on register level. We are aware that it is not officially supported so it is up to us to make the translation.  We are using Async Rust, and are therefore using the nrf-embassy library/crate. These have a Peripheral Access Crate (PAC) for the 'not yet perfectly implemented parts'. Which is generated directly from the Systems View Descriptions (SVD) file. So I can manipulate all bare metal registers easily.

    As you might have noticed, I spell out most abbreviations since they have a different meaning in every context. What do you mean with SDC? Software Defined Clock? I couldn't find the abbreviation in the Glossary

    Kind regards, and have a nice weekend,

    - Matthew

Related