I'm using ATTiny412 because I needed an 8-pin with UART and I2C. The UART works fine, I got that going in 5 minutes. The TWI on the other hand is a total prick. I'm talking to an LTC2487 16-bit ADC, a sweet little chip I might add.
The first time I had this trouble it was with the ATTiny814, and I thought the troubles were isolated to that chip because it has a lot in the errata regarding TWI.
I'm using an ATTiny412 now (actually I ordered a 402 and that's what's written on the IC but Atmel Studio says its a 412), and the trouble I'm having is that I can't send I2C Stop sequences. The chip apparently has strobe commands, via register MCTRLB. In theory writing 0x03 to this register will issue a Stop command but it does nothing. I can only talk to the ADC once after power-up and then my I2C bus is jammed. My workaround is to take over the IO and bit-bang a stop sequence. Ugly but it works.
I'd like to know if anyone has succeeded in getting the TWI hardware to work as intended?
Here are my relevant functions:
void TWI_Init() { TWI0.MBAUD = 0x1F; //TWI0.MCTRLA = 1 << TWI_ENABLE_bp | 1<<TWI_SMEN_bp | 1<<TWI_QCEN_bp; TWI0.MCTRLB |= TWI_FLUSH_bm; TWI0.MSTATUS |= (TWI_RIF_bm | TWI_WIF_bm); } void TWI_Enable() { TWI0.MCTRLA = 1 << TWI_ENABLE_bp | 1<<TWI_SMEN_bp; TWI0_MSTATUS |= TWI_BUSSTATE_IDLE_gc; } void StopBitDelay() { volatile int d; d=25; while(d--); } void TWI_Stop() { TWI0_MCTRLA &= ~TWI_ENABLE_bm; //Disable TWI, TWI0_MCTRLB = 0; //Manual stop sequence :/ PORTA_OUTCLR = 6; PORTA_DIRSET = 6; //Both low. StopBitDelay(); PORTA_DIRCLR = 4; //SCL High. StopBitDelay(); PORTA_DIRCLR = 2; //SDA High. StopBitDelay(); }
And usage:
TWI_Init(); while(1) { TWI_Enable(); TWI_Start(LT2487_ADDR_WRITE); TWI_Write(0b10100000); TWI_Write(0b10000000); TWI_Start(LT2487_ADDR_READ); regData[0] = TWI_Read(1); regData[1] = TWI_Read(1); regData[2] = TWI_Read(0); TWI_Stop();
I borrowed the bulk of the code from this post: https://www.avrfreaks.net/commen...
The stop function in that post doesn't work for me though.