I2C Library Problems with ATtiny817

Go To Last Post
58 posts / 0 new

Pages

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

Regular international mail is fine. I was surprised to hear you say DHL when El Tangas's photos show regular mail.
.
It will be interesting to see how you get on with the UPDI and mEDBG chip.
And of course the new features of the Tiny817.
.
David.

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

I was surprised to hear you say DHL

I'm getting something else trough DHL so I ASS_U_MEd that the board was in the same package.

 

So the UPDI clock defaults to 100KHz and the main clock at 20MHz. I'm not messing around with those until I understand a lot more.

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Hello, 

 

I try to implement I2C routine on Attiny 817 Xplained mini for reading T° on LM75A device and I would like to share it once it will be fully functional!

First I looked at I2C blocks available on atmel start, but they are so complex and twisted!

So here is my code.

The problem is that the read with Ack or Nack doesn't seem to work. I receive twice the same value (never the second byte from LM75A).

Perhaps it misses a test to check that the previous operation is done?

Any idea and suggestion is welcome!

 

 

#define F_CPU 20000000UL

#include <util/delay.h>

#include <stdlib.h>

 

/* -------------------------------------------------------*/

 

#define TWI0_BAUD(F_SCL)      ((((float)F_CPU / (float)F_SCL)) - 10 )

#define LM75A_ADDRESS_W 0b10010000

#define LM75A_ADDRESS_R 0b10010001

#define LM75A_TEMP_REGISTER 0x00

 

void TWI_init()

{

TWI0.MBAUD = (uint8_t)TWI0_BAUD(100000);                          // set MBAUD register for 100kHz

TWI0.MSTATUS |= (0x1);                                                         //Force TWI state machine into IDLE state

TWI0.MCTRLA = 1 << TWI_ENABLE_bp                                    /* Enable TWI Master: enabled */

| 1 << TWI_QCEN_bp                                                             /* Quick Command Enable: enabled */

| 0 << TWI_RIEN_bp                                                              /* Read Interrupt Enable: disabled */

| 0 << TWI_SMEN_bp                                                             /* Smart Mode Enable: disabled */

| TWI_TIMEOUT_DISABLED_gc                                                /* Bus Timeout Disabled */

| 0 << TWI_WIEN_bp;                                                            /* Write Interrupt Enable: disabled */

}

 

void TWI_start(uint8_t slaveAddr)

{

TWI0.MADDR = slaveAddr;                                                    //Create TWI start condition by loading slave address into MADDR register

}

 

uint8_t TWI_read(uint8_t ACK)                                             // ACK=1 send ACK ; ACK=0 send NACK 

{

if (ACK) TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp);              //  si ACK=1 mise à 0 ACKACT => send ACK

else  TWI0.MCTRLB |= (1<<TWI_ACKACT_bp);                     //  sinon (ACK=0) => mise à 1 ACKACT => send NACK 

return TWI0.MDATA ;                                                          // lecture du registre MDATA et envoi de l'action définie par ACKACT

}

 

void TWI_WRITE(uint8_t write_data)

{

TWI0.MDATA = write_data;                                                 //Transfer write_data into MDATA register

}

 

void TWI_STOP(void)

{

TWI0.MCTRLB |= (1<<TWI_ACKACT_bp);                           // Set acknowledge action to NACK

TWI0.MCTRLB |= (TWI_MCMD_gm);                                   //Triggers Master to execute acknowledge action (NACK), succeeded by issuing STOP condition

}

 

TWI_init();

uint8_t tempHigh;

uint8_t tempLow;

 

while (1)

{

_delay_ms(200);

PORTC_OUTTGL = (1<<PIN0_bp);

TWI_start(LM75A_ADDRESS_R);

tempHigh = TWI_read(1);                    // read avec ack

tempLow = TWI_read(0);                    // read avec nack

TWI_STOP();

 

utoa (tempHigh, buffer, 10);

printString(buffer);

printString("/");

utoa (tempLow, buffer, 10);

printString(buffer);

printString(" ");

}

Attachment(s): 

 main.c

 terminal out.jpg

 IMG_0543.JPG

Attachment(s): 

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

The nice thing about I2C protocol is, it will tell you when something goes wrong, but you wrote all of your I2C functions with void return values!!!  So it throws away any chance to do that!

Re-write your I2C functions to return the twi status register value and test it for correctness (expected value) and you will do much better.

Take some time to study what others have successfully done, ask questions if you need help understanding why they did it the way they did.

 

Jim

 

Edit: Please use the "<>" button to post code to preserve correct spacing!

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Thu. Oct 12, 2017 - 07:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Jim,

 

here is the list of functions :

 

void TWI_init();
void TWI_start(uint8_t slaveAddr);
uint8_t TWI_read(uint8_t ACK);
void TWI_WRITE(uint8_t write_data);
void TWI_STOP(void);

 

the read function returns an uint8_t value read from MDATA

I don't need values back from other function (init, start; write, stop).

 

So I don't think it's the problem.

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

Really, how do you know you got an ACK to your start(address)?  A very common failure seen here by Freaks!

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

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

Hello,

 

I worked again recently on I2C/TWI simple routines on my Attiny817Xplained mini board connected to an HDC1080 module.

The code is working nice, so I just post it to share with Avrfreak community.

 

I get inspired from JRAB post :

https://www.avrfreaks.net/comment/2390341#comment-2390341 

but I added the Read part, which is somehow capital for Twi/i2c complete working.

 

#define TWI0_BAUD(F_SCL)      ((((float)F_CPU / (float)F_SCL)) - 10 )
#define HDC1080_ADDRESS_W		0b10000000
#define HDC1080_ADDRESS_R		0b10000001
#define HDC1080_TEMP_REGISTER	0x00
#define HDC1080_CONFIG_REGISTER	0x02

void TWI_init()
{
	TWI0.MBAUD = (uint8_t)TWI0_BAUD(100000);	        // set MBAUD register for 100kHz
	TWI0.MCTRLA = 1 << TWI_ENABLE_bp			/* Enable TWI Master: enabled */
	| 0 << TWI_QCEN_bp					/* Quick Command Enable: disabled */
	| 0 << TWI_RIEN_bp					/* Read Interrupt Enable: disabled */
	| 1 << TWI_SMEN_bp					/* Smart Mode Enable: enabled */
	| TWI_TIMEOUT_DISABLED_gc				/* Bus Timeout Disabled */
	| 0 << TWI_WIEN_bp;					/* Write Interrupt Enable: disabled */

	TWI0.MCTRLB |= TWI_FLUSH_bm ;				/* Purge MADDR and MDATA */
	TWI0.MSTATUS |= TWI_BUSSTATE_IDLE_gc ;		        //Force TWI state machine into IDLE state
	TWI0.MSTATUS |= (TWI_RIF_bm | TWI_WIF_bm) ;
}

uint8_t TWI_start(uint8_t deviceAddr)
{
	if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) != TWI_BUSSTATE_BUSY_gc)		//Verify Bus is not busy
	{
		TWI0.MCTRLB &= ~(1 << TWI_ACKACT_bp);
		TWI0.MADDR = deviceAddr ;
		if (deviceAddr&0x01)	{while(!(TWI0.MSTATUS & TWI_RIF_bm));}  //si addressRead
		else			{while(!(TWI0.MSTATUS & TWI_WIF_bm));}  //si addressWrite
		return 0;
	}
	else return 1;	                                                        //Bus is busy
}

uint8_t TWI_read(uint8_t ACK)							// ACK=1 send ACK ; ACK=0 send NACK
{

	if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc)		//Verify Master owns the bus
	{
		while(!(TWI0.MSTATUS & TWI_RIF_bm));				// Wait until RIF set
		uint8_t data=TWI0.MDATA;
		if	(ACK==1)	{TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp);}		// si ACK=1 mise à 0 ACKACT => action send ack
		else			{TWI0.MCTRLB |= (1<<TWI_ACKACT_bp);	}	// sinon (ACK=0) => mise à 1 ACKACT => nack préparé pour actionstop

		return data ;
	}
	else
	return 1;	//Master does not own the bus

}
uint8_t TWI_WRITE(uint8_t write_data)
{
	if ((TWI0.MSTATUS&TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc)			                //Verify Master owns the bus
	{
		TWI0.MDATA = write_data;
		while (!((TWI0.MSTATUS & TWI_WIF_bm) | (TWI0.MSTATUS & TWI_RXACK_bm))) ;		//Wait until WIF set and RXACK cleared
		return 0;
	}
	else
	return 1;	//Master does not own the bus
}

void TWI_STOP(void)
{
	TWI0.MCTRLB |= TWI_ACKACT_NACK_gc;
	TWI0.MCTRLB |= TWI_MCMD_STOP_gc;
}

 

now the use of these routines :

 

        TWI_init();
	TWI_start(HDC1080_ADDRESS_W);
	TWI_WRITE(HDC1080_CONFIG_REGISTER);
	TWI_WRITE(0x10);			// 0b0011 0000		0 : RST clear, 0 : reserved, 1 : heater enabled, 1 : Temp+Humid acquisition mode, 0 : battery status,
	                                        //       		0 : Temp 14 bits, 00 : humid 14 bits,
	TWI_WRITE(0x00);			// 0b0000 0000		[7:0] reserved, must be 0
	TWI_STOP();

	TWI_start(HDC1080_ADDRESS_W);
	TWI_WRITE(HDC1080_TEMP_REGISTER);	// séquence pour démarrer une conversion
	_delay_ms(20);				// temps de conversion en 14 bits = 6,5ms (T°) + 6,5ms (HR)

	while (1)
	{
	TWI_start(HDC1080_ADDRESS_R);
	temp_H = TWI_read(1);	// read avec ack
	temp_L = TWI_read(1);	// read avec ack
	humid_H = TWI_read(1);  // read avec ack
	humid_L = TWI_read(0);  // read avec nack
	TWI_STOP();

	/*
        code for treatment data and conversion
	code for results display
	*/

	}	

I hope it will be useful, because up-to-now I didn't find any simple code for I2C/TWI for the wonderful new Attiny AVR-1 cores (the code proposed in Atmel.start is very complex).

 

Let me know your comments!

Fabrice.

Last Edited: Mon. Oct 15, 2018 - 03:37 PM

Pages