I2C initialisaton

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

Hi,

 

I am just working through my first IC2 project using a ATmega324P and the GY521 , and it is not working.  Before I dig deeper can I confirm some of my settings are correct:

 

GY521 using MPU6050 chip settings:

 

VCC 3v3 volt.  Some websites say it is OK to use at 3v3, and others say it must use 5v.  

SDA using 2k2 resistor.  Should this be unrated to 4k7 as using 3v3?

SDL using 2k2 resistor.   Should this be unrated to 4k7 as using 3v3?

 

 

1)  When the below two wire interface is enabled, are the I/O pin pull ups disabled?

 

TWCR = (1<<TWEN);    

2)  Am I correct in understanding to change the frequency of the IC2, the TWBR register can be loaded with a value from 0 - 15.  Because I want to run the GY521 at 100kHz and therefore reduce the value of TWBR to lower than 12. 

 

void initialize_i2c(void)
{
	 //set SCL to 400kHz          // SCL Frequency = (CPU Clock Frequency)/ (16+2(TWBR).4^TWPS
	 TWSR = 0x00;                 // SCL Frequency = (4E6)/ (16+2(12).4^1 = 4E6/864 = 4.629 Khz          
	 TWBR = 0x0C;                 
	 //enable TWI
	 TWCR = (1<<TWEN);	
}

 

Thanks,

 

Tuurbo46

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

I guess you are right about that, but I noticed that you enable the interface in the init - process. The I2C ( TWI) has do be enabled only in combination with Start-Sign or other commands. I will be doing that today when I am finished I will  share.

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

Here are my Header and C File:

Please let me know if you think it is helpful.

/*
 * TWIFunctions.h
 *
 * Created: 01.12.2015 00:13:42
 *  Author: Philipp
 * For ATMEGA 32u4 MUC
 * Code not tested yet, if not working correction shall be made
 * Published for AVR Freaks Community at 03.12.2015 11:51am
 */ 

#ifndef TWIFUNCTIONS_H_
#define TWIFUNCTIONS_H_
#endif /* TWIFUNCTIONS_H_ */

static void setFuses(void);
static void InitPORTOthers(void);
static void SetUPTimerOne(void);
static void SetUPTWI(void);
static void SendStart(void);
static void CheckStatus(const unsigned char* isOkay);
static void LoadData(const unsigned char* packet);
static void SendStop(void);
//EOF
/*
 * TWILaborWorkoutSimple.c
 *
 * Created: 01.12.2015 00:12:38
 * Author: Philipp
 * For ATMEGA 32u4 MUC
 * Code not tested yet, if not working correction shall be made
 * Published for AVR Freaks Community at 03.12.2015 11:51am
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#include "TWIFunctions.h"

//#A: compiler tends to optimize away 0 values therefore: "volatile"
volatile uint8_t TIMERONEFLAG = 0;
volatile uint8_t TWINTSETFLAG = 0;
volatile uint8_t TOGGLEDATAFLAG = 0;//For varying toggling data bytes

int main(void)
{	
	//SLAW & DATA
	// "const" declares: "Data shall be the same at all times"
	const unsigned char SLAW = 0x70;//SLAW
	const unsigned char PORTALLONE = 0xFF;
	const unsigned char PORTALLZERO = 0x00;//I guess Compiler will optimize
	//Unused: #B: using "Explicit-Type-Casting" to point to the correct data type
	//Status Codes for ATMEGA 32u4 MUC
	const unsigned char StartTransmitted = 0x08;
	const unsigned char SLAWACKTransmitt = 0x18;
	const unsigned char DataACKReceived = 0x28;
	//
	//Initial Process
	setFuses();
	InitPORTOthers();
	SetUPTimerOne();
	SetUPTWI();
	sei();//After all is configured give free interrupts
	
    while(1)
    {
        //TODO:: Please write your application code
		switch (TIMERONEFLAG){
			
			case 1 :
					SendStart();//Begin of Master-Slave-Session
					while(! TWINTSETFLAG);//Wait until TWI finished
					TWINTSETFLAG = 0;//Clear Flag for reuse
					CheckStatus(&StartTransmitted);
					TWCR &= ~(1 << TWSTA);//Disable START-Signal
					LoadData(&SLAW);//Address + Write-Bit
					while(! TWINTSETFLAG);//Wait until TWI finished
					TWINTSETFLAG = 0;//Clear Flag for reuse
					CheckStatus(&SLAWACKTransmitt);
					
					if(TOGGLEDATAFLAG) LoadData(&PORTALLONE);//Slave PORT shall be 0xFF
					else LoadData(&PORTALLZERO);//Slave PORT shall be 0x00
					
					while(! TWINTSETFLAG);//Wait until TWI finished
					TWINTSETFLAG = 0;//Clear Flag for reuse
					CheckStatus(&DataACKReceived);
					SendStop();//End of Master-Slave-Session
					
					TOGGLEDATAFLAG ^= (1 << 0);//Toggle bit 0 (7 6 5 4 3 2 1 0)
					//'1' at Bit 0 or '0' at Bit 0
					TIMERONEFLAG = 0;// 1.048448s - 60.2ms =~ 0.988248s until next Master-Slave-Session
					break;//Jump to end of "switch-case"
			case 0 :
					//Here other important program routines shall be executed
					break;
		}
    }
}

//"static" gives away an only local use of function
static void setFuses(void){
	
	MCUCR |= (1<<JTD);//Within four cycles to disable the JTAG interface
	MCUCR |= (1<<JTD);
	CLKPR = 0x80;// Change Enable
	CLKPR = 0x01;// Clock Division Factor 2 - 16/2
}
static void InitPORTOthers(void){
	
	DDRD |= (1 << DDD6);//ERROR LED
	PORTD &= ~(1 << PORTD6);//LOW
}
static void SetUPTimerOne(void){
	
	
	TCNT1 = 0xE000;//65535 - 8191 = 57344  -> 8191 * delta t =~ 1.048448s total	for Overflow
	TCCR0B |= (1 << CS12);
	TCCR0B &= ~(1 << CS11);
	TCCR0B |= (1 << CS10);//1024 //delta t = 1024 / 8MEGA = 128µs
	TIMSK0 |= (1 << TOIE1);//Enable Overflow Interrupt vector
}
static void SetUPTWI(void){
	
	TWBR = 0x2F;//47
	TWSR &= ~(1 << TWPS1);
	TWSR |= (1 << TWPS0);//256
	//Clock CPU is 8 Mega Hertz
	//SCL Frequency = 8MHz/(16+2*47*256)
	//332.2259 Hertz - 3.01 ms per Data-Bit 
	//8 bits from Slave one ACK after each packet + 1 bit for Start and Stop bit -> 8*2 + 2 + 2 = 20 bits each transmission
	//20 total so 60.2ms for one transmission
	TWCR |= (1 << TWIE);//Enable TWI Interrupt vector
}
ISR(TIMER1_OVF_vect){
	
	TCNT1 = 0xE000;
	TIMERONEFLAG = 1;
}
ISR(TWI_vect){//When TWI done
	
	TWINTSETFLAG = 1;
}
static void SendStart(void){
	
	TWCR |= (1 << TWINT) | (1 << TWSTA);
	TWCR |= (1 << TWEN);//Enable after other Control Bits are set
}
static void CheckStatus(const unsigned char* isOkay){
	
	unsigned char TWSRMasked;
	
	TWSRMasked = (unsigned char)(TWSR & 0xF8); //Mask TWI PRE-Scaler-Bits
	
	if(TWSRMasked != *isOkay) PORTD |= (1 << PORTD6);//Error
	
	else PORTD &= ~(1 << PORTD6);//LOW
}
static void LoadData(const unsigned char* packet){
	
	TWDR = *packet;
	TWCR |= (1 << TWINT);
	TWCR |= (1 << TWEN);//Enable after other Control Bits are set
}
static void SendStop(void){
	
	TWCR |= (1 << TWINT) | (1 << TWSTO);
	TWCR |= (1 << TWEN);//Enable after other Control Bits are set
}

 

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

Why do you enable twi interrupts?

Setup timer1 for ctc mode rather than overflow.

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

Hi,

 

Thanks for your help LDPKananDethin.  I am just waiting for some 4k7 resistor to turn up before I get back into the code.

 

Kartman, how many years have you been on AVR's?  You seem to find all this very easy... what is your trick.  I am quite new to AVR's but I must say I struggle on most of it.  

 

Thanks,

 

Tuurbo46

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

No trick tuurbo - just a lot of time. Been using AVRs since they became available in the late ''90s.
Stay here a while and you get to see the same problems over and over again - like setting fuses and uart problems.
The resistor value is not super critical. 2k2 is fine, but 10k is getting a bit high.

Last Edited: Thu. Dec 3, 2015 - 09:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I have found my problem.  I have been trying to convert the Arduino Short Example Sketch code on this link http://playground.arduino.cc/Mai... over to my ATmega324P.  My problem is I cannot work out how to write the code for wire.begintransmission().  I2C communication packet, must have a START, ADDRESS PACKET (7 bit lead by data direction bit + acknowledge bit) , DATA PACKET (8 bits + acknowledge bit), STOP.   Am I correct in understanding my write_i2c is not doing the same as wire.begintransmission().  Also is wire.endtransmission() the same as my stop_i2c?

 

Any input will be gladly accepted.

 

Thanks,

 

Tuurbo46

 

So I am converting the below Ardunio function into my ATmega324P code

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
}

 

My ATmega324P code

 

void initialize_mpu6050(void)
{
	start_i2c();         // START_i2c
	write_i2c(MPU_addr); // I2C ADDRESS PACKET of the MPU-6050
	write_i2c(0x6B);     // DATA PACKET
	write_i2c(0);        // set to zero (wakes up the MPU-6050)
        stop_i2c();          // STOP_i2c
}
void start_i2c(void) 
{
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while ((TWCR & (1<<TWINT)) == 0);	
}

void stop_i2c(void) 
{
	TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);	
}

void write_i2c(uint8_t data)
{
	TWDR = data;
	TWCR = (1<<TWINT)|(1<<TWEN);
	while ((TWCR & (1<<TWINT)) == 0);
}

 

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

First off.    Use a respected library.  e.g. Fleury.

 

Note that the < Wire.h> library uses 7-bit addresses.   Fleury uses 8-bit.   e.g. 0x68 for Wire, 0xD0 for Fleury.

 

When you have everything working 100% with a Library,   you can then think about rolling your own.

Before you start,   think very carefully about the API of any functions that you want to write.

 

Remember that void functions are the work of the Devil.   Sometimes they are appropriate but generally they just mean you have to work blindfolded.

 

If you find it exhilarating to drive a car in the dark without headlights and your eyes shut,   go for it.

 

David.

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

Hi,

 

I have taken Davids advice and downloaded the I2C libary.  I have added the i2cmaster.h and twinmaster.c files to my project, but I am unsure if I should add the i2cmaster.s to my project.  Do I only add this if I as writing and using assembler code?

 

It built OK with just the i2cmaster.h and twinmaster.c files but I am unsure on the i2cmaster.s.

 

Thanks,

 

Tuurbo46

 

 

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

There are HTML documentation files that you can read with your Browser.

Ask if there is anything that you do not understand. If your intention is to write your own library in the future, it is essential to understand how and why the Fleury code works. Then you can improve it.

I will let you discover the necessity for i2cmaster.S

David.

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

Hi,

 

OK I have fully read the HTML doc, and I guessed I have to add the .s file into my project.  I have added the .s file the same way I would add the .c and .h files.  After making all the port pin definitions, my next problem is when I rebuild my project I get:

 

Error    6    multiple definition of `i2c_init'   
Error    7    multiple definition of `i2c_start'    
Error    8    multiple definition of `i2c_start_wait'    
Error    9    multiple definition of `i2c_rep_start'    
Error    10    multiple definition of `i2c_stop'    
Error    11    multiple definition of `i2c_write'    
Error    12    multiple definition of `i2c_readAck'    
Error    13    multiple definition of `i2c_readNak'    
Error    14    ld returned 1 exit status    collect2.exe    

 

I understand the above definition names are in both the .c file and also the .s file.  How do I include the .S file differently to overcome these rebuild errors?

 

Thanks,

 

Tuurbo46.

 

 

 

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

Obviously you have made no attempt to READ the Fleury documentation.

I do not believe that anyone needs to write their own I2C code. But they certainly have read HOW to use a ready made library.

If there is something that you do not understand, quote the page number or copy-paste the paragraph that is giving you trouble. This shows that you have made the effort to find the documentation. And we will be very happy to help you.

David.

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

David,

 

The first line of your above post is INCORRECT.  I do not understand the terminology of the below paragraph. I currently have included the .c and .h files and the output is still incorrect.  I understand I add either the .s or .c file to my project but not both.  Is this correct?

 

This I2c library is implemented as a compact assembler software implementation of the I2C protocol which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).  Since the API for these two implementations is exactly the same, an application can be linked either against the software I2C implementation or the hardware I2C implementation.

 

Thanks,

 

Tuurbo46.

 

 

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

Yes,  that is correct.   You should only add ONE file.   Your error messages implied that you had added both .S and .c file to the project.

 

The other thing is external pull-up resistors.    4k7 is a typical value for 5V operation.    Anything from about  to 10k  should work ok.   

Your 2k2 is fine.   The MPU6050 is a 3.3V device.

Note that the < Wire.h> library uses 7-bit addresses.   Fleury uses 8-bit.   e.g. 0x68 for Wire, 0xD0 for Fleury.

 

You must use the correct hardware Slave address for your hardware chip.    It probably has some addressing pins in hardware.

 

Then you use the return value from i2c_start() or i2c_write().    This will tell you immediately whether you are using the correct Slave address.

 

David.

Last Edited: Mon. Dec 7, 2015 - 08:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Dave,

 

Thanks for your input.

 

I have it running now.  My next task is to print an int16.  My current print is int8.  I will have a think how I can output an int16.  I miss printf in visual studio.

 

Thanks,

 

Tuurbo46.

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

Avr-gcc has printf! You need to do a little work to have it go to the uart or wherever. There's also sprintf() and itoa()