atTiny85 programmed under Arduino problems

I have read the reference and all the IF, CONDITIONAL, WHILE sections...
but I am obviously missing something or things important!

The program I am trying to implement is really simple and small, and VERY well commented.

Could some kind soul have a look and give me a couple pointers on what I am missing?

/*Program to work as the shutdown and powerup 
circuit for the Tripath TA0104a Class T (aka
Class D) audio amplifier using an 8-pin atTiny.
I'm using an 85, but even an atTiny25 is plenty -
it uses a whole 17 bytes of dynamic memory.
I just wanted a simple way to do what is needed
in a small PCB footprint. Here's what it does.
It mutes the amplifier long enough on power up
for the power supplies to stablize and mutes it
on a powerfail or being turned off. This is done
by using a single diode from the power transformer
secondary to an R-C network and a digital 
transistor which pulls the powerSense pin on
the atTiny to ground when the transformer is
putting out a stream of positive pulses (because
the power to the amp is turned on). The R-C time
constant of the analog interface circuit is short
(about 50 milliseconds or so) so that the LOW 
drive to the powerSense goes HIGH when you (or
something) cuts off the AC power, aka mains power.
The little analog interface is for ruggedness. 
The Tripath module is muted by setting pin 4 on 
the Tripath module HIGH. Th e Tripath MUTE pin 
is is connected to the output of pin 5 on the
atTINY85 DIP package, aka PB0 in AVR parlance. 
The circuit also checks for input overdrive\output
clipping and lights an LED connected to the output
of the atTINY85 DIP package pin 3 (aka PB4). The
atTiny program includes a "pulse stretcher" which
makes very brief amp clipping visible by keeping 
the LED on for at least the LED stretch time (so 
you won't miss seeing when occasional peaks are
being clipped). The atTiny circuit will also mute
the amplifier (which stops the Tripath driver from
sending pulses to the output MOSFETs)if prolonged
clipping is present to protect the speakers as 
well as the amplifier.
If the overdrive has been going on too long, the 
atTiny85 circuit will latch the amplifier in MUTE
which requires the power to be cycled to restart
the amp, or you can have a reset switch connected
to the atTiny85 DIP package pin 1 to pull the pin
LOW if you want a switch for this function.  
Designed by MR COFFEE September 14, 2015
Modified: not yet*/

// ATMEL ATTINY85 / ARDUINO
//
//                                 +-\/-+
//                Ain0 (D 5) PB5  1|    |8  Vcc
//                Ain3 (D 3) PB3  2|    |7  PB2 (D 2)  Ain1 (powersense input)
// (clip LED out) Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1  (clipping input)
//                           GND  4|    |5  PB0 (D 0) pwm0  (mute output)
//                                 +----+

// CONSTANTS 

// Set pin numbers:

    // below is the number of the ATtiny INPUT  
    // pin that is connected to the power sense
    // circuit through a transistor inverter. It 
    // goes LOW when power is good. The "pin"
    // number isn't the actual pin number on
    // the IC package - it is the "Port pin" 
    // number which corresponds to the actual 
    // pin number on the 8-pin DIP. It is:
const int powerSense = 2; // port pin 2 is on DIP pin 7

    // below is the number of the ATtiny INPUT
    // pin which will be connected to Pin 2
    // on Tripath module. Pin 2 on the Tripath
    // module goes LOW when the amp clips. The
    // "pin" number isn't the actual pin
    // number on the chip - it is the "Port pin"
    // number which corresponds to the actual
    // pin number on the 8-pin DIP. It is:
const int clip = 1; // port pin 1 is on DIP pin 6

    // below is the number of the ATtiny OUTPUT  
    // pin that is connected to the connected to
    // Pin 4 (the MUTE input) on Tripath module.
    // The "pin" number isn't the actual pin 
    // number on the IC package - it is the 
    // "Port pin" number which corresponds to 
    // the actual pin number on the 8-pin DIP. It is:
const int mute = 0; // port pin 0 is on DIP pin 5
     
    // below is the number of the ATtiny OUTPUT  
    // pin that is connected to the connected to
    // a LED overload indicator. The pin goes
    // HIGH on clipping peaks with a stretched
    // output duration to ensure visibility. 
    // The "pin" number isn't the actual pin 
    // number on the IC package - it is the 
    // "Port pin" number which corresponds to 
    // the actual pin number on the 8-pin DIP. It is:
const int overloadIndicator = 4; // port pin 4 is DIP pin 3 

// PROGRAM CONSTANTS THAT MAY NEED TO BE CHANGED 
  // These values will need to be tweaked
  // Values in (roughly) multiples of loop time
const long startUpDelay = 32000L;
const long ODtooLong = 300L;
const long tolerableClipping = 50L;
const long LEDstretchTime = 30L;

// VARIABLES 
      // counts time after some overdrive has
      // occurred so occasional peaks don't
      // cause unneeded muting\shutdown
long  timeWithoutOverdrive = 0L;
      // counts time that overdrive has been
      // occurring to trigger muting the amp
long  overdriveDuration = 0L;
    // count how long the power to
    // the Amplifier has been good 
long  powerGoodDetected = 0L;

void setup() 
{
    // Set pins as inputs or outputs
pinMode(clip, INPUT_PULLUP);
pinMode(powerSense, INPUT_PULLUP);
pinMode(mute, OUTPUT);
pinMode(overloadIndicator, OUTPUT);

    // Initialize output pins to start-up state
    // initially Tripath should be MUTE, which
    // requires holding the MUTE pin HIGH
digitalWrite(mute,HIGH);
    // initially the overload indicator should be off
digitalWrite(overloadIndicator,LOW);
}
  // MAIN LOOP:
void loop()
{
    // Make sure the amp isn't already shutdown. If it is shutdown, 
    // terminate the loop 
  while(overdriveDuration < ODtooLong) 
    {
      // Check if power to the amp is good and had time to stabilize
    if (digitalRead(powerSense) == LOW && powerGoodDetected > startUpDelay)
       digitalWrite(mute,LOW);
       // Check if power to the amp just came up
    if (digitalRead(powerSense) == LOW && powerGoodDetected < startUpDelay) 
      powerGoodDetected = powerGoodDetected ++;
       // Check if the amp is clipping but has NOT
       // been clipping for very long or clipping a lot
    if (digitalRead(clip) == LOW && overdriveDuration < ODtooLong)
      {
      digitalWrite(overloadIndicator, HIGH);
      overdriveDuration = overdriveDuration ++;
      }
       // Check if the amp is clipping and has been clipping
       // for too long a time or at least clipping a lot recently
    if (digitalRead(clip) == LOW && overdriveDuration > ODtooLong)
        {
          // this means the amp is clipping continuously
          // or at least quite a bit in a short time
          // so shut it down NOW before you damage it
        digitalWrite(mute,HIGH);
        digitalWrite(overloadIndicator, HIGH);
        }
        // Now if the amp isn't clipping now, begin backing off
        // the overdrive counter so it won't overflow with occasional
        // clipped peaks. Check that the counter won't go below
        // zero before doing the subtraction, and skip it if it already
        // very close to zero and would underflow.
    if (digitalRead(clip) == HIGH && overdriveDuration >= tolerableClipping)
        overdriveDuration = (overdriveDuration - tolerableClipping);
    delay(250); 
    } // end of while
} // end of main loop

I'm changing things guessing at what I may not be getting about how the C++ compiler works - do I just need to re-do this as a pile of nested if-else statements? Do IF conditions need to be computed before the IF statement, like in a simple little procedure?

Please don't just tell me I need to read some more - just a few clues would help a lot!!!

mr coffee

What you are missing is explaining what is wrong. You posted some code, and you are wondering what to change. What does it do? What do you expect it to do?

Read this before posting a programming question

This is wrong:

      powerGoodDetected = powerGoodDetected ++;
...
      overdriveDuration = overdriveDuration ++;

Those operations are undefined. From Wikipedia:

In general, any instance of undefined behavior leaves the abstract execution machine in an unknown state, and any subsequent behavior is also undefined. If it is not required that the compiler diagnose undefined behavior, programs invoking undefined behavior may compile and run producing correct results, incorrect results, or have any other behavior. Because of this, undefined behavior can create errors that are difficult to detect.

Nick,
Thanks for reply. I changed the increment statements, and the link to your tips and tricks was helpful.

Interestingly, I learned to do increment statements that (wrong) way from my old Adam Osbourne ansi C reference book from the 70's.

I've got other problems going on, that I will investigate further before re-posting, that I think are related to the pinmode and pin assignment constants setup.

I think somehow the input pullups on the output pins are enabled, and possibly pin assignments aren't as I expected. The atTiny pin numbering scheme is REALLY confusing, which is why I put all those comments in at the top.

Thanks again. I'll be back when I can get a clearer idea of what is going on. You don't know of a link that discusses pinmode tips and tricks, and the "board" numbering business, do you? I've searched Google, but it is a smidgen here, smidgen there as far as I could tell.

mr coffee

I can't see anything obviously wrong, and your comments are comprehensive. I like to fix things I spot (like the increment issue) first, even though conceivably it won't affect the results ("undefined" meaning it might happen to do what you want).

@Nick,
Thanks for looking it over. I thought the conditional && statements in the IF branch were OK, but I wasn't sure.

Nick (and all),

I've been searching for information on fuse setting and turning the on-chip pull-ups on, but can't find anything so far about turning the pull-ups off.

I'm planning on trying external pull-ups on the inputs, and not specifying any on chip pull-ups at all when I get back to it this evening to see if that eliminates the partial illumination on the output (Hypothesis, that using INPUT_PULLUP to set the input pins using pinmode may be turning ALL the pullups on, including on the mute OUTPUT on PB0, which is possibly still configured as an input from serial programming or something???)

I'm still not sure I have got the right pin numbering scheme going, although I seem to be getting outputs on the right DIP pins, and the inputs will completely turn off the overloadIndicator LED.

Unfortunately, the overloadIndicator LED is partially lit on startup, although the program line in setup,

digitalWrite(overloadIndicator,LOW);

should make it completely off as I understand things.

Is it OK to use

pinMode(overloadIndicator, OUTPUT);

again, after

digitalWrite(mute,HIGH);

to see if that will straighten out the pullup issue?

Also, do I need to use

void loop()

for the main program loop if I am going to be using using the while statement (which will cause the program to repeat)? i.e., can I just start the main loop with the while statement?

mrcoffee

For a pin set to INPUT mode, doing a digitalWrite of HIGH turns the pull-ups on, and doing a digitalWrite of LOW turns them off.

Thanks, NICK

Using INPUT in the pinMode statement rather than INPUT_PULLUP fixed the partial LED lighting.

I'm using 47K discrete resistors for pullups now. Now I need to figure out what's wrong with my coding. I'll start a new thread for that since I had to fix and redo several things to get to where it is now, and I haven't figured out how to edit a post to redo the coding above which had quite a few errors in it.

Thanks again!!

mr coffee

Hi,

Simply reply to the thread and repost your code in your new post ....

Please refer to the file/drawing I have attached.
If you wish to detect the level of the power sense level wich is tied to physical pin 7 of the chip, that corresponds to Arduino pin # 2. The Arduino pin numbers are in brown on the drawing ...
If you with to detect physical pin 6 of the chip (clipping input), then you would need to refer to Arduino pin # 1.
But nothing prevents from defining a constant (CONST) in order to use meaningful names instead of meaningless numbers.

I hope it helps ...

dan

  const int myLED1 = 13;
  const int myLED2 = 8;
  const int FlashDuration = 500;
  
void setup() {
  
    
  pinMode(myLED1, OUTPUT);
  pinMode(myLED2, OUTPUT);

}

void loop() {
 
  digitalWrite(myLED1, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(myLED2, HIGH);   // turn the LED on (HIGH is the voltage level)
  
  delay(FlashDuration);              // wait for a second
  
  digitalWrite(myLED1, LOW);    // toggling the LED...
  digitalWrite(myLED2, LOW);    // toggling the LED...

  delay(FlashDuration);              // waiting ...
  
}

Here is a slightly simpler version of the code:

  const int myLED1 = 13;
  const int FlashDuration = 500;
  
void setup() {
    
  pinMode(myLED1, OUTPUT);

  digitalWrite(myLED1, HIGH);   // initial level of the pin is high.

}

void loop() {
   
  digitalWrite(myLED1, LOW);    // turn the LED off by making the voltage LOW
  
  delay(FlashDuration);              // waiting....
  
}