Teensy 3.0 arrived

Anything not related to a specific project.

Teensy 3.0 arrived

Postby jbeale » Thu Oct 04, 2012 3:43 pm

Yesterday's mail had my Teensy 3.0 (ARM Cortex-M4 with Arduino-style programming). This is from Paul's kickstarter (US Mail takes 2 days from OR to CA, it seems). Some pics: Teensy3, and on breadboard

My first test was to see how good the on-board ADC is. It is 16 bits, but Paul had said due to noise, it is effectively only 13 bits. You can see my experimental setup in this photo. ADC0 is driven by a 499/1.0k resistive divider from Vdd to AGND (analog ground pin), and a 0.1 uF cap from ADC0 to AGND. In this case Vref = Vdd = 3.266 V and ADC0 input is 2.171 V (per Fluke 179). This gives an expected reading of 65535*(2.171/3.266) = 43563 counts, where 1 LSB = 49.84 uV. Running the below code, with a sample size of 10000 readings, I get a standard deviation of just about 1 LSB (so RMS noise = 50 uV) and peak-peak noise of 7 counts, and a DC offset from the expected reading of 10-20 LSBs (= 0.5 to 1 mV).

The noise and offset from the expected reading depends somewhat on the clock rate set. Without that 0.1 uF cap from ADC0 to AGND, both p-p and std.dev noise increase about 3.5 times. The board is being powered by (no doubt noisy) +5.18V from a USB hub on a PC monitor, the 3.266 V is from the on-board regulator. The AGND pin is sensitive with this simple unshielded setup: even just connecting the ground lead of my battery-powered Fluke 179 multimeter and nothing else (and with the meter powered off) increases RMS noise from 0.9 to 1.6 LSB.

By the way, compiling and downloading code to T3 is a lot faster than with a standard Arduino. The attached code compiles, downloads, and is running in about 2.5 seconds! Also, the USB ACM interface is remarkably faster than the 115.2k Arduino if you want to send a lot of data via serial.print() output.

Sample Output from ADC test program:
Code: Select all
# Teensy 3.0 @ 96 MHz
# Samples/sec: 2246.69 Avg: 43582.86 Offset: 19.94 P-P noise: 7 St.Dev: 0.944
# Samples/sec: 2245.68 Avg: 43583.17 Offset: 20.25 P-P noise: 8 St.Dev: 0.938
# Samples/sec: 2245.68 Avg: 43583.22 Offset: 20.31 P-P noise: 7 St.Dev: 0.931
# Samples/sec: 2245.68 Avg: 43583.40 Offset: 20.48 P-P noise: 8 St.Dev: 0.940
# Samples/sec: 2246.18 Avg: 43583.25 Offset: 20.33 P-P noise: 8 St.Dev: 0.921

# Teensy 3.0 @ 48 MHz
# Samples/sec: 2236.64 Avg: 43583.83 Offset: 20.92 P-P noise: 9 St.Dev: 1.116
# Samples/sec: 2236.64 Avg: 43583.67 Offset: 20.76 P-P noise: 8 St.Dev: 1.123
# Samples/sec: 2236.14 Avg: 43583.81 Offset: 20.89 P-P noise: 8 St.Dev: 1.117
# Samples/sec: 2236.64 Avg: 43583.73 Offset: 20.81 P-P noise: 10 St.Dev: 1.107

# Teensy 3.0 @ 24 MHz
# Teensy 3.0 ADC test start:
# Samples/sec: 2156.10 Avg: 43573.35 Offset: 10.44 P-P noise: 7 St.Dev: 0.913
# Samples/sec: 2156.10 Avg: 43573.42 Offset: 10.50 P-P noise: 8 St.Dev: 0.928
# Samples/sec: 2156.10 Avg: 43573.55 Offset: 10.64 P-P noise: 7 St.Dev: 0.927
# Samples/sec: 2156.10 Avg: 43573.44 Offset: 10.52 P-P noise: 7 St.Dev: 0.907
# Samples/sec: 2156.10 Avg: 43573.33 Offset: 10.42 P-P noise: 7 St.Dev: 0.923


Code for ADC test program
Code: Select all
// Analog input test for Teensy 3.0    Oct 4 2012 J.Beale
// Setup: https://picasaweb.google.com/109928236040342205185/Electronics#5795546092126071650

    #define VREF (3.266)         // ADC reference voltage (= power supply)
    #define VINPUT (2.171)       // ADC input voltage from resistive divider to VREF
    #define ADCMAX (65535)       // maximum possible reading from ADC
    #define EXPECTED (ADCMAX*(VINPUT/VREF))     // expected ADC reading
    #define SAMPLES (10000)      // how many samples to combine for pp, std.dev statistics

    const int analogInPin = A0;  // Analog input is AIN0 (Teensy3 pin 14, next to LED)
    const int LED1 = 13;         // output LED connected on Arduino digital pin 13

    int sensorValue = 0;        // value read from the ADC input
    long oldT;

    void setup() {    // ==============================================================
      pinMode(LED1,OUTPUT);       // enable digital output for turning on LED indicator
      analogReference(INTERNAL);  // set analog reference to internal ref
      analogReadRes(16);          // Teensy 3.0: set ADC resolution to this many bits
     
      Serial.begin(115200);       // baud rate is ignored with Teensy USB ACM i/o
      digitalWrite(LED1,HIGH);   delay(1000);   // LED on for 1 second
      digitalWrite(LED1,LOW);    delay(3000);   // wait for slow human to get serial capture running
     
      Serial.println("# Teensy 3.0 ADC test start: ");
    } // ==== end setup() ===========

    void loop() {  // ================================================================
     
      long datSum = 0;  // reset our accumulated sum of input values to zero
      int sMax = 0;
      int sMin = 65535;
      long n;            // count of how many readings so far
      double x,mean,delta,sumsq,m2,variance,stdev;  // to calculate standard deviation
     
      oldT = millis();   // record start time in milliseconds

      sumsq = 0; // initialize running squared sum of differences
      n = 0;     // have not made any ADC readings yet
      mean = 0; // start off with running mean at zero
      m2 = 0;
     
      for (int i=0;i<SAMPLES;i++) {
        x = analogRead(analogInPin);
//        Serial.println(x,0);
        datSum += x;
        if (x > sMax) sMax = x;
        if (x < sMin) sMin = x;
              // from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
        n++;
        delta = x - mean;
        mean += delta/n;
        m2 += (delta * (x - mean));
      }
      variance = m2/(n-1);  // (n-1):Sample Variance  (n): Population Variance
      stdev = sqrt(variance);  // Calculate standard deviation

      Serial.print("# Samples/sec: ");
      long durT = millis() - oldT;
      float datAvg = (1.0*datSum)/n;
      Serial.print((1000.0*n/durT),2);

      Serial.print(" Avg: ");     Serial.print(datAvg,2);
      Serial.print(" Offset: ");  Serial.print(datAvg - EXPECTED,2);
      Serial.print(" P-P noise: ");  Serial.print(sMax-sMin);
      Serial.print(" St.Dev: ");  Serial.println(stdev,3);
     
//     while (true) {}
    } // end main()  =====================================================
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 arrived

Postby bearmos » Thu Oct 04, 2012 11:41 pm

jbeale wrote:y first test was to see how good the on-board ADC is

You crazy kids and your high resolution ADC's ;-)

I think it's great you're drawing attention to the *practical* resolution of ADC's in so many different ways - definitely something a lot of people don't appreciate when first dealing with them.
bearmos
Hero Member
Hero Member
 
Posts: 748
Joined: Tue Nov 02, 2010 10:02 pm

Re: Teensy 3.0 arrived

Postby jbeale » Thu Oct 04, 2012 11:51 pm

Explanation of terms used in descriptions of ADCs (analog to digital converters)

LSB = least significant bit. "1 LSB" is one count from an ADC. The 10-bit Arduino (ATmega328p) ADC has 210 = 1024 levels, so the size of 1 LSB is 1/1024 of full scale or about 0.1 %. Normally full scale is the power supply of 5 V, so 1 LSB is about 5 mV. On the '328p you can also select the internal 1.2V reference, with the function analogReference(INTERNAL); ...in which case 1 LSB is just over 1 mV, or select the external reference input pin, so 1 LSB is about 0.1% of whatever voltage that is.

On the Teensy 3, in full-resolution mode you get 216 or 65536 levels, so 1 LSB is 1/65536 of full scale, which is about 15 ppm (parts per million). So the Teensy 3's ARM chip has 64 times more levels on its ADC than the '328p gives you, but you may not get that much actual resolution if there is a lot of noise (difference between the actual voltage and the reading you get). Noise can come (for example) by capacitive pickup of digital signals elsewhere in the CPU chip, or thermal noise in resistors, etc.

P-P noise = Peak to Peak noise. This is the difference between the maximum and the minimum reading, for a fixed input value. It should be specified with a sample size, as it does not converge to a fixed value with larger numbers of samples, like root-mean-square noise does. As you keep sampling for longer times, you pick up increasingly rare, ever larger noise peaks.

Standard Deviation is a statistical value describing how widely a set of values varies from the average. If you put a fixed, noise-free voltage into an ADC and take some large number of readings, and then take the standard deviation of those readings, that is the RMS (root mean squared) noise of the ADC itself. The Teensy 3 ADC has about 1 LSB of RMS noise in the circuit I tested. With a 3.3V supply as the reference, that means I have Vrms = 50 uV. With the "white noise" assumption (usually correct), about 68% of all readings I take will be within +/- 1 standard deviation = 50 uV of the true value. See also: Wiki: Standard Deviation.

Relatively low resolution ADCs (8 or 10 bits) often have much less than 1 LSB of noise, so with a fixed voltage input, a set of 100 readings might all be the same value. In that case, averaging readings will not improve your resolution. With 1 LSB of noise, averaging together n=100 readings will (in theory) improve the resolution of your measurement by a factor of sqrt(n) = 10. Note that resolution is not the same thing as accuracy.

For an ADC to be accurate, the voltage offset (counts with 0 input), the gain (counts per volt), and the integral and differential nonlinearity (hopefully negligible) must be known and unchanging so that a calibration remains valid. I have not tested those parameters on the Teensy 3 yet, although I did note the offset depends on input capacitance, and system clock frequency. The ADC resolution as a fraction of full scale is described by the bit depth and the noise, and is independent of gain and voltage offset.
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 arrived

Postby arakis » Fri Oct 05, 2012 4:44 am

Awesome work on the Teensy 3.0.. Also thanks for posting all this stuff on the ADC. Question: May we have your permission to run this on the blog.
best regards FIlip.
arakis
Crew
Crew
 
Posts: 1044
Joined: Wed May 25, 2011 11:15 am
Location: Belgrade, Serbia

Re: Teensy 3.0 arrived

Postby jbeale » Fri Oct 05, 2012 9:27 am

Arakis: Sure. ( I assume anything in the forum might go on the blog also. )
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 arrived

Postby jbeale » Sun Oct 07, 2012 2:31 am

UPDATE Oct. 8 2012: The below overlong post is only left here for historical interest. The problem I was debugging here was simply me not setting up the host serial port properly. Feel free to skip this one, and continue with the next post if you're still interested. -John


This is mostly a note to myself, but any USB protocol experts are certainly welcome to comment! This really should go to a "Teensy 3" forum on the vendor's website (PJRC.com), but a forum there is still a work in progress.

Summary: the Teensy 3.0 is a USB ACM device. A program running on it which sends serial output via USB works just fine on 3 different WinXP computers. It does not talk properly to a Raspberry Pi (Raspbian Linux 3.2.27+), or a 6-year-old Dell Inspiron 9300 laptop running Debian Linux 2.6.32-5-686. The R-Pi has known USB issues, but the Laptop USB is normally reliable. The symptom is the first line of text (actually 68 bytes in two lines, but one USB packet) sent by Teensy 3.0 is received by the host (eg. by cat /dev/ttyACM0) but no further communication is received. Interestingly, the Teensy 2.0 is also a USB ACM device, and the *same* program running on that (smaller, slower) CPU works just fine sending data to these two Linux boxes (and also on Windows).

I'm a complete novice at low-level USB, but I set up Wireshark 1.2.11 on my laptop, and did 'modprobe usbmon' and 'mount -t debugfs / /sys/kernel/debug' so I could monitor USB packets. I plugged the Teensy 2 set up with my program into my laptop USB port, did 'cat /dev/ttyACM0' to capture the output, and logged the USB packets. Then I stopped it with control-C, and unplugged the device. Then I did the same with the Teensy 3, running the same program (which is nearly the same one as in my first post on this thread). A hand-transcribed excerpt of the USB packet trace is below. In each case, you see the initial line of 68 bytes of text (starting 'min,sps,avg,pkpk,') come in as one packet, an "in progress" reply, and then each byte is forwarded in a separate packet to a different port/USB endpoint (that being my shell 'cat' command? I don't know how USB works...) The difference seems to be that actually fewer of the separate bytes in the Teensy 2 case get forwarded in this way, and later acknowledged (but I don't even know if this trace is relevant to the actual problem.) You see the second line of text from Teensy 2 (starting '0.07') and also subsequent data, but with Teensy 3, this and subsequent data lines never show up. The action stops with confirmation of the one-byte 'k' packet, URB id 0xf6f90b80 and nothing further seen until about 14 seconds later when I killed the cat command and unplugged the device.

The actual dumps (readable in Wireshark, at least on my machine) are in the attached zip file.

In the listing below, the first line shows a USB packet containing a line with 68 bytes of text coming from source (USB endpoint 5.4 or 4.4) which is the Teensy 2 or 3 respectively, to the destination which is the laptop Linux box. The second line, about 20 microseconds later, is a reply from the Linux host to the Teensy with a status update saying that USB Request Block (URB) is 'in progress'.

Code: Select all
time(sec)   src   dest   type   data or status      bytes   URB id:
----------------------------------------------------------------------------------
Teensy 2.0 USB-ACM packet trace      Linux debian 2.6.32-5-686  Wireshark 1.2.11
----------------------------------------------------------------------------------
14.627059   5.4   host   C   min,sps,avg,pkpk,...   68   0x00000000f61b5800
14.627076   host   5.4   S   -EINPROGRESS (-115)   0   0x00000000f61b5800
14.628010   host   5.3   S   m (-EINPROGRESS)   1   0x00000000f61b5900
14.628019   host   5.3   S   i (-EINPROGRESS)   1   0x00000000f61b5600
14.628023   host   5.3   S   n (-EINPROGRESS)   1   0x00000000f61b5380
...
14.628081   host   5.3   S   k (-EINPROGRESS)   1
14.629057   5.3   host   C   Success         0   0x00000000f61b5900
14.629064   5.3   host   C   Success         0   0x00000000f61b5600

16.324065   5.4   host      0.07,5899.70,175...      33   0x00000000f61b5180
16.324084   host   5.4      -EINPROGRESS (-115)   0   0x00000000f61b5180
...
22.258057   5.4   host   C   -ENOENT         0   0x00000000f61b5180
22.259057   5.4   host   C   -ENOENT         0   0x00000000f61b5800
----------------------------------------------------------------------------------
Teensy 3.0 USB-ACM packet trace    Linux debian 2.6.32-5-686   Wireshark 1.2.11
----------------------------------------------------------------------------------
22.004169   4.4   host   C   min,sps,avg,pkpk,...   68   0x00000000f61e9e80
22.004189   host   4.4   S   -EINPROGRESS (-115)   0   0x00000000f61e9e80
22.008006   host   4.3   S   m (-EINPROGRESS)   1   0x00000000f61e9400
22.008016   host   4.3   S   i (-EINPROGRESS)   1   0x00000000f61a3880
22.008020   host   4.3   S   n (-EINPROGRESS)   1   0x00000000f6f90400
...
22.008077   host   4.3   S   k (-EINPROGRESS)   1   0x00000000f6f90b80
22.008155   4.3   host   C   Success         0   0x00000000f61e9400
22.008162   4.3   host   C   Success         0   0x00000000f61a3880
22.009165   4.3   host   C   Success         0   0x00000000f6f90400
...
22.009206   4.3   host   C   Success         0   0x00000000f6f90b80

36.196116   host   4.0   S   (-EINPROGRESS)      0   0x00000000f6286100
------------------------------------------------------------------------------------------


Text output of program run on Teensy 2.0 (despite "Teensy 3.0" text) until ^C terminated cat command. (the original was actually double-spaced as it was sending out DOS-style CR-LF line endings.)
Code: Select all
root@debian:/home/john# cat /dev/ttyACM0
min,sps,avg,pkpk,stdev
# Teensy 3.0 ADC test v1.1 2012.10.6 JPB
0.07,5899.70,175.05,905,214.296
0.10,5934.72,70.29,98,11.796
0.13,5941.77,72.79,98,11.616
0.16,5927.68,71.95,105,14.226


Text output of program run on Teensy 3.0, until ^C terminated cat command. (the original was actually double-spaced as it was sending out DOS-style CR-LF line endings.)
Code: Select all
root@debian:/home/john# cat /dev/ttyACM0
min,sps,avg,pkpk,stdev
# Teensy 3.0 ADC test v1.1 2012.10.6 JPB



Here is the exact code running on both Teensy 2 and Teensy 3
Code: Select all
    // Analog input test for Teensy 3.0    Oct 4 2012 J.Beale
    // Setup: https://picasaweb.google.com/109928236040342205185/Electronics#5795546092126071650

        #define VREF (3.266)         // ADC reference voltage (= power supply)
        #define VINPUT (2.171)       // ADC input voltage from resistive divider to VREF
        #define ADCMAX (65535)       // maximum possible reading from ADC
        #define EXPECTED (ADCMAX*(VINPUT/VREF))     // expected ADC reading
        #define SAMPLES (10000)      // how many samples to combine for pp, std.dev statistics

        const int analogInPin = A0;  // Analog input is AIN0 (Teensy3 pin 14, next to LED)
        const int LED1 = 13;         // output LED connected on Arduino digital pin 13

        int sensorValue = 0;        // value read from the ADC input
        long oldT;

        void setup() {    // ==============================================================
          pinMode(LED1,OUTPUT);       // enable digital output for turning on LED indicator
          analogReference(INTERNAL);  // set analog reference to internal ref
          //analogReadRes(16);          // Teensy 3.0: set ADC resolution to this many bits
         
          Serial.begin(115200);       // baud rate is ignored with Teensy USB ACM i/o
          digitalWrite(LED1,HIGH);   delay(1000);   // LED on for 1 second
          digitalWrite(LED1,LOW);    delay(3000);   // wait for slow human to get serial capture running
         
          Serial.println("min,sps,avg,pkpk,stdev ");
          Serial.println("# Teensy 3.0 ADC test v1.1 2012.10.6 JPB ");
        } // ==== end setup() ===========

        void loop() {  // ================================================================
         
          long datSum = 0;  // reset our accumulated sum of input values to zero
          int sMax = 0;
          int sMin = 65535;
          long n;            // count of how many readings so far
          double x,mean,delta,sumsq,m2,variance,stdev;  // to calculate standard deviation
         
          oldT = millis();   // record start time in milliseconds

          sumsq = 0; // initialize running squared sum of differences
          n = 0;     // have not made any ADC readings yet
          mean = 0; // start off with running mean at zero
          m2 = 0;
         
          for (int i=0;i<SAMPLES;i++) {
            x = analogRead(analogInPin);
    //        Serial.println(x,0);
            datSum += x;
            if (x > sMax) sMax = x;
            if (x < sMin) sMin = x;
                  // from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
            n++;
            delta = x - mean;
            mean += delta/n;
            m2 += (delta * (x - mean));
          }
          variance = m2/(n-1);  // (n-1):Sample Variance  (n): Population Variance
          stdev = sqrt(variance);  // Calculate standard deviation

         // Serial.print("# Samples/sec: ");
          long durT = millis() - oldT;
          float datAvg = (1.0*datSum)/n;
          Serial.print(oldT/60000.0,2);
          Serial.print(",");
          Serial.print((1000.0*n/durT),2);
          Serial.print(",");
         
          Serial.print(datAvg,2);
//          Serial.print(" Offset: "); 
//          Serial.print(datAvg - EXPECTED,2);
          Serial.print(","); 
          Serial.print(sMax-sMin);
          Serial.print(","); 
          Serial.println(stdev,3);
         
    //     while (true) {}
} // end main()  =====================================================

       


Additional note: if I wait for a long time after connecting the Teensy 3, before typing 'cat /dev/ttyACM0' I can get several more lines of data, just over half a minute's worth, which appears all at once, as shown below. But it does not continue beyond this initial burst.
Code: Select all
root@debian:/home/john# cat /dev/ttyACM0
min,sps,avg,pkpk,stdev
# Teensy 3.0 ADC test v1.1 2012.10.6 JPB
0.07,2238.14,32788.21,8,0.886
0.14,2238.14,32788.15,7,0.902
0.22,2238.14,32788.16,7,0.923
0.29,2238.14,32788.14,6,0.926
0.37,2238.14,32788.13,7,0.907
0.44,2238.14,32788.14,6,0.894
0.52,2237.64,32788.24,6,0.885
0.59,2238.14,32788.21,6,0.871
Attachments
Teensy23-trace.zip
Wireshark USB traces from Teensy 2 and 3
(5.04 KiB) Downloaded 296 times
Last edited by jbeale on Mon Oct 08, 2012 11:38 am, edited 1 time in total.
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Teensy 3.0 working with Linux now (was my fault...)

Postby jbeale » Sun Oct 07, 2012 4:57 pm

I have both my laptop and the Raspberry Pi working now with Teensy3. What works is using the command
'screen /dev/ttyACM0 115200' (and also, presumably, any normal terminal emulator; minicom also works ok on the R-Pi, although not on my laptop for some reason. Paul, the developer of the board uses seyon on his Ubuntu system).

What did not work was just using the command 'cat /dev/ttyACM0'. I didn't realize 'cat' was not well-defined for opening serial ports, I guess it just happened to work with Teensy2.

Update: 'cat' does work, as long as you use 'stty' to set the serial parameters first. This two-line script works for me:
Code: Select all
stty -F /dev/ttyACM0 1:0:80001cb1:0:3:1c:7f:15:4:5:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
cat /dev/ttyACM0 > /home/pi/teensy3.log


Curious note: for whatever reason, the measured RMS noise of the ADC is slightly lower when connected to the R-Pi (typically 0.85 LSB's, vs 1.20 on my laptop, and near 1.0 for the desktop at work.) This is true even using a hacked USB splitter cable so the +5V power comes from a separate supply from the USB host.
Last edited by jbeale on Mon Oct 08, 2012 12:59 am, edited 1 time in total.
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 working with Linux now (was my fault...)

Postby bearmos » Sun Oct 07, 2012 7:42 pm

jbeale wrote:Curious note: for whatever reason, the measured RMS noise of the ADC is slightly lower when connected to the R-Pi (typically 0.85 LSB's, vs 1.20 on my laptop, and near 1.0 for the desktop at work.) This is true even using a hacked USB splitter cable so the +5V power comes from a separate supply from the USB host.


Aren't you still sharing the ground connection with the PC (for the single ended control signals)? I'd point a finger at the ground setup if this is the case. If you really wanted to get crazy, you could try out some of the USB Isolators from ADI to completely isolate the board from the computer.
bearmos
Hero Member
Hero Member
 
Posts: 748
Joined: Tue Nov 02, 2010 10:02 pm

Re: Teensy 3.0 arrived

Postby jbeale » Mon Oct 08, 2012 12:26 am

Yes, the ground is shared, but right now the ADC is just looking at a resistive divider from the chip's Vdd, nothing external- so with only one shared connection point there is no circuit (except for stray capacitive coupling, which is probably the culprit).

Yes, USB isolation would be one useful test. I was thinking of just running the Teensy 3 standalone (no USB at all) off a clean power supply, and blinking out the RMS ADC readings in morse code on the built-in LED. Which I guess might also be considered a one-way, low-bandwidth opto-isolator. The Teensy also has a normal UART and I already have a serial optoisolator, somewhere around here...
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 arrived

Postby bearmos » Mon Oct 08, 2012 6:57 am

jbeale wrote:Yes, the ground is shared, but right now the ADC is just looking at a resistive divider from the chip's Vdd, nothing external- so with only one shared connection point there is no circuit (except for stray capacitive coupling, which is probably the culprit).


The reason I was blaming ground was mainly because of the different behavior from different computers - the only changing parameter being the shared ground, who's quality varies along with the computer being used.

jbeale wrote:I was thinking of just running the Teensy 3 standalone (no USB at all) off a clean power supply, and blinking out the RMS ADC readings in morse code on the built-in LED


It doesn't get much more stand-alone than this:)

jbeale wrote: The Teensy also has a normal UART and I already have a serial optoisolator, somewhere around here...

...probably your best bet without turning this into a project in itself ;-)
bearmos
Hero Member
Hero Member
 
Posts: 748
Joined: Tue Nov 02, 2010 10:02 pm

Teensy 3 internal temp sensor

Postby jbeale » Wed Oct 10, 2012 1:49 pm

Just FYI, another feature of the Teensy 3.0 ARM chip is an internal temperature sensor. analogRead(38) gets you a reading proportional to the temperature of the chip. On my device, in 16 bit mode I get 14400 counts at 25 C, and -35.7 counts per deg. C above that (so 40 C is 13868). The internal sensor is a transistor Vbe drop. My temperature reference was a thermocouple taped to the top of the ARM chip. With my rather limited, casual test, it looks linear through the 25 C to 45 C range at least.

The scatter from the linear fit that you see in the chart may have more to do with the rate of change of temperature causing a difference between inside & outside of the chip package. I did not use a thermal chamber for this; this was mostly just waving a heat gun around.

Teensy3-TempCal.png
Teensy 3.0 temperature sensor
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Teensy3 maximum pin toggle rate is 24 MHz

Postby jbeale » Thu Oct 11, 2012 6:57 pm

Using the program below and looking at the LED pin on my scope, I measure 12.0 MHz out @24M clock, 24.0 MHz @48M, but also 24.0 MHz @96M with either 20% or 80% duty cycle. So from the standpoint of the maximum GPIO pin toggle rate, overclocking beyond the "stock" 48 MHz does not make it faster.

Code: Select all
#define T GPIOC_PTOR = 1<<5; // toggle state of PortC,bit5 = LED pin
void setup() {pinMode(13, OUTPUT);} // make LED pin an output
void loop() { T T T T T T T T T T T T T T T T T T T } // toggle pin 19x as unrolled loop

But if I instead use a single "T" as the body of loop() then the overclock is indeed 2x faster (2.4MHz @48M and 4.8MHz @96M) so the overclock is meaningful if you're not trying to do I/O at that frequency. Also, running the ARM at 96 MHz you can generate an isolated 10 ns wide pulse, of either polarity. (Well, approximately 10 ns, but with the rise time at about 6 ns, it's hard to say.)

The equivalent program on a standard 16 MHz ATmega328p Arduino generates a 8 MHz square wave:
Code: Select all
#define H PORTB = 1<<5; // Arduino set D13 (LED pin) high
#define L PORTB = 0; // make PortB all zeros
void setup() {pinMode(13, OUTPUT);}  // make LED pin an output
void loop() { H L H L H L H L H L H L H L H L H L H L }
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

SPI is working (with default clock rate)

Postby jbeale » Fri Oct 12, 2012 7:34 pm

I was happy to see that I can get data via SPI from an 18-bit ADC and send it out one of the three serial ports on the Teensy 3. The below code is the same as the Arduino version I used earlier with the MAX11209 chip, with one exception: at the moment (Teensy 3 beta 5) the SPI.setClockDivider() command is not working, so I have to settle for the default SPI clock rate (4 MHz).

Code: Select all
/* -----------------------------------------------------------------
  Interface between Teensy 3.0 and MAX11209 18-bit ADC
  compiled with Arduino 1.0.1 Teensy 3 beta 5
  October 12 2012 John Beale

  Note: this ADC requires 3.3V logic levels.

   MAX11209  <---------->  Arduino Device
   11: /CS  <- to digital pin 10  (SS pin)
   12: MOSI <- to digital pin 11 (MOSI pin)
   13: MISO -> to digital pin 12 (MISO pin)
   14: SCLK <- to digital pin 13 (CLK pin)
    4: GND  - ground
    9: AVDD - 3.3V supply
   10: DVDD - 3.3V supply
------------------------------------------------------------------ */

/*   MAX11209 8-bit Command Byte, and Status & Control Registers
------------------------------------------------------------------------
#  name     b7     b6     b5     b4     b3     b2     b1     b0      dir
------------------------------------------------------------------------
- COMMAND  START  MODE   CAL1   CAL0   IMPD   RATE2  RATE1  RATE0     W
0 STAT1    SYSOR  RATE2  RATE1  RATE0  OR     UR     MSTAT  RDY       R
1 CTRL1    LINEF  U/B    EXTCLK REFBUF SIGBUF FORMAT SCYCLE UNUSED   R/W
2 CTRL2    DIR4   DIR3   DIR2   DIR1   DIO4   DIO3   DIO2   DIO1     R/W
3 CTRL3    DGAIN2 DGAIN1 DGAIN0 NOSYSG NOSYSO NOSCG  NOSCO  RESERVED R/W
----------------------------------------------------------------------- */

// NOTE: MAX11209 SlaveSelect pin must be toggled high & low between each command
// (despite data sheet claim to the contrary)

#include <SPI.h>  // include the SPI library for talking with chip

#define UC unsigned char    // 8 bits unsigned char = 1 byte
#define STAT1 0            // addresses of ADC status/control registers
#define CTRL1 1
#define CTRL2 2
#define CTRL3 3

// set I/O pins used in addition to clock, data in, data out
const byte slaveSelectPin = 10;  // digital pin 10 for /CS
const byte SPICLK = 13;  // digital pin for SPI Clock
const byte SPIMISO = 12;  // digital pin for MISO
const byte SPIMOSI = 11;  // digital pin for MOSI

// analog calibration numbers
#define ADCMID 131072   // 2^17 is 0 with 18-bit offset binary
#define VMINUS 2492000.0    // negative analog Vinput (microvolts)
#define TWOE18 262144   // 2^18
#define VFS (1.236*2)        // ADC Volts full-scale = 2(VrefP-VrefN)
#define LSBSIZE (VFS/TWOE18)
#define AVERAGES 48    // for approx 100 millisecond output period

void setup() {
 
    Serial1.begin(115200);      // set up serial port #1 output at this baud rate
    delay(3000);
    SPI.begin(); // initialize SPI, configures SPIMOSI,SPIMISO,SPICLK signals
    pinMode (slaveSelectPin, OUTPUT);   // make CS/ pin an output
    digitalWrite(slaveSelectPin,HIGH);  // CS/ chip select is active low   
    SPI.setBitOrder(MSBFIRST);  // data is clocked in MSB first
   
    // MAX11209 max SPI clock is 5 MHz (assuming no problem with long wires...)
    // SPI.setClockDivider(SPI_CLOCK_DIV16);  // this cmd is not currently supported on Teensy 3.0 beta 5

    Serial1.println("sec,degC");
    Serial1.println("# MAX11209 ADC Test Oct 12 2012");

    initADC();

    // ==== ADC SAMPLING RATE set by this SendCmd() command
    // Possible sampling rates: 1-120 Hz in single shot; 60-480 Hz in continuous
   
    SendCmd(0b10000111); // start converting at Max Rate 120/480 sps
//    SendCmd(0b10000100); // start converting at Rate 15/60 sps
    digitalWrite(slaveSelectPin,LOW);   // enable chip, to monitor RDY/DATA for "conversion ready"
    for (int i=0; i<16; i++) {
      readADC();   // First few readings in continuous mode are invalid (settling time)
    }
}

void loop() { //             ================ MAIN LOOP ===========================
long adcSum;
 
  adcSum = 0;
  for (int i=0;i<AVERAGES;i++) {
    adcSum += readADC();   // get 18 bit ADC reading
  }
 
  float Vin = ((float)(adcSum - (ADCMID*AVERAGES)) * (LSBSIZE/AVERAGES));
  Serial1.println(Vin*100.0,4);          // send ADC value out serial port
     
} //  =================== END of main loop() =================================

// ======================== set up ADC chip registers ==============
void initADC(void) {

// NOTE: if Signal or Ref buffer ON, Sig or Ref must be 100 mV above GND and 100 mV below AVdd
// with buffers OFF, Sig and Ref can swing over full range (actually, 30 mV beyond rails)

/* SCYCLE: The single-cycle bit, SCYCLE, determines if the device runs in “no-latency”
single-conversion mode (SCYCLE = 1) or continuously (SCYCLE = 0). When in single-cycle
conversion mode, the device completes one no-latency conversion and then powers down
into a leakage-only state. When in continuous mode, the part is continuously converting
and the first three data from the part are incorrect due to the SINC4 filter latency.  */

//  WriteReg8(CTRL1, 0b00011110); // 60 Hz,bipolar,intClk,RefBuf,SigBuf,Offset,SingleCycle
//  WriteReg8(CTRL1, 0b00000110); // 60 Hz,bipolar,intClk,NoRefBuf,NoSigBuf,Offset,SingleCycle
    WriteReg8(CTRL1, 0b00000100); // 60 Hz,bipolar,intClk,NoRefBuf,NoSigBuf,Offset,Continuous
    WriteReg8(CTRL2, 0b11110010); // DIO1-4 all outputs, set 4 output pins to 0010
    WriteReg8(CTRL3, 0b00011000); // Gain=1,no system gain/offset, use self-cal gain/offset
   
    SendCmd(0b10010000); // start self-calibration cycle
    delay(220);    // self-calibration takes 200 msec
   
} // end initADC()

// =======================================================
//   Get ADC data from 24-bit register 4.
long readADC(void) {
 
  do {} while (digitalRead(SPIMISO) == HIGH);  // wait for next ADC conversion result to be ready

  digitalWrite(slaveSelectPin,LOW);   // take the SS pin low to select the chip
  long result = SPI.transfer(0b11001001); // send command to read register 4
  result |= SPI.transfer(0x00);   // obtain high-order byte
  result = result << 8;          // shift left one byte
  result |= SPI.transfer(0x00);   // obtain 2nd byte
  result = result << 8;          // shift left one byte
  result |= SPI.transfer(0x00);   // obtain low-order byte
 
  digitalWrite(slaveSelectPin,HIGH);   // take the SS pin high, ending SPI transaction
  digitalWrite(slaveSelectPin,LOW);   // enable chip, to monitor RDY/DATA for "conversion ready" 
  result = result >> 6;         // 24-bit word: 18 data bits, and low-order 6 bits = 0
  return(result);
}

// ===================  read an 8-bit register (Registers 0,1,2,3)
UC ReadReg8(UC addr) {
// mode 1 command byte
// b7 b6 b5 b4  b3  b2  b1  b0
// 1  1  0  RS3 RS2 RS1 RS0 1   (b0 = W/R)

digitalWrite(slaveSelectPin,LOW);   // take the SS pin low to select the chip
UC a = (addr << 1) | 0b11000001;  // set b7,b6,b0 = 1
a &= 0b11011111;    // set b5 = 0
UC result = SPI.transfer(a);   // send command to read register 'addr'
result = SPI.transfer(0x00);   // obtain 1-byte register value
digitalWrite(slaveSelectPin,HIGH);   // take the SS pin high to deselect chip
return(result);
} // end ReadReg8()

// =======================================================
// write an 8-bit register (Registers 0,1,2,3)

void WriteReg8(UC addr, UC data) {
// mode 1 command byte
// b7 b6 b5 b4  b3  b2  b1  b0
// 1  1  0  RS3 RS2 RS1 RS0 0   (b0 = W/R)

digitalWrite(slaveSelectPin,LOW);   // DEBUG
delay(4);  // DEBUG
digitalWrite(slaveSelectPin,HIGH);  // DEBUG
delay(4); // DEBUG

digitalWrite(slaveSelectPin,LOW);   // take the SS pin low to select the chip
UC a = (addr << 1) | 0b11000000;  // set b7,b6 = 1
a &= 0b11011110;    // set b5,b0 = 0
SPI.transfer(a);   // send command to read register 'addr'
SPI.transfer(data);   // obtain 1-byte register value
digitalWrite(slaveSelectPin,HIGH);   // take the SS pin high to deselect chip

} // end WriteReg8()


// =======================================================
// send Command Byte (MODE = 0)

void SendCmd(UC data) {
// === mode 0 command byte format =======
// b7 b6 b5   b4   b3   b2    b1    b0
// 1  0  CAL1 CAL0 IMPD RATE2 RATE1 RATE0
digitalWrite(slaveSelectPin,LOW);   // take the SS pin low to select the chip
UC a = data | 0b10000000;  // set b7 = 1
a &= 0b10111111;    // set b6 = 0
SPI.transfer(a);   // send command byte
digitalWrite(slaveSelectPin,HIGH);   // take the SS pin high to deselect chip
} // end SendCmd()

// =======================================================
// read a 24-bit register (Registers 4,5,6,7,8)

long ReadReg24(UC addr) {
// mode 1 command byte
// b7 b6 b5 b4  b3  b2  b1  b0
// 1  1  0  RS3 RS2 RS1 RS0 W/R

digitalWrite(slaveSelectPin,LOW);   // take the SS pin low to select the chip
UC a = (addr << 1) | 0b11000001;  // set b7,b6,b0 = 1
a &= 0b11011111;    // set b5 = 0
long result = SPI.transfer(a);   // send command to read register 'addr'
result |= SPI.transfer(0x00);   // obtain high-order byte
result = result << 8;          // shift left one byte
result |= SPI.transfer(0x00);   // obtain 2nd byte
result = result << 8;          // shift left one byte
result |= SPI.transfer(0x00);   // obtain low-order byte
digitalWrite(slaveSelectPin,HIGH);   // take the SS pin high to deselect chip

return(result);  // return 24-bit value
 
} // end ReadReg24()
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 arrived

Postby jbeale » Wed Oct 24, 2012 12:54 am

The new touch sensing function is pretty neat. I get a very noticeable capacitance change when I bring my finger within 1 cm from a length of 22-gauge hookup wire, and then move it away. This data is from the below program (which averages many readings together, for a 500 msec update rate).

T3-Touch-2012.png
T3-Touch-2012.png (5.88 KiB) Viewed 28572 times

moving finger to 1 cm from wire, and then away
Code: Select all
val,n,p-p,stdev
#Teensy3.0 Touchprogram Oct.232012
688.03,4315,7,1.465
688.07,4318,7,1.461
687.99,4317,8,1.477
687.95,4318,7,1.454
687.81,4319,7,1.468
689.23,4315,9,1.786
691.18,4307,6,1.307
690.99,4309,6,1.302
690.90,4310,7,1.275
690.84,4308,7,1.281
690.81,4309,8,1.287
690.82,4309,7,1.290
690.58,4309,7,1.291
690.69,4309,7,1.284
688.76,4312,10,1.865
687.82,4318,7,1.458
687.78,4318,7,1.457
687.77,4317,8,1.465
687.85,4318,7,1.469
687.93,4318,7,1.466
687.94,4317,7,1.465
687.81,4319,7,1.459
687.77,4317,7,1.451
687.87,4318,7,1.460
687.77,4317,7,1.477
688.02,4318,8,1.478
687.93,4318,7,1.472


Grabbing the insulated portion of the wire, then the bare end of the wire- a big signal. The pk-pk reading change and standard deviation also goes through the roof when touching the wire, I assume that is 60 Hz pickup. The T3 is connected to my computer via its USB cable during these tests.
Code: Select all
val,n,p-p,stdev
# Teensy 3.0 Touch program Oct. 23 2012
908.20,3713,18,2.854
910.23,3708,22,2.910
912.22,3704,23,3.007
831.56,3901,233,102.050
689.36,4312,8,1.458
689.57,4313,9,1.502
1230.76,3084,2859,877.954
3574.54,1376,981,155.670
3795.12,1308,941,170.153
3923.82,1272,1118,186.593
4035.86,1242,1058,194.914
2393.54,1911,3912,1677.471
688.00,4315,8,1.540
687.82,4318,7,1.438
687.85,4317,7,1.445


Touch sensing example code:
Code: Select all
/*  Test capacitive touch sensor function on Teensy 3.0
    using Teensy 3.0 beta 6 (Windows) release    J.Beale Oct. 23 2012
*/

#define SAMPLES (5000)   // maximum number of separate readings to take
#define TIMEOUT (500)    // maximum sample integration time in milliseconds

int led = 13;

void setup() {               
  pinMode(led, OUTPUT);     
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(3000);               // wait for user to start up logging program
  Serial.begin(115200);       // baud rate is ignored with Teensy USB ACM i/o
  delay(2000);
  Serial.println("val,n,p-p,stdev");
  Serial.println("# Teensy 3.0 Touch program Oct. 23 2012");
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
}

void loop() {
int t1;
long tStart;  // starting time
long datSum;  // reset our accumulated sum of input values to zero
int sMax;
int sMin;
long n;            // count of how many readings so far
double x,mean,delta,sumsq,m2,variance,stdev;  // to calculate standard deviation

  datSum = 0;
  sumsq = 0; // initialize running squared sum of differences
  n = 0;     // have not made any ADC readings yet
  mean = 0; // start off with running mean at zero
  m2 = 0;
  sMax = 0;
  sMin = 65535;
         
  tStart = millis();
  for (int i=0;i<SAMPLES && ((millis()-tStart)<TIMEOUT);i++) {
            x = touchRead(A1);
            datSum += x;
            if (x > sMax) sMax = x;
            if (x < sMin) sMin = x;
                  // from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
            n++;
            delta = x - mean;
            mean += delta/n;
            m2 += (delta * (x - mean));
          }
  variance = m2/(n-1);  // (n-1):Sample Variance  (n): Population Variance
  stdev = sqrt(variance);  // Calculate standard deviation

  Serial.print(mean);
  Serial.print(","); 
  Serial.print(n);
  Serial.print(","); 
  Serial.print(sMax-sMin);
  Serial.print(","); 
  Serial.println(stdev,3);
}
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm

Re: Teensy 3.0 arrived

Postby jbeale » Fri Oct 26, 2012 8:00 pm

By the way, Paul has now set up a forum of his own for Teensy discussion. It is at http://forum.pjrc.com/forum.php
jbeale
Full Member
Full Member
 
Posts: 158
Joined: Thu Jan 13, 2011 6:48 pm


Return to General discussion