Weird phenomen on digispark/attiny85 during pin configuration.

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

Hy everybody,

I am experiencing some effect on my digispark (probably clone) that i cant quite explane myself.

I know on a digispark only PORTB 0 to 2 are free and 3 and 4 are for USB communication and 5 is reset (on a clone)

Since i am not using usb while my program is running I tried using these ports anyways and it turns out PORTB 4 can be used as input if u take a slightly smaller pullup.

Now I tried to configure PORTB 3 as output and here the weirdness begins:

If I configute it as input the Attiny85 works perfect.

If I configure it as output inserting DDRB|=(1<<3); in the setup, things get bizarre even without any physical connection to this port:

With pullups on the i2c ports the attiny (at least the display) stops doing anything, and a statechange/low on port4 triggers a reset????

Without pullups on the i2c ports it messes up i2c communication and the text on the connected display turns to gibberisch before it stops working.

 

The Only explanation I can come up with for this is that due to the small pullups (1K) and the Zehner Diode on the digispark the attiny is somehow overwelmed and voltage levels drop to low.

Or something like that.

I dont use any capacitor scince i assume there is already on on the digispark board. Possible source of trouble?

 

Anybody here with more experience than me?

 

P.S. I know I kow! Take a chip with more outputs, u are not supposed to use the USB pins, .....  But I just want to try and understand!

 

Here some code (I am using Arduino IDE):

 

The importend part of the code: here the line market as comment is the crucial one that makes things go haywire if uncommented.

 

#define LCD_ADDR     0x27
#define LCD_WIDTH    16
#define LCD_HEIGHT   2
#define TEMP_ADDR 0x40
#define ENC_A        1
#define ENC_B        4
#define OUT_1        3
#define OUT_2        5

void setup(void)
{ DDRB&=~(1<<ENC_A+1<<ENC_B);
  //DDRB|=(1<<OUT_1);
  PORTB|=1<<ENC_A+1<<ENC_B;
  lcd.init();
  lcd.backlight();
  i2c_w8(TEMP_ADDR, 0xFE); //sensor reset
  initTimer();
  readEEPROM();
};

 

 

All the code for the curious ones:

 

#include <avr/io.h>
#include <EEPROM.h>
#include <util/delay.h>
#include <TinyWireM.h>
#include <LiquidCrystal_attiny.h>

#define LCD_ADDR     0x27
#define LCD_WIDTH    16
#define LCD_HEIGHT   2
#define TEMP_ADDR 0x40
#define ENC_A        1
#define ENC_B        4
#define OUT_1        3
#define OUT_2        5

#define state_delay_on 5  //in sec
LiquidCrystal_I2C lcd(LCD_ADDR, LCD_WIDTH, LCD_HEIGHT); // set address & 16 chars / 2 lines

volatile int8_t enc_old = 2;  //encoder state memory
volatile int8_t Enc_turn = 0;   //how often encoder has been turned
volatile int8_t Enc_sw = 0;   //if encoder has been pushed
volatile unsigned long t_activ = millis(); //time of last encoder state change

int16_t temp = 999; //ist-temp*10
uint8_t temp_retry = 0, temp_state = 0;
int16_t t_lim = 150, t_on = 60, t_off = 60, t_count = 0; //soll-temp*10
uint8_t t_hyst = 10, state_swich_delay = 0; //in min
uint8_t state = 0, t_state = 0; //state: 0=ports off, 1=1 port on, 2= 2 ports on t_state: meomrizes timing cykle.
uint16_t t_statechange = 0;

#define menu_len 7
char* Menu[menu_len] = {"Exit   ", "Temp   ", "OnTime ", "OffTime", "Repeat ", "Hyst.  ", "Save   "};
uint8_t mode = 1;
int8_t pos_m = 1;

void writeEEPROM()
{ uint16_t v2;
  uint8_t v1;
  EEPROM.get(11, v2);
  if (t_lim != v2) EEPROM.put(11, t_lim);
  EEPROM.get(13, v2);
  if (t_on != v2) EEPROM.put(13, t_on);
  EEPROM.get(15, v2);
  if (t_off != v2) EEPROM.put(15, t_off);
  EEPROM.get(17, v1);
  if (t_hyst != v1) EEPROM.put(17, t_hyst);
  EEPROM.get(18, v1);
  if (state_swich_delay != v1) EEPROM.put(18, state_swich_delay);
  EEPROM.get(19, v1);
  if (mode != v1) EEPROM.put(19, mode);
}
void readEEPROM()
{ uint8_t v1;
  EEPROM.get(10, v1);  //check for initialisation
  if (v1 != 0b01010111)
  {
    writeEEPROM();
    EEPROM.put(10, 0b01010111);
    return;
  };
  EEPROM.get(11, t_lim);
  EEPROM.get(13, t_on);
  EEPROM.get(15, t_off);
  EEPROM.get(17, t_hyst);
  EEPROM.get(18, state_swich_delay);
  EEPROM.get(19, mode);
}
uint8_t i2c_w8(uint8_t addr, uint8_t data) //send i2c command
{ TinyWireM.beginTransmission(addr);
  TinyWireM.send(data);
  uint8_t r = TinyWireM.endTransmission();
  return r;
};

static inline void initTimer(void)
{
  TCCR1 |= (1 << CTC1);  // clear timer on compare match
  TCCR1 |= (1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10); //clock prescaler 8192
  OCR1C = 1; // compare match value
  TIMSK |= (1 << OCIE1A); // enable compare match interrupt
  sei();
};

ISR(TIMER1_COMPA_vect)  //timed interrupt to read encoder state
{
  enc_old = (enc_old & 0b110000) | (enc_old & 0b11) << 2 | ((PINB >> ENC_A & 1) << 1) | (PINB >> ENC_B & 1);
  if (enc_old == 0b001101)
  { Enc_turn--;
    enc_old |= 0b010000;
    t_activ = millis();
  }
  else if (enc_old == 0b001110 )
  { Enc_turn++;
    enc_old |= 0b010000;
    t_activ = millis();
  }
  else if (enc_old == 0b001100) {
    Enc_sw = 1;
    t_activ = millis();
  }
  else if ((enc_old & 0b110011) == 0b010000) enc_old &= 0b001111;
};

void setup(void)
{ DDRB&=~(1<<ENC_A+1<<ENC_B);
  //DDRB|=(1<<OUT_1);
  PORTB|=1<<ENC_A+1<<ENC_B;
  //PORTB &= ~ ( 1 << OUT_1);

  //TinyWireM.begin();
  lcd.init();
  lcd.backlight();
  i2c_w8(TEMP_ADDR, 0xFE); //sensor reset

  initTimer();
  readEEPROM();
};

void show_val(int16_t val, uint8_t dec, char* unit) //show int16 as float
{ uint8_t pos, pot = 1;
  int8_t rval, dec1 = dec;
  uint16_t lval = val;
  if (unit != "m")
    while (dec1--)
    { val = val / 10;
      pot *= 10;
    }
  else
  { dec = 2;
    val = val / 60;
    pot = 60;
  };
  rval = abs(lval) % pot;
  if (val > 99) pos = 0;
  else if (val > 9) pos = 1;
  else pos = 2;
  if ((unit == "m" or val < 0) and pos > 0) pos--;
  while (pos--)  lcd.print(" ");
  lcd.print(val);
  if (dec)
  { if (unit != "m") lcd.print("."); else lcd.print("h");
    if (dec == 2 and rval < 10) lcd.print("0");
    lcd.print(rval);
    if (unit != "m") lcd.print(unit);
  };
};

uint16_t set_val(int16_t val, uint8_t dec, uint8_t step, char* unit) //show and adjust a numerical value with encoder
{ uint8_t mystep = step, turn_old = Enc_turn;
  Enc_turn = 0;
  while (true)
  { lcd.setCursor(3, 1);
    show_val(val, dec, unit);
    if (Enc_sw)
    { Enc_sw = 0;
      Enc_turn = turn_old;
      return val;
    }
    else
    { if (step == 0) mystep = (abs(val) >> 3) + 1;
      val += mystep * Enc_turn;
      Enc_turn = 0;
//      if (unit == "m" and val < 0) val = 0;
    }
    if (millis() - t_activ > 5000) break;                   //quit menu on inactive
    delay(100);
  };
}

inline uint8_t measure()   //read temperature sensor (call repeatedly until result)
{ uint8_t s;
  temp_retry++;
  if (temp_retry % 20 == 0)
  { i2c_w8(TEMP_ADDR, 0xFE); //reset
    temp_state = 0;
  };
  if (temp_state == 0)
  { i2c_w8(TEMP_ADDR, 0xF3); //start measurement
    temp_state = 1;
  }
  else temp_state = TinyWireM.requestFrom(TEMP_ADDR, 2); //read temperature
  if (!temp_state)
  { uint16_t hi = TinyWireM.receive() << 8;
    hi += TinyWireM.receive();
    temp = (((long(1757) * hi) >> 15) - 937) >> 1;
    temp_retry = 0;
    return 0;
  }
  else if (temp_retry > 600)
  { temp = -999;
    temp_state = 0;
    temp_retry = 0;
    return 2;
  };
  return 1;
};

void show_tt()    //display actual temperature, set temperature and timing
{ uint16_t t = t_on + t_off - (millis() / 60000 - t_count);
  lcd.setCursor(0, 0);
  lcd.print((int)state);
  lcd.print(" T");
  show_val(temp, 1, "");
  if (mode & 0b01)
  { lcd.print(" >");
    show_val(t_lim, 1, "C");
  };
  if (mode & 0b1110)
  { lcd.setCursor(0, 1);
    lcd.print("On");
    if (t_state == 0 or t_state == 2) show_val(t_on, 0, "m");
    else if (t_state == 1)  show_val(t - t_off, 0, "m");
    else if (t_state == 3)  show_val(t, 0, "m");
  };
  if (mode & 0b1100)
  { lcd.setCursor(8, 1);
    lcd.print("Off");
    if (t_state != 2) show_val(t_off, 0, "m");
    else show_val(t - t_on, 0, "m");
  };
  //lcd.setCursor(0, 1);
  //lcd.print((int)PORTB);
};

inline void set_state()     //swich state/ports according to temperature
{ uint16_t mill = millis() / 60000;
  if ((mill - t_statechange > state_swich_delay) or (t_statechange == 0 and millis()/1000 > state_delay_on))
  { uint8_t oldstate = state;
    t_state = 0;
    if (t_count == 0) t_count = mill; //restart timing
    if (mode & 0b1100)
    { if (t_count == 0) t_count = mill;
      if (mill - t_count < t_off ) {
        state = 0;
        t_state = 2;
      }
      else if (mill - t_count > t_on + t_off)
      { state = 0; t_state = 0;
        if (mode & 8) t_count = 0;  //restart if loop
      }
      else {
        state = 1;
        t_state = 3;
      };
    }
    else if (mode & 2)
    { if (mill - t_count < t_on)
      {
        state = 1;
        t_state = 1;
      }
      else
      {
        state = 0;
        t_state = 0;
      }
    };
    if (mode & 1)
    { if (temp <= t_lim) state = 1;
      if (temp <= t_lim - t_hyst) state = 2;
      else if (temp >= t_lim + t_hyst) state = 0;
    };
    if (oldstate != state)
    { t_statechange = mill;
      PORTB =(PORTB & ~(1<<OUT_1))| ((state&1)*(1<<OUT_1));
    };
  };
}

void loop() {
  measure();
  show_tt();
  set_state();
  if (Enc_sw or Enc_turn)                       //if user input
  { Enc_sw = 0;
    if (pos_m < 0)                                    //if display was off, display on
    { lcd.backlight();
      pos_m = 0;
    }
    else if (Enc_turn)                                //if encoder turned adjust temperatuer setting
    { if (mode | 1) t_lim += 5 * Enc_turn;
      else if (mode == 2) t_on += Enc_turn * ((abs(t_on) >> 2) + 1);
      Enc_turn = 0;
    }
    else                                              //if encoder pushed show menu
    { lcd.clear();
      uint8_t change_val = 0;
      while (1)
      { lcd.setCursor(3, 0);
        lcd.print(Menu[pos_m]);                                 //show menu item in line 1
        lcd.setCursor(13, 0);
        if (pos_m > 0 && pos_m < 5)
        { if (mode & (1 << (pos_m - 1)) ) lcd.print(" On");     //show state of menu item
          else lcd.print("Off");
        }
        else lcd.print("   ");
        lcd.setCursor(3, 1);
        if (change_val)
        { if (pos_m == 1) t_lim = set_val(t_lim, 1, 5, "C");
          else if (pos_m == 2) t_on = set_val(t_on, 2, 0, "m");
          else if (pos_m == 3) t_off = set_val(t_off, 2, 0, "m");
          change_val = 0;
          lcd.clear();
        }
        else if (pos_m < menu_len - 1) lcd.print(Menu[pos_m + 1]);    //show menu item of line 2
        else lcd.print("         ");
        delay(100);
        if (Enc_sw)                                         //if pushbutton execute menuitem
        { Enc_sw = 0;
          if (pos_m == 0)
            break;                                                   //quit menu
          else if (pos_m < 5)
          { mode ^= (1 << (pos_m - 1));                            //toggle options (temp mode, time mode,...)
            if (mode & (1 << (pos_m - 1))) change_val = 1;
            if (pos_m > 1) t_count = 0;                             //reset time counting
          }
          else if (pos_m == 5)
          { lcd.setCursor(13, 0);                                   //adjust hysteresis
            t_hyst = set_val(t_hyst, 1, 1, "C");
            if (t_hyst < 0) t_hyst = -t_hyst;
          }
          else if (pos_m == 6)
          { writeEEPROM();
            break;
          }
          //Enc_turn=pos_m;
          lcd.clear();
        }
        else      //if Enc_turn is out of limits (number of menu itims)
        {
          if (Enc_turn < 0) Enc_turn = 0;
          else if (Enc_turn > menu_len - 1) Enc_turn = menu_len - 1;
        }
        pos_m = Enc_turn;
        if (millis() - t_activ > 5000) break;                   //quit menu on inactive
      };
      lcd.clear();
    };
  };
  delay(100);
  if (millis() - t_activ > 20000)                             //backlight off if inactive
  { lcd.noBacklight();
    lcd.init();
    pos_m = -1;
  };
};

 

 

Last Edited: Fri. Dec 13, 2019 - 05:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

blubbersprudel wrote:
digispark

You mean this:  http://digistump.com/products/1 ?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes, somethigng compatible to that. 

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

Did it come with a schematic?

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

 

 

 

from net net:

(why are there 2 capacitors in parallel? isnt it the same as one capacitor especially considering the sizes?)

from the net

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

PB3 is already connected to USB D-, how could it be used for anything else??

 

Looks like you probably need an AVR with more pins.

 

A standard Arduimno Uno (clone) costs $5 and has a 28 pin AVR so there's plenty of "spare" pins.

 

It's odd how a lot of people that visit Freaks think that using chips with few pins or very little memory are "easier to use" - it's quite the opposite!

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

blubbersprudel wrote:
isnt it the same as one capacitor

If they were ideal capacitors - yes.

 

But they aren't.

 

Practical high-value capacitors (eg, the 4.7uF one) are poor at filtering out high-frequency noise - so a "small" capacitor (like the 0.1uF) is commonly added for that.

 

https://electronics.stackexchange.com/questions/21686/whats-the-purpose-of-two-capacitors-in-parallel

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Dec 13, 2019 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@ avnail: thx, learned sometinhg new again!

@clawson: I didnt mention explicitely, that i use the USB only for uploading the program, not while it is running. Thus I am using PB4 as input even though it is connected for USB also.

Only PB3 is making trouble when i want to use it as output. I just would like to know why.

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

Well two things:

 

1) when you are not uploading do you actually remove the USB cable?

 

2) even with no USB connection to a PC host the fact is that the PB3 is loaded with R1, R3 and D1 anyway. These may well influence the operation of PB3 whether you use it as an input or drive it as an output.

 

Your best bet might be to try and add some form of jumper isolation to the right of R1 so the line is open and floating when a jumper disconnects it from the rest of the USB interface.

 

Or splash $5 on an Uno!

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

Well, adding a jumper isolation would be ideal, but on these tiny boards its all but impossible.

I already have a Nano to replace the digispark, but i just would like to understand the behavior. Its not that i get the wrong voltage levels or the port is just not working. Just configuring it as output messes up all the other ports too. 

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

blubbersprudel wrote:
If I configure it as output inserting DDRB|=(1<<3);

Don’t use the rmw operation, |=, just set the port or ddr reg using =

Because you don’t know what will be read, and you don’t care, just set it how you want it with an assignment to what you want it to be.

 

jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...