Already using my I2C port.

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all

EDIT: New question at below post

I'm using an ATmega128 and I'm utilising port D0 and D1 as interrupts for wireless comms. I now need to use a compass IC which uses I2C to communicate (SCL and SDA). Unfortunately for the ATmega128 these ports are shared. Any suggestions?

NB: The atmega128 is part of a dev kit, and port DO and D1 are PCB tracked to the wireless chip, I can change the interrupts easily enough in code, but not so easy hardware wise.

Thanks,

Jags

DataSheet I am using;
http://www.atmel.com/dyn/resourc...

Last Edited: Mon. May 2, 2011 - 05:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unless someone has an easier/cheaper suggestion, I'm thinking of using this product, I can't see any major issues with it.

http://www.sparkfun.com/products...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since noone else is answering, I will offer my worthless advice.

It wasn't too bright to put the SDA_SCK on the INT0 and INT1 lines. Good thing they only did it on one device of the AVR line. Terrible luck that that (double 'that'; one is a relative pronoun, the other is a conjunction. Ain't English a wonderful language? Almost as crazy as C) was the device selected for the WiFi board.

I suspect that the I2C_to_UART may not work. I assume that the UART section of the I2C_to_UART would go to the AVR and the I2C to the compass. But the
I2C_to_UART is a slave device and the compass might be a slave device also. So the I2C_to_UART is assuming that its I2C section will be driven by a microcontroller master I2C and the UART being connected to the peripheral device. It may not work 'backwards'.

If that is correct, it may be easier to recreate the I2C signals manually using two free port pins: on bidirectional pin for data and one output pin for the I2C clock. The AVR code would make the start condition and then the I2C configuration byte. It would manually move the clock pin high and low for eight pulses and then one more to read the acknowledge bit from the compass. Then it would read the data from the compass while again generating the clock pulses. It's confusing but not difficult to do. Search the forums for 'I2C bit-banging' as a start.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I didn't even think of that, and it seems you're right, they are both slave devices. Woe is me. I will look into bit-banging, I'm only relatively beginnerish at microcontrollers and have not heard the term before. My first thought, before the converter, was to program ports althougth I'd never heard the term, and had no idea how to search to see if someone had done it before.

in summary, thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes you can quite easily make any two IO pins to work as a software I2C host. For starters I would suggest taking a glimpse at Philips/NXP I2C specification or at least the Wikipedia page on I2C, which even has some non-AVR specific sample code how to do it.

Simonetta wrote:

it may be easier to recreate the I2C signals manually using two free port pins: on bidirectional pin for data and one output pin for the I2C clock.

I would not recommend that as it is against the specification and some chips may refuse to work when clock is output only.

Both clock and data pin must be bidirectional and used in open-collector mode, only the resistors are allowed to pull a wire high and only the devices are allowed to pull a wire low.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bit-bang the I2C on any other pins. Just add the Fleury "i2cmaster.S" to your project.

I cannot see why you want a i2c_to_uart interface board. The mega128 has got two UARTs in the first place.

I agree that INT0 on the SCL pin is crazy.
Likewise INT2 shares with RXD1.

As far as I can remember, the mega128 does not have PCINT interrupts. However there are pin-compatible mega128 replacements.

Anyway, it sounds as if you must make some compromises with your existing hardware. It does not stop you having a full and frank discussion with the board designer. It may make you feel better!

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please educate me. In a simple one master/one slave I2C interface, why would the clock pin not be an output of the master? I understand that in a multi-master I2C system it could happen. But even though multi-master is part of I2C specification, has anyone ever been obsessive/compulsive enough to actually build a multi-master I2C design?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:
Please educate me. In a simple one master/one slave I2C interface, why would the clock pin not be an output of the master? I understand that in a multi-master I2C system it could happen. But even though multi-master is part of I2C specification, has anyone ever been obsessive/compulsive enough to actually build a multi-master I2C design?
So that slaves can "stretch the clock" to keep the master from overrunning their receivers. Most slave peripherals are implemented in hardware, but the spec allows for stretching, and my software bitbanged slaves make good use of it

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Exactly. It may be the slave that drives the clock down while processing the just received byte. For example AVRs do that when they are slaves, and some hardware slave chips (but these may have some kind of core running software, but just look hardware chips to users).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After some searching, I found the I2C code by peter fleury (the one mentioned above). Anything I should know/do apart from reading up on I2C protocol more before implementing? e.g. I think I have to have pull up resistors on the pins from memory.

I've been focusing on other parts of the design the last few days instead of this I2C business, kinda ~procrastination, though fruitful procrastination.

Thanks for all the replies.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi I have a further Question, In implementing Peter Fleurys code, There is some editing required to the s file. The code below, as well as the time delay.

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA     	4		// SDA Port D, Pin 4   
#define SCL		5		// SCL Port D, Pin 5
#define SDA_PORT        PORTD           // SDA Port D
#define SCL_PORT        PORTD           // SCL Port D         

;******

;-- map the IO register back into the IO address space
#define SDA_DDR		(_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR		(_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT		_SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT		_SFR_IO_ADDR(SCL_PORT)
#define SDA_IN		(_SFR_IO_ADDR(SDA_PORT) - 2)
#define SCL_IN		(_SFR_IO_ADDR(SCL_PORT) - 2)

I have modified it to

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA     	1		// SDA Port D, Pin 4   
#define SCL		0		// SCL Port D, Pin 5
#define SDA_PORT        PORTF           // SDA Port D
#define SCL_PORT        PORTF           // SCL Port D         

;******

;-- map the IO register back into the IO address space
#define SDA_DDR		(_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR		(_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT		_SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT		_SFR_IO_ADDR(SCL_PORT)
#define SDA_IN		(_SFR_IO_ADDR(SDA_PORT) - 2)
#define SCL_IN		(_SFR_IO_ADDR(SCL_PORT) - 2)

I am getting an error in the SFR_IO_ADDR macro, "number must be positive and less than 32' and i am guessing this is to do with PORT F causing the macro to go out of range. I know I have to probably modify the -1 and -2, but i am just not sure how, I can't even find a decent explanation of the macro online. Could someone please explain it to me?

p.s. I am using the ATmega128

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not the -1 and -2 parts.

The PORTF just cannot be used via the IO commands because it does not fit into the IO mapped register range of 0-31, so it has to be used as memory mapped register like SRAM.

You should use a IO mapped port register, if you are not prepared to change all the lines that use the ports as IO mapped to MEM mapped.

Or you could just write the I2C routines in C yourself - it is propably easier than changing the ASM code to work with mem-mapped registers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA        1      // SDA Port D, Pin 4   
#define SCL      0      // SCL Port D, Pin 5
#define SDA_PORT        PORTF           // SDA Port D
#define SCL_PORT        PORTF           // SCL Port D        

Surely it is sensible to make your comments match the code?

If you want to use PORTF, you simply change the _SFR_IO_ADDR() to the mem-mapped equivalents. e.g.

#define SDA_OUT      _SFR_MEM_ADDR(SDA_PORT)

This is why Mr Fleury said:

;***** Adapt these SCA and SCL port and pin definition to your target !!

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jepael wrote:
Not the -1 and -2 parts.
In the particular case of the mega128 (and the mega64, too), the offsets are a problem too since PINF is not in the "normal" position relative to DDRF and PORTF. If you're going to use pins on PortF on the mega128, you'll need to write a special macro for SDA_IN and SCL_IN.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so I've had a look at the data sheet and some header files, would the code become something like this?

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA        1      // SDA Port F, Pin 1   
#define SCL      0      // SCL Port F, Pin 0
#define SDA_PORT        PORTF           // SDA Port F
#define SCL_PORT        PORTF           // SCL Port F         

;******

;-- map the IO register back into the IO address space
#define SDA_DDR      (_SFR_MEM_ADDR(SDA_PORT) - 1)
#define SCL_DDR      (_SFR_MEM_ADDR(SCL_PORT) - 1)
#define SDA_OUT      _SFR_MEM_ADDR(SDA_PORT)
#define SCL_OUT      _SFR_MEM_ADDR(SCL_PORT)
#define SDA_IN      PINF
#define SCL_IN      PINF

PINF is defined in iom128.h which is included in io.h by the following line

/* Input Pins, Port F */
#define PINF      _SFR_IO8(0x00)

Alternatively, could I just have the address ~hardcoded (from the datasheet)

e.g. 0x00

or a massive offset?

#define SDA_IN      (_SFR_MEM_ADDR(SDA_PORT) - 98)
#define SCL_IN      (_SFR_MEM_ADDR(SCL_PORT) - 98)

I appreciate the help gentlemen, I am more a hardware guy then software, and it is really doing my head in comprehending the layers of coding.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well turns out cbi and sbi don't work plus 0x1F anyway, so im pulling out some LED's and changing ports.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jagbags wrote:
Well turns out cbi and sbi don't work plus 0x1F anyway, so im pulling out some LED's and changing ports.

That is what I meant when I said they are memory mapped.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PINF is in IO_space
DDRF, PORTF is in MEM_space

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA        1      // SDA Port F, Pin 1   
#define SCL      0      // SCL Port F, Pin 0
#define SDA_PORT        PORTF           // SDA Port F
#define SCL_PORT        PORTF           // SCL Port F         

;******

;-- map the IO register back into the IO address space
#define SDA_DDR      (_SFR_MEM_ADDR(SDA_PORT) - 1)
#define SCL_DDR      (_SFR_MEM_ADDR(SCL_PORT) - 1)
#define SDA_OUT      _SFR_MEM_ADDR(SDA_PORT)
#define SCL_OUT      _SFR_MEM_ADDR(SCL_PORT)
#define SDA_IN      (_SFR_IO_ADDR(PINF))
#define SCL_IN      (_SFR_IO_ADDR(PINF))

Untested. Make sure that you have not touched "i2cmaster.S".

Life is easier in C. But ASM is not too bad providing you check the data sheet for the SFR addresses.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
But ASM is not too bad providing you check the data sheet for the SFR addresses.
Better still, use macros for reading/writing I/O ports that will automatically use in/out or lds/sts as needed.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net