Example sketches for the new Arduino IDE for ESP8266

Moderator: igrr

User avatar
By oliverseal
#49850 So if you're like me, you really want to read this analog data from a moisture sensor, but the controller for the thing requires 3v3 input. Cool. It outputs 3v3 analog voltage, though. Getting that to step down to 1v for the analog port on the ESP8266 is nearly out of the question, so what do you do?

You buy a bunch of MPC3002 ADCs because they're cheap and easy. SPI! ESP8266 does SPI, right? So they show up, you bust it out and hook up the SPI pins and open up http://www.ee.ic.ac.uk/pcheung/teaching/ee2_digital/MCP3002.pdf to learn how to talk to the thing. Page 15. Sweet.

Wait. Oh yeah. This thing said 10-bit resolution over SPI. Coolcoolcoolcool. Nodoubtnodoubtnodoubt. Umm...

At least the packet diagram is crystal clear. So 4 bits for command info and then 11 bits for data.
Side-note: I really love that all the diagrams say "Don't Care" for the remaining input bits in the transaction. Thanks, Microchip.

The most difficult bit of all this with the ESP8266 is getting the SPI clock mode and speed and all that stuff to sync up. ESP8266 is faster than an ATMega, so it doesn't always work out like I hope.

So without further fanfare, here's how to read that packet.
Hint: Just cheat and use a union!

Code: Select all#include <SPI.h>

/**
 - Every ESP8266 device is different but for NodeMCU and HUZZAH apparently
   7280000 is the sweet spot.
 - MSBFIRST is the default and figures 6-1 and 6-2 in the docs assume it anyway.
 - MODE0 means low low clock mode. We're hoping to catch the bits on the falling edge of the oscillation.
   Learn about some SPI clocks. It's interesting stuff.
*/
SPISettings spiSettings(7280000, MSBFIRST, SPI_MODE0);

const int SPI_CS = 15;

void setup() {
    // we'll talk to this pin to let the SPI know when we're talking.
    pinMode (SPI_CS, OUTPUT);
    // this gets things all clocky
    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setFrequency(7280000);
   
    // blahblahblah whatever else you need to do for your stuff
}


void loop() {
    // So we're gonna start chatting with the device
    SPI.beginTransaction(spiSettings);
    // HEY, DEVICE, HOPE YOU'RE READY!
    digitalWrite (SPI_CS, LOW);
    /**
     Okay this is rather specific. Remember that "Don't Care" part I
     mentioned? That means we have to front-load the command bits we'll be
     sending to the SPI inside an int8_t. 0b notation works great for
     cheating on this. Page 13 of the manual for the MCP3002 explains
     this in a much longer form than I do here.
     bit 1: Start -- Set it to 1 so that the SPI knows this is the start
     bit 2: SGL/DIFF -- Tough to explain this. Just send a 1 here unless you know what the opposite does.
     bit 3: ODD/SIGN -- Set to 1 for channel 1 or 0 for channel 0 on the ADC.
     bit 4: Endian -- So Little or Big? We'll be sending 0 send it allows us to use "word" which does a lot of endian handling for us.
    */
    uint8_t cmd = 0b11000000; // as in read channel 0
    byte msb, lsb;
    word assembled;
   
    // now we'll just start pulling in the bits.
    msb = SPI.transfer(cmd);
    lsb = SPI.transfer(0);
   
    // Ignore that null bit and apply a bit mask. It has a 10 bit resolution, so 10 1's at the end would do it.
    assembled = word(msb, lsb);
    Serial.println(assembled);
    // HEY, DEVICE, I'M DONE TALKING. BYE!
    digitalWrite (SPI_CS, HIGH);
    SPI.endTransaction();
   
    // This is just some processing I do for my own application. I left
    // it in here as an example.
    double reading = (1.0 - (assembled / 1024.0)) * 100.0;
}


I have a working example of this in my own project, so if there are any issues with it let me know. I'll update this, and I'll test to make sure my own project isn't derping.

EDITS: I discovered a lot of issues with the way I was parsing this stuff and realized that I was having clock issues. Tweaked those a bit and started moving bits around. The numbers I get with the updates seem more reliable, though I still have some doubts since I can't perfectly reconcile my approach with the docs.

FURTHER EDITS: I was overthinking this problem completely. Should have been using a `word` to handle the output this whole time.
Last edited by oliverseal on Sat Jul 02, 2016 12:35 am, edited 2 times in total.
User avatar
By mrburnette
#50357
oliverseal wrote:So if you're like me, you really want to read this analog data from a moisture sensor, but the controller for the thing requires 3v3 input. Cool. It outputs 3v3 analog voltage, though. Getting that to step down to 1v for the analog port on the ESP8266 is nearly out of the question, so what do you do?
<...>


There is a solution for just using the internal AD on the ESP8266 for those of us that simply need only the one A0 ... use a modeling program (free) to set the resistor voltage divider values. It is very fast and very easy. I will give an example that I recently did...

The ESP8266 is 3.3V (I measured 3.345 on my DVM) and I am powering the ESP8266 from my PC. I want to use A0 to read the value of a 10K NTC thermistor. I need to measure from 0C to 100C, so I go to the Vishay datasheet for my thermistor and write down the two resistance values:
@-7C == 45K Ohms
@100C == 0.7K Ohms
Of course, at 25C the value of the thermistor is 10K Ohms. But I am only concerned about the two end points of the thermistor as this will help me determine the best series resistance.

Using the Circuit Simulator here: http://www.falstad.com/circuit/
I'm going to create a simple circuit that looks like the one I attached as a JPG.

Now, I just started and guessed at 100K for my series resistor and I set the potentiometer (wired as a rheostat) to a value that could accommodate both of the previous values for the thermistor, therefore I used a 50K value. I configured A0 to be graphed and I played around with the value of Rs until I got a nice value for A0 that kept me under 1.0 Volts but still gave me high enough mV reading when the thermistor was hot.

Play around with this enough and it gets second nature. I chose a 150K which worked out pretty well as can be seen on the spreadsheet graph: created from moving the thermistor from an ice-bath into my hot coffee!
ImageScreenshot from 2016-07-06 09:46:36 by Rayburne, on Flickr

Ray
You do not have the required permissions to view the files attached to this post.
User avatar
By drewyboy
#57362 I'm using EspresIf's own development board and I can't seem to get any SPI clock that works higher thank 10khz. This is literally worthless to me if that's all I can do. If I try any other frequency, I've tried 2Mhz, 1Mhz, 500khz, 200khz, and a few others and the data returns as 1023 for everything.

Any idea's on how to find a frequency that actually provides worthwhile data? IE more than 1Mhz.