Beginner Q: ATtiny13A LED driver query

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

Hello,
I wrote a simple sketch to test out multitasking using LED's.
It is based on a simple blink sketch plus a button input to light a second LED when pressed.

 

Tech info:
ATtiny 13A
Programmed via ESP8266 using Arduino IDE

Power supply: 3.3VDC regulated supply

 

The way I intended it to work:
The Red LED would always blink on and off within 1 second (500 ms half cycle).
The Yellow LED would remain off while the button is not depressed.
The Yellow LED will light when the button is held down only.

 

The observed outcome:
The Red LED blinks as expected. (yes)
The Yellow LED remains off while the button is not pressed. (yes)
The Yellow LED does turn on when the button is held down. (yes)

 

All good so far .....

However, an extra unwanted behaviour is observed....

The Yellow LED 'flickers' in that it drops intensity when the Red LED is on,
 and then gains back intensity when the Red LED turns off.

 

I am wondering why the Yellow LED does not come one with a single intensity when the 
button is pressed, and what is making it drop intensity when the Red LED turns on.

Any insight would be greatly appreciated.

 

Schematic

 

#include <avr/io.h> // seems to be needed for IO

/*
  Blink
  ------------------------------------------------------------------------------

  PINOUT
  PB5   u   VCC
  PB3       PB2
  PB4       PB1
  GND       PB0

*/

const uint8_t RED_PIN = 4;  // PB4 = package pin 3 (edited to fix comment)
const uint8_t YELLOW_PIN = 1; // PB1 = package pin 6 = yellow (edited to fix comment)
const uint8_t BUTTON_PIN = 0 ; // button pin is pin 5 PB0
uint8_t flg = HIGH; //button status
uint32_t tme = 0; //unsigned time integer
uint8_t tog = 0; // toggle switch
uint32_t tog_flag = millis(); // initial time

void setup()
{

    DDRB |= (1 << RED_PIN)| (1 << YELLOW_PIN); // make led pins  outputs

} /// setup end

void toggle(){      // toggle the flag 'tog' between 1 & 0 every 500 ms
  if (millis() - tog_flag > 500){
    if (tog == 0){
      tog = 1; // toggle the tog
    }
    else {
      tog = 0; // toggle
    }
    tog_flag = millis(); // reset the flag timer
  }
}   // end toggle

void yellow(){      // turn on the yellow LED if button push detected
  flg = digitalRead(BUTTON_PIN);
  if (flg == LOW)
  {
    PINB |= (1 << YELLOW_PIN);
  }
}

void red() // red blink loop - simply blink on/off in 1s cycle
  {
  if (tog == 1)
  {
    PINB |= (1 << RED_PIN);
  }
  if (tog == 0)
  {
    PINB |= (0 << RED_PIN);
  }
}

void loop()
{
  yellow(); // poll the button and light yellow if button held on
  toggle(); // call the toggle timer
  red();    // blink red on/off forever
}

 

============== EDIT 27-APRIL-20 ===========

Updated schematic following mod's of post #3

Note that I have kept LED2 marked as yellow just to differentiate it - even though it has been changed to a red LED.

 

updated schematic

 

Y-Lee-Dingo

Last Edited: Mon. Apr 27, 2020 - 12:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to AVRFreaks.

 

I haven't examined your code, but suggest/ask as follows:-

 

- why have you left the reset pin floating? At the very least it should be pulled high with a 10K resistor or similar.

 

- what is the purpose of your R1 resistor inline with the power supply? A varying drawn current will simply modulate your supply voltage at the Vcc pin.

 

- what is the forward voltage drop across your yellow led? Your supply voltage may be insufficient to keep its intensity constant especially with a varying Vcc supply.

 

- are you sure that R2 and R3 are 1K resistors? If they were misread 100 ohm values your observed behaviours would be entirely expected.

Ross McKenzie ValuSoft Melbourne Australia

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

valusoft wrote:

Welcome to AVRFreaks.

 

I haven't examined your code, but suggest/ask as follows:-

 

- why have you left the reset pin floating? At the very least it should be pulled high with a 10K resistor or similar.

 

- what is the purpose of your R1 resistor inline with the power supply? A varying drawn current will simply modulate your supply voltage at the Vcc pin.

 

- what is the forward voltage drop across your yellow led? Your supply voltage may be insufficient to keep its intensity constant especially with a varying Vcc supply.

 

- are you sure that R2 and R3 are 1K resistors? If they were misread 100 ohm values your observed behaviours would be entirely expected.

 

Thanks for the welcome smileycool:)

 

And also thanks for your input & comments. I've followed each of your ideas through:

 

  1. Floating reset pin. Thanks for the insight.  10k pullup is now installed. 
  2. R1 resistor was a sense resistor I was using to see current draw. Based on your comment I have now removed it so as to remove a possible cause. Pin 8 is now directly connected to the supply rail.
  3. Fwd voltage drop on Yellow LED is ~2V. But to help eliminate this as a possible cause I have swapped it with another red LED & raised the supply voltage to 4.5V.
  4. Following your comment I have now checked with a meter all resistors. All check out as 1k. (The 1 ohm resistor in the supply line is now removed.)

 

After following the above, I still see a depression in intensity on LED2 (was yellow but now red) whenever LED1 is lit.

 

I scoped the pins at each of the LED's.

This is what I saw:

 

LED drive pins

 

It seems like when both LED's are driven, the signal to the pins is a square wave of approx 16.7 kHz.

But when LED1 is not on, the drive signal to LED2 seems almost flat - or maybe a much higher frequency I haven't detected.

What should I be seeing?

 

Y-Lee-Dingo

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

You do not turn off the red led correctly. Anything ‘or’ed with zero does nothing.
The comments seem to be wrong.

Last Edited: Sun. Apr 26, 2020 - 12:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Arduino related at all???

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

js wrote:

Arduino related at all???

 

I didn't initially think so...

I opened the thread in the megaAVR & tinyAVR forum, but it was shifted here by a moderator. 

??

Y-Lee-Dingo

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

Kartman wrote:
You do not turn off the red led correctly. Anything ‘or’ed with zero does nothing. The comments seem to be wrong.

 

Sorry - I'm not following.

Could you please explain a bit more?

Y-Lee-Dingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 PINB |= (0 << RED_PIN); //what does this do?

0 shifted as many times as you like is still 0. 0 'or'ed with anything does nothing. So what did you want that line of code to do?

 

const uint8_t RED_PIN = 4;  // Pin 2 = PB2 = package pin 7; pin 0 = package pin 5
const uint8_t YELLOW_PIN = 1; // Pin PB2 = pin 7 = yellow

Those comments aren't quite correct are they?

 

Are you related to Wile E Coyote?

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

Kartman wrote:

 PINB |= (0 << RED_PIN); //what does this do?

0 shifted as many times as you like is still 0. 0 'or'ed with anything does nothing. So what did you want that line of code to do?

 

const uint8_t RED_PIN = 4;  // Pin 2 = PB2 = package pin 7; pin 0 = package pin 5
const uint8_t YELLOW_PIN = 1; // Pin PB2 = pin 7 = yellow

Those comments aren't quite correct are they?

 

Are you related to Wile E Coyote?

 

 PINB |= (0 << RED_PIN);

Intent is t write a '0' or LOW to the RED_PIN to turn it off.

Seems to work ok. The red LED turns on & off as expected. 

Is there something wrong with doing it this way?

 

const uint8_t RED_PIN = 4;  // Pin 2 = PB2 = package pin 7; pin 0 = package pin 5
const uint8_t YELLOW_PIN = 1; // Pin PB2 = pin 7 = yellow

OK. Mea culpa.  sad

Comments in this section contain errors.

Edit - I've corrected the comments in the code in post #1.

 

Ah yes. Wile E. Great guy. For sure his judgment was not sound. But his perseverance must be admired.  laugh

 

 

Y-Lee-Dingo

Last Edited: Mon. Apr 27, 2020 - 12:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
PINB |= (0 << RED_PIN);

The line of code does not change the value written back to pinb. Are you sure 'it works'? It might appear to work, but there might be other factors involved. Besides writing to the PIN register enables toggle in some AVRs.

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

Anyone who tells you the RESET pin is floating is giving you misinformation.  It's already pulled up internally with a 50-60K pullup.  An external 10K pullup is not at all necessary for what you are doing.

 

You also could drop the pullup for the button and use INPUT_PULLUP mode.

 

Which Arduino core are you using?  MicroCore?

 

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:

Anyone who tells you the RESET pin is floating is giving you misinformation.  It's already pulled up internally with a 50-60K pullup.  An external 10K pullup is not at all necessary for what you are doing.

 

You also could drop the pullup for the button and use INPUT_PULLUP mode.

 

Which Arduino core are you using?  MicroCore?

 

 

Thanks for the info.

I'll try the internal Pullup on the button.

 

Regarding the core... 

When I look in the library for installed cores, the only ATtiny listed is

"ATTinyCore Built-In Version unknown"

 

(I'm running Arduino  1.8.0 for some legacy reason I no longer recall - something to do with programming ESP8266 at the time)

 

====== edit ===

I will try MicroCore - I wasn't aware of it - thanks for the heads-up

 

 

Y-Lee-Dingo

Last Edited: Mon. Apr 27, 2020 - 02:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

PINB |= (0 << RED_PIN);

The line of code does not change the value written back to pinb. Are you sure 'it works'? It might appear to work, but there might be other factors involved. Besides writing to the PIN register enables toggle in some AVRs.

 

OK. I thought that code was to write 0 to PINB.

That part does appear to work fine and it blinks the red LED - video here.

You can see in the video when the button is pressed the Yellow LED lights, but it dims just a bit whenever the red LED is on.

 

 

Y-Lee-Dingo

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

Again, 'appear to work' - time to read the datasheet and look at little closer as to what it is you are actually doing.  The line of code is reading PINB, doing nothing logically  then writing the same value back. if PINB was 0, then 0 gets written, otherwise, no dice.

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

Kartman wrote:

Again, 'appear to work' - time to read the datasheet and look at little closer as to what it is you are actually doing.  The line of code is reading PINB, doing nothing logically  then writing the same value back. if PINB was 0, then 0 gets written, otherwise, no dice.

 

OK. I thought that code was a write instruction for the defined pin.

So the intention was that:

PINB |= (1 << RED_PIN);

will write a HIGH to turn on the LED, and

PINB |= (0 << RED_PIN);

will write a LOW to turn off the LED.

 

But I hear you're saying that is incorrect.

What is the correct format of the code to write HIGH and LOW as intended?

I thought I had understood the datasheet, but apparently not. 

 

Y-Lee-Dingo

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

js wrote:

Arduino related at all???

I didn't initially think so...

I'm running Arduino  1.8.0  

 So it is Arduino related.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

The critical piece of information is (from the datasheet):

However, writing a logic one to a bit in the PINx Register, will result in a toggle in the correspond- ing bit in the Data Register

 

 

So writing a 0 to the PIN register will do nothing. Writing a '1' toggles the port bit. This explains why your code appears to 'work'. This is the point I was trying to make.

 

What you thought you were doing is:

 

PORTB |= (1 << RED_PIN); //to turn the pin on - note the use of the PORTB register, not PINB

and to turn it off:

PORTB &= ~(1 << RED_PIN); //lesson here - & to clear bits, | to set bits

Alles klaar her komisar?

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

Arduino is designed to allow you to avoid all the low-level details of an I/O port's operation. Use the Arduino pin value for RED_PIN (which is 2), instead of the digital value of PORTB2 (which is 4).

 

On some AVRs, writing to a bit on the PIN register will toggle that pin.  Again, try to avoid low-level interfacing when using Arduino.

 

This code might work better:

#define RED_PIN      2         // Tiny13 PB2  
#define YELLOW_PIN   1         // Tiny13 PB1 
#define BUTTON_PIN   0         // Tiny13 PB0
#define RED_TOGGLE_INTERVAL  500   // 0.5 second

uint32_t  toggleCount = 0; 

void setup()
{
    pinMode(RED_PIN,    OUTPUT);
    pinMode(YELLOW_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT_PULLUP);
}  

void loop() {      
    if (millis() >= toggleCount) {
      digitalWrite( RED_PIN, ! digitalRead( RED_PIN );
      toggleCount = millis() + RED_TOGGLE_INTERVAL;
    }
    
    if (digitalRead(BUTTON_PIN) == LOW) digitalWrite( YELLOW_PIN, LOW);
    else digitalWrite( YELLOW_PIN, HIGH);

}

 

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


Y-Lee-Dingo wrote:

ralphd wrote:

Anyone who tells you the RESET pin is floating is giving you misinformation.  It's already pulled up internally with a 50-60K pullup.  An external 10K pullup is not at all necessary for what you are doing.

 

 

Thanks for the info.

I'll try the internal Pullup on the button.

 

 

 I prefer the manufacturer's recommendations.

 

Ross McKenzie ValuSoft Melbourne Australia

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

This is your bug:

    PINB |= (1 << RED_PIN);

This is what we call a "Read-Modify-Write" instruction.

Consider when the Yellow LED is ON and you wish to toggle the RED. The above instruction will read a byte from PINB to find the bit for Yellow = high, it will OR the bit for RED into that byte, and write it back to PINB. Therefore you will toggle BOTH Yellow & Red LEDS whenever the Yellow is ON.

 

The code you need for both Red & Yellow is: (i.e. a write operation only)

    PINB = (1 << RED_PIN);
    PINB = (1 << YELLOW_PIN);    

 

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

Frosty - good catch. That wraps up the forensic investigation of how the unit appeared to work.

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

@Kartman & N.Winterbottom

 

Thanks. You helped me understand my code for writing to the pins was rubbish. 

 

I've now used plain 'writes' to turn the LEDs on/off.

Writing to PORTB rather than to the PINB (which I now get that the latter is a toggle, not an assignment).

 

Ie.

void red() // red blink loop - simply blink on/off in 1s cycle
  {
  if (tog == 1)
  {
    PORTB = (1 << RED_PIN);
  }
  if (tog == 0)
  {
    PORTB = (0 << RED_PIN);
  }
}

void yellow(){      // turn on the yellow LED if button push detected
  flg = digitalRead(BUTTON_PIN);
  if (flg == LOW)
  {
    PORTB = (1 << YELLOW_PIN);
  }
  if (flg != LOW)
  {
    PORTB = (0 << YELLOW_PIN);
  }
}

Hopefully I've understood the lessons and now my code is sensible??

 

The code works and the LEDs do the expected thing.

Am I now talking to the pins correctly or have I just fluked an outcome that looks correct?

 

@Simonetta...

Thanks also for your input. I appreciate I could use the high level Arduino language.

Part of this exercise was for me to learn some of the low level language.

When I'm happy I can write and read pins, I want to move on to learn about interrupts - so I think knowledge at this level will help.

Something to engage and entertain while in lockdown. smiley

 

 

Y-Lee-Dingo

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

@valusoft - thanks for the reference info on Reset pullups.

Y-Lee-Dingo

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

Err no. One step forward, two steps back. The operation of PORTB is different to that of PINB. You need to use |= or &= with PORTB otherwise you will affect the other bits. The code in #17 is the correct method.

The point Frosty was making was with your original code, you would read PINB and if there were any bits set, then it would toggle them when you wrote it back.
There’s a tutorial here on bit manipulation. This should give you a better understanding of what is going on.

Last Edited: Tue. Apr 28, 2020 - 07:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Err no. One step forward, two steps back. The operation of PORTB is different to that of PINB. You need to use |= or &= with PORTB otherwise you will affect the other bits. The code in #17 is the correct method. The point Frosty was making was with your original code, you would read PINB and if there were any bits set, then it would toggle them when you wrote it back. There’s a tutorial here on bit manipulation. This should give you a better understanding of what is going on.

 

haha. Maybe I can regain some ground...

So my last effort got the result but badly.

I think I found the tutorial you referred to (but the search result turned up many results) "Bit manipulation (AKA "Programming 101")"

 

Having read through the above tutorial (but not the many pages of comments) & after re-reading the posts above, I have had another shot.

Here is my latest, which also 'appears' to operate as desired - but hopefully with correct syntax.

I'm excited about applying the toggle function of the PINB operator! - so I'm using that for the red LED - is that a valid use?

But I'm writing directly to PORTB for the yellow LED.

 

(Once I've understood writing, I next want to replace the digitalRead command.)

 

void yellow()
{      // turn on the yellow LED if button push detected
  flg = digitalRead(BUTTON_PIN);
  if (flg == LOW)
  {
    PORTB |= (1 << YELLOW_PIN);
  }
  if (flg != LOW)
  {
    PORTB &= ~(1 << YELLOW_PIN);
  }
}

void red() // red blink loop - simply blink on/off in 1s cycle
{
  if (tog == 1)
  {
    PINB = (1 << RED_PIN); // PIN TOGGLED!
    tog = 0;                 // RESET TOG
  }
}

 

 

 

Y-Lee-Dingo

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

Ok - you got the cigar this time. You port manipulation are correct.

 

Some logic  - 

if (flg == LOW)
 if (flg != LOW)

You want an if/else construct here. flg is either LOW else not. You only need to do one test.

 

 

 

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

Kartman wrote:

Ok - you got the cigar this time. You port manipulation are correct.

 

Some logic  - 

if (flg == LOW)
 if (flg != LOW)

You want an if/else construct here. flg is either LOW else not. You only need to do one test.

 

 

 

 

Great.

Thanks for your help.

I feel that the needle on my port-understanding gauge is no longer resting on the zero stop. laugh

 

 

Y-Lee-Dingo