2013-02-15 08:35 AM
Hi,
I'm using CMSIS to set up an I2C driver. As an example device I have an EEPROM - tried and tested on PIC18s, so I've been through the learning curve for I2C - just getting it going on STM32. Configured CLS and SDA pins as AF_PP. Written interrupt handlers for EVT/BUF and ERR. I have enabled the interrupts and called I2C_GenerateSTART() The interrupt fires, reports SR1 SB bit set; so then I call I2C_Send7bitAddress() with direction_Transmitter Problem - on logic analyzer, I'm getting the Start + address going out, but then NACK, ie SDA goes high for the 9th bit. Before you ask, the address is correct; besides, I've tried unplugging the EEPROM and putting a 2k pulldown resistor on SDA. On a scope, this is enough to pull it down when I tristate it; but when my I2C runs, it shows no sign at all of being pulled down. (Also this technique worked well when I was working with other processors - useful for eliminating the possibility that it's the EEPROM playing hard to get.) So I conclude that the processor is not releasing the SDA line in the 9th bit (ACK/NACK). I have tried all colours and flavours of pixie-dust, nothing seems to work yet. Any ideas? I tried configuring the SDA pin as AF_OD but then nothing worked at all, not even the SCL. Henry #i2c2013-02-15 09:34 AM
So I conclude that the processor is not releasing the SDA line in the 9th bit (ACK/NACK).
The I2C is an Open-Collector/Drain interface, the processor won't be driving it high, it can only drive it low. AF_PP is clearly inappropriate for the interface. You'll want external pull-up on the two pins. The slave won't ACK if the address is wrong, make sure there isn't a shift resulting from the 7-bit representation.
2013-02-15 10:24 AM
Thanks Clive.
Yes, I have pull-ups right next to the EEPROM. The EEPROM board is as used to develop another I2C interface, I am confident it works. When I disconnect the board, and simply have a pull DOWN on SDA, I can see the correct Start-address sequence on clock/SDA, using my logic analyzer - also on a scope. But then the 9th bit is being pulled high. Now the only thing I have hooked up is that pull-down resistor, so it follows that it must be the processor pulling it high. I agree, AF_PP does not look appropriate; but I would expect the I2C hardware to be overriding that, to tristate the pin during the 9th bit transfer, so as to allow the slave to assert Ack. The problem is, looking at all the options I have for setting up the pin, in the GPIO configuration, I have input-AIN, In-floating, In-pulldown, In-pullup, In-open-drain, out-push-pull; and the only Alterfate Function options areAF-PP and AF-OD. AF-OD on SDA does not seem to work at all (I left SCL as AF-PP as I am only operating this as a master). The only AF option that seems to do anything at all is SCL = SDA = AF_PP. So while I agree with you that AF-PP is not right for the 9th bit, what options do I have? I cannot believe I'm supposed to be switching it myself in the interrupt!!! No way; and not even possible as I don't get an interrupt after the 8th bit. So I'm still baffled. My hardware by the way is Discovery Cortex M3 - it'll be STM32F100 (from memory - I'm away from the lab right now). Sometimes I find the missing ingredient is sleep. But this time I don't think even that will work.2013-02-15 01:33 PM
Stop shooting randomly, and try and figure out how you're breaking the pin configuration and I2C. The processor should never drive the pin high.
/**
* @brief Initializes the LM75_I2C..
* @param None
* @retval None
*/
void LM75_LowLevel_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< LM75_I2C Periph clock enable */
RCC_APB1PeriphClockCmd(LM75_I2C_CLK, ENABLE);
/*!< LM75_I2C_SCL_GPIO_CLK, LM75_I2C_SDA_GPIO_CLK
and LM75_I2C_SMBUSALERT_GPIO_CLK Periph clock enable */
RCC_APB2PeriphClockCmd(LM75_I2C_SCL_GPIO_CLK | LM75_I2C_SDA_GPIO_CLK |
LM75_I2C_SMBUSALERT_GPIO_CLK, ENABLE);
/*!< Configure LM75_I2C pins: SCL */
GPIO_InitStructure.GPIO_Pin = LM75_I2C_SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(LM75_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure LM75_I2C pins: SDA */
GPIO_InitStructure.GPIO_Pin = LM75_I2C_SDA_PIN;
GPIO_Init(LM75_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure LM75_I2C pin: SMBUS ALERT */
GPIO_InitStructure.GPIO_Pin = LM75_I2C_SMBUSALERT_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(LM75_I2C_SMBUSALERT_GPIO_PORT, &GPIO_InitStructure);
}
2013-02-15 01:38 PM
Yes, of course, it's got to be AF_OD on both lines. There's no tristating going on.
as soon as I stopped working on it, I realized. My test with SDA set to AF_OD didn't work: but that must have been finger trouble, I bet the Vcc got disconnected or something. I'll try it again, it's bound to work. Duh. Thanks Clive, that was spot on.