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.
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?
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! PM for strategy
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).
I have tested your TWI code on an ATTiny402 talking to an I2C ADC. It works okay, but at the end of the transaction it doesn't send the stop sequence. I've scoped the signals to confirm this and it also appears that the bus is latching up and not returning to "idle". Can you please confirm that your code above works for more than one transaction. In other words, have you put it in a loop to get data from the HDC1080 more that once?
When the master is done receiving data from the slave, it must NAK the last data byte, this informs the slave to release the bus so the master can send the stop!
Jim
Click Link: Get Free Stock: Retire early! PM for strategy
It's only 1 entry, top line is the friendly name that people wants, the bottom line is the internal/symbolic name that other people wants. Makes more sense on other fuses, I grant you...
Posted by Jesse_G_EE: Wed. Sep 18, 2019 - 09:32 PM
1
2
3
4
5
Total votes: 0
I know this is a bit to the party, but I was struggling with STMICRO LIS2DH12 accelerometer (and attiny817 xplained pro)and stumbled on here. I attempted using the above mentioned code, but the old Fleury library made it happen for me. I changed the following from the i2cmaster.S:
;***** Adapt these SCA and SCL port and pin definition to your target !!
;
; .kbv use VPORTs on Tiny817 or Xmega.
; .kbv I use delay loop instead on NOPs if F_CPU > 4MHz
#define SDA 1 // SDA PB1 (alternate func PA1 on tiny817)
#define SCL 2 // SCL PB0 (alternate func PA2)
#define SDA_PORT VPORTA_OUT //
#define SCL_PORT VPORTA_OUT //
;******
In the example main:
#include <avr/io.h>
#define F_CPU 5000000UL
#include <util/delay.h>
#include "i2cmaster.h"
#define Slave 0x33
#define LIS2DH12_W 0x32
#define LIS2DH12_R 0x33
#define WHOAMI_REG 0x0f
#define TEMP_CFG_REG 0x1f
#define TEMP_SEN_EN 0xc0
#define CTRL_REG1 0x20
#define ACCEL_EN_LP 0x47
#define CTRL_REG4 0x23
#define BDU_HR_EN 0x88
#define X_ACCEL_REG 0xa8 //OR'd with 0x80 for multiple return data bytes /* SEE PAGE 25 FOR EXPLANATION*/
#define Y_ACCEL_REG 0xaa //OR'd with 0x80 for multiple return data bytes
#define Z_ACCEL_REG 0xac //OR'd with 0x80 for multiple return data bytes
void initAccel(void){
uint16_t ret;
/* SPECIFIC ORDER FOR READING VALUE OF REGISTER (VERIFY DEVICE ID)*/
i2c_start(LIS2DH12_W); //.kbv
i2c_write(WHOAMI_REG);
i2c_rep_start(LIS2DH12_R);
ret = i2c_readNak();
i2c_stop();
(ret == 0x33) ? PORTB.OUTSET : PORTB.OUTCLR; //if ret!=33 there was a problem
i2c_stop();
/* CONFIG TEMPERATURE SETTINGS */
i2c_start(LIS2DH12_W);
i2c_write(TEMP_CFG_REG);
i2c_write(TEMP_SEN_EN);
i2c_stop();
/* CONFIG LOW POWER AND ACCELEROMATER X-Y-Z */
i2c_start(LIS2DH12_W);
i2c_write(CTRL_REG1);
i2c_write(ACCEL_EN_LP);
i2c_stop();
/* CONFIG BLOCK UPDATE/HIGH RESOLUTION MODE */
i2c_start(LIS2DH12_W);
i2c_write(CTRL_REG4);
i2c_write(BDU_HR_EN);
i2c_stop();
}
int main(void)
{
/* SETTING UP LED */
PORTB.DIRSET = PIN4_bm;
PORTB.OUTCLR = PIN4_bm;
/* BUTTON SET */
PORTB.DIRCLR = PIN5_bm; // SET PIN5 AS INPUT
PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // SET PULL UP
/* INITIALIZE I2C */
i2c_init();
/* INITIALIZE ACCELEROMETER */
initAccel();
while (1)
{
if(PORTB.IN & PIN5_bm){
/* APPEARS TO BE WORKING USING THIS SPECIFIC READ SEQUENCE */
i2c_start(LIS2DH12_W); //.kbv
i2c_write(X_ACCEL_REG);
i2c_rep_start(LIS2DH12_R);
i2c_readAck();
i2c_readNak();
i2c_stop();
}
_delay_ms(500);
}
}
I set up the button so I could use my logic analyzer to trigger on the packets. This should also work for the LIS3DH but this is the general read write functionality with this device. Sorry if this is obvious to most I'm still a newb and figured I'd share.
Cheers,
Jesse_G an EE writing firmware...what could go wrong...
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.
- Log in or register to post comments
TopI'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
- Log in or register to post comments
TopHello,
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):
Attachment(s):
- Log in or register to post comments
TopThe 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! PM for strategy
share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...
- Log in or register to post comments
TopThanks 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.
- Log in or register to post comments
TopReally, 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! PM for strategy
share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...
- Log in or register to post comments
TopHello,
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.
now the use of these routines :
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.
- Log in or register to post comments
TopHi Fabrice,
I have tested your TWI code on an ATTiny402 talking to an I2C ADC. It works okay, but at the end of the transaction it doesn't send the stop sequence. I've scoped the signals to confirm this and it also appears that the bus is latching up and not returning to "idle". Can you please confirm that your code above works for more than one transaction. In other words, have you put it in a loop to get data from the HDC1080 more that once?
Regards,
Trevor.
- Log in or register to post comments
TopWhen the master is done receiving data from the slave, it must NAK the last data byte, this informs the slave to release the bus so the master can send the stop!
Jim
Click Link: Get Free Stock: Retire early! PM for strategy
share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...
- Log in or register to post comments
TopFabrice, Can you please confirm that the code above works for more than one transaction?
- Log in or register to post comments
TopOr its a bug.
- Log in or register to post comments
TopHello,
sorry for me late reply. I have to check how to receive an email when the thread is updated!
I use my code (posted #58) successfully on an Attiny817 Xplained Mini, with an Oled I2C screen and a HDC1080 breakout sensor on the same bus.
The sequence is working fine, even if I never checked the bus with an oscilloscope.
here are the routines for HDC1080 :
The key point for several reads, is to use the last read with with Nack : TWI_read(0) .
Then you can issue a Stop.
I hope this will work for you too.
Best regards
Fabrice.
- Log in or register to post comments
TopI know this is a bit to the party, but I was struggling with STMICRO LIS2DH12 accelerometer (and attiny817 xplained pro)and stumbled on here. I attempted using the above mentioned code, but the old Fleury library made it happen for me. I changed the following from the i2cmaster.S:
In the example main:
I set up the button so I could use my logic analyzer to trigger on the packets. This should also work for the LIS3DH but this is the general read write functionality with this device. Sorry if this is obvious to most I'm still a newb and figured I'd share.
Cheers,
Jesse_G an EE writing firmware...what could go wrong...
- Log in or register to post comments
TopPages