I have a FRDM-K22F wired to a Teensy Audio Shield which is essentially an SGTL5000.
Whenever I attempt an I2C write I get a strange result - instead of getting an ACK I get a NACK. Checking with a logic analyser I can see that the I2C SDA line is pulled down only halfway. See the attached screenshot showing the analog output of Channel 2 which is I2C SDA - the problem point is marked at 1.902 V. What could be causing this strange behaviour?
I'm pretty sure it has to do with my K22F board configuration - perhaps I need to disable a pull up resistor somewhere?
解決済! 解決策の投稿を見る。
No, if you see the MCLK clock output, you are OK.
Regarding the I2C signal levels.
What i2C port/pins are used, are there external pull-ups used?. Is the Port PCR set to Open Drain mode?
Hi Don,
One of the reasons why the SGTL5000 is not responding to I2C commands may that the SGTL5000 is not running, i.e it doesn't have master clock present (MCLK). Are you generating the MCLK signal (lets say 12.288MHz) by K22. This signal provides a main clocking reference for codec.
- I don't see any crystal on the teense board (please check) so the clock must be provided externally.
This is just one of the reasons,
THanks,
Michael
Thanks Michael. You might be on to something there. I am generating a MCLK signal at 12.288MHz but the analog output looks strange:
See how it alternates between 2 ranges: 1.38V-1.62V and 1.63V-1.89V. I wonder if that could cause the SGTL5000 to behave erratically.
Here's the code I'm using to generate MCLK:
// Initialise the SAI/I2S module
g_sai_tx_config.protocol = kSAI_BusI2S;
g_sai_tx_config.syncMode = kSAI_ModeAsync;
g_sai_tx_config.mclkOutputEnable = true;
g_sai_tx_config.mclkSource = kSAI_MclkSourceSysclk;
g_sai_tx_config.bclkSource = kSAI_BclkSourceMclkDiv;
g_sai_tx_config.masterSlave = kSAI_Master;
SAI_TxInit(I2S0, &g_sai_tx_config);
// Set the format of the data
g_sai_tx_format.bitWidth = kSAI_WordWidth16bits;
g_sai_tx_format.channel = 0; // Taken from Kinetis Serial Audio Training P17
g_sai_tx_format.sampleRate_Hz = kSAI_SampleRate48KHz;
g_sai_tx_format.masterClockHz = 256 * kSAI_SampleRate48KHz; //12.288MHz
g_sai_tx_format.stereo = kSAI_Stereo;
g_sai_tx_format.protocol = kSAI_BusI2S;
SAI_TxSetFormat(I2S0, &g_sai_tx_format, CLOCK_GetCoreSysClkFreq(), CLOCK_GetCoreSysClkFreq());
Am I doing something wrong in the MCLK generation?
No, if you see the MCLK clock output, you are OK.
Regarding the I2C signal levels.
What i2C port/pins are used, are there external pull-ups used?. Is the Port PCR set to Open Drain mode?
"Is the Port PCR set to Open Drain mode?" I don't think so, and I think this is the problem.
I'm using PTB0 and PTB1 for SCL and SDA respectively. Here's my initialisation code:
// Initialise the pins used for I2C
CLOCK_EnableClock(kCLOCK_PortB);
// I2C0_SCL - I2C Clock on PTB0
PORT_SetPinMux(PORTB, 0u, kPORT_MuxAlt2);
// I2C0_SDA - I2C Data on PTB1
PORT_SetPinMux(PORTB, 1u, kPORT_MuxAlt2);
I think I just need to add the following:
PORT_HAL_SetOpenDrainCmd(PORTB, 0u, true);
PORT_HAL_SetOpenDrainCmd(PORTB, 1u, true);
I'll test this in a few hours when I'm back with my MCU to verify. This is probably a stupid question but without open drain enabled, why isn't the SGTL5000 able to pull the SDA line to 0V (GND)?
Thanks very much for your help - really appreciate it!
It's working now. Here's the full code I used (I'm using KSDK 2.0 so some functions had to be updated):
#include "fsl_i2c.h"
// Configure I2C GPIO pins: SCL on PTB0, SDA on PTB1
#define I2C_PORT PORTB
#define I2C_SCL_PIN 0U
#define I2C_SDA_PIN 1U
port_pin_config_t pinConfig = {0};
pinConfig.pullSelect = kPORT_PullUp;
pinConfig.openDrainEnable = kPORT_OpenDrainEnable;
PORT_SetPinConfig(I2C_PORT, I2C_SCL_PIN, &pinConfig);
PORT_SetPinConfig(I2C_PORT, I2C_SDA_PIN, &pinConfig);
Thanks very much for your help.
OK, thanks for that update. / welcome!
To your question, why the I2C slave device (SGTL) is unable to pull the line low to 0V is easy answer:
- Where the pin is in normal (push-pull) configuration, It actively drives both 1/0 on the output, so if there is a log.1 on the pin output, there is a strong 3V3 signal driven - so the external device is unable to pull it down, and two outputs are fighting resulting to the middle levels.
In the Open drain mode, only 0 is actively driven onto the output, while the 1 (3V3) is managed by external pull-up, which represents very weak signal, which can be pulled low easily by the external device.
So this is it.
/MG