ATtiny416 TWI not enabling?

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

Hi folks, been a while since I've been here. I'm very experienced with I2C, been using it for years. Used many, many Megas and Tinys before, as well as PIC and PIC32MX for I2C intensive projects (many slaves, lots of data). I recently found the new tinyavr1 series of chips, and I am super impressed. For the price/performance/package size, they seem to be in their own class at the moment. So I am designing one into a project. In the meantime I picked up an ATtiny416 xPlained Nano board from Digikey. First project was to create the TWI class, and also the SSD1306 class (the display driven over I2C I will be using).

 

In the constructor function for the TWI class, I have the following:

 

i2c::i2c() {
    // set up i2c pins and registers
    PORTMUX.CTRLB |= (1 << 4); // activate PB0 and PB1 as TWI
    TWI0.MBAUD = 85; // 100kHz
    TWI0.MCTRLA = 0x03; // enable TWI and smart mode
    TWI0.MSTATUS |= 0x01; // set bus to idle
    return;
}

The TWI0.MSTATUS |= 0x01 was a gotcha. The registers and overall usage of the TWI modules on these chips is so vastly different than the old AVR chips I've used. Anyway, the TWI0.MCTRLA = 0x03 should be setting both the ENABLE bit and the SMEN bit. However, when I watch it in the debugger, after that statement TWI0.MCTRLA is still 0x00. The MBAUD and MSTATUS registers are correctly set. Does this register always read as zero? That doesn't seem right.

 

Later on in my code it hangs while waiting for the WIF flag to be set after sending the slave address.

            address8Bit = (deviceAddress << 1);
            TWI0.MADDR = address8Bit; // load data
            while (!(TWI0.MSTATUS & 0x40) || (!(TWI0.MSTATUS & 0x80))); // wait for addr to send
            if(TWI0.MSTATUS & 0x08) {
                statusCode = WADDRESS_NACK_CODE;
                return statusCode;
            }

I saw that if there is a bus error, it will instead set the RIF flag and set the status register. However, even in while() loop checking both of those registers, they stay at zero. So nothing is happening at all, confirming that the TWI module is indeed not enabled.

 

Anyone have any ideas? Are there any other registers that need to be set before the TWI0 module can be enabled? I'm really scratching my head on this one. When I saw the requirement to set MSTATUS bus state bits to IDLE, I thought I had solved it, but that had no effect. Any advice is greatly appreciated!

 

EDIT: Okay, suddenly the registers do seem to be set correctly when I watch them while debugging. I don't know what I changed, if anything, but the while loop still gets stuck. I guess I'd better pull out my ChronoVu or my Bus Pirate and see if the TWI lines are doing anything... but if there was an address NACK then it should pass that while() loop anyway?!

Last Edited: Wed. Feb 26, 2020 - 01:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
PORTMUX.CTRLB |= (1 << 4); // activate PB0 and PB1 as TWI

Writing a 1 to this bit selects the alternate pins. The alternate pins for twi0 on a 416 are PA1/PA2. If you want the default pins of PB1/PB0, then that bit needs to remain as the default, which is 0.

 

I didn't read the rest of the post as it probably doesn't mean much if using the wrong pins.

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

curtvm wrote:

PORTMUX.CTRLB |= (1 << 4); // activate PB0 and PB1 as TWI

Writing a 1 to this bit selects the alternate pins. The alternate pins for twi0 on a 416 are PA1/PA2. If you want the default pins of PB1/PB0, then that bit needs to remain as the default, which is 0.

 

I didn't read the rest of the post as it probably doesn't mean much if using the wrong pins.

 

Had you bothered to read the rest of my post, you'd see that enabling the wrong pins wouldn't have affected the heart of the actual problem. Part of the issue is the documentation around enabling peripherals -- in other micros I've used, you had to explicitly set a bit in a PORT register to tell that pin to be under peripheral control; while in the tinyavr1 series, it seems you just set the pins to whatever state the peripheral needs and then activate that peripheral.

Just got I2C output after realizing that. Re-read the PORT section of the datasheet about 5 times without seeing any mention of peripheral registers and just assumed it was taking control ... not a great way to switch ports to peripheral control.

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

>Had you bothered to read the rest of my post, you'd see that enabling the wrong pins wouldn't have affected the heart of the actual problem

 

Sorry. Wasn't that interested in trying to figure out the rest when the wrong pins are being used. You can apply for a refund if the info provided was not helpful.

 

 

I will try some more.

 

>Later on in my code it hangs while waiting for the WIF flag to be set after sending the slave address.

 

while (!(TWI0.MSTATUS & 0x40) || (!(TWI0.MSTATUS & 0x80)));

 

Waiting in the while loop when either RIF and WIF bits are 0 seems like a long wait as the RIF will not get set. Not sure why RIF is being checked here when a write was just done, but I'm not an i2c expert.

 

 

>I saw that if there is a bus error, it will instead set the RIF flag and set the status register

 

Bit 7 – RIF Read Interrupt Flag
This bit is set to '1' when the master byte read operation is successfully completed, i.e. no arbitration lost or bus error occurred during the operation.

 

Doesn't look to me like the RIF flag is set with a bus error. 

 

 

Last Edited: Wed. Feb 26, 2020 - 05:22 PM