TWI on XMEGA [Solved]

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

Hi,

is there some simple example for the TWI in Master Mode, no interrupt on the XMEGA ? I have the example from Atmel which seems to be a little too much blown up for me. I'm trying to interface an RTC (DS1340) with requires a 7 byte datagram. At the moment I'm only observing the PC0 and PC1 pins on the Xmega128A1 with an oscilloscope and nothing happens at all. I'd say at least the address should be sent ? Here is the code so far :

#define CPU_SPEED 32000000
#define BAUDRATE    400000
#define TWI_BAUD(F_SYS, F_TWI) ((F_SYS / (2 * F_TWI)) - 5)
#define TWI_BAUDSETTING TWI_BAUD(CPU_SPEED, BAUDRATE)

#define RTC_SLAVE_ADDRESS 0xD0; // already shifted !!!!


/******************************************************************/

TWI_t * rtc = &TWIC;

uint8_t twitest[7]={0x05, 0x06, 0x07, 0x08, 0x25, 0x45, 0x65}; // only some test bytes


/****************************************************/

void twi_init(TWI_t * twiname){

  
  twiname->MASTER.CTRLB = TWI_MASTER_SMEN_bm;
  twiname->MASTER.BAUD = TWI_BAUDSETTING;
  twiname->MASTER.CTRLA = TWI_MASTER_ENABLE_bm;  
  twiname->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;


return;
}

/****************************************************/

void twi_write_rtc(TWI_t *twiname, uint8_t *writeData){

   uint8_t i;
   
   twiname->MASTER.ADDR = RTC_SLAVE_ADDRESS;  // write to RTC
   while(!(twiname->MASTER.STATUS&TWI_MASTER_WIF_bm));
   twiname->MASTER.DATA = 0x00;       // write word addr
   while(!(twiname->MASTER.STATUS&TWI_MASTER_WIF_bm));
   for(i=0;i<7;i++){                  // write date and time
      twiname->MASTER.DATA =writeData[i];
	   while(!(twiname->MASTER.STATUS&TWI_MASTER_WIF_bm));
   }


return;
}

/****************************************************/

void twi_read_rtc(TWI_t *twiname, uint8_t *readData){
                                            // read from RTC
   uint8_t i;
   uint8_t address = RTC_SLAVE_ADDRESS;

   address |= 0x01;
   twiname->MASTER.ADDR = RTC_SLAVE_ADDRESS;  
   while(!(twiname->MASTER.STATUS&TWI_MASTER_WIF_bm));
   twiname->MASTER.DATA = 0x00;       // write word addrpointer first
   twiname->MASTER.ADDR = address;    // send read command
   for(i=0;i<7;i++){                  // read date and time
  	 while(!(twiname->MASTER.STATUS&TWI_MASTER_RIF_bm));
	   readData[i] = twiname->MASTER.DATA;
   }


return;
}

/****************************************************/

int main(void){

	twi_init(rtc);

        while(1){
	  
	   twi_write_rtc(rtc, twitest);
  	}

return 0;
}

thanks for any help or comment
Mat

EDITED 03.05.2011

Last Edited: Tue. May 3, 2011 - 06:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have pullups on the SDA and SCL lines?

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

in the schematics-to-be yes, currently no, at the moment there's only the pins of my STK600, the line can't be driven by the port itself ? Can I activate internal pullups together with the TWI functionality ?

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

mzeu wrote:
in the schematics-to-be yes, currently no, at the moment there's only the pins of my STK600, the line can't be driven by the port itself ? Can I activate internal pullups together with the TWI functionality ?
If you read the TWI (I2C) spec you will find that SDA and SCK are "open collector" signals, meaning they are designed to have only pull-downs on them. Pull-up resistors are mandatory.

Again, if you read the spec, you will find that the value of the pull-up is dependent on two factors: the desired speed of the bus and the total load. IIRC, the approximate 100 KOhm pull-up in the AVR is not sufficient to drive the TWI bus at anything close to a reasonable speed.

Yes, the pull-up is required. No, the internal pull-up is not sufficient.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

The internal pullups are probably not good enough(depending on speed and layout etc.) As for "the line can't be driven by the port itself", the SDA line always needs to be bidirectional. So does the SCL line, if slave clock stretching is to work. Although I have seen bit-banged implementations where the SCL was driven, I would not recommend it.

Four legs good, two legs bad, three legs stable.

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

No. You must have external pull-ups.

If you use the TWI then you automatically have the lines controlled in the proper way.

Is it really too difficult to add two 4k7 resistors ?

You can of course choose to ignore the TWI, the i2c spec and bit bang the bus with driven lines. Do not be surprised if the slave devices have their output stages burned out.

You can always save damaging the i2c slaves by just shorting two AVR output pins. Then in software drive one high and the other low. The AVR will probably survive, but you have definitely exceeded the output pin currents. Now you try the same experiment with your i2c Slave.

David.

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

ok, thanks, then I'll wait for the "real" board with the pullups and get back here later then :-)

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

I have also been trying to get TWI to work on an xmega64a3(CPU 2MHZ internal osc, TWI is 100KHz, pull-ups 1.8K). The slave is a pic18F8620. I have code similar to yours but writing to the slave register and then reading the value back. It doesn't work. If I look at the DSO trace the slave address is sent, an ack bit is present, then the slave register address is present, then SDA goes high and SCL remains low.

If an LED is used to indicated the slave's receipt of the slave address it flashes(i.e. address received). If an LED is used to indicated whether the slave register address is received it does not flash.

If the slave is reset by pulling the MCLR low, SCL remains low. If the xmega is reset the SCL line goes high. I assumed this means that its the master holding the SCL line low.

The slave works fine with another PIC so I assume it is not the problem.

Did mzeu gets their code to work?

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

The xmega TWI works just fine. It is different to the mega TWI module though.

It is always safest to test your TWI code with a real hardware device. e.g. say a 24Cxx.

I have no idea whether your PIC is implementing the I2C spec properly.

Remember that if you read from a Slave you must tell it when to stop. i.e. you NAK the last read.

David.

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

Thanks for your reply. I created the code for the PIC using CCS picc and the slave does actually work when accessed from another pic programmed using the CCS i2c library functions. Not sure yet what's going on there. I tried ST 24256 i2c memory ic with the AV1308 eg code and it does seem to work but does not yet work with the code above. I will try what you said and write back later. Mark.

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

I presume that you are not using the cr*p code posted by mzeu at the start of this thread.

I would test your code with the 24C256 chip, and make sure that behaves normally.
e.g. it will not ACK its own address while it is busy writing.
e.g. a multiple write will wrap inside the internal eeprom page
e.g. when you do a multiple read, the master tells the slave with an ACK for every byte, and a NAK for the last one.

You also need to observe what happens if you try a REP_START without the NAK.

If your code handles the 24C256 ok, then it should handle your PIC device too.

Please post your code if you find an anomaly.

David.

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

Interesting. Why didn't you tell me it is cr*p code earlier, David ? I'm just on it again now, so what should I do to not directly run into problems now ?

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

The cr*p code works now, there were only some waits for transmit/receive missing. But I bet you already knew, right ? Totally sufficient for a 1-master, 1-slave configuration.

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

Hello,

I have a problem setting up xmega TWI polling the data, not using interrupts. My source is like:

short TWI_GetData(unsigned char twi_data) {
	short data=0;

	TWIC.MASTER.ADDR = SL_ADDR & ~0x01;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm) || (TWIC.MASTER.STATUS & TWI_SLAVE_RXACK_bm));
	TWIC.MASTER.DATA = twi_data;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm));

	TWIC.MASTER.ADDR = SL_ADDR | 0x01;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_RIF_bm));
	data = TWIC.MASTER.DATA;
	TWIC.MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
	data = data << 8 || TWIC.MASTER.DATA;
	TWIC.MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;

	return data;
}

So far as I have traced the communication and I can say I can transmit, but I can not receive anything. It is like RIF never goes up.

I am using atxmega192D3. My TWI is set up as follows:

void TWI_MasterInit(){
  	TWIC.MASTER.BAUD = TWI_BAUDSETTING;
  	TWIC.CTRL = 0;      // clear common register
    
    // enable TWI / I2C / SMBUS
    TWIC.MASTER.CTRLA = TWI_MASTER_ENABLE_bm;
    TWIC.MASTER.CTRLC = 0;
    
    // force initial bus state to idle
    TWIC.MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
};

I have tested 3 standard I2C devices (pressure sensor, accelerometer, RTC) but without much success. My code just hangs when I go to READ mode.

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

Are you sure the electrical part is as it should be ? (pull-ups, see my mistakes :-) ) can you actually measure your transmission with an oscilloscope ? If so I'd say you should at least be able to read a 0x00 back. Did you get the address right ? (may require shift to bits 7:1 ). Are you sure the I2C part gets the correct command so you get something to read ? Which RTC did you use for example ? we could have a look at the datasheet.

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

I have been using ds1338, BMP085, BMA020.
I have no oscilloscope but I have done some experiments to check the write transmission:
1. I have checked the return value of the TWIC.MASTER.STATUS and it shows the WIF, CHKHOLD flags to be correct when I have or I have no slave device on the I2C line, addressed with the correct address and with a fake one.
The pull-ups and so on are correct. I am just migrating a project I have done with atmega168 to xmega, and the new TWI is confusing me a bit.

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

the ds1338 seems to have the same control logic as the ds1340 I use. My code is working if the

while(!(twiname->MASTER.STATUS&TWI_MASTER_WIF_bm));

is added after every write
and

while(!(twiname->MASTER.STATUS&TWI_MASTER_RIF_bm));

after every read.
If you say the same electronics already worked, the problems could be maybe the baudrate or the (not)acknowledges. Is the Xmega clocked right anyway?
And (just my personal "problem") I don't trust any signal until I can see it :wink:

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

I have a bit of a progress after correcting the read part of the source code clearing some bits from the TWIC.MASTER.STATUS. The code is as follows:

short TWI_GetData(unsigned char twi_data) {
	short data=0;

	TWIC.MASTER.ADDR = SL_ADDR & ~0x01;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm) || (TWIC.MASTER.STATUS & TWI_SLAVE_RXACK_bm));
	TWIC.MASTER.DATA = twi_data;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm) || (TWIC.MASTER.STATUS & TWI_SLAVE_RXACK_bm));

	TWIC.MASTER.ADDR = SL_ADDR | 0x01;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_RIF_bm));
	TWIC.MASTER.STATUS |= TWI_MASTER_RIF_bm;
	TWIC.MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
	while (!(TWIC.MASTER.STATUS & TWI_MASTER_RIF_bm));
	data = data << 8 | TWIC.MASTER.DATA;
	TWIC.MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc;

	return data;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good evening.
I'm some test about xMega256 and i want test TWI
I connect the MPU to a PCF8563 device.
I write some code lines that i attach.
The problem is that MPU send address when i write it in TWIE_MASTER_ADDRESS, the decice send an ACK but MPU don't send the data that i'write in TWIE_MASTER_DATA. with AVR simulator, see that when i write something in ADDRESS register the same is writen to DATA end after, nothing is possible transfer to DATA register.
With an oscilloscope i see the same, the value of MASTER ADDRESS passing on SCL and SDA lines after nothing is transfer.
Thank you

Attachment(s): 

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

I solve my problem.
I looked the RXACK and my system don't work.
No i look CLKHOLD and everything work.

Good day

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

mzeu wrote:
The cr*p code works now, there were only some waits for transmit/receive missing. But I bet you already knew, right ? Totally sufficient for a 1-master, 1-slave configuration.

I agree with you, and would like to know what changes you made to your original listing (top of this thread) to add some delays to make it work. I am looking for a very simple TWI interface that runs without interrupts. Thanks.

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

hi peason

I updated the listing in the first posting, please have a look.

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

Mat, thanks. The code appears to be working in my simple app. just what I needed
Paul

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

hi all,

 

i tried with this code but sometimes it works and most times it's blocked on 

while(!(twiname->MASTER.STATUS&TWI_MASTER_WIF_bm));

after a write

 

can you please help me on this

Last Edited: Fri. Oct 23, 2015 - 02:14 AM