Saturday, February 15, 2014

teensy logic analyzer - first try

I would need to be able to do logic analysis on the ADB data channel if I was going to implement ADB (although I'm intimidated by the difficulty so I may not do this), I also thought that interfacing with a microchip and getting data from it back to the computer is a really good 'next step' in learning to use the microcontroller.

So I built up a circuit which uses a 555 timer to generate a clock pulse at around 13Hz:

ohmslawcalculator/555_astable
and then I used the clock pulse of that to drive my 4017 binary counter - put a couple LEDs down to test it and it worked okay (the counter seemed to skip certain numbers every few cycles.. but I tried moving the LEDs to different output pins of the 4017 and then it looked okay).

I got this circuit working with a 9V battery, then I halved the resistors and got it working again but powered by the teensy (but not having the teensy connected to it in any other way).

Now the datasheet for the decade counter shows the kind of output you get:

so what I wanted to do what put a connector cable on each pin of port F (say) of the teensy, and then use these as probes to watch the logic levels coming out of the counter microchip. I spent a long time worrying about whether there was a danger of a short-circuit and that I needed to use a resistor to do this safely (or maybe pullups, pulldowns), I'm still not 100% sure what is safe and not but I gather that input pins are "high impedance" having internal resistance around 10k or 1M ohm, you can check the data sheets and see that the voltage output of the counter is within bounds of the acceptable voltage inputs of the micro - that was fine. So having satisfied myself that it was safe I attached some probes and started to write...


I don't know the best way to "stream" data from the teensy into my computer through the USB port - it takes time to output a packet so this severely limits the sampling rate (if I don't want to just fill the RAM up a quick capture running as fast as possible before stopping analysis and uploading it - hopefully wont need to go this route).

On the teensy site there's USB example code:
  1. https://www.pjrc.com/teensy/usb_serial.html
  2. https://www.pjrc.com/teensy/rawhid.html 
  3. https://www.pjrc.com/teensy/uart.html 
The first implements a serial terminal device on the teensy that lets you communicate with it. The second let's you send 64 byte packets directly with a command line program that prints them out, the example code there so this was already very close to what I needed to do so I picked that one to modify to get something working as soon as possible. The third says "this function returns quickly if your byte can be stored in the buffer" so that sounds really promising to me, I think this might be the best tool for this.

So here "logic.c" which is the usb example code sped up to sample about 20x faster and instead of outputting ADC inputs it just outputs the valee of the F port (all 8 pins):

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usb_rawhid.h"
#include "analog.h"

#define CPU_PRESCALE(n)    (CLKPR = 0x80, CLKPR = (n))

volatile uint8_t do_output=0;
uint8_t buffer[64];

int main(void)
{
    uint8_t i;
    uint16_t count=0;

    // set for 16 MHz clock
    CPU_PRESCALE(0);
  
    // set the F port to act as input pins without a pullup resistor
    PORTF = 0;
    DDRF = 0;

    // Initialize the USB, and then wait for the host to set configuration.
    // If the Teensy is powered without a PC connected to the USB port,
    // this will wait forever.
    usb_init();
    while (!usb_configured()) /* wait */ ;

    // Wait an extra second for the PC's operating system to load drivers
    // and do whatever it does to actually be ready for input
    _delay_ms(1000);

        // Configure timer 0 to generate a timer overflow interrupt every
        // 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock
        TCCR0A = 0x00;
        TCCR0B = 0x05;
        TIMSK0 = (1<<TOIE0);

    while (1) {
        // if time to send output, transmit something interesting
        if (do_output) {
            do_output = 0;
            // send a packet, first 2 bytes 0xABCD
            buffer[0] = 0xAB;
            buffer[1] = 0xCD;
             // put input pin values in the next byte
            buffer[2] = PINF;
            // most of the packet filled with zero
            for (i=3; i<62; i++) {
                buffer[i] = 0;
            }
            // put a count in the last 2 bytes
            buffer[62] = count >> 8;
            buffer[63] = count & 255;
            // send the packet
            usb_rawhid_send(buffer, 50);
            count++;
        }
    }
}

// This interrupt routine is run approx 61 times per second.
ISR(TIMER0_OVF_vect)
{
    static uint8_t count=0;

    // set the do_output variable every 2/20 seconds
    if (++count > 3) {
        count = 0;
        do_output = 1;
    }
}


so running this went fine, nothing exploded - and I extracted the bytes from the packets, converted to a binary file with

#include <stdio.h>

void main(void) {
  char b;
  while(1 == scanf("%x", &b)) putchar(b);
}

then used the command line sigrok tool to turn it into a sigrok session, loaded it into pulseview and saw this!

shows four counter pins, brown is the clock pulse and green is the carry-out channel

next step get it sampling much faster and maybe put in some error detection!

No comments:

Post a Comment