martin2250 / ADCTouch

touch sensing library for Arduino
MIT License
101 stars 24 forks source link

ATTINY85 (Digispark) returns negative values. #6

Closed pastprimitive closed 2 years ago

pastprimitive commented 5 years ago

Right now the ADCTouch.read() seems to be returning negative results when running on a 16 or 16.5mhz ATTINY85. The sensitivity of the same conductive pad is really low compared to the same pad and code run on an ATMEL MEGA32U4. (Pro Micro) setup. I get values of 0 to -36 on the ATTINY85. The same setup gets a range of 0 to around 500.

I realize this might be a limitation of the ATTINY85. Although getting negative values seems odd.

The code I used for the digispark setup is below. I used an exact copy for the Pro Micro setup, except I replaced the DigiKeyboard references with serial print and the proper analog pin reference on the Pro Micro.

Any help would be much appreciated!

#include <ADCTouch.h>
#include "DigiKeyboard.h"

int ref0;     //reference values to remove offset

void setup()
{
  // No pins to setup, pins can still be used regularly, although it will affect readings
  ref0 = ADCTouch.read(0,500);    //account for the capacitance of the pad
}

void loop()
{

  int value0 = ADCTouch.read(0);  //   default --> 100 samples

  //byte aptdp = analog_pin_to_digital_pin;

  value0 -= ref0;       //remove offset

    DigiKeyboard.print(value0 > 40);    //send (boolean) pressed or not pressed
    DigiKeyboard.print("\t");           //use if(value > threshold) to get the state of a button

    DigiKeyboard.print(value0);             //send actual reading
    DigiKeyboard.println("\t");
  DigiKeyboard.delay(100);

  DigiKeyboard.sendKeyStroke(0);
}`
martin2250 commented 5 years ago

Strange... I have to admit I didn't do any testing on AtTinys myself, that work was done by @gculik. I have no idea why the capacitance would decrease relative to the reference value.

if that doesn't work, you could try copying the code from ADCTouch.cpp to your sketch and playing around with different combinations of ADCChannel and digitalPin, maybe there is a mismatch.

pastprimitive commented 5 years ago

After talking to my brother who's an electrical engineer and a professor at a local university teaching embedded programming. He seems to agree that the issue is most likely in a mismatch of some sort. Sent him a copy of the code to look at, and he's going to get back to me if he has any revelations.

I've not thoroughly researched the slower clock speeds yet. I'll have to get back to you on that.

In the meantime, I'll see what I can do with what you suggested in regards to playing with different ADCChannel and digitalPin combinations.

Thanks for the quick response!

pastprimitive commented 5 years ago

So after pulling the ADCTouch.cpp code into the sketch and turning it into a function I could butcher to my heart's content. I discovered that the main problem seems to be setting the digital pins to inputs. I know in the Digispark Basics guide it says that you have to set the analog pins to inputs before you read from them. But for whatever reason, this messes with the reference voltage reading is my guess... I'm really no expert when it comes to this level of things. So I am really guessing. Either way I was able to get very reliable readings with the below code. Got a response range of 1 - 300 with the adjusted value0 reads.

Going to see if I can mess around with it a bit more to increase sensitivity. But it's getting close to exceeding my project needs already. I'll report back if I have more success.

int ADCTouchread(byte ADCChannel, int samples = 100)
{
  long _value = 0;
  for (int _counter = 0; _counter < samples; _counter ++)
  {
    // set the digital pin corresponding to the analog pin as an input pin with a pullup resistor
    // this will start charging the capacitive element attached to that pin
   // pinMode(2, INPUT_PULLUP);

    // connect the ADC input and the internal sample and hold capacitor to ground to discharge it
    ADMUX = (ADMUX & 0xF0) | 0b11101;

    // start the conversion
    ADCSRA |= (1 << ADSC);

    // ADSC is cleared when the conversion finishes
    while ((ADCSRA & (1 << ADSC)));

  // pinMode(2, INPUT_PULLUP);

    _value += analogRead(ADCChannel);
  }
  return _value / samples;
}

#include "DigiKeyboard.h"

int ref0;     //reference values to remove offset

void setup()
{
  ref0 = ADCTouchread(1, 100);   //account for the capacitance of the pad
}

void loop()
{

  int value0 = ADCTouchread(1,50);  //   default --> 100 samples

  value0 -= ref0;       //remove offset

  DigiKeyboard.print(value0 > 40);    //send (boolean) pressed or not pressed
  DigiKeyboard.print("\t");           //use if(value > threshold) to get the state of a button

  DigiKeyboard.print(value0);             //send actual reading
  DigiKeyboard.println("\t");
  DigiKeyboard.delay(100);

  DigiKeyboard.sendKeyStroke(0);
}
martin2250 commented 5 years ago

I'm a bit surprised that it works at all without enabling the pullup resistor, right now your sketch doesn't do much more than using analogRead(). Is it possible that your readings are caused by electric charges on your body? Try grounding yourself and the circuit before testing it.

stre425 commented 2 years ago

I don't know if this is still relevant, but there seems to be a bug in the Digispark Arduino core. pinMode(xxx,INPUT) does not disable the internal pullup. So if it has been activated once by pinMode(xxx,INPUT_PULLUP) it needs to be manually reset.After adding a digitalWrite(digitalPin,LOW) in ADCTouch.cpp it works as intended.

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
        pinMode(digitalPin, INPUT);
        digitalWrite(digitalPin,LOW);
#else
        pinMode(ADCChannel, INPUT);
#endif
        _value += analogRead(ADCChannel);
martin2250 commented 2 years ago

Hey @stre425,

thanks for looking into this! I'll update the library rightaway

Cheers Martin

stre425 commented 2 years ago

Hi Martin,

Thanks for changing this so fast. I also raised an issue in the Digispark to fix this in the Digispark core - link.

I'm still not 100% sure if Digispark implementation of pinMode is done deliberately like that, but at least according to the Arduino reference the expected behavior would be that pinMode(xxx,INPUT) should disable the pullup.

Rgds