SpenceKonde / ATTinyCore

Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8
Other
1.59k stars 308 forks source link

TinyWireM returns 3 #122

Closed ghost closed 7 years ago

ghost commented 7 years ago

I wonder what TinyWireM library should work, I've tried the version from Adafruit but it does not seem to work. I use a piece of the I2C Scanner code to check if it works.

It always return 3, I found info about that here

received NACK on transmit of data

#include <TinyWireM.h>
#include <SoftwareSerial.h>

#define L_PIN PB3
#define TX_PIN PB4
#define RX_PIN PB1
// I2C SDA PB0 LM75-1
// I2C SCL PB2 LM75-2

byte error;
SoftwareSerial mySerial(RX_PIN, TX_PIN);

void setup() {
  TinyWireM.begin();
  mySerial.begin(2400);
  mySerial.println("Start");
  delay(1000);
}

void loop() {
  TinyWireM.beginTransmission((byte) 0x48);
  error = TinyWireM.endTransmission();
  mySerial.print(error);

  delay(1000);
}
SpenceKonde commented 7 years ago

I recommend my fork of TinyWireM.

What chip are you using? My core supports 19 different chips with three different types of I2C hardware, so it's pretty important to make that clear.

Don't use the PNx notation (ie, PB1) to refer to pins; use the Arduino pin number, or the PIN_Nx (ie, PIN_B1) defines. On the Tiny85 it happens to work with PNx notation, but everywhere else, it won't. The avr libraries provide defines for the PNx pin names - but they're meant to be used with the registers and bitshift operators, eg, PORTB|=(1>>PB2); - that is, they're defined as the number after the two letters, so they don't actually uniquely identify a pin. On the tiny85 these happen to line up, and there's only one port, so it's fine. Everywhere else, it won't work.

Are you sure that your external device is connected correctly? Do you have hardware pullup resistors in place? I've had issues with I2C functionality without external pullups, the internal ones are weak. I'd put 4.7k from SCL to Vcc and SDA to Vcc if you don't have that in place already. Also make sure you're using the correct form of the address (7 vs 8 bits - I don't recall off the top of my head which is right).

ghost commented 7 years ago

Sry I did not mention the chip right away..

It's an ATtiny85, I use the PB pins because I used platformio and Arduino IDE and they kept switching up the pin numbers. Thanks for your advice, I will keep this in mind.

The connection must be correct, I switch the ATtiny in place with a Arduno Nano and then it all works. I use 4.7K pullups on SCL and SDA. The address should be okay since it works when I use the Nano.

Could there be a problem due to difference in clock speed between Nano and ATtiny?

SpenceKonde commented 7 years ago

Clock speed is unlikely to be an issue. Check the state of the pins - are they high while idle like they're supposed to be and all?

What is it talking to? I don't think TinyWireM supports I2C clock stretching, which a small number of devices depend on.

Got a schematic that I can give a once-over to?

ghost commented 7 years ago

The chip is the LM75.

This is the circuit I use but I use 4.7K pull-ups and no LED jah man

Here it shows HIGH on the right pins, also software serial printing the values. logic

bperrybap commented 7 years ago

See this issue: https://github.com/adafruit/TinyWireM/issues/7

bperrybap commented 7 years ago

@SpenceKonde, the key to making this stuff really work is to provide a compatible Wire library vs a library which is a fork of a core specific library - even if that library is better. So that sketches and libraries don't have to wonk up their code to deal with a different/separate/special API for tiny vs all the other Arduino cores. Since all the other cores provide a Wire library with a consistent interface, the same should be true for a tiny core. This allows code to be fully portable. Also, it is MUCH better to include the library in the core which is installed with the boards package vs having a separate library that is installed separately and gets installed in the users sketchbook/libraries area. Adafruit has done this in their tiny core by providing a simple wrapper around TinyWireM and providing a Wire library with their adafruit boards package; however there are issues. Beyond the silly error of returning garbage from endTransmission(), some of the under the hood TinyWireM functions don't follow the Wire API correctly so the Wire API functions end up not returning the proper status. Some functions like requestFrom() return a boolean status (or sometimes a i2c state status) rather than the byte count as documented here: https://www.arduino.cc/en/Reference/WireRequestFrom Unfortunately the Adafruit library has some broken things in their platform file and their boards file that don't allow you to burn a bootloader with an ISP programmer. (So you can't set the fuses) They also use a bootloader in their boards so you can't use all the flash even if you are using an ISP programmer to burn the part. While you can fix all this with a few edits to the boards files and the platform file the Adafruit board package/core is not acceptable for use on raw tiny parts "as is".

@Thijxx the fixes to the TinyWireM code aren't that difficult; 2 one line changes; however, you can often work around these issues in the near term if you don't want to go muck in that library code. You can use endTransmission(1) instead of endTransmission() TinyWireM will return proper status if you use that instead. This API function is available starting in Arduino 1.0.1 so it should also be compatible with all the other Wire libraries for all the the other arduino cores/boards. If you have an issue with requestFrom(), one way to get around it is not to look at the return value from requestFrom() and just start reading the values using read(). Once you get a < 0 status from read() you are at the end of the data. It depends on the code but in many cases this is acceptable. This is what I did as I have a LCD library that I want to work on tiny chips like the attiny85 but I don't want to have to walk users of my library through how to fix their broken Attiny wire libraries.

Another alternative work around is to install the Adafruit core, then grab the libraries/Wire directory down under the package directory and copy it to your other tiny core - I've done this to add Wire support to Mellis' core: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json This will give you a Wire compatible i2c library for the attin85, but you will still have the issues with endTransmission() and requestFrom() unless you down in the library code and fix it. Both are 1 line changes to the code so they are pretty simple fixes.

SpenceKonde commented 7 years ago

@bperrybap - I totally agree with you. I've had plans for a while (see issue #53 ) to add a version of the wire and SPI libraries that is drop-in compatible with the default one, and will automatically pick the right code to use for the chip in question (as some of these tinies have a USI, and some have hardware SPI, one has hardware I2C master, some have no hardware I2C master support at all and need to use softwire).

There are also now two candidates for the USI Wire library - the other one is in issue #125

SpenceKonde commented 7 years ago

This is now fixed in my fork of TinyWireM ( I think )

bperrybap commented 7 years ago

The incorrect return status of requestFrom() might be reported next .... ;-)

SpenceKonde commented 7 years ago

What needs to be changed to fix that? (ie, do you have a working version of TinyWireM with that fix?)