SpenceKonde / ATTinyCore

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

I2C issue on tiny84 #386

Closed SpenceKonde closed 4 years ago

SpenceKonde commented 4 years ago

From forum PM:

I'm working on a digital clock displaying time and date. I am recieving the time data from the german DCF77.5 Broadcast. The data is processed by the controller and send to a DS1307. The output is displayed via a MAX7221. On ebay i found 6 new old stock ATtiny85. They work completely fine with your tiny Core, i found on github. There occurs just one problem, when it comes to I2C between DS1307 and the tiny. I tested the code on Arduino Nano and Uno, where it works without problems. Although i use 4k7 resistors on SDA and SCL, the controller obviously gets stuck on the line i start the Wire communication.

`#include

//DCF77 data Pin

define DCF 5

//MAX7221/7219 Pins

define DATA 1 //Data / SDA

define CS 2 //Chip Select

define CLK 3 //Clock / SCL

// DS1307 I2C Address

define DS1307 0x68

//Control Switches

define reset_Pin 0

define refresh_DCF 1

bool check; bool Datarray[58] = {0}; bool clock_change; bool MESZ; bool MEZ; bool leap_second; int years_DCF = 0; int months_DCF = 0; int dayofweek_DCF = 0; int days_DCF = 0; int hours_DCF = 0; int minutes_DCF = 0; unsigned long t; unsigned long dt; unsigned long pause; bool leave;

int s = 0; int m = 0; int h = 0; int dow = 0; int d = 0; int mth = 0; int y = 0;

byte seconds = {0}; byte minutes = {0}; byte hours = {0}; byte dayofweek = {0}; byte days = {0}; byte months = {0}; byte years = {0};

void setup() { Wire.begin(); pinMode(DCF, INPUT); pinMode(DATA, OUTPUT); pinMode(CS, OUTPUT); pinMode(CLK, OUTPUT); pinMode(reset_Pin, INPUT); pinMode(refresh_DCF, INPUT); initialize(); validate_DCF(); set_DS1307(); }

void loop() { get_DS1307(); //OUTPUT section cut pause = millis(); do{ if(digitalRead(refresh_DCF)){ validate_DCF(); set_DS1307(); } }while((millis() - pause) < 5000); get_DS1307();

//OUTPUT section cut

pause = millis(); do{ if(digitalRead(refresh_DCF)){ validate_DCF(); set_DS1307(); } }while((millis() - pause) < 5000); }

void set_DS1307(){ Wire.beginTransmission(DS1307); Wire.write((uint8_t) 0x00); Wire.write((uint8_t) 0x00); for(int i = 0;i <= 6;i++){ if(Datarray[i+21]){bitSet(minutes,i);} } bitClear(minutes,7); Wire.write(minutes); for(int i = 0;i <= 5;i++){ if(Datarray[i+29]){bitSet(hours,i);} } for(int i = 6;i <= 7;i++){bitClear(hours,i);} Wire.write(hours); for(int i = 0;i <= 2;i++){ if(Datarray[i+42]){bitSet(dayofweek,i);} } for(int i = 3;i <= 7;i++){bitClear(dayofweek,i);} Wire.write(dayofweek); for(int i = 0;i <= 5;i++){ if(Datarray[i+36]){bitSet(days,i);} } for(int i = 6;i <= 7;i++){bitClear(days,i);} Wire.write(days); for(int i = 0;i <= 4;i++){ if(Datarray[i+45]){bitSet(months,i);} } for(int i = 5;i <= 7;i++){bitClear(months,i);} Wire.write(months); for(int i = 0;i <= 7;i++){ if(Datarray[i+50]){bitSet(years,i);} } Wire.write(years); Wire.write((uint8_t) 0x00); Wire.write((uint8_t) 0x00); Wire.endTransmission(); }

void get_DS1307(){ Wire.beginTransmission(DS1307); Wire.write((uint8_t) 0x00); Wire.endTransmission(); Wire.requestFrom(DS1307, 7); seconds = Wire.read(); minutes = Wire.read(); hours = Wire.read(); dayofweek = Wire.read(); days = Wire.read(); months = Wire.read(); years = Wire.read(); }`

SpenceKonde commented 4 years ago

Totally unrelated - there is no I2C code shared between the two. Under the hood, everything is different.

veganism commented 4 years ago

Hah, whoops. I jumped to conclusions about it - sorry.

SpenceKonde commented 4 years ago

Have the parts in stock to check this, will investigate this weekend

SpenceKonde commented 4 years ago

Ugh - finally started looking at this (now that the impending-virus-anxiety that destroyed my productivity over the past month and change has been replaced by virus-lockdown-boredom driven productivity...). There are two bugs in the above code, either of which alone are sufficient to cause the problem you described. First, you have DATA and refresh_DCF, which both appear to refer to pin numbers, set to the same pin.

The pinMode() of SDA and SCL are set to OUTPUT by Wire.begin() (the calls to pinMode(DATA,OUTPUT); and pinMode(CLK, OUTPUT); should be removed, as they are redundant and just waste flash) - but a few lines later, you call pinMode(refresh_DCF, INPUT); - since DATA and refresh_DCF refer to the same pin, you've set that pin to INPUT. With a pullup in place, the pin set INPUT will never go low, so the device you are trying to talk to will never see any data. The pins used for SDA and SCL need to be OUTPUT when using any I2C functionality.

Second, please refer to the pinout chart here: https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x5.md SCL is on pin 2, SDA is on pin 0 (arduino pin numbers). Those pins are dictated by hardware, you cannot choose whichever pins you want for those functions (and you have pin 0 set as INPUT too)

Third, you are trying to use pin 5 in your sketch, however, pin 5 is the hardware reset pin. That pin cannot be used for I/O unless you have HV programming hardware, and are manually setting the RSTDSBL fuse (my core does not provide this option because such hardware - and the understanding of how to use it - is rare in Arduino circles, so it would serve as a trap for the unwary to "brick" their chips). You also have a pin #define'ed as "reset_PIN", but that pin isn't the actual hardware reset pin, which seems strange....

Anyway - it is clear that this sketch could never function as written. Feel free to ask followup questions if needed, but as there is no evidence that this indicates a bug in the core, I am closing the issue. Might I suggest you consider a part with more I/O pins, like the ATtiny84?