Strange I2C Hang

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
axel
Posts: 6
Joined: Sun Oct 04, 2020 8:12 pm

Strange I2C Hang

Post by axel »

Hi all!

I'm attempting to get basic I2C communication running with a WM8731 audio codec (NOT I2S - that comes later).

I'm trying to stay nice and organized with my code, splitting out functions to separate .cpp/.h files, and I'm wondering if that's possibly the source of the issue.

Let's start from the basics. If I set up a simple I2C sketch, using PB3/PB10, things work perfectly fine:

Code: Select all

#include <Wire.h>

TwoWire hI2C(PB3,PB10);

void setup() {
    hI2C.begin();
}

void loop() {
    hI2C.beginTransmission(0x1B);
    hI2C.write(0x00);
    hI2C.endTransmission();
}
This yields me a nice message on the I2C lines, as I'd expect. Note that the codec isn't even connected at this point, so I won't get anything more than the first byte:

Image

Now, let's jump into my current code that is causing me all kinds of headaches.

The main .ino file contains this (non-relevant stuff trimmed out):

Code: Select all

// Arduino library includes
#include <Wire.h>

// custom file includes
#include "wm8731.h"

// Primary I2C Device (only used for WM8731 control right now)
TwoWire hI2C(PB3,PB10);

void setup() {
    // communication initialization
    hI2C.begin();           // hardware I2C for codec comms
    
    // hardware initialization
    WM_reset(hI2C, 48000, sampleWidth);     // reset and initialize the codec
}
Now, inside wm8731.cpp, I've got the following (again, excess fluff is trimmed out):

Code: Select all

/**
 * basic register write Functions
 * returns I2C error code (0: OK, 1: data too long, 2: addr NACK, 3: data NACK, 4: other error)
 */
static uint8_t WM_writeRegister(TwoWire hI2C, unsigned char addr, unsigned char value) {
    // initialize error code to 5
    uint8_t errorCode = 5;
    // split 16-bit value into two 8-bit bytes
    unsigned char byte1 = (addr<<1) | ((value>>8) & 0x1);
    unsigned char byte2 = value & 0xFF;
    // send the message
    hI2C.beginTransmission(0x1A);
    hI2C.write(byte1);
    hI2C.write(byte2);
    errorCode = hI2C.endTransmission();
    // finally, return the error code (hopefully 0)
    return errorCode;
}
/**
 * codec reset Function
 * resets the entire WM8731 codec chip, and sets all functions back to startup defaults
 */
uint8_t WM_reset(TwoWire hI2C, uint32_t audioFreq, codecSampleWidth_t wordSize) {
    uint8_t errorCode = 5;
    // send the reset command and make sure it set okay
    #ifdef DEBUG_WM_I2C
        Serial.print(DEBUG_WM_PREFIX);
        Serial.println("Resetting WM8731");
    #endif
    errorCode = WM_writeRegister(hI2C, WM_REG_RESET, 0); // <-- WM_REG_RESET is 0x1E
}
The code is hanging at the hI2C.endTransmission() line, and I have no clue why. As far as I can tell, there should be no difference between an I2C transaction in setup() or loop(), and one in a .cpp file included with the main sketch. Regardless, the sketch is hanging at that endTransmission() line and all I see on the scope is the following:

Image

Both lines just drop to ground and stay there until the board is reset, and then they do the same thing again.

I've got 4k7 pullups on both I2C lines, and right now they're not even connected to anything on the breadboard other than the MCU (a Nucleo F401RE). Can anyone help shed some light on what's going on here? Is passing in a TwoWire object as a function argument not a valid thing you can do with Arduino? Is there something specific to running I2C in a .h/.cpp file that I'm missing? The compiler gives no errors, so I'm out of ideas. It seems like regardless of what data I try and write with that function, it still hangs at the endTransaction() line.

Any and all help or suggestions is appreciated! I know posting full code is recommended, but I've got multiple 100+ line code files in this project so I'm trying to keep the spam to a minimum.
by stevestrong » Mon Oct 05, 2020 7:14 am
Which OS?
Which development environment (Arduino)?
Do you have warnings? If you use Arduino please turn on verbose for compile.

Usually, objects should be passed by pointers, I don't know how is working in your version.
Go to full post
User avatar
fpiSTM
Posts: 1745
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Strange I2C Hang

Post by fpiSTM »

Which core you use?
stevestrong
Posts: 502
Joined: Fri Dec 27, 2019 4:53 pm
Answers: 8
Location: Munich, Germany
Contact:

Re: Strange I2C Hang

Post by stevestrong »

Which OS?
Which development environment (Arduino)?
Do you have warnings? If you use Arduino please turn on verbose for compile.

Usually, objects should be passed by pointers, I don't know how is working in your version.
axel
Posts: 6
Joined: Sun Oct 04, 2020 8:12 pm

Re: Strange I2C Hang

Post by axel »

Sorry, I probably should've included that information in the OP.

Board: Nucleo F401RE (STM32F401RE)
Core: Arduino_Core_STM32
IDE: Arduino IDE (only for compiling, using VS Code for editing)

No warnings in the compiler, even with verbose mode on.

Good point (heh) about the pointers though. I'm not a c programmer by trade so stuff like that I would never figure out on my own. I'll see if I can get the code working with pointer references to the I2C device.

Thanks for the suggestion!
axel
Posts: 6
Joined: Sun Oct 04, 2020 8:12 pm

Re: Strange I2C Hang

Post by axel »

So I did the simplest thing, just added an ampersand to all the function variables to create a reference to the TwoWire object. That seems to have done the trick - the code no longer hangs and sends the I2C data properly! Thanks for that suggestion.

Now I'm getting data NACKs when trying to talk to the WM8731, but this is apparently a common issue with high data rates. I'll add some inline resistors and slow things down a bit to solve that. For now, though, I think I'm good!

Thanks again everyone, I learned something new.
Post Reply

Return to “General discussion”