-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Weird address issues on ATtiny2313-10PU #4
Comments
Just a wild guess. I've never used this on an attint2313, but the 2313 Also, please note that anytime i2c doesn't get a proper answer (i.e. |
I've just gotten my hands on a couple more chips, including a 2313A, believing that perhaps I had a faulty chip. I've taken a look at the USI section of the datasheets for both the '2313A and the '85 and they appear identical. There's nothing in the errata either. On a raspberry pi now, it cannot find my ATtiny at all, however it can find other devices on the same bus (see below for devices tested against). I've created a TWI master test setup, and am using the following code on an ATmega328P with Peter Fleury's I2C Master library. I'm running 5V logic level, with 4.7kOhm pullups. It finds a read address on 0x40 but crashes when it tries to write on 0x40. I've tested this scan code against a couple of "real" I2C devices on the same bus, a DS1307 (at 0x68), and two 24LC256 (at 0x53 and 0x57) EEPROMs and it can find all of them with one sweep if the ATtiny is disconnected. I've also tried commenting out init_gpio, thinking that perhaps it's inadvertently messing something up somehow to no avail: // Probes the i2c bus for devices.
void i2c_scan(void)
{
i2c_init();
printf("%S", I2C_SCAN_HEADER);
printf("%S", I2C_SCAN_TABLE_SEPARATOR);
for(unsigned char high_addr = 0x00; high_addr <= 0x70; high_addr += 0x10) {
printf("|%X_|", high_addr>>4);
for(unsigned char low_addr = 0x00; low_addr <= 0xF; low_addr++) {
unsigned char address = (high_addr|low_addr) << 1;
unsigned char access_status = i2c_start(address+I2C_READ);
if(access_status == 0) {
putchar('R');
// if we can hit a read address, we actually need to read something and send a NACK
i2c_readNak();
} else {
putchar(' ');
}
i2c_stop();
access_status = i2c_start(address + I2C_WRITE);
i2c_stop();
if(access_status == 0) {
putchar('W');
} else {
putchar(' ');
}
printf("|");
_delay_ms(100);
}
if(high_addr != 0x70) {
printf("%S", I2C_SCAN_TABLE_SEPARATOR);
}
}
printf("%S", I2C_SCAN_TABLE_FOOTER);
} |
I find some unexplainable problems come from marginal power supply, you I am running this code for a few years now, so I guess it can work ;-) I You might want to try a crystal (or even ceramic resonator), but in |
Power's all good and everything's appropriately decoupled. I've taken a peek over the code as well as my scanner and i2cdetect (raspberry pi's). I may have an idea of what's going on. Have you ever tested a stop condition immediately after start_[device-write-address]? I can't find anything in your library that would seem to handle something like that but my mind may be shutting it out after staring at code for days now :P. It might explain why the raspberry pi thinks consecutive address are showing up (in reality, the i2c slave is sending ACKs thinking it's getting data when the raspberry pi is thinking it's getting ACKs from probing out the next addresses) If such functionality doesn't exist, I'd be happy to try and implement it and submit a patch :) |
Nice. Please note that twi does feature a start condition interrupt, it does You might want to try it with power saving off, by the way (no idle |
Yep, all of my tests were with idle disabled. I'm definitely going to to try and revisit this when I have some time. For now I guess I'll have to suffice with a dummy write when testing for devices. I'm guessing the fix is going to be a little more involved than the following, although it did end up scanning successfully (haven't tested how it actually affects the buffer states) case(of_state_request_ack):
{
of_state = of_state_check_ack;
USIDR = 0x00;
set_counter = 0x0e; // receive 1 bit (2 edges)
set_sda_to_input(); // initiate receive ack
// if there's a stop condition, however...
if((PORT_USI & (_BV(PIN_USI_SDA))) && (PORT_USI & (_BV(PIN_USI_SCL))))
twi_reset();
break;
} |
I'm (really) late to the party but I have noticed on the tiny25 that if you want anything even remotely close to 400kHz I2C bus speed you've got to be running up near 64MHz. I was quite surprised that even at 8MHz (internal RC, no PLL, CLKDIV8 not set) 100kHz was iffy. As soon as I enabled the PLL things just started working properly. |
@akohlsmith Where are you enabling the PLL? Can you post the line of code? I had some issues as well, and I started running my ATTINY85 with a 16mhz external crystal for needing more accurate timing. It improved, but on occasion I get some problems. I'd like to try. |
Yes confirmed. You need to run > 8 Mhz to make I2C reliable. It can be done quite easily with the PLL clock (which the larger models don't have...), without a crystal. I2C is not sensitive to timing, so it doesn't matter that the RC clock isn't accurate. It just needs to be FAST, at least with the USI-implementation. The problem is in the acknowledgement of the address after a start condition. It's very easy to take to long for that and the master will give up. Unfortunately the USI-implementation cannot acknowledge in hardware. There is another problem with USI and that's there is no interrupt for STOP conditions. So you need to rely on STOP conditions always coming right before a START condition. Or monitor the line all of the time, but that's not what we want. |
@gismofx it's done in the fuses. http://www.engbedded.com/fusecalc/ shows that CKSEL=0001 will select the PLL (on ATTINY25). |
@eriksl that seems odd; USI's supposed to be taking the hard part away from software. I'm almost positive that I could bit-bang an I2C slave if I was running at 64MHz. No matter, I've got it figured out now. Do you think it might be worth adding a note to that in the readme? |
Funny you mention that. Definitely more people have mentioned this fact. The USI isn't helping very much indeed, I also found out. If you're going to do a full-blown I2C slave, you'd better switch to an atmega with full I2C support. The USI implementation would be sufficient for an I2C master though. On a side note, how did you manage to get it running at 64 Mhz??? I am sure you can get the clock that high using the PLL, but it isn't supposed to work (max 20 Mhz!). |
I'm not doing anything spectacular. The ATTINY25's PLL takes a source clock and multiplies it by 8. The default input clock is the 8MHz internal RC oscillator. Section 6.1.5 of the datasheet. I am guessing that the 20MHz limit is the clock pin input limit. |
Or the clock is limited internally! Are you sure it really runs at the full 64 Mhz? With limited voltage (e.g. 3.3V) it can't even run on 20 Mhz... |
EDIT: I may be doing something wrong with my code, however, I've found that when configuring my ATtiny2313V-10PU to be an I2C slave on 0x40, probing the I2C bus with my raspberry pi using i2cdetect sometimes gets hits on just 0x40, sometimes on 0x40 and 0x41, sometimes on 0x40, 0x41, AND 0x42, and sometimes even 0x40, 0x41, 0x42, and 0x43.
I've blanked out this issue in the meantime while I investigate even further, but I have a feeling that something fishy is going on here. Here's my original code. I can confirm that that the address select pins are giving me a get_i2c_address() of 0b01000000 (0x40) using bit_bang_spi to drive a shift-register based LED driver. i2c_slave.h is of course, usitwislave.h
The text was updated successfully, but these errors were encountered: