Orangutan X2 - I2C

hi,
im trying to connect Compass Module - HMC6352 ( sparkfun.com/products/7915 ) to my orangutan x2 and I really dont know how.
Compass has “simple” I2C interface, and i read a lot about i2c but i still cant understand how to use it. i know, that some of LCD pins are SDA and SCL but i have free UART1, and if i am not wrong i can use it (PD2 - SDA, PD3 - SCL). And here my problem begins: i have no idea how to write program using I2C communication! pololu avr library command reference and C/C++ library user’s guide says nothing about that :confused:

Help!

EDIT: ok, i know sth more about I2C now, but it just doesnt work.
im using orangutan-lib, connecting lines SCL and SDA to PC0 and PC1
i cant debug to LCD becouse dont know how to use it in 4-bit mode!
i cant find any info how to modify libs to work in 4bit-mode.
but im using leds to debug info,here is my simple code:

#include <pololu/orangutan.h>
#include "i2cmaster.c"

typedef unsigned char UC;

int compSlAddr = 0x42;
int getVarByte = 0x41;
int heading =0;

int main()
{
	red_led(HIGH);
	green_led(HIGH);
	delay_ms(2000);
	i2c_init();
	red_led(LOW);
	delay_ms(1000);
	i2c_start_wait(compSlAddr+I2C_WRITE);
	green_led(LOW);
	i2c_write(getVarByte);
	i2c_stop();
	delay_ms(500);
	i2c_start_wait(compSlAddr+I2C_READ);
	heading = i2c_readAck() << 8;
	heading += i2c_readNak();
	i2c_stop();
	
	if (heading)
		green_led(HIGH);
	while(1);
}

init goes well, but start_wait stucks, and green led never disables :confused:

Maybe somebody could just tell me how to use this lcd in 4bit mode??

Hello.

I’m sorry you are having trouble. There are certainly many things that could go wrong here. One thing I noticed is that the PC0 (hardware SCL) line on the Orangutan X2 is pulled down by a user LED, but I2C lines are supposed to be pulled up. (The comments in i2cmaster.h from Orangutan-lib recommend a 4.7k pull-up resistor.)

Maybe you should do software I2C on some other I/O lines that do not have things attached them. Peter Fleury has code for doing that here (i2cmaster.s):
homepage.hispeed.ch/peterfleury/ … tware.html
You are currently using orangutan-lib, which includes Peter Fleury’s i2cmaster.c, which uses hardware i2c and is written in C. You should try to use his i2cmaster.s, which is written in assembly and can be easily adapted to use any pin on the AVR. Both of them use the same header file, i2cmaster.h. I haven’t tried this so I can’t say for sure if it will work.

Most of our other Orangutans use the LCD in 4-bit mode, so you can look at the source code of the Pololu AVR C/C++ Library (particularly OrangutanLCD.cpp) and look at the Orangutan SV-328 schematic to see how to do that. The datasheet of the LCD will also be useful:
pololu.com/catalog/product/738/resources

–David

Some time ago I described modifications of Peter Fleury’s I2C C code, to connect a Baby O with a compass module and/or an EEPROM chip. The routines can be easily configured for any available I/O pin and the source files are still available.

thanks for help, i think can’t get through peter fleury’s code, so maybe i will try my own software i2c on other digital pins, now i have only one question:
how to write bits to output? if communication speed is 100kHz, sending a 1 bit should look like this? :

  1. pull line HIGH
  2. wait (1/100kHz)= 10 microseconds (HOW ???)
  3. pull line LOW
    what with 0 bit?

if you could write simple piece of code, which is writing 2 bits: 1 and 0 bit for example to IO_D4?

For information about how to drive lines high, drive them low, or read them as inputs, you should see the “Orangutan Digital I/O Functions” section of the Pololu AVR C/C++ Library User’s Guide.

For delaying 10 microseconds, you can use the delay_us section from the Pololu AVR C/C++ Library, which is described in the “Timing and Delays” section of the Pololu AVR Library Command Reference.

–David

Hello.

I just wanted to point out that the wikipedia article on I2C has some pseudo-C code for bit-banging master I2C. You would just need to write the functions:

bool read_SCL(void);  // Set SCL as input and return current level of line, 0 or 1
bool read_SDA(void);  // Set SDA as input and return current level of line, 0 or 1
void clear_SCL(void); // Actively drive SCL signal low
void clear_SDA(void); // Actively drive SDA signal low

to perform the proper I/O manipulation, as described by the comments. David linked you to some documentation about how to do this using our AVR library, but please ask if you have any questions about this.

Also, if you do use that wikipedia code as a starting point, I suggest you replace I2C_delay() function with the appropriate delay_us() call, and you probably can skip anything to do with arbitration (that only comes up if you have a system with multple I2C masters on the same bus).

- Ben

thanks a lot, i just didn’t know that it is so simple :wink:

now, why i am not receiving ACK from my slave?
this code only sends device adress and checks reply bit (always got NACK :confused: )

#include <pololu/orangutan.h>


#define SDA_PIN IO_D2
#define SCL_PIN IO_D3

typedef unsigned char UC;

const UC compSlAddr = 0x42;
const UC getVarByte = 'A';
int heading =0;

void SDA(UC state)
{
	if (state)
		set_digital_output(SDA_PIN,HIGH);
	else
		set_digital_output(SDA_PIN,LOW);
}
void SCL(UC state)
{
	if (state)
		set_digital_output(SCL_PIN,HIGH);
	else
		set_digital_output(SCL_PIN,LOW);
}

void i2c_init()
{
	SCL(1);
	SDA(1);
}

void i2c_start()
{
	SDA(0);
	delay_us(10);
	SCL(0);
}

void i2c_stop()
{
	delay_us(5);
	SCL(1);
	delay_us(10);
	SDA(1);
	delay_us(10);
}

void i2c_write(UC byteToSend)
{
	for (int i=0;i<8;++i)
	{
		delay_us(5);
		SDA(((byteToSend << i) & 256)>>8)
		delay_us(5);
		SCL(1);
		delay_us(10);
		SCL(0);
	}
	SDA(0);
	set_digital_input(SDA_PIN,PULL_UP_ENABLED);
	delay_us(10);
	SCL(1);
	delay_us(10);
	if (is_digital_input_high(SDA_PIN))
	{
		printf("NACK!!!!\n");
		while(1);
	}
	else
		printf("ACK :)\n");
	SCL(0);
}


int main()
{
	lcd_init_printf();
	printf("Start");
	i2c_init();
	delay_ms(1000);
	i2c_start();
	i2c_write(compSlAddr);
	while (1);//should print only ACK until here
	i2c_write(getVarByte);
	i2c_stop();
	
}

Is there some reason you didn’t take Ben’s advice to just copy the Wikipedia code and then define the undefined functions? I think that’s a good way to start because the Wikipedia code is less likely to have bugs than the new code that you write.

For example, I think this line you wrote has a bug:

SDA(((byteToSend << i) & 256)>>8)

When i is 0, this line will set SDA to 0 regardless of the value of byteToSend.

–David

maybe You are right, I should have done this. But i checked this compass with arduino - it works perfect! I just downloaded code, connected everything and it works. I’m sorry, but i haven’t more time to make it works on orangutan, for now, arduino will write analog output to orangutan’s analog input with heading info. Later i will try to do it on orangutan.