WM8731 setup with stm32f4DISC

I was following MI clouds codec initialization as stm32f405 and stm32f407 (chip inside discovery board) are really similar. After few days with no results I’ve decided to write this post. Hope it will be helpful not only for me but also for other people who make first steps with synths.

/* USER CODE BEGIN Header *//** ******************************************* - Pastebin.com here’s a pastebin with code.

I started with a simple idea → run hardcoded sine using I2S. I decided to stick with HAL.

The schematic for a codec board I use can be found here:

For now as I do not use ADC, I just connected following lines:

PC9 → codec SDA
PA8 → codec SCL

PB12 → codec DACL
PB13 → codec SCK
PB15 → codec MOSI

MISO and ADCL pins are not connected

All perihperal setups are generated using stm32cubeide.

I2C: standard 100kHz mode 7 bit

  • mode: half-duplex master, mco disabled
  • transmission: mode master transmit
  • communiction: i2s philips
  • data: 16 bits on 16bits
  • sampling rate: 48kHz
    (No dma IT for now)

The code compiles and returns no errors but unfortunately there’s no output signal.
I would really like to hear from you how to deal with such things as simply running via debugger doesn’t show any problems here.

Do you have an oscilloscope or logic analyzer? Can you probe those lines and see if you’re getting any signals? I use a Saleae analyzer in situations like this because it will decode the data for you if you’re not super familiar with the communication protocol.

Did you follow the start up sequence outlined in the WM8731 manual? You need to configure its registers over I2C before it will output anything.

The WM8731 has a weird data field from what I can remember. Every control message write to the WM8731 contains: a 7 bit device address, and then two bytes of data… but those two bytes of data consist of a 7 bit register address and a 9 bit value for the value you’re trying to write to the register (aka the value you’re trying to write to the register is split between two frames).

I have some working code written for your exact setup… but I’d like to see if you can figure it out yourself before I spill the beans!

Unfortunately I do not have logic analyzer, plan to buy it, for now just cheap pcb osciloscope.
Yes I do configure I2C, please check the pastebin if possible. Being honest I was not aware that WM8731 has any weird data field. I use HAL_I2C_Mem_Write function for it. So any hints what should I do now?

Break out the scope and look at the datasheet for the WM8731 :slightly_smiling_face:

One thing I’m curious about… why are you shifting the value of 0x1A for the device address? The datasheet says to use 0x1A or 0x1B for the device depending on the CSB pin settings (check the Mikro schematic for that info). I don’t think you need to shift those bits.

Disregard the above… i believe you do need to shift the address by 1.

You do need to get creative with the contents of MemAddress and the data you’re pointing to though.

Maybe read up on I2C a little more… remember… for WM8731 there is a device address, a register address, and the data you want to write to the register. The WM8731 has a 7 bit address + a read/write bit (typical for I2C), then it wants 7 bits for the internal register address and 9 bits for the data going into that register… this is odd because the data frames in I2C are normally 8 bits. You have to get creative and mix in 1 bit from the data frame into the register address frame (see datasheet snippet below).

That’s where the whole ((address<<1) & 0xfe | ((data >> 8) & 0x01) in Emilie’s code comes from.

Thank you so much! I have to admit I’m not so confident about this, that’s what I figure out but still… not work

uint8_t mi_write(uint8_t region, uint16_t data) {
    uint8_t byte_1 = ((region << 1) & 0xfe) | ((data >> 8) & 0x01);
    uint8_t byte_2 = data & 0xff;
    return HAL_I2C_Mem_Write(&hi2c3, (0x1A << 1), byte_1, 1, &byte_2, 1, HAL_MAX_DELAY); }

Break out the scope? Monitor the I2C data and clock lines and see if you’re getting data after power up. Trigger on the rising or falling edge of one of those lines and see what you get.

Well like I said I have for now only this cheap chinese DSO138. Can you tell me if the mi_write function looks fine and there’s some other issue or I2C transfer is still wrong?

I don’t see where it sends 7 bits for the internal register and 9 bits for the data. These is the snippet from wm8731 datasheet and it says that both frames are 8 bit, do I miss something?

Screen Shot 2021-04-09 at 12.20.48

The first byte contains 7 bits of address and the highest data bit.
The second byte contains the lowest 8 bits of data.

It’s also kind of obvious from the rest of the datasheet that register address is 7-bit, and data has 9 bits.

Screen Shot 2021-04-09 at 12.19.14

Ohh right thanks a lot! It wasn’t clear for me from the I2C chart above but now I see it

Next day fighting with codec. I think function for writing i2c I posted above is correct. At least I managed to activate IC. Trying transmitting sinewave over I2S failed. Well… I see on the scope that there’s voltage, but it neither looks or sounds like sine, just noise. Hope logic analyzer will come soon. As for now it’s like a blind game.

There’s one potential issue here, please correct me if I’m wrong. The cables I use are quite long (20cm female-female conn), not sure if these could distort signal so much?

Certainly not!

Interesting. Is it at the expected amplitude? Is there any kind of periodicity in it? Does it look like an obvious format issue?

Ok I have to correct few things. When I zoom in it like a lot, it looks sometimes like sine, the voltage range also seems ok but sounds really noisy. Hope the video will be more informative.