2016-07-18 12:19 AM
Hey friends,
I am trying to initialize I2C to read the content of 24AA02E48TEEPROM but after initializing the I2C busy_flag stays set. the code gets stock atwhile(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY )); inI2C_burst_read().void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
/* RCC system reset(for debug purpose) */
RCC_DeInit();
HSEStartUpStatus = SUCCESS;
RCC_HSICmd(ENABLE);
if(HSEStartUpStatus == SUCCESS)
{
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* Flash 2 wait state */
FLASH_SetLatency(FLASH_Latency_2);
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_6);
// RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
/* TIM2 clock enable */
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3|RCC_APB1Periph_USART2, ENABLE);
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_SPI2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
| RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1 | RCC_APB2Periph_SPI1, ENABLE);
}
}
//===============================
void I2C_init(I2C_TypeDef* I2Cx, uint32_t speed)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_ClockSpeed = speed;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2Cx, &I2C_InitStructure);
I2C_Cmd(I2Cx, ENABLE);
}
//===============================
void I2C_burst_read(I2C_TypeDef* I2Cx, uint8_t HW_address, uint8_t addr, uint8_t n_data, uint8_t *data)
{
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY ));
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2Cx, HW_address, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2Cx, addr);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2Cx, ENABLE);
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2Cx, HW_address, I2C_Direction_Receiver);
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
I2C_AcknowledgeConfig(I2Cx, ENABLE);
while(n_data--) {
if(!n_data) I2C_AcknowledgeConfig(I2Cx, DISABLE);
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));
*data++ = I2C_ReceiveData(I2Cx);
}
I2C_AcknowledgeConfig(I2Cx, DISABLE);
I2C_GenerateSTOP(I2Cx, ENABLE);
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
}
//===============================
int main(int argc, char* argv[])
{
int ret;
uint8_t EE_Content[6] = { 0 };
RCC_Configuration();
I2C_init(I2C1, 100000);
I2C_burst_read(I2C1, 0xA0, 0xFA, 6, EE_Content);
while (1) {
;
//infinite loop
}
}
I read several posts on internet but I could not find anything that helps. I would really appreciate any help.
#stm32f103-i2c-eeprom
2016-07-18 07:27 PM
GPIOB_Pin8 and GPIOB_Pin9
pins to push/pull mode and toggled them. They are my SCL and SDA in I2C mode. I can get state high, 3.3VDC, and low successfully by toggling the pins. In addition, following some suggestions, I putRCC_APB2PeriphClockCmd()
after GPIO_Init() but it did not help neither. This was supposed to be a work around for a bug(?).Can anyone see what I am doing wrong? I appreciate any help in advanced. Best regards,-Alex2016-07-18 07:55 PM
I2C does not use a push-pull driver, it uses an open-drain/colllector driver, with external pull-up resistors. Using PP is going to defeat the slave ACK.
The SPL I2C example code has specific initialization ordering, I2C_Cmd() before I2C_Init(). You should review those, and the EEPROM/FLASH examples. STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\I2C\EEPROM2016-07-19 05:21 AM
Hi clive1,
Thanks for your response. I know that I2C is open drain and I have a 10k pull up on SDA and SCL. if you look at my code im initializing it toGPIO_Mode_AF_OD
.
I just performed that test to verify that hardware is working and pin can change the state. I made some progress since last time. According to table 55 on page 180 of RM0008 Reference manual, I have to remap I2C1 since I am using GPIOB pin8 and pin9 instead of 6 and 7. So I added GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE); after enabling GPIOB and AFIO clock in I2C_init(). This fixed the issue. Best regards,-Alex2016-11-13 12:36 AM
GPIO_Pin_8 | GPIO_Pin_9
for I2C then invoid I2C_init(I2C_TypeDef* I2Cx, uint32_t speed),
you needGPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
Best regards,-Alex