2025-10-08 11:14 AM
Hi Guys, for an internship I am making a dual channel datalogger. So for that datalogger, I am using DS1338 RTC. Now instead of doing I2C normally, I am doing Bit-banging.
I am using Nucleo-F030R8 board for my prototyping and I am using PA0(SDA) and PA1(SDA).
After using DSO I was able to verify start condition, stop condition and slave address transfer. Also I tried to test ack by manually pulling the sda down and the output was as expected.
Now the issue is I am not able to write or read the RTC and I am getting FFFF while reading it. And there are no hardware issues as I have tested the RTC. This makes me think there is problem with my I2C read function.
Following is the snippet of code I am using for this purpose -
#define I2C1_SDA_HIGH() (GPIOA->BSRR = (1U << SDA1_PIN))
#define I2C1_SDA_LOW() (GPIOA->BSRR = (1U << (SDA1_PIN + 16)))
#define I2C1_SCL_HIGH() (GPIOA->BSRR = (1U << SCL1_PIN))
#define I2C1_SCL_LOW() (GPIOA->BSRR = (1U << (SCL1_PIN + 16)))
#define I2C1_SDA_READ() ((GPIOA->IDR >> SDA1_PIN) & 0x1)
#define I2C1_SDA_INPUT() (GPIOA->MODER &= ~(3U << (SDA1_PIN * 2))) // Input mode = 00
#define I2C1_SDA_OUTPUT() (GPIOA->MODER = (GPIOA->MODER & ~(3U << (SDA1_PIN * 2))) | (1U << (SDA1_PIN * 2)))
UINT8 i2c1_getdata(void)
{
UINT8 dat = 0;
I2C1_SDA_HIGH();
I2C1_SDA_INPUT();
for(UINT8 i = 0; i < 8; i++)
{
dat <<= 1;
I2C1_SCL_HIGH();
delay_us(I2C1_DELAY);
if(I2C1_SDA_READ()) dat |= 0x01;
I2C1_SCL_LOW();
delay_us(I2C1_DELAY);
}
I2C1_SDA_OUTPUT();
return dat;
}
void i2c1_opdata(UINT8 dat)
{
for(UINT8 i = 0; i < 8; i++)
{
if(dat & 0x80) I2C1_SDA_HIGH();
else I2C1_SDA_LOW();
I2C1_SCL_HIGH();
delay_us(I2C1_DELAY);
I2C1_SCL_LOW();
delay_us(I2C1_DELAY);
dat <<= 1;
}
i2c1_waitack();
}
void i2c1_waitack(void)
{
I2C1_SDA_HIGH();
I2C1_SDA_INPUT();
i2c1_wait_tout = I2C1_WAIT_TOUT;
I2C1_SCL_LOW();
delay_us(I2C1_DELAY);
I2C1_SCL_HIGH();
delay_us(I2C1_DELAY);
while (I2C1_SDA_READ())
{
if (i2c1_wait_tout-- == 0) break; // Timeout
delay_us(5);
}
I2C1_SCL_LOW();
delay_us(I2C1_DELAY);
I2C1_SDA_OUTPUT();
}
Help will be really appreciated!
Footnotes-
1)delay_us() is a software delay, hence not very precise, but I have fine tuned the I2C1_delay to get 100khz SCL
2)The time out for ack after calculating came out to be almost 5 us, considering 48Mhz sysclock.
2025-10-08 11:20 AM
Are pins in open-drain mode?
Can you show a logic analyzer capture of what's happening? Do you get an ACK?
You show functions, but not the larger context that calls them.
2025-10-08 11:44 AM
Yes, I have configured the pins as open drain, so that isn't the problem.
Following are the outputs i observed on the dso-
This is the start condition
And this is the slave address.
And about ACK, i manually pulled the sda down but I didn't get time to check for RTC. But it is working as the HAL code was functional.
And for the larger context, following is the flow(I am unable to provide full code as my mentor has placed some restrictions)-
Please do point out if I am making any mistake here.
2025-10-08 1:45 PM - edited 2025-10-08 1:52 PM
You should put external pullups so SDA/SCL are idle high. At the start of your start condition, both are low, which is not a valid state to start off with. May or may not be okay.
At the end of your start condition, you have SDA low and SCL low, which is good.
At the start of your slave address, SCL is now somehow low again. That's a problem and suggests other things are happening between start condition and sending the address.
Ignoring/hardcoding ACK isn't ideal and robs you of knowing whether or not the slave is responding.
2025-10-09 2:57 AM
Hello @niranukroshah
The following post might be useful for you.
I2C Bit-Banging on STM32F103 - STMicroelectronics Community
2025-10-09 3:07 AM
In your scope photo, I see only 8 clock cycles.
The I2C protocol requires 9 clock cycles, 8 for data bits and the 9th for ACK.
2025-10-09 4:44 AM
Thank you for sharing this post. I have referred it previously, but I will go through the repo once again to get a point of reference.
2025-10-09 4:45 AM
Yeah, that issue was actually caused because of a small delay I was using, I removed that delay, and now the ack clock pulse is visible.
2025-10-09 4:53 AM
Thankyou for bringing up the low SCL at the start. That was happening because of a small improper delay I was using.
And about the ack part, I tried it today with my RTC and I was not able to observe the ack on my dso. This tells me that either my RTC is not receiving my signals properly or my SDA pin is not switching to input mode properly, due to which my RTC even though bring SDA low, my chip is not reading it.
2025-10-09 5:41 AM
Basically all I2C devices I know have a static design, i.e. you can halt a transmission at any point, wait an arbitrary amount of time, and continue without problems. Just saying.
Not sure if you worked through the DS1338 datasheet, and you didn't show some other relevent code.
Have you noticed and implemented the so-called "repeated start condition" between many single byte transfers ?