Read value from Tinker analogWrite pins

I am running the Tinker app and trying to read some analog input as set by the mobile app.

On the app I have set pins A0-A2 as analogWrite, and in the code I have set those same pins to analogRead to try and grab the values set by the app. Main loop looks like so:

int cRed=0;
int cGrn=0;
int cBlu=0;

void setup()
{
	//Setup the Tinker application here

	//Register all the Tinker functions
	Spark.function("digitalread", tinkerDigitalRead);
	Spark.function("digitalwrite", tinkerDigitalWrite);

	Spark.function("analogread", tinkerAnalogRead);
	Spark.function("analogwrite", tinkerAnalogWrite);

}

void loop()
{

    cRed = analogRead(A2) / 16;
    cGrn = analogRead(A1) / 16;
    cBlu = analogRead(A0) / 16;
    
    RGB.control(true);    
    RGB.color(cRed, cGrn, cBlu);
    RGB.control(false);
    delay(100);
    
}

The values from the app don’t seem to make it into the core, so the LED never changes color. Instead, A0-A2 are constantly being read as expected - I can brush the pins with my finger and the LED changes color.

I assume that this is not working because I am constantly setting the pins to read… what’s the proper way to read the analogWrite values from the app?

I see what you’re trying to do but unfortunately it won’t quite work that way. That said you could set A0, A1 and A2 as analogWrites, then jump those three pins to A3, A4 and A5 which you’d set as the analogReads.

That’s not a bad idea! Works well, thanks for your thoughts :smile:

I retract my previous statement, as I have goofed.

Through troubleshooting, I finally found out why my read values were so strange… analogRead pins were reporting either 0 or 4095 (0% or 100%), and it bounced around wildly, almost like it depended on when you refreshed the Tinker app.

analogWrite produces a PWM. Yes, a square wave, that is either 3.3v or 0v. Derp.

This method will not work for reading analogWrite values from the Tinker app. Anybody care to weigh in on an alternative?

Repeating from other thread:

You should low pass filter your PWM before trying to take an A/D reading on the average value.

Use something like a 1k ohm resistor between your PWM output and analog input, and a 1uF capacitor from your analog input to ground. Alternatively 10k and 0.1uF, or values slightly higher will work fine without too much lag in the voltage settling.

1 Like

Great question @emc2—It sounds like you want to do something with the Tinker mobile app that it was not intended to do. However, what you're trying to accomplish is possible, and I can imagine that others might have a similar confusion about read and write, embedded and mobile, and how Spark ties these things together. So, I'm going to walk through the solution here to help make the whole system's interactions clear.

It sounds like you want to:

  • Use 3 analog sliders in the Tinker mobile app
  • One pin should represent red, another green, another blue
  • These sliders should not control the pins they're actually hooked to in the Tinker firmware app—instead they should control the color of the RGB LED

If I'm right about all that, then you don't need to call analogRead() or analogWrite() anywhere in firmware because you do not actually care about reading or writing electrical values on the pins sticking out of the Core.

When you finish dragging an analogWrite slider in the Tinker mobile app, it sends a web request to our API. The request endpoint looks like this:

POST /v1/devices/<DEVICE_ID>/analogwrite

The request body contains two parameters.

  • Your access token (since only you can control your Core)
  • The string argument that will be passed to the firmware function, for example: A4,177 or D0,36

Because the end of the URL is analogwrite, the Core will run whatever Spark.function is registered with that key in setup(). For example, if the function is registered like this:

Spark.function("analogwrite", updateRGBLEDColor);

then any web request to to analogwrite will call the firmware function updateRGBLEDColor. This also means you actually have to define that function so that it does whatever you want it to do with the incoming string.

In your code above, you register but don't define any of tinkerDigitalRead, tinkerDigitalWrite, tinkerAnalogRead, or tinkerAnalogWrite. If you're successfully flashing and running that code, it must be linking with the versions defined in the standard Spark firmware, so this is the code that runs when you move your sliders:

https://github.com/spark/core-firmware/blob/master/src/application.cpp#L152

Also, side note—If you were trying to write an analog PWM value to pin A2, it wouldn't work. If the mobile app gives you analogWrite as an option for A2, then that's a bug. The android app definitely doesn't allow this, but the iOS app might. As the Analog Outputs section of the Spark Core Hardware Reference says, analogWrite

is only available on the following pins: A0, A1, A4, A5, A6, A7, D0 and D1.

So let's plan to do this with A4 as red, A5 as green, and A6 as blue.

Here's a gist that you can copy-paste into the Spark web IDE that will do exactly what I describe above. It defaults to a pinkish color when the app first starts. After that you can change the color using analogWrite on A4, A5, or A6 in the Tinker mobile app. After each change, the color will remain for a few seconds (until loop() has been called a thousand times), then it will relinquish control of the RGB LED so it goes back to breathing cyan.

If you just want to see the color without changing it, do analogWrite on some other pin. This will still call updateRGBLEDColor, but none of the if statements will match.

Hope that clarifies how the Tinker mobile app and your firmware work together!

Cheers!

3 Likes

:open_mouth:

Processing and testing! THANK YOU SO MUCH for writing that out!

The code above was actually just a snippet of the main loop and some globals… the full code block can be found over at https://community.spark.io/t/tinker-neopixel-a-test/2196. Warning: it’s a mess.

Update: iOS app has analogWrite on A0, 1, 2, 5, 6, 7. Everything except A3 and A4.

The updateRGBLEDColor() function works like a charm - so cool! I have a much better understanding of how this works now, thanks again.

I’ve integrated this with the Neopixel library and am having some trouble with the core dis- and re-connecting after the first colorWipe event however… https://community.spark.io/t/tinker-neopixel-a-test/2196/8. Not sure at this point if this is related to interrupt timing or what.