2020-02-20 01:01 AM
I am programming Blue Pill stm32f103c8t6 mcu, and I am having troubles implementing I2C driver for it. I have tried one I2C example from one site, then tried to implement it on my own by datasheet, yet it does not work - it does not generate START.
I know this I2C and I2C device work, because I have tried using STM32Duino software and the device with address 72 replied, but I have troubles reimplementing it on my own. I use CMSIS, no HAL and the minimal code is as follows:
void i2c_init() {
I2C_InitTypeDef i2c_initstruct;
I2C_StructInit(&i2c_initstruct);
// Initialize I2C
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
i2c_initstruct.I2C_ClockSpeed = 100e3;
i2c_initstruct.I2C_Mode = I2C_Mode_I2C;
i2c_initstruct.I2C_DutyCycle = I2C_DutyCycle_2;
i2c_initstruct.I2C_OwnAddress1 = 0;
i2c_initstruct.I2C_Ack = I2C_Ack_Disable;
i2c_initstruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C2, &i2c_initstruct);
I2C_Cmd(I2C2, ENABLE);
// Initialize GPIO as open drain alternate function
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void i2c_start2(uint8_t addr_with_mode) {
nlio_print("(0");
// Wait until no longer busy
while((I2C2->SR2 & I2C_SR2_BUSY) != 0);
// Send start bit
I2C2->CR1 |= I2C_CR1_START;
// Wait until no longer busy
while((I2C2->SR2 & I2C_SR2_BUSY) != 0);
//while((I2C2->SR2 & I2C_SR2_MSL) == 0);
nlio_print("(1");
// Wait until START bit is actually sent
while((I2C2->SR1 & I2C_SR1_SB) == 0);
nlio_print("(2");
// Write address
I2C2->DR = addr_with_mode;
nlio_print("(3");
// Wait for ACK (address match)
while((I2C2->SR1 & I2C_SR1_ADDR) == 0);
nlio_print("(4");
// Read SR1 followerd by SR2 to clear (I2C->SR1 & ADDR)
(void) I2C2->SR2;
}
void i2c_send(uint8_t byte) {
// Wait until Data register is empty
while((I2C2->SR1 & I2C_SR1_TXE) == 0);
// Send byte
I2C2->DR = byte;
}
void i2c_end() {
// Wait until Data register is empty
while((I2C2->SR1 & I2C_SR1_TXE) == 0);
// Wait until Byte transfer finished
while((I2C2->SR1 & I2C_SR1_BTF) == 0);
// Send stop
I2C2->CR1 |= I2C_CR1_STOP;
}
#define WRITE 0
void i2c_test() {
i2c_init();
nlio_print("Hello\r\n");
i2c_start2((72 << 1) | WRITE);
nlio_println("Chp1");
i2c_send(0);
nlio_println("Chp2");
i2c_end();
// i2c_write(72, 0);
nlio_println("Chp4");
uint8_t rec;
i2c_read(72, &rec);
nlio_println("Chp5");
// uart_println("Wait busy");
// i2c_wait_busy();
// uart_println("Wait done");
// info();
while(1);
// uart_println("Sending STOP");
// i2c_read(72);
// uart_println("DONE\n");
// while(1) {
// info();
// }
}
int main() {
// ...
nlio_print("NLIO\r\n");
i2c_test();
while(1);
}
and it hangs when waiting for START condition, so the output is as follows:
NLIO
Hello
(0(1
I have also soldered two pull-up 5k1 resistors connecting SDL and SCL to 3.3V, yet it still hangs.
I have no clue what I am doing wrong. Any help is appreciated.
2020-02-20 01:20 AM
Observe SDA/SCL pins, using oscilloscope/logic analyzer.
Read out the I2C registers and check/compare to working example.
JW
2020-02-20 01:38 AM
Thanks for your answer. It ***** that I currently I don't have an oscilloscope, even though I have recently ordered low speed one. I will try the register reading at least, and if it won't help I guess I will have to wait until it arrives.
2020-02-20 01:38 AM
Thanks for your answer. I currently I don't have an oscilloscope, even though I have recently ordered low speed one. I will try the register reading at least, and if it won't help I guess I will have to wait until it arrives.
2020-02-20 05:40 AM
Try initializing GPIO first, and I2C afterwards. Print the control and status registers at every step.
2020-02-20 05:50 AM
Tried initializing GPIO first, didn't help. Looking at the registers, even though I don't really know what exactly I should look for.
2020-02-20 06:21 AM
The content of the registers immediately after printing "(0" is following
CR1 0001
CR2 0024
OAR1 4000
OAR2 0000
DR 0000
SR1 0000
SR2 0000
TRIS 0025
and immediately after printing "(1" the registers change and SR2 indicates I2C is busy:
CR1 0101
CR2 0024
OAR1 4000
OAR2 0000
DR 0000
SR1 0000
SR2 0002
TRIS 0025
and since then nothing changes, the registers remaing with those values.
2020-03-16 06:08 AM
Did you check "anolog function" init?
AFIO->MAPR &=~ 0x00000002; // GPIOB 6 and 7 AF
if you wanna use 8.and 9. pins, then
AFIO->MAPR =| 0x00000002; // GPIOB 8 VE 9 AF
and if i am not wrong, your pins cant be 10 and 11