unsigned int dier;
unsigned short cnt;
unsigned short tmpreg = 0;
unsigned short freqrange = 0;
unsigned short result = 0;
/* Enable periphereal clocks */
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
/* Pin: Alternate function, open drain */
GPIOB->CRL |= (GPIO_CRL_CNF6_0 |
GPIO_CRL_CNF6_1 |
GPIO_CRL_CNF7_0 |
GPIO_CRL_CNF7_1 |
GPIO_CRL_CNF5_0 |
GPIO_CRL_CNF5_1 |
GPIO_CRL_MODE5_0 |
GPIO_CRL_MODE5_1 |
GPIO_CRL_MODE6_0 |
GPIO_CRL_MODE6_1 |
GPIO_CRL_MODE7_0 |
GPIO_CRL_MODE7_1 );
/* Enable I2C1 reset state */
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
/* Release I2C1 from reset state */
RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;
/*---------------------------- I2C1 CR2 Configuration ------------------------*/
/* Get the I2Cx CR2 value */
tmpreg = I2C1->CR2;
/* Clear frequency FREQ[5:0] bits */
tmpreg &= ((unsigned char)0xFFC0);
/* Get pclk1 frequency value */
RCC_GetClocksFreq(&rcc_clocks);
pclk1 = rcc_clocks.PCLK1_Frequency;
/* Set frequency bits depending on pclk1 value */
freqrange = (unsigned short)(pclk1 / 1000000);
/* Write to I2Cx CR2 */
I2C1->CR2 = ((freqrange) | I2C_CR2_ITEVTEN | I2C_CR2_ITERREN );
/*---------------------------- I2Cx CCR Configuration --------------------*/
/* Disable the selected I2C peripheral to configure TRISE */
I2C1->CR1 = 0;
/* Reset tmpreg value */
/* Clear F/S, DUTY and CCR[11:0] bits */
tmpreg = 0;
/* Configure speed in standard mode */
result = (unsigned short)(pclk1 / (I2C_CLOCKSPEED << 1));
/* Set speed value for standard mode */
tmpreg |= result;
/* Set Maximum Rise Time for standard mode */
I2C1->TRISE = freqrange + 1;
/* Write to I2C CCR */
I2C1->CCR = tmpreg;
/*---------------------------- I2Cx CR1 Configuration --------------------*/
/* Enable the selected I2C peripheral */
I2C1->CR1 = I2C_CR1_PE;// |
// I2C_CR1_SMBUS |
// I2C_CR1_SMBTYPE ;
// I2C_CR1_ENPEC |
// I2C_CR1_ACK );
/*---------------------------- I2Cx OAR Configuration --------------------*/
/* Set I2Cx Own Address1 and acknowledged address */
I2C1->OAR1 = ((SMB_ADR_HOST << 1) + (1 << 14));
/*---------------------------- Setup I2C IRQs ----------------------------*/
NVIC_SetPriority(I2C1_EV_IRQn, SMB_IRQ_PRIO);
NVIC_EnableIRQ(I2C1_EV_IRQn);
NVIC_SetPriority(I2C1_ER_IRQn, SMB_IRQ_PRIO);
NVIC_EnableIRQ(I2C1_ER_IRQn);
/* Generates the start condition */
I2C1->CR1 |= I2C_CR1_START;
/* Wait until the START condition is generated on the bus:
the START bit is cleared by hardware */
while ((I2C1->CR1&0x100) == 0x100);
Have fun reading the errata:
https://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/ERRATA_SHEET/CD00197763.pdf
Try to check the SR1 bit0 instead of CR1.
You will have a lot of problems by checking the registers that way. Try to use the latest I2C libraries from ST; functions like I2C_CheckEvent() or I2C_GetLastEvent may help.
Someone at ST screwed up the I2C controller interface big-time. You may pass through a lot of states like "sending the N-1 or N-2" bytes in master mode, etc.
I will try to google some decent code, but I see that some few uses the I2C interrupt mode in the proper way.
If the pin is not moving you should check the other end of the I2C pins. Perhaps it's an output to 0 stretching down the line.
I am not sure if I understand what you mean... do you mean that there could be some problems with the I2C peripheral?If it's not connected, try to configure the pin as an output and move it to exclude HW problems (you can do it directly in debug, with the keil interface you have in the screenshots).
The I2C pins are not connected to anything else than the pull-up resistors so there is not another output stretching down the line.
I am not sure if I understand what you mean... do you mean that there could be some problems with the I2C peripheral?
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void HMC5883L_I2C_Init() { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable I2C and GPIO clocks */ RCC_APB1PeriphClockCmd(HMC5883L_I2C_RCC_Periph, ENABLE); RCC_APB2PeriphClockCmd(HMC5883L_I2C_RCC_Port, ENABLE); /* Configure I2C pins: SCL and SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(HMC5883L_I2C_Port, &GPIO_InitStructure); /* I2C configuration */ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x3C; // HMC5883L 7-bit adress = 0x1E; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; /* Apply I2C configuration after enabling it */ I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); }
Code C - [expand] 1 2 /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
[B]insert delay here. I added 10000uS delay.[/B]
/* Release I2C1 from reset state */
RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;
Evgeny makes an important point - I haven't used the STM32 part, but I have observed issues with other peripherals in other vendors' ARM processors when you try to do too much and end up creating a RMW (Ready modify write) situation. In some cases, the peripheral doesn't have the time to respond to the initial bit change. In other cases, the compiler optimizes the operation so that either a cached/local copy of the hardware register's previous contents are used, or only the final results are written out. Be aware that peripheral controllers require some clock cycles of their own to process and transition to the next state reliably.
void I2C3_init(uint32_t I2C_baudrate)
{
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C3); // Deinit I2C3
// configure I2C3
I2C_InitStructure.I2C_ClockSpeed = I2C_baudrate; // 100kHz
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; // I2C mode
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // own address, not relevant in master mode
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // Enable acknowledge when reading (can be changed later on)
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
I2C_Init(I2C3, &I2C_InitStructure); // init I2Cx
I2C_Cmd(I2C3, ENABLE); // Enable I2C3
}
void I2C_GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStructure;
//Configure the GPIO_LED pin
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOI, &GPIO_InitStructure);
/* setup SCL and SDA pins
* You can connect the I2Cx functions to two different
* pins:
* 1. SCL on PH7
* 2. SDA on PH8
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8; // we are going to use PB6 and PB9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven high
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // enable pull up resistors
GPIO_Init(GPIOH, &GPIO_InitStructure);
// Connect I2Cx pins to AF
GPIO_PinAFConfig(GPIOH, GPIO_PinSource7, GPIO_AF_I2C3); // SCL
GPIO_PinAFConfig(GPIOH, GPIO_PinSource8, GPIO_AF_I2C3); // SDA
}
/*===============================================================================================================*/
/* I2C_Write_Byte */
/*===============================================================================================================*/
void I2C_Write_Byte(I2C_TypeDef* I2Cx, uint8_t reg_addr , uint8_t reg_data, uint8_t dev_Addr)
{
//USART_SendData_s( USART3,"I2C_GetFlagStatus:\r\n");
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));/* While the bus is busy */
//USART_SendData_s( USART3,"I2C_GenerateSTART:\r\n");
I2C_GenerateSTART(I2Cx, ENABLE);/* Send I2C3 START condition */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
//USART_SendData_s( USART3,"Sending Device address:\r\n");
I2C_Send7bitAddress(I2Cx, dev_Addr , I2C_Direction_Transmitter);/* Send Device slave Address for write */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
//USART_SendData_s( USART3,"Sending register address:\r\n");
I2C_SendData(I2Cx, reg_addr);/* Send the Device internal register address */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
//USART_SendData_s( USART3,"Sending Data:\r\n");
I2C_SendData(I2Cx, reg_data);/* Send I2C3 EEPROM data */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_AcknowledgeConfig(I2Cx, DISABLE);/* Disable Acknowledgement */
Delay(1);/* Generate 12.285uS delay which is required*/
//USART_SendData_s( DEBUG_COM,"I2C_GenerateSTOP:\r\n");
I2C_GenerateSTOP(I2Cx, ENABLE);/* Send I2C3 STOP Condition */
Delay(1);/* Generate 12.285uS delay which is required*/
I2C_AcknowledgeConfig(I2Cx,ENABLE);/* Enable Acknowledgement to be ready for another reception */
}
/*===============================================================================================================*/
/* I2C_Read_Byte */
/*===============================================================================================================*/
uint8_t I2C_Read_Byte(I2C_TypeDef* I2Cx, uint8_t reg_addr, uint8_t dev_Addr)
{
char Red_reg;
/*------------------------------ Start Dummy write ----------------------------------------*/
//USART_SendData_s( DEBUG_COM,"I2C_GetFlagStatus:\r\n");
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));/* While the bus is busy */
//USART_SendData_s( DEBUG_COM,"I2C_GenerateSTART:\r\n");
I2C_GenerateSTART(I2Cx, ENABLE);/* Send I2C3 START condition */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
//USART_SendData_s( DEBUG_COM,"Sending Device address:\r\n");
I2C_Send7bitAddress(I2Cx, dev_Addr, I2C_Direction_Transmitter);/* Send Device slave Address for write */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
//USART_SendData_s( DEBUG_COM,"Sending register address:\r\n");
I2C_SendData(I2Cx, reg_addr);/* Send the Device internal register address */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/*------------------------------- Dummy write End -----------------------------------------*/
/*------------------------------ Random Read Start ----------------------------------------*/
//USART_SendData_s( DEBUG_COM,"Sending Repeated start:\r\n");
I2C_GenerateSTART(I2Cx, ENABLE);/* Send STRAT condition a second time called repeated start*/
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
//USART_SendData_s( DEBUG_COM,"Sending Device address:\r\n");
I2C_Send7bitAddress(I2Cx, (dev_Addr | 0x01) , I2C_Direction_Receiver);/* Send Device slave Address for read */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/* Test on I2C3 EV7 and clear it */ /* Check for BUSY, MSL and RXNE flags =(EV7)*/
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));
Red_reg = I2C_ReceiveData(I2Cx);
I2C_AcknowledgeConfig(I2Cx, DISABLE);/* Disable Acknowledgement */
Delay(1);/* Generate 12.285uS delay which is required*/
I2C_GenerateSTOP(I2Cx, ENABLE);/* Send I2C3 STOP Condition */
Delay(1);/* Generate 12.285uS delay which is required*/
//I2C_AcknowledgeConfig(I2C3,ENABLE);/* Enable Acknowledgement to be ready for another reception */
//USART_SendData_s(USART3,"I2C read done..\r\n");
return Red_reg;/*Return data which is to be read from device*/
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?