Hello,
Attached is an initial I2C peripheral driver for AVR processor. It was tested with the Arduino Mega with an external FM24C64 FRAM connected on the I2C channel. I only tested with external pull-ups. I'll test with the internal PORT pull-ups and if it works I'll make a patch just with the correct configuration.
This version has the following limitations:
1. Doesn't have timeouts (always INFINITE)
2. Doesn't support acting as a slave on the bus.
Fabio Utzig
I2C master driver for AVR
-
- Posts: 359
- Joined: Sat Jan 07, 2012 6:22 pm
- Location: Brazil
- Has thanked: 1 time
- Been thanked: 20 times
- Contact:
I2C master driver for AVR
- Attachments
-
- avr_platform.patch.gz
- AVR's platform.(mk|dox) support for I2c
- (477 Bytes) Downloaded 343 times
-
- avr_i2c_files.tgz
- AVR I2C driver source files
- (3.54 KiB) Downloaded 398 times
Re: I2C master driver for AVR
Using internal pull-ups for I2C is commonly bad idea because their resistance is too high. Good value for I2C is 1k..5k1 (for 3.3v supply voltage). What resistance have pull-ups in AVR?
-
- Posts: 359
- Joined: Sat Jan 07, 2012 6:22 pm
- Location: Brazil
- Has thanked: 1 time
- Been thanked: 20 times
- Contact:
Re: I2C master driver for AVR
The Manual says Min: 20k, Max: 50k. I'm using external 10k pull-ups with 5V.
Fabio Utzig
Fabio Utzig
Re: I2C master driver for AVR
Hm... try them, but check results with oscilloscope. Let us know, how it works.
-
- Posts: 359
- Joined: Sat Jan 07, 2012 6:22 pm
- Location: Brazil
- Has thanked: 1 time
- Been thanked: 20 times
- Contact:
Re: I2C master driver for AVR
It sometimes works and sometimes don't. First I tried using only the internal pull-ups and it worked at both 100khz and 400khz clocks. Disabling the pull-ups returns NOT ACK errors as expected. But when I added the oscilloscope it just stopped working. Then removing it it still didn't work. What happens is that it sometimes work and sometimes don't. When it stops working the SDA line is pulled down. This causes the TWI subsystem to hang forever and the thread that is using the I2C driver also hangs 'cause there's not TIMEOUT implemented yet.
With external pull-ups it seems to always work.
Fabio Utzig
With external pull-ups it seems to always work.
Fabio Utzig
Re: I2C master driver for AVR
Try to slow down I2C clock. Pull up resistors in I2C needed to return line state to logical "1". More resistance cause more time to recharge line parasitic capacitance, oscilloscope probe adds its own capacitance. Read this article http://dsscircuits.com/articles/effects ... stors.html
-
- Posts: 359
- Joined: Sat Jan 07, 2012 6:22 pm
- Location: Brazil
- Has thanked: 1 time
- Been thanked: 20 times
- Contact:
Re: I2C master driver for AVR
Hi barthess,
Right now I'm using 3.9K resistors and a clock of 100khz. It's been running for 3 hours without problems. I'm using a "wired-up" I2C FRAM (FM24C64).
Yesterday I was using another board but with the FRAM soldered on board and with 10K resistors and 400KHz (running ChibiOS). I've been using the I2C on this board for 2 months with that configuration without errors (barebones FW with no OS).
Fabio Utzig
Right now I'm using 3.9K resistors and a clock of 100khz. It's been running for 3 hours without problems. I'm using a "wired-up" I2C FRAM (FM24C64).
Yesterday I was using another board but with the FRAM soldered on board and with 10K resistors and 400KHz (running ChibiOS). I've been using the I2C on this board for 2 months with that configuration without errors (barebones FW with no OS).
Fabio Utzig
-
- Posts: 359
- Joined: Sat Jan 07, 2012 6:22 pm
- Location: Brazil
- Has thanked: 1 time
- Been thanked: 20 times
- Contact:
Re: I2C master driver for AVR
There's an "error" which can happen now when running on an multi-master configuration.
The "default" in the IRQ handler's switch statement doesn't set errors variable to a valid error. So the i2c call will return an error status but i2cGetError will return I2CD_NO_ERROR. That could only happen if there's other master in the bus or if TWSR is read before it's updated which can't happen because the code is interrupt based.
The correct code for the default should probably be:
Although this is not exactly correct, I guess, since there's no I2CD_SOME_UNKNOWN_ERROR that would do the trick for now.
Fabio Utzig
Code: Select all
default:
/* FIXME: only gets here if there are other MASTERs in the bus */
TWCR = ((1 << TWSTO) | (1 << TWINT) | (1 << TWEN));
wakeup_isr(i2cp, RDY_RESET);
The "default" in the IRQ handler's switch statement doesn't set errors variable to a valid error. So the i2c call will return an error status but i2cGetError will return I2CD_NO_ERROR. That could only happen if there's other master in the bus or if TWSR is read before it's updated which can't happen because the code is interrupt based.
The correct code for the default should probably be:
Code: Select all
default:
/* FIXME: only gets here if there are other MASTERs in the bus */
i2cp->errors |= I2CD_BUS_ERROR;
Although this is not exactly correct, I guess, since there's no I2CD_SOME_UNKNOWN_ERROR that would do the trick for now.
Fabio Utzig
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Who is online
Users browsing this forum: No registered users and 20 guests