Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
2,442 Views

Getting data from a rtc device through I2C

Hi all, 

 

I would like to retrieve information from a RTC device which is directly connected to a GPIO, using the i2c protocol. So, the first step was to load the i2c-gpio driver with this piece of code: 

 

# define GPIO_RTC_SDA 100# define GPIO_RTC_SCL 99 MODULE_DESCRIPTION("i2c via gpio module"); MODULE_LICENSE("GPL"); static struct i2c_gpio_platform_data rtc_device_data = { .sda_pin = GPIO_RTC_SDA, .scl_pin = GPIO_RTC_SCL, .udelay = 25 }; static struct platform_device i2c_gpio_bus_rtc = { .name = "i2c-gpio", .id = 0, .dev = { .platform_data = &rtc_device_data, } }; static int __init i2c_gpio_bus_init(void) { int ret; return platform_device_register(&i2c_gpio_bus_rtc); } static void __exit i2c_gpio_bus_exit(void) { platform_device_unregister(&i2c_gpio_bus_rtc); } module_init(i2c_gpio_bus_init); module_exit(i2c_gpio_bus_exit);  

 

Once loaded, I get a new device in the /sys/bus/i2c/devices directory. For testing purpose I then use i2cdetect utility to scan the i2c bus to see if I could find my rtc device. But, I could not find it. So, I added manually a device at address 0x68 on the i2c bus with the following command: 

echo m41t83 0x68 > /sys/devices/platform/i2c-gpio.0/i2c-0 (m41t83 is my rtc device) as it is explained in the Documentation/i2c/instantiating-devices file. However, it is still not working. 

 

Does somebody understand what’s going on? 

 

Info : I work with a nios II processor under linux (uClinux distrib). I use a device tree to setup board devices.
0 Kudos
15 Replies
Altera_Forum
Honored Contributor I
189 Views

You won't need the bus driver. Please check the gpio and rtc devicetree nodes, which I used in my NEEK extension design. 

 

gpio_0: gpio@0x1500 { 

compatible = "opencores,bit-gpio-2.0","opencores,bit-gpio-rtlsvn2"; 

reg = < 0x1500 0x10>; 

bidir-width = <8>; 

input-width = <4>; 

# gpio-cells = <2>; 

gpio-controller; 

}; //end gpio (gpio_0) 

 

i2crtc { 

# address-cells = <1>; 

# size-cells = <0>; 

compatible = "i2c-gpio"; 

gpios = <&gpio_0 7 0 

&gpio_0 6 0>; 

scl-is-output-only; 

 

rtc@68 { 

compatible = "ds1307"; 

reg = <0x68>; 

}; 

};
Altera_Forum
Honored Contributor I
189 Views

Hello hippo, 

 

Thank for replying to my post. I tried your solution but when my board is booting, the i2c-gpio driver reports an error about the i2crtc node as we can see below: 

 

altera_gpio: /sopc@0/gpio@0x6002630: registered, irq -6 altera_gpio: /sopc@0/gpio@0x6002640: registered, irq -6 altera_gpio: /sopc@0/gpio@0x6002650: registered, irq -6 altera_gpio: /sopc@0/gpio@0x6002660: registered, irq -6 altera_gpio: /sopc@0/gpio@0x6002670: registered, irq -6 /sopc@0/i2crtc: invalid GPIO pins, sda=-22/scl=-22 JFFS2 version 2.2. © 2001-2006 Red Hat, Inc. msgmni has been set to 25 io scheduler noop registered (default) ttyAL0 at MMIO 0x6002540 (irq = 2) is a Altera UART console enabled  

 

I looked on the source code and I found that error -22 match the EINVAL errno value (invalid argument) in the i2c-gpio driver's probe function. Extract below: 

/* Check if devicetree nodes exist and build platform data */ static int i2c_gpio_of_probe(struct platform_device *pdev, struct i2c_gpio_platform_data *pdata) { struct device_node *np = pdev->dev.of_node; const __be32 *prop; int sda_pin, scl_pin; int len; if (!np || of_gpio_count(np) < 2) return -ENXIO; sda_pin = of_get_gpio_flags(np, 0, NULL); scl_pin = of_get_gpio_flags(np, 1, NULL); if (sda_pin < 0 || scl_pin < 0) { pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", np->full_name, sda_pin, scl_pin); return -ENXIO; } }  

 

 

So I think, something goes wrong in my device tree. Here is what I did: 

-> in my device tree, I replaced the I2C_RTC node (described as a sub node of the sopc) 

sopc@0 { ranges; # address-cells = < 1 >; # size-cells = < 1 >; device_type = "soc"; compatible = "ALTR,avalon", "simple-bus"; bus-frequency = < 50000000 >; I2C_RTC: gpio@0x6002660 { compatible = "i2c-gpio"; reg = < 0x06002660 0x00000010 >; width = < 2 >; /* width type NUMBER */ resetvalue = < 0 >; /* resetValue type NUMBER */ }; //end gpio@0x6002660 (I2C_RTC) }; //end sopc@0  

 

by: (see bold text) 

 

sopc@0 { ranges; # address-cells = < 1 >; # size-cells = < 1 >; device_type = "soc"; compatible = "ALTR,avalon", "simple-bus"; bus-frequency = < 50000000 >; gpio_0: gpio@0x6002660 { compatible = "ALTR,pio-10.0","ALTR,pio-1.0"; reg = < 0x6002660 0x00000010 >; //bidir-width = <8>; //input-width = <4>; width = < 2 >; resetvalue = < 0 >; # gpio-cells = <2>; gpio-controller; }; //end gpio (gpio_0) i2crtc { # address-cells = <1>; # size-cells = <0>; compatible = "i2c-gpio"; gpios = < &gpio_0 100 0 /* SDA signal */ &gpio_0 99 0 >; /* SCL signal */ scl-is-output-only; rtc@68 { compatible = "m41t83"; /* as my rtc chip is an ST m41t83 */ reg = <0x68>; }; }; //end i2crtc }; //end sopc@0  

 

Where am I going wrong?
Altera_Forum
Honored Contributor I
189 Views

Actually, when parsing the device tree, the i2c-gpio driver could not retrieve the 'gpios' field use to describe the SDA and SCL pins. So I decided to come back to a module which create an i2c bus and then, populate this bus. 

 

# include <linux/module.h> # include <linux/init.h> # include <linux/i2c-gpio.h> # include <linux/i2c.h> # include <linux/platform_device.h> # include <linux/kernel.h> # define GPIO_RTC_SDA 100 # define GPIO_RTC_SCL 99 MODULE_DESCRIPTION("i2c via gpio module"); MODULE_LICENSE("GPL"); static struct i2c_gpio_platform_data rtc_device_data = { .sda_pin = GPIO_RTC_SDA, .scl_pin = GPIO_RTC_SCL, .udelay = 2.5, //f=400kHz .scl_is_open_drain = 1, .sda_is_open_drain = 1 }; static struct platform_device i2c_gpio_bus_rtc = { .name = "i2c-gpio", .id = 0, .dev = { .platform_data = &rtc_device_data, } }; static struct i2c_board_info i2c_gpio_bus_devices = { { I2C_BOARD_INFO("m41t83", 0x68), .platform_data = &rtc_device_data, }, }; static int __init i2c_gpio_bus_init(void) { int ret; struct i2c_adapter *bus; struct i2c_client *rtc; ret = platform_device_register(&i2c_gpio_bus_rtc); if (ret) printk(KERN_ERR "i2c_bus_driver: Error when registering: %d\n", ret); /* Populate bus */ bus = i2c_get_adapter(0); rtc = i2c_new_device(bus, i2c_gpio_bus_devices); if (rtc == NULL) printk(KERN_ERR "i2c_bus_driver: no device added to %s bus\n", bus->name); return ret; } static void __exit i2c_gpio_bus_exit(void) { platform_device_unregister(&i2c_gpio_bus_rtc); } module_init(i2c_gpio_bus_init); module_exit(i2c_gpio_bus_exit);  

 

However, I still do not found my device at the address 0x68 with the i2cdetect utility :-( 

Could someone help me?
Altera_Forum
Honored Contributor I
189 Views

Hi everyone, 

 

As I cannot found my rtc device on the i2c bus, I am using an oscilloscope to see what's happening on the bus. Here are the measures performed on the SDA and SCL pins: 

 

https://www.alteraforum.com/forum/attachment.php?attachmentid=7752  

 

 

We can see that we get a NAK from the device. But something catch my attention: the time the clock is high between the first SCL's rising edge and the following falling edge. Is it normal? 

 

Remember that my rtc device address is 0x68
Altera_Forum
Honored Contributor I
189 Views

Hi, 

 

Maybe you need the function 'i2c_put_adapter' like 

 

static int __init i2c_gpio_bus_init(void) { int ret; struct i2c_adapter *bus; struct i2c_client *rtc; ret = platform_device_register(&i2c_gpio_bus_rtc); if (ret) printk(KERN_ERR "i2c_bus_driver: Error when registering: %d\n", ret); /* Populate bus */ bus = i2c_get_adapter(0); rtc = i2c_new_device(bus, i2c_gpio_bus_devices); i2c_put_adapter(bus); // <--- here if (rtc == NULL) printk(KERN_ERR "i2c_bus_driver: no device added to %s bus\n", bus->name); return ret; }  

 

Kazu
Altera_Forum
Honored Contributor I
189 Views

Hi Kazu, 

 

Thank you for your reply. I added the i2c_put_adapter(bus) in my module, however I do not have the expected result. Actually, I get some strange result, as you can see on the image below: 

 

https://www.alteraforum.com/forum/attachment.php?attachmentid=7759  

 

On the 9th SCL's rising edge I get a half voltage level which is interpreted as a NAK by the i2cdetect utility. This curious case disappears if I configure the SCL as "output only". This brings me to think about my pins configuration: as the SCL and SDA lines are open drained, I configured them as such. 

 

Am I right, or I need to set them as output only as Hippo told me? 

In both cases I get a NAK... 

 

jrm
Altera_Forum
Honored Contributor I
189 Views

Hi, 

 

 

--- Quote Start ---  

On the 9th SCL's rising edge I get a half voltage level which is interpreted as a NAK by the i2cdetect utility. This curious case disappears if I configure the SCL as "output only". This brings me to think about my pins configuration: as the SCL and SDA lines are open drained, I configured them as such. 

 

--- Quote End ---  

 

 

Did you make the SCL and SDA 'hardware pins' open-drain ? It seems that a bus fighting occurs. The SDA line is used bidirectionally, your FPGA pin must be tri-state when the slave returns the ACK (= 0) signal. The open-drain pin is a simple method to achieve this. The SCL pin can be 'output only' if you don't have other I2C master except your FPGA. 

 

Kazu
Altera_Forum
Honored Contributor I
189 Views

Hi Kazu, 

 

Thank you for these explanations. Indeed, the 'hardware' SCL and SDA pins are open-drained with a 4k7 resistor, so I configured them as such in the module I wrote. 

Our design uses the basic altera GPIO, and I came upon this webpage: http://www.alterawiki.com/wiki/gpio where the author uses the opencore GPIO instead of the basic altera GPIO. So, do you think the bug I cope with can come from this difference? 

 

jrm
Altera_Forum
Honored Contributor I
189 Views

Hi, 

 

 

--- Quote Start ---  

 

Indeed, the 'hardware' SCL and SDA pins are open-drained with a 4k7 resistor, so I configured them as such in the module I wrote. 

Our design uses the basic altera GPIO, and I came upon this webpage: http://www.alterawiki.com/wiki/gpio where the author uses the opencore GPIO instead of the basic altera GPIO. So, do you think the bug I cope with can come from this difference? 

 

--- Quote End ---  

 

 

At first, please check the resistor's value, soldering of SDA line, m41t83's power line. And check the rising and falling time of SCL. It must be < 300ns. Please refer 

 

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/cd00127116.pdf 

 

at pp.53. If the rising time of SLC is not enough, it is one method to set the SLC hardware pin as output. 

 

In the i2c-gpio method, SCL and SDA signals are generated directly by your Nios CPU, and this is the reason why the SLC clock period is not constant. If you have any doubt, there is another way to use an 'opencore's i2c core'. 

 

Kazu
Altera_Forum
Honored Contributor I
189 Views

Hello, 

 

 

--- Quote Start ---  

 

At first, please check the resistor's value, soldering of SDA line, m41t83's power line. And check the rising and falling time of SCL. It must be < 300ns. Please refer 

 

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/cd00127116.pdf 

 

at pp.53.  

--- Quote End ---  

 

Everything is okay, I checked all timing specifications at pp.53. However, the SCL's frequency is never higher than 12kHz, even if I set the struct i2c_gpio_platform_data's udelay field (in the linux module) to 2 for example. Normally, the SCL's frequency should be 500kHz when setting udelay to 2. Anyway, even at 12kHz, the RTC device should acknowledged to I2C frames. 

 

So I think I am going to try with the opencore's GPIO.. 

 

jrm
Altera_Forum
Honored Contributor I
189 Views

Hi, 

 

 

--- Quote Start ---  

 

Everything is okay, I checked all timing specifications at pp.53. However, the SCL's frequency is never higher than 12kHz, even if I set the struct i2c_gpio_platform_data's udelay field (in the linux module) to 2 for example. Normally, the SCL's frequency should be 500kHz when setting udelay to 2. Anyway, even at 12kHz, the RTC device should acknowledged to I2C frames. 

 

--- Quote End ---  

 

 

Please note that the SLC's frequency is not so important, but its tf and tr are important because SLC is used as the clock of Flip-Flops. If you observe the same 'half voltage' phenomenon at the 9th clock rising edge, please change the pull-up resistors value high if possible. If you can lower the voltage, this is the problem of m41t83's output abilities, though it means some malfunction. And of course, you connect X'tal etc. and the internal circuit of your m41t83 is working correctly? 

 

Kazu
Altera_Forum
Honored Contributor I
189 Views

I'm coming back after a while ;-) 

 

So I eventually succeed in detecting my i2c device (RTC) despite I still get some half-amplitude i2c signals. Actually it was not a software issue but rather a FPGA configuration problem. To explain it simple: 

 

https://www.alteraforum.com/forum/attachment.php?attachmentid=7811  

 

On figure 1, you can see that we used intermediate signals between the GPIO and the SDA and SCL hardware pins to adapt the 2-bit-wide bus. However it seems that it was not a proper solution because when by-passing these signals I could be able to scan successfully the rtc, using the i2cdetect utility.  

 

But, as I described below, I still get some weird i2c frames... Anyway, I can now get data from my rtc device so my problem is solved! 

 

Thanks to both of you ;-)
Altera_Forum
Honored Contributor I
189 Views

Hi, 

 

 

--- Quote Start ---  

So I eventually succeed in detecting my i2c device (RTC) despite I still get some half-amplitude i2c signals. Actually it was not a software issue but rather a FPGA configuration problem. To explain it simple: 

 

--- Quote End ---  

 

 

If you still observe the half-amplitude i2c signals on your SDA, I strongly recommend you to check again whether your SDA pin is open-drain or not. The half voltage at the ACK phase means that someone is driving your SDA line high despite your rtc is driving it low. In normal case, only the pull-up resistor can make the SDA line high and it's force is not so strong because you are using 4k7.  

 

Kazu
Altera_Forum
Honored Contributor I
189 Views

For what it's worth, I just finished debugging an I2C interface that had very similar issues and found this knowledge base item from Altera was the cause. I did some digging in the Chip Planner (Arria 10 w/ Q16.0) and found that my tristate buffer in SDA and SCL was always driving (!OE = GND) and control signal was wired to the BUF_IN port. This is exactly the opposite of what I was expecting (!OE = control and BUF_IN = GND). Therefore, we were always driving the bus and the half-voltage on the SDA pin was a function of the two ends fighting each other. 

 

https://www.altera.com/support/support-resources/knowledge-base/solutions/rd01262015_264.html 

 

The solution is to create a psuedo-ground signal and set an attribute to keep it in the synthesizer. Confirmed that this fix resulted in a working I2C bus and the Chip Planner also confirmed that they were utilized properly in the IO buffer.
Altera_Forum
Honored Contributor I
189 Views

In the i2c-gpio method, SCL and SDA signals are generated directly by your Nios CPU, and this is the reason why the SLC clock period is not constant. If you have any doubt, there is another way to use an 'opencore's i2c core'.

Reply