DIYstompboxes.com

DIY Stompboxes => Digital & DSP => Topic started by: patrick398 on September 09, 2020, 06:24:12 AM

Title: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 06:24:12 AM
Hello all, hoping someone can give me a few pointers here. I'm programming an Attiny85 using arduino but it's not working as expected and i can't figure out why.

What should happen is this:
I want ATtiny85 pin 0 (TRIGGER_IN) to read the voltage coming from a flip flop elsewhere in the circuit. If it's HIGH it sends pin 1 (TRIGGER_OUT) HIGH after a delay period defined by analogRead (pin 2),  and is HIGH for a duration defined by PULSE (50ms).
Simply put, if pin 0 is HIGH, pin 1 flashes high for 50 ms after a delay between 0-1543 ms set by a pot.
If pin 0 is LOW pin 1 is also LOW.

Pin2 is reading a potentiometer, the voltage dictates the delay period from TRIGGER_IN detecting a HIGH voltage and TRIGGER_OUT outputing a HIGH voltage. I need a delay period of between 0-1500 ms so i figured since the analogRead is between 0 and 1023 i could just multiply that by 1.5 to get my desired range.

Seems relatively straight forward but i can seem to get it to work. Are there some glaring errors in my code?

int TRIGGER_IN = 0; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = 2; // arduino pin (7) connected to pot wiper
int readValue; // variable to read pot




void setup() {
  // put your setup code here, to run once:
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (POT_PIN, INPUT); // define POT_PIN as an input

}

void loop() {
  // put your main code here, to run repeatedly:

  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5

  if (TRIGGER_IN = HIGH) { // detect state of TRIGGER_IN
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }


  else (TRIGGER_IN = LOW); { // detect state of TRIGGER_IN
    digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
  }
}


Thank you!
Title: Re: ATtiny85 code issues
Post by: niektb on September 09, 2020, 06:50:12 AM
The line
else (TRIGGER_IN = LOW); { // detect state of TRIGGER_IN
feels wrong to me. I think the ';' might terminate the line and so the body between the brackets never (or always, i'm not sure) executes.

I think you want to change it to just
else

Also, what do you want to happen in case the TRIGGER_IN stays high for longer than the delay+PULSE? (because with your current code, the delayed TRIGGER_OUT is executed again)

EDIT:
Also, what definitely is wrong is the way you do your checks in the IF-statement! Use '==' instead of '='! (because now you assign the value to TRIGGER_IN, meaning it will always execute)

EDIT 2:
And shouldn't you use digitalRead() when checking the state of TRIGGER_IN?


int TRIGGER_IN = 0; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = 2; // arduino pin (7) connected to pot wiper
int readValue; // variable to read pot

void setup() {
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (POT_PIN, INPUT); // define POT_PIN as an input
}

void loop() {
  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5

  if (digitalRead(TRIGGER_IN) == HIGH)  // detect state of TRIGGER_IN
  {
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }
  else
  {
    digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
  }
}

Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 07:16:22 AM
Thanks so much for the help. I've just hooked it up and it's kind of working which is a lot further than i got. The pot doesn't seem to affect the delay. When i send pin0 HIGH pin1 goes HIGH for 50ms after a delay period which seems to fluctuate slightly but the pot does not affect this.

Quote from: niektb on September 09, 2020, 06:50:12 AM
Also, what do you want to happen in case the TRIGGER_IN stays high for longer than the delay+PULSE? (because with your current code, the delayed TRIGGER_OUT is executed again)

Good point...if i hold TRIGGER_IN HIGH, TRIGGER OUT stays HIGH after a short delay. Do i need another if statement to negate that?


Quote from: niektb on September 09, 2020, 06:50:12 AM
EDIT:
Also, what definitely is wrong is the way you do your checks in the IF-statement! Use '==' instead of '='! (because now you assign the value to TRIGGER_IN, meaning it will always execute)

Thanks, i'll have to read up on the difference between them

Quote from: niektb on September 09, 2020, 06:50:12 AM
EDIT 2:
And shouldn't you use digitalRead() when checking the state of TRIGGER_IN?

Yes i did actually spot that after i started the topic :)
Title: Re: ATtiny85 code issues
Post by: niektb on September 09, 2020, 07:50:10 AM
Have you tried Serial.println() to see what values you actually get from analogRead()?

Quote from: patrick398 on September 09, 2020, 07:16:22 AM
Good point...if i hold TRIGGER_IN HIGH, TRIGGER OUT stays HIGH after a short delay. Do i need another if statement to negate that?
I think removing the 'else' part (but leaving the digitalWrite(TRIGGER_OUT, LOW);) would already solve the stay high issue:


void loop() {
  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5

  if (digitalRead(TRIGGER_IN) == HIGH)  // detect state of TRIGGER_IN
  {
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }

  digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
}
Title: Re: ATtiny85 code issues
Post by: FiveseveN on September 09, 2020, 08:41:36 AM
Quote from: niektb on September 09, 2020, 07:50:10 AM
Have you tried Serial.println() to see what values you actually get from analogRead()?
I second that.
There's also a map() function (https://www.arduino.cc/reference/en/language/functions/math/map/) that remaps ranges. Useful for pots in case you need a more complex transformation.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 08:49:13 AM
You can't serial.print on attiny85 so i tried to set it up using the arduino itself. Now when i try and set up the arduino to program the attiny85 again i get an error message and when i try and burn the bootloader i get:

avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00

This happened to me before and it took ages to fix and i never really worked out what happened. Lots of uninstalling and reinstalling programs and libraries if i remember correctly.  :icon_exclaim:
Title: Re: ATtiny85 code issues
Post by: FiveseveN on September 09, 2020, 09:33:51 AM
Wait, why would you need to (re?)burn the bootloader? Are you using a new chip?

Quotei tried to set it up using the arduino itself.
You're saying you tried to upload the same sketch to an Uno, right? Did you remember set the board options? Does the IDE recognize the Uno? What other information does the console offer if you enable verbose output?
You can use software serial on the ATtiny: https://www.hackster.io/porrey/easy-serial-on-the-attiny-2676e6
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 10:01:22 AM
Quote from: FiveseveN on September 09, 2020, 09:33:51 AM
Wait, why would you need to (re?)burn the bootloader? Are you using a new chip?

Quotei tried to set it up using the arduino itself.
You're saying you tried to upload the same sketch to an Uno, right? Did you remember set the board options? Does the IDE recognize the Uno? What other information does the console offer if you enable verbose output?
You can use software serial on the ATtiny: https://www.hackster.io/porrey/easy-serial-on-the-attiny-2676e6

Yeah i changed all the settings and it uploaded to the arduino. When i switched the settings back to program the attiny85 it kept coming back with the error message.  Seems to be a fairly common problem and there doesn't seem to be a single solution, and nothing i have tried so far has worked. It's very frustrating. Last time it happened it took me days to resolve and i'm not even sure what fixed it.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 10:17:41 AM
Ok back in business (THANK GOD)
in case anyone suffers similar issues in the future (or when i inevitably need to fix this again, go here: https://www.instructables.com/id/How-to-Program-an-Attiny85-From-an-Arduino-Uno/)

I'm going to follow your suggestion and sort out the serial print

Thanks again!
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 01:50:04 PM
I gave up trying to get serial monitor working with the attiny, but i have got the code working on the arduino and the circuit hooked up to the arduino works.
I have the serial monitor printing the readValue from the pot and it's working properly. When i send TRIGGER_IN HIGH, TRIGGER_OUT goes HIGH and i can control the delay of this, but the problem is as previously mentioned, it seems to execute a few times if i hold TRIGGER_IN HIGH for more than a split second. It is affected by where the pot is set too. Obviously when the readValue is lower (and the delay is less) it has time to execute the code many times in the time it takes me to connect TRIGGER_IN to 5v and then release.

How would i go about making sure the code only executes once when TRIGGER_IN goes HIGH?

here's what i have:

int TRIGGER_IN = 5; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 3; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = A0; // arduino pin (7) connected to pot wiper
int readValue; // variable to read pot

void setup() {
  Serial.begin (9600);
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (POT_PIN, INPUT); // define POT_PIN as an input
}

void loop() {
  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5
Serial.println(readValue);
  if (digitalRead(TRIGGER_IN) == HIGH)  // detect state of TRIGGER_IN
  {
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }

  digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
}
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 03:03:51 PM
Weirdly when i try that same code (with pin number changes) on the ATtiny85 the pot stops working...i've tried using a few different pins for the pot, thinking i need a specific one to function as an analog in but nothing seems to work. Strange!
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 09, 2020, 04:39:52 PM
Alright i think i'm pretty much there...if anybody is still listening to my ramblings.
The problem i was having seemed to be in the labelling of the attiny85 pins and how they're referenced in the code. I got rid of defining POT_PIN as an INPUT in the setup. It is defined as pin 4 in the globals but i also had to set up a global variable stating that readValue = analogRead(2). That seemed to be the key. Despite the fact that they're the same pin it's referenced as two different numbers. Maybe that's wrong and i'm misunderstanding something, but it works!

Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that? I could set up another if statement checking the length of time it senses the pin being HIGH....

Thanks again!
Title: Re: ATtiny85 code issues
Post by: anotherjim on September 09, 2020, 04:49:07 PM
Long time since I've used my programmer's brain...
When looking for a state change, it's always worth making it find the opposite case first then and only then acting...
loop1
Is it low?
no then loop1
Yes!
loop2
Is it high?
no then loop2
Yes!
Do the thing
Back to loop1

This way it will never scoot back and repeat while the state is still high.
Title: Re: ATtiny85 code issues
Post by: FiveseveN on September 09, 2020, 05:11:13 PM
Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?
I can't vouch for the best way since my programming is amateurish at best, but I would usually use a flag to remember the state. Which I hear is bad because global variables bad (even 1 bit?!). Something like so:

bool triggered = false;
...

if (digitalRead(TRIGGER_IN) == HIGH && !triggered)  // TRIGGER_IN is HIGH and 'triggered' is not true
  {
    triggered = true; // set the flag
delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  } else if (digitalRead(TRIGGER_IN) == LOW) // if TRIGGER_IN is LOW
  {
triggered = false; // reset the flag
  }

digitalWrite (TRIGGER_OUT, LOW); // write TRIGGER_OUT low
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 09, 2020, 07:48:36 PM
Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?

I suspect that you don't want to detect when TRIGGER_IN is high (which it looks like is what you've written), but instead when *it goes high*. The first is something that occurs and then continues to occur, the second is something that occurs once only (or at least only once until the TRIGGER_IN goes low again).

I don't know enough about Arduino code to tell you how to make that differentiation, but I'm sure there's a way. It's common enough problem that many people must have solved it already. Try a few searches for detecting "Input goes high" or "Input rising edge" or similar on Arduino sites and see what you come up with.

Title: Re: ATtiny85 code issues
Post by: potul on September 10, 2020, 01:51:24 AM
Quote from: ElectricDruid on September 09, 2020, 07:48:36 PM
Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?

I suspect that you don't want to detect when TRIGGER_IN is high (which it looks like is what you've written), but instead when *it goes high*. The first is something that occurs and then continues to occur, the second is something that occurs once only (or at least only once until the TRIGGER_IN goes low again).

I don't know enough about Arduino code to tell you how to make that differentiation, but I'm sure there's a way. It's common enough problem that many people must have solved it already. Try a few searches for detecting "Input goes high" or "Input rising edge" or similar on Arduino sites and see what you come up with.

You can also use existing libraries for button debouncing. They usually have events triggered on button push, button release, button hold, etc...
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 11, 2020, 07:17:02 AM
Thanks for all the replies, i went and did some reading on state detection etc.. definitely what i'm after.
I've got that part working well now, but it seems something about that is stopping the analogRead reading the pot value. The led flashes for 50ms when the pin goes HIGH but doesn't remain on which is good, but the delay isn't being applied. I can't see why this would be the case

//don't forget 10k pulldown on TRIGGER_IN



int TRIGGER_IN = 0; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = 4; // arduino pin (3) connected to pot wiper
int readValue = analogRead(2); // variable to read pot, analog read defined as analog pin 2 even though pot pin is previously defined as pin 4
int triggerState = 0;
int lastTriggerState = 0;

void setup() {
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
 
}

void loop() {
   readValue = analogRead(POT_PIN); // read pots value between 0 and 1023
   triggerState = digitalRead(TRIGGER_IN); // read the trigger in pin


  if (triggerState != lastTriggerState) { // is trigger state not equal to last trigger state
  if (triggerState == HIGH) { // if trigger state has changed...
 
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }

lastTriggerState = triggerState;

  digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
}

}


I tried this but it also stopped the pot working and didn't stop the trigger_out remaining high when trigger_in is held high. Thanks for the help!

Quote from: FiveseveN on September 09, 2020, 05:11:13 PM
Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?
I can't vouch for the best way since my programming is amateurish at best, but I would usually use a flag to remember the state. Which I hear is bad because global variables bad (even 1 bit?!). Something like so:

bool triggered = false;
...

if (digitalRead(TRIGGER_IN) == HIGH && !triggered)  // TRIGGER_IN is HIGH and 'triggered' is not true
  {
    triggered = true; // set the flag
delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  } else if (digitalRead(TRIGGER_IN) == LOW) // if TRIGGER_IN is LOW
  {
triggered = false; // reset the flag
  }

digitalWrite (TRIGGER_OUT, LOW); // write TRIGGER_OUT low


Title: Re: ATtiny85 code issues
Post by: patrick398 on September 11, 2020, 08:03:36 AM
After some more tweaking i got the pot working again but the timings seemed to be way off. I was using programming with the internal 8mhz clock as suggested whenever i've read about programming attiny85 with arduino. I just used the 1mhz internal clock and now the timings seem spot on.
Is it ok to use the 1mhz clock?
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 11, 2020, 10:07:30 AM
Is it possible to also use the ATtiny to read the frequency of incoming pulses (from a separate tap tempo circuit) and output the same tempo but on the off beat? I stupidly thought this might be quite straight forward but the more i read the harder it seems  :icon_redface:
Title: Re: ATtiny85 code issues
Post by: niektb on September 11, 2020, 11:25:49 AM
Quote from: patrick398 on September 11, 2020, 10:07:30 AM
Is it possible to also use the ATtiny to read the frequency of incoming pulses (from a separate tap tempo circuit) and output the same tempo but on the off beat? I stupidly thought this might be quite straight forward but the more i read the harder it seems  :icon_redface:

The attiny (and all avr microcontrollers for that matter) are not very equipped to perform multiple tasks in parallel, especially not for starting programmers. If you want to do so, you need to read up on interrupts and how you can use them. Unfortunately, many things can go wrong with interrupts :/

It can definitely work. I think the flow chart would look something like this:
(https://i.postimg.cc/bsbKJhGG/Untitled-Diagram.png) (https://postimg.cc/bsbKJhGG)

the loop() function idles indefinitely until a rising edge is detected on either TAP_TEMPO or TRIGGER_IN. the interrupt function will do something with an asynchronous timer to create a delay without interfering with the other interrupt, and returns to idle. When the timer reaches the delay time, it will trigger an interrupt and fires the Timer function (which performs the action that is required, like setting TRIGGER_OUT)
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 11, 2020, 05:01:08 PM
I'd rather say that the Arduino model isn't really set up for doing stuff in parallel. After all, no processor (ok, no processor like these little ones) ever does more than one thing at once. "Parallel processing" on a little single core chip is jumping back and forth between different things quickly enough no-one notices. Arduino tends to screw that up because delay loops and many other processes hold up the whole chip until the delay is finished. Which is fine if that's the only thing you're doing, but often, you could be using that time when that process doesn't need dealing with to be doing other stuff instead. In my view, interrupts are only for stuff that is *time critical* - that has to be done at a *particular* time, like getting a sample out to a DAC. Any variation there in when it goes out leads to noise in the output. Not good. The *calculation* of that sample however could be done any time, as long as it's completed before it's needed. That gives you much more flexibility.

Cripes, I'm in a philosophical frame of mind tonight. Sorry, I'll shut up.

T.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 12, 2020, 03:02:27 AM
OK thanks for that, i think i may have underestimated what the chips are capable of and also how easily achievable what i want to do is. I think it's best for now if i use separate chips, one for the delayed trigger i've already done and one for the tempo measure and off beat trigger. That should simplify things for me ha.
Am i right in thinking i want to use the pulseIn function to measure the high and low state of the pin attached to the tap tempo? Then i can add them to get the period length and multiply that by something to get the BPM? Then i guess i'd need to delay that for the length of one high or low state, then trigger the output to go high and low with a delay of one period...that should match the input tempo but output on the offbeat right?
Maybe that made no sense
Title: Re: ATtiny85 code issues
Post by: potul on September 12, 2020, 04:58:09 AM
I think you can do this in one chip, but you need to change something in the approach.

I would start by never using the delay() function. Instead, you can use millis() to record your initial time and simply compare this with the new millis() in every loop until you reach the needed delay. This way you don't stop the rest of activities.

I've done similar things with an attiny for a tap tempo chip I developed for the FV-1.

You need to base your coding on millis() and trigger state changes based on it and inputs coming from buttons, etc...


Title: Re: ATtiny85 code issues
Post by: patrick398 on September 12, 2020, 05:44:26 AM
Quote from: potul on September 12, 2020, 04:58:09 AM
I think you can do this in one chip, but you need to change something in the approach.

I would start by never using the delay() function. Instead, you can use millis() to record your initial time and simply compare this with the new millis() in every loop until you reach the needed delay. This way you don't stop the rest of activities.

I've done similar things with an attiny for a tap tempo chip I developed for the FV-1.

You need to base your coding on millis() and trigger state changes based on it and inputs coming from buttons, etc...

Using a separate chip isn't really an issue and if it makes things a lot easier i think i'd rather do that. I've been looking at some code for tap tempo using arduino and i feel like it's a bit above my pay grade.
This one specifically i can get working but i can't figure out how to take the tempo output and use if to set an output on a different pin.


// include the ArduinoTapTempo library
#include <ArduinoTapTempo.h>

// define the pin you want to attach your tap button to
const int BUTTON_PIN = 5;

// make an ArduinoTapTempo object
ArduinoTapTempo tapTempo;

void setup() {
  // begin serial so we can see the state of the tempo object through the serial monitor
  Serial.begin(9600);

  // setup your button as required by your project
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH);
}

void loop() {
  // get the state of the button
  boolean buttonDown = digitalRead(BUTTON_PIN) == LOW;
 
  // update ArduinoTapTempo
  tapTempo.update(buttonDown);

  // print out the beats per minute
  Serial.print("bpm: ");
  Serial.println(tapTempo.getBPM());
}
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 12, 2020, 06:50:59 AM
Thanks Rob!

https://www.diystompboxes.com/smfforum/index.php?topic=121506.0

Got this working nicely, not sure if it's going to play nice with continuous pulses coming from the existing tap tempo. I'll try it out and report back
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 12, 2020, 07:54:13 AM
As suspected, this tap tempo doesn't like receiving continuous pulses. Is there something in the code that could be modified so that the output is constantly following the input (i can worry about delaying it later). It also occured to me that surely this could be as simple as reading the high/low state of the input pin and just writing that state to the output pin?


void setup() {
  pinMode( 12, INPUT_PULLUP );   /*   /* tap button - press it to set the tempo */
  pinMode( 11, OUTPUT );  /* tempo display light - shows the current tempo */

}


int lastTapState = LOW;  /* the last tap button state */
unsigned long currentTimer[2] = { 500, 500 };  /* array of most recent tap counts */
unsigned long timeoutTime = 0;  /* this is when the timer will trigger next */

unsigned long indicatorTimeout; /* for our fancy "blink" tempo indicator */

void loop()
{
  /* read the button on pin 12, and only pay attention to the
     HIGH-LOW transition so that we only register when the
     button is first pressed down */
  int tapState = digitalRead( 12 );
  if ( tapState == LOW && tapState != lastTapState )
  {
    tap(); /* we got a HIGH-LOW transition, call our tap() function */
  }
  lastTapState = tapState; /* keep track of the state */

  /* check for timer timeout */
  if ( millis() >= timeoutTime )
  {
    /* timeout happened.  clock tick! */
    indicatorTimeout = millis() + 30;  /* this sets the time when LED 13 goes off */
    /* and reschedule the timer to keep the pace */
    rescheduleTimer();
  }

  /* display the button state on LED 2 */
  digitalWrite( 13, tapState );

  /* display the tap blink on LED 13 */
  for ( int i = 2 ; i < 12 ; i++ ) {
    if ( millis() < indicatorTimeout ) {
      digitalWrite( i, HIGH );
    } else {
      digitalWrite( i, LOW );
    }
  }
}

unsigned long lastTap = 0; /* when the last tap happened */
void tap()
{
  /* we keep two of these around to average together later */
  currentTimer[1] = currentTimer[0];
  currentTimer[0] = millis() - lastTap;
  lastTap = millis();
  timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */
}

void rescheduleTimer()
{
  /* set the timer to go off again when the time reaches the
     timeout.  The timeout is all of the "currentTimer" values averaged
     together, then added onto the current time.  When that time has been
     reached, the next tick will happen...
  */
  timeoutTime = millis() + ((currentTimer[0] + currentTimer[1]) / 2);
}
Title: Re: ATtiny85 code issues
Post by: anotherjim on September 12, 2020, 08:36:44 AM
Interrupts are the obvious way to make the CPU multitask, but pin change interrupts are unexpectedly difficult to deal with. Setting them up is trivial, but the pin interrupts are shared between ports, so the interrupt handling code has to make time to read the pins to find out which pin did it and quickly before it changes! I have coded a Mega328 to read six pots and six trigger pins using pin interrupts while the ADC reading is in the main loop, but it did make my brain hurt! I programmed in AVR assembler and have no idea where to start in Arduino, but I would hope the Arduino interrupt library will do the fancy work for you.

Peripheral interrupts (ADC, UART etc) are far easier. An ADC interrupt (only one of them) is obvious to handle and the ADC can be made to automatically start a new conversion when the last value is read out of it.

Arduino Analog read is easy to use but inefficient. It takes time (many CPU clocks) from the start of conversion to completion during which a lot could be done. Directly coding in either assembler or C (you can easily include C code in an Arduino sketch*) lets you choose all the ADC options such as conversion speed and a slightly faster 8bit result. When reading multiple pins with the ADC, your own code can change the pin it reads Before completion and start another conversion right after reading the value of the previous pin. You can change the read pin selected early because a few clocks after starting the ADC, the last pin voltage is stored on the ADC sampling capacitor and disconnected from the pins while the conversion is taking place.

Tiny85 has a special trick - a PLL frequency multiplier that can either increase the rate of internal peripheral clocking, or the CPU or both. The CPU clock boost only allows doubling. The internal RC clock, when set for 8Mhz, can be doubled to 16Mhz!

*I would always have my doubts about what other Arduino functions you could wreck by making direct changes outside of the language.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 12, 2020, 09:08:42 AM
Thanks for the reply Jim, it's going to take a while to digest that! I have so much to learn  :icon_eek:
I'm fairly set on using a separate chip for this task now, using interrupts seems like a lot could go wrong considering how little i know. Just to clarify, are you talking about using interrupts for doing everything on one chip? Or are you talking about using interrupts to modify the code i just posted to get it to continually track the input?

Sorry i'm not making myself very clear and i seem to be getting more confused by the minute haha
Title: Re: ATtiny85 code issues
Post by: anotherjim on September 12, 2020, 12:00:02 PM
Interrupts mean not having to have the code looping and waiting for one thing to happen before it can do something else. Interrupts have their own overheads and you must have some RAM reserved for the stack. It's possible to do many projects without interrupts though. Some I've done haven't even used a stack at all because I wanted all of the RAM for audio samples.
Title: Re: ATtiny85 code issues
Post by: potul on September 12, 2020, 05:52:38 PM
Quote from: patrick398 on September 12, 2020, 07:54:13 AM
As suspected, this tap tempo doesn't like receiving continuous pulses. Is there something in the code that could be modified so that the output is constantly following the input (i can worry about delaying it later). It also occured to me that surely this could be as simple as reading the high/low state of the input pin and just writing that state to the output pin?


I don't see any reason why it does not work. It should output following the input clock. The only thing is that it is doing an average of the last 2 pulses, and the length of each pulse is fixed at 30ms. For very fast speeds it will not work. What clock rates are you trying to use?
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 13, 2020, 06:35:30 AM
I'm actually reading the squarewave output of a stomplfo chip, I've just had a thought though, it's a pen output, is the arduino reading incredibly fast pulses rather than the overall squarewave output?
I did load a frequency counted onto the arduino and it was reading the stomplfo output as 18khz or something like that I think
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 13, 2020, 06:38:26 AM
Quote from: patrick398 on September 13, 2020, 06:35:30 AM
I'm actually reading the squarewave output of a stomplfo chip, I've just had a thought though, it's a pen output, is the arduino reading incredibly fast pulses rather than the overall squarewave output?
I did load a frequency counted onto the arduino and it was reading the stomplfo output as 18khz or something like that I think

The raw StompLFO output is a PDM signal at about 2MHz, iirc. So yeah, you should put a simple RC lowpass in before you feed it to your Arduino, or you could get very weird results.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 13, 2020, 06:53:34 AM
Ok great! I'll give that a go tomorrow and fingers crossed it'll work. Then I've just go to work out how to put the output on the off-beat. Expect many more irritating questions  :icon_redface:
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 14, 2020, 06:06:56 AM
Quote from: potul on September 12, 2020, 05:52:38 PM
I don't see any reason why it does not work. It should output following the input clock. The only thing is that it is doing an average of the last 2 pulses, and the length of each pulse is fixed at 30ms. For very fast speeds it will not work. What clock rates are you trying to use?

You were spot on, it does work but at higher speeds it goes out of time. I'd say it goes out of time when it hits around 4 pulses per second. Why is this the case?

Thank you!
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 14, 2020, 09:25:47 AM
Quote from: patrick398 on September 14, 2020, 06:06:56 AM
You were spot on, it does work but at higher speeds it goes out of time. I'd say it goes out of time when it hits around 4 pulses per second. Why is this the case?

The timing accuracy is milliseconds, right? So 4 pulses per second is a timer value of 250 milliseconds, which seems big enough to avoid rounding errors or similar. I doubt that's the problem.

How fast does the code go around the loop? Millisecond-accurate timing is no good is you're only checking back to see if anything's happened every 100msecs.

Title: Re: ATtiny85 code issues
Post by: potul on September 14, 2020, 09:32:42 AM
I was expecting it to fail more in the range of 33 per second...

First thing you can try is to have a variable pulse width. Now the pulse width is always 30ms, but you can try to make it always equal to T/2 (being T the current period)

So Instead of this:

  if ( millis() >= timeoutTime )
  {
    /* timeout happened.  clock tick! */
    indicatorTimeout = millis() + 30;  /* this sets the time when LED 13 goes off */
    /* and reschedule the timer to keep the pace */
    rescheduleTimer();
  }


you can use this:


  if ( millis() >= timeoutTime )
  {
    /* timeout happened.  clock tick! */
    indicatorTimeout = millis() + (currentTimer[0] + currentTimer[1]) / 4;  /* this sets the time when LED 13 goes off */
    /* and reschedule the timer to keep the pace */
    rescheduleTimer();
  }


The other thing you can try is to comment this line out:

  timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */

As this is forcing to restart a pulse whenver a new pulse is received by the input, and can screw up the whole timing. The ides of the tap tempo is not to be tapping continously..... so this makes sense in a tap tempo context, but I don't think it's needed here.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 14, 2020, 10:07:37 AM
Quote from: ElectricDruid on September 14, 2020, 09:25:47 AM
How fast does the code go around the loop? Millisecond-accurate timing is no good is you're only checking back to see if anything's happened every 100msecs.

I'm not sure, doesn't it just run through the code as fast as it can?

Quote from: potul on September 14, 2020, 09:32:42 AM
I was expecting it to fail more in the range of 33 per second...

First thing you can try is to have a variable pulse width. Now the pulse width is always 30ms, but you can try to make it always equal to T/2 (being T the current period)

So Instead of this:

  if ( millis() >= timeoutTime )
  {
    /* timeout happened.  clock tick! */
    indicatorTimeout = millis() + 30;  /* this sets the time when LED 13 goes off */
    /* and reschedule the timer to keep the pace */
    rescheduleTimer();
  }


you can use this:


  if ( millis() >= timeoutTime )
  {
    /* timeout happened.  clock tick! */
    indicatorTimeout = millis() + (currentTimer[0] + currentTimer[1]) / 4;  /* this sets the time when LED 13 goes off */
    /* and reschedule the timer to keep the pace */
    rescheduleTimer();
  }


The other thing you can try is to comment this line out:

  timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */

As this is forcing to restart a pulse whenver a new pulse is received by the input, and can screw up the whole timing. The ides of the tap tempo is not to be tapping continously..... so this makes sense in a tap tempo context, but I don't think it's needed here.


I tried both of these but no difference i'm afraid  :(
On slow speeds i can see that the indicator LED i'm using never fully dims. The output of the square LFO is 0.04v to 5v. Do i need to have an if statement saying that if level of input is below a certain threshhold the pin gets written low? I wonder if that could be affecting the timing?

EDIT: if i use pin 13 as the output it does turn completely off, still problem of going out of time though
...in fact if i use any other pin as output it's jittery as hell, even with RC filter
Title: Re: ATtiny85 code issues
Post by: potul on September 14, 2020, 10:38:49 AM
Where did you put the low pass filter?
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 14, 2020, 10:39:50 AM
Quote from: potul on September 14, 2020, 10:38:49 AM
Where did you put the low pass filter?

Just before the LED. Pin 8 into a 1k resistor, cap to ground, LED
Title: Re: ATtiny85 code issues
Post by: potul on September 14, 2020, 12:14:36 PM
Quote from: patrick398 on September 14, 2020, 10:39:50 AM
Quote from: potul on September 14, 2020, 10:38:49 AM
Where did you put the low pass filter?

Just before the LED. Pin 8 into a 1k resistor, cap to ground, LED

Ok, this might be the problem. The low pass filter must be put between the stompLFO and your arduino input, not at the output of your arduino. Try to remove it and see how it performs.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 14, 2020, 12:26:46 PM
Yes i did think that just after i sent my last message so i tried with the RC filter on the stompLFO output and all it did was make the LED blink a lot less. It seemed to turn off a lot less. Also no difference without the RC filter.
Title: Re: ATtiny85 code issues
Post by: potul on September 14, 2020, 04:37:05 PM
You need a low pass filter after the stomplfo because it uses PWM to generate the different voltages.
You don't need a lpf after the arduino, as it only generates a square signal (0 or Vcc).
You need to choose the right values so that you are filtering your pwm frequency, but still allowing your desired frequencies to pass.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 15, 2020, 05:26:23 AM
Quote from: potul on September 14, 2020, 04:37:05 PM
You need a low pass filter after the stomplfo because it uses PWM to generate the different voltages.
You don't need a lpf after the arduino, as it only generates a square signal (0 or Vcc).
You need to choose the right values so that you are filtering your pwm frequency, but still allowing your desired frequencies to pass.

With the filtering after the stompLFO it's the same issue of going out of time. I'm using 10k>47n>100k>4n7, caps to ground, as suggested by the stompLFO docs.

I'm starting to think this might be the wrong approach.

In my head what i want to do actually seems quite straight forward. There is an existing tap tempo circuit controlling another circuit. I want to read the output of this tap tempo (which is putting out roughly 4v pulses). The arduino input pin will read the existing tap tempo output, when it is HIGH, it will output an arduino pin HIGH, when the input is LOW it will output that pin LOW.

I need to calculate the tempo of the incoming pulses so i guess i would use pulseIn to measure the 'high time' of the input, and pulseIn to measure the 'low time of the input'. Adding them together would give me the period.

I then need to apply a delay somehow to the output, so that it falls exactly on the off beat. I guess the length of this delay would be equal to 'high time' or 'low time' since that's half of the period.

Anyway, here is a sketch i threw together quickly. For now i have ignored the delay aspect. It's probably completely wrong but maybe it's a better starting point...


int input = 12;
int output = 11;
unsigned long highTime;
unsigned long lowTime;
unsigned long period;
unsigned long time;


void setup() {
  pinMode (input, INPUT_PULLUP);
  pinMode (output, OUTPUT);

}

void loop() {

  time = millis();
  highTime = pulseIn (input, HIGH); // read time input is high
  lowTime = pulseIn (input, LOW); // read time input is low
  period = (highTime + lowTime); // period is equal to high time plus low time

  digitalRead (input); // read input pin
  if (input == HIGH) { // if input pin is high write output pin high
    digitalWrite (output, HIGH);

  }

  digitalWrite (output, LOW); // write output pin low

}
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 15, 2020, 01:48:48 PM
Quote from: patrick398 on September 15, 2020, 05:26:23 AM
With the filtering after the stompLFO it's the same issue of going out of time. I'm using 10k>47n>100k>4n7, caps to ground, as suggested by the stompLFO docs.

That should be fine.

Quote
In my head what i want to do actually seems quite straight forward. There is an existing tap tempo circuit controlling another circuit. I want to read the output of this tap tempo (which is putting out roughly 4v pulses). The arduino input pin will read the existing tap tempo output, when it is HIGH, it will output an arduino pin HIGH, when the input is LOW it will output that pin LOW.

Yep, that seems simple, and wouldn't even really need any timing. Just read it, output it, done. Go round the loop, do it again. Keep doing it until someone pulls the power.

Quote
I need to calculate the tempo of the incoming pulses so i guess i would use pulseIn to measure the 'high time' of the input, and pulseIn to measure the 'low time of the input'. Adding them together would give me the period.

I then need to apply a delay somehow to the output, so that it falls exactly on the off beat. I guess the length of this delay would be equal to 'high time' or 'low time' since that's half of the period.

If you just want a square wave that's half-a-wavelength out of phase, that's the same as 180 degrees out of phase - e.g. inverted. Instead of trying to delay it, just read the input state, and then output the inverse. It'll give you the same effect without the messing around.

Title: Re: ATtiny85 code issues
Post by: patrick398 on September 15, 2020, 03:29:30 PM
Quote from: ElectricDruid on September 15, 2020, 01:48:48 PM

Quote
I then need to apply a delay somehow to the output, so that it falls exactly on the off beat. I guess the length of this delay would be equal to 'high time' or 'low time' since that's half of the period.

If you just want a square wave that's half-a-wavelength out of phase, that's the same as 180 degrees out of phase - e.g. inverted. Instead of trying to delay it, just read the input state, and then output the inverse. It'll give you the same effect without the messing around.

That's a remarkably simple solution Tom, thank you. I think my lack of knowledge is causing me to really over complicate this.

So, with this very simple code i threw together it basically does what i want. I'm measuring the voltage from pin 8. It's at 5v because of the internal pull-up. when i touch pin 7 to 5v pin 8 goes to 0.06v. So that's all fine.

When i hook an LED up it's fairly dim, even with a 100ohm CLR. The voltage on pin 8 drops to 1.8v where it was 5v before. Seems strange.

I've just hooked up an LED from the stompLFO, placed it next to the one form pin 8 on the arduino and i think they're flashing perfectly in sync one after the other :)
I'm not even using any filtering now, it just started working and i have no idea what i did differently!

I wonder why i'm dropping so much voltage at the led though...


Here's where i'm at:
int input = 7;
int output = 8;
int inputState;



void setup() {
  pinMode (input, INPUT_PULLUP);
  pinMode (input, OUTPUT);
  Serial.begin (9600);


}

void loop() {

  inputState = digitalRead (input);
  if (inputState == LOW) {
    digitalWrite (output, HIGH);
  }

  if (inputState == HIGH) {
    digitalWrite (output, LOW);
   
  }

}
Title: Re: ATtiny85 code issues
Post by: anotherjim on September 15, 2020, 04:05:02 PM
pinMode (input, OUTPUT);         ?

Don't you want...
pinMode (output, OUTPUT);        ?
...to set pin8 as output.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 15, 2020, 04:08:07 PM
Quote from: anotherjim on September 15, 2020, 04:05:02 PM
pinMode (input, OUTPUT);         ?

Don't you want...
pinMode (output, OUTPUT);        ?
...to set pin8 as output.

Crikey, what on earths going on here. Hang on i'll check that out
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 15, 2020, 04:17:25 PM
Ok thanks for that Jim, that seems to have been causing the LED brightness issue.

int input = 7;
int output = 8;
int inputState;

void setup() {
  pinMode (input, INPUT_PULLUP);
  pinMode (output, OUTPUT);
  Serial.begin (9600);
}

void loop() {
  inputState = digitalRead (input);
  if (inputState == LOW) {
    digitalWrite (output, HIGH);
  }

  if (inputState == HIGH) {
    digitalWrite (output, LOW);
   
  }

}


Which can be simplified to:
int input = 7;
int output = 8;
int inputState;



void setup() {
  pinMode (input, INPUT_PULLUP);
  pinMode (output, OUTPUT);
  Serial.begin (9600);


}

void loop() {

  digitalWrite(output, !digitalRead(input));
}



Given that this is now basically one line of code, can i do this on the same chip that is doing the bass drum trigger this thread was about originally, or will i still need an interrupt?

Thanks so much guys
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 15, 2020, 05:15:28 PM
Did some research on interrupts. I'm not sure what best practice is or whether this would screw something up, but i think i'm interrupting the main code every 100 milliseconds to execute the tempo read and write on off-beat section. Ignore the pin numbers for now, they're half arduino half attiny85, i'll sort that later.

What do you think?

//don't forget 10k pulldown on TRIGGER_IN

#include <TimerOne.h>

int TRIGGER_IN = 0; // ATtiny pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // ATtiny pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int triggerState = 0; // set variale for trigger state
int lastTriggerState = 0; //set variable for last trigger state
int tempoInput = 7;
int tempoOutput = 8;
int inputState;



void setup() {
  Timer1.initialize (100000);   // starting interrupt which will go off every ' 100,000 ' microseconds (100 milliseconds)
  Timer1.attachInterrupt (offBeat);
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (tempoInput, INPUT);
  pinMode (tempoOutput, OUTPUT);
}



void loop() {


  int readValue = analogRead(2) * 3; // read pots value between 0 and 1023 and multiplies it by 3
  triggerState = digitalRead(TRIGGER_IN); // read the trigger in pin


  if (triggerState != lastTriggerState) { // is trigger state not equal to last trigger state
    if (triggerState == HIGH) { // if trigger state has changed...

      delay (readValue); // delay for period set by POT_PIN
      digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
      delay (PULSE);
    }

    lastTriggerState = triggerState;

    digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
  }
}

void offBeat(){
  digitalWrite(tempoOutput, !digitalRead(tempoInput));
  return;
}

Title: Re: ATtiny85 code issues
Post by: potul on September 16, 2020, 03:21:47 AM
This is a much simpler approach, it's a good idea to just invert the signal.

You can do this in the same microcontroller, and I don't think you need to do any interrupt. You just need to get rid of the delay() instruction, and instead just measure the time that passed since last check. This way the code will never stop.

Although interrupt might work as well.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 16, 2020, 05:19:20 AM
Yes very thankful to Tom for pointing out how much simpler it could be!
I have it working with the interrupt though i had to play with the interrupt timing. At 100000 microseconds it was working but i could detect a slight lag periodically one the LED indicating the 'off-beat'. I guess this was caused by the interrupt as changing the timing to 1000 seems to have sorted that.
Do you foresee any issues with this method?

Thanks again
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 16, 2020, 06:13:20 AM
Quote from: patrick398 on September 16, 2020, 05:19:20 AM
I have it working with the interrupt though i had to play with the interrupt timing. At 100000 microseconds it was working but i could detect a slight lag periodically one the LED indicating the 'off-beat'. I guess this was caused by the interrupt as changing the timing to 1000 seems to have sorted that.
Do you foresee any issues with this method?

No, interrupts are a *very* useful technique and you should use them! Especially if they're as simple to set up as they seem to be from your code - that's great! The early PICs I used didn't even include any context saving, so when you entered an interrupt you had to manually store anything important onto the stack for later, and then recover it all at the end of the interrupt routine. A right PITA.

I'm not surprised you shortened the interrupt period. 100msec is sssssllllllooooowwwww in uP terms. 1msec is still long enough for the chip to run (say) 8000 instructions, so it's not tight at that.

Title: Re: ATtiny85 code issues
Post by: patrick398 on September 16, 2020, 07:46:41 AM
Quote from: ElectricDruid on September 16, 2020, 06:13:20 AM

. 1msec is still long enough for the chip to run (say) 8000 instructions, so it's not tight at that.

Crikey, i don't think i've got my head around just how quick these things are yet!

Thanks for your help.

I'm yet to try this chip with the rest of the actual circuit its for yet so i doubt this will be the last you hear from me on the matter haha
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 21, 2020, 09:14:00 AM
As i feared this doesn't quite work with the tap tempo circuit i'm trying to use it with. The tap tempo is someone elses, i have the chip, it's a PIC12F629, but i can't read any voltage spikes coming from it's output pin with my DMM and i can barely see the pulses on my oscope. The tap tempo does work though, i've hooked it up to a flip flop and it's flashing an LED.
I feel like i'm missing something critical here. Either the voltage spikes are two low for the attiny to detect a high state, or they're too quick? But i doubt that they're too quick somehow. I'm not really sure what to do now, it really doesn't help that i can't measure anything coming out of the tap tempo...
Is there something i'm missing? A reason why the attiny wouldn't be able to read the tap tempo chip?

Thanks...and sorry for all this arduino based misery lately
Title: Re: ATtiny85 code issues
Post by: ElectricDruid on September 22, 2020, 06:23:02 PM
Some of us love a bit of uP-based misery! Makes such a change from all that analogue misery on the rest of this forum!

Could you modify the tap tempo code to *toggle* a pin instead of producing such a short pulse? Or is there a way you can find out what sets the timing of the pulse it outputs and make it longer?

It sounds like the Tap Tempo output pulse is only the very briefest spike and the input is simply not fast enough to catch it. You say you doubt they're too quick, but how quick are they exactly? You also say you can barely see them on an *osciiloscope* and that makes them sound pretty damn quick to me!
Title: Re: ATtiny85 code issues
Post by: anotherjim on September 23, 2020, 11:21:04 AM
Try a small cap to ground on the tap pulse to act as a pulse stretcher -  probably no larger than 1nF. A simple bodge that can work, although it reduces the peak of the pulse, it will be wider and it doesn't have to reach 5v to be seen as high (normally >3v). Also you can enable pull-up on the input to make it a little easier to go high.

Title: Re: ATtiny85 code issues
Post by: patrick398 on September 23, 2020, 05:12:14 PM
Quote from: ElectricDruid on September 22, 2020, 06:23:02 PM
Some of us love a bit of uP-based misery! Makes such a change from all that analogue misery on the rest of this forum!
Ha yeah it's a nice change for me too, but bringing back a lot of painful memories from when i started trying to teach myself electronics...so much to learn, so little time!

Quote from: ElectricDruid on September 22, 2020, 06:23:02 PM
Could you modify the tap tempo code to *toggle* a pin instead of producing such a short pulse? Or is there a way you can find out what sets the timing of the pulse it outputs and make it longer?
The tap tempo is written by someone else, i've just been supplied the chip. It's a bit of a black box scenario.

Quote from: ElectricDruid on September 22, 2020, 06:23:02 PM
It sounds like the Tap Tempo output pulse is only the very briefest spike and the input is simply not fast enough to catch it. You say you doubt they're too quick, but how quick are they exactly? You also say you can barely see them on an *osciiloscope* and that makes them sound pretty damn quick to me!
Yeah you're right, it's super quick so probably too quick for the input. It also seems to be low voltage as well, but i'm having real difficulty measuring the thing.

Quote from: anotherjim on September 23, 2020, 11:21:04 AM
Try a small cap to ground on the tap pulse to act as a pulse stretcher -  probably no larger than 1nF. A simple bodge that can work, although it reduces the peak of the pulse, it will be wider and it doesn't have to reach 5v to be seen as high (normally >3v). Also you can enable pull-up on the input to make it a little easier to go high.
I seem to recall trying an RC filter on the output of the tap tempo but perhaps the resistor negated the effect of pulse stretching you're suggesting. I'll give it a try.

There is another possible solution i've overlooked which could potentially be a lot simpler. The tap tempo is triggering a kind of side chain which lights an LED on every beat the tap tempo is putting out. I could probably use this output, rather than the tap tempo itself, into the attiny85. I'm sorry i can't be more specific about the details, i'm trying to do this as a favour for someone and have only had a few glimpses of the schematic of the whole circuit. It seemed quite straight forward at first, but now you lot have been roped in ha.

The pulse from the side chain section has been described to me as looking like the top wave in this (childrens) picture i've drawn. The bottom wave is the expected output of the attiny, doing the inverse (off beat) The problem i see is that the rising edge of the 'off beat' won't fall in the middle of the first waves duty cycle, so won't actually be on the off beat.

(https://i.postimg.cc/jCMzcg4z/9359238-E-4-EC6-4-A39-969-A-9-B4-D934-C97-F1.jpg) (https://postimg.cc/jCMzcg4z)

The first and third pulses are triggering a 'bass drum', second and fourth a 'snare'. I'm trying trigger a 'high hat' on every off beat, but as i see it the off beat should fall exactly in the middle of two pulses, which it surely won't in this scenario.

I hope i'm making sense, this has got me in a pickle
Title: Re: ATtiny85 code issues
Post by: potul on September 24, 2020, 02:48:37 AM
Unfortunately, Tom's proposal to just invert the input will only work if you have a square signal with 50% duty cycle, or similar. You got the point.
I see two options:
1-If you know well the waveform of the pulse, you can still use the inverting tip, but you would need to compensate with some delay in the response. This delay will not be fixed, most probably will have to be a function of the frequency. Not very convenient
2-Measure the peak to peak time (or edge to edge) (pretty easy using millis() ), and apply a delay of T/2. In this case, you go back to needing peak/edge detection.

Title: Re: ATtiny85 code issues
Post by: patrick398 on September 24, 2020, 04:50:30 AM
Yes i was thinking it would involve something like this. So i would achieve peak detection using state change?
I'm not sure how i would go about measuring the peak to peak time using millis()...my first thought was to use pulseIn to measure the high time, pulseIn to measure the low time, add them to get the peak to peak time and then divide that by two. Interested to know if its easier using millis() though

Thanks
Title: Re: ATtiny85 code issues
Post by: potul on September 24, 2020, 10:58:34 AM
The issue with using PulseIn is that if I'm not wrong, it pauses execution until the pulse is done. This means that in order to do your full measure (High and LOW) you may have to wait more than one full cycle because the function needs 2 transitions to do the measure.
I will try later to draft some code for you on how to use states and millis() to do this in one shot.

Title: Re: ATtiny85 code issues
Post by: potul on September 24, 2020, 12:43:19 PM
Here you have a piece of code that works on my end using millis(). It does only the tap tempo thing, not the rest. It does not use any interrupt but code never stops (it runs as fast as possible)
I think you could add your trigger code easily following the same scheme. Take a look and ask whatever questions you may have.

You just need to change the pin numbers to your circuit.


int tempoInput = 0;
int tempoOutput = 1;
int inputState;
bool lastInputState=LOW;
unsigned long lastEdgeTime=millis();
unsigned long pulsePeriod=0;

void setup() {
  pinMode (tempoInput, INPUT);
  pinMode (tempoOutput, OUTPUT);
}

void loop() {
 
  // check input
 
  bool inputState = digitalRead(tempoInput);
 
  if (inputState){  //input is HIGH
    if (!lastInputState) {  //last state was LOW, so we have a rising edge
      pulsePeriod = millis() - lastEdgeTime;
      lastEdgeTime = millis();
    }
  } 
  lastInputState = inputState;

  //set output

if (millis()-lastEdgeTime > pulsePeriod/2){
    digitalWrite(tempoOutput, HIGH);
  } else {
    digitalWrite(tempoOutput, LOW);
  }

}
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 25, 2020, 04:21:50 AM
Wow thank you so much for that man, i really appreciate you taking time to do that for me. I'll go through it with a fine tooth comb and try to understand as much of it as i can, though i may have questions.

The other part of the code is using a delay so this won't interfere with that, but is this short enough to run during an interrupt of the other code?

Thanks again!
Title: Re: ATtiny85 code issues
Post by: potul on September 25, 2020, 06:30:10 AM
This code needs to be "free running". If the rest of the code uses delay instructions, then you will need to put the tap tempo code inside an interrupt to ensure it is not stopped.  It should be fast to execute each loop, so just drop it into the interrupt and adjust interrupt time if needed.

Title: Re: ATtiny85 code issues
Post by: pruttelherrie on September 25, 2020, 07:07:41 AM
Quote from: patrick398 on September 25, 2020, 04:21:50 AM
Wow thank you so much for that man, i really appreciate you taking time to do that for me. I'll go through it with a fine tooth comb and try to understand as much of it as i can, though i may have questions.

The other part of the code is using a delay so this won't interfere with that, but is this short enough to run during an interrupt of the other code?

Thanks again!

You can implement the delayed-trigger without using the delay() function, using the same technique as used here:

Quote
if (millis()-lastEdgeTime > pulsePeriod/2){
    digitalWrite(tempoOutput, HIGH);
  } else {
    digitalWrite(tempoOutput, LOW);
  }

Then everything can stay free-running.
Title: Re: ATtiny85 code issues
Post by: potul on September 25, 2020, 08:21:01 AM
That's right. what my code does is simply a delayed trigger by half of the period. You can use whatever delay you want here.
Title: Re: ATtiny85 code issues
Post by: patrick398 on September 28, 2020, 11:59:07 AM
That worked beautifully, thanks so much!

Here's the full code on the off chance any of this is useful to anybody:

#include <TimerOne.h>

//don't forget 10k pulldown on TRIGGER_IN



int TRIGGER_IN = 0; // ATtiny pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // ATtiny pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int triggerState; // set variale for trigger state
int lastTriggerState = 0; //set variable for last trigger state
int tempoInput = 2; // ATtiny pin (7) connected to tap tempo output
int tempoOutput = 3; // ATtiny pin (2) connected to high hat trigger
int inputState;
bool lastInputState = LOW;
unsigned long lastEdgeTime = millis();
unsigned long pulsePeriod = 0;



void setup() {
  Timer1.initialize (1000);   // starting interrupt which will go off every ' 1000 ' microseconds (1 millisecond)
  Timer1.attachInterrupt (offBeat);
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (tempoInput, INPUT);
  pinMode (tempoOutput, OUTPUT);
}



void loop() {


  int readValue = analogRead(2) * 3; // ATtiny pin (3) read pots value between 0 and 1023 and multiplies it by 3
  triggerState = digitalRead(TRIGGER_IN); // read the trigger in pin


  if (triggerState != lastTriggerState) { // is trigger state not equal to last trigger state
    if (triggerState == HIGH) { // if trigger state has changed...

      delay (readValue); // delay for period set by POT_PIN
      digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
      delay (PULSE);
    }

    lastTriggerState = triggerState;

    digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
  }
}

void offBeat(){
 
// check input

  bool inputState = digitalRead(tempoInput);

  if (inputState){  //input is HIGH
    if (!lastInputState) {  //last state was LOW, so we have a rising edge
      pulsePeriod = millis() - lastEdgeTime;
      lastEdgeTime = millis();
    }
  }
  lastInputState = inputState;

  //set output

if (millis()-lastEdgeTime > pulsePeriod/2){
    digitalWrite(tempoOutput, HIGH);
  } else {
    digitalWrite(tempoOutput, LOW);
  }
  return;
}
Title: Re: ATtiny85 code issues
Post by: potul on September 29, 2020, 02:12:05 AM
glad to see it works. Don't hesitate to ask if you need more help