cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F030 Nucleo: Bit-Banging I²C to DS1338 RTC returning 0xFFFF

niranukroshah
Visitor

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.

 

2 REPLIES 2
TDK
Super User

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.

If you feel a post has answered your question, please click "Accept as Solution".

Yes, I have configured the pins as open drain, so that isn't the problem. 

Following are the outputs i observed on the dso-

1000091364.jpg

 This is the start condition 

1000091365.jpg

 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)-

  • I am using timer3 to produce interrupt every 1 second, and hence the reading of RTC is done every 1sec.
  • The RTC is initialized by start condition - sending it's address 0xd0(write mode) and then I am waiting for ack. Then I am accessing 07h control register and writing 09h.
  • After this initialization i am just reading from 00h register of RTC. I am handling read and write bit properly so that is not causing any issue.

Please do point out if I am making any mistake here.