RSS Add a new post titled:

Snek Adopts More Python Scoping

Python's implicit variable declarations are tricky and Snek had them slightly wrong. Fixing this meant figuring out how they work in Python, then figuring out the simplest possible expression to make the result fit in the ROM.

Local Variable Declaration

Local variables are declared in Python either as formal parameter names, or by placing them on the left hand side of a simple assignment operator:

def foo(a, b):
    c = 12
    return a + b + c

There are three local variables in function foo — a, b and c.

Global Variable Declaration

Global variables are declared in Python in one of two ways:

1) A simple assignment at global scope

2) A simple assignment in a function which also has a 'global' statement including the same name

a = 12

def foo(c):
    global b
    b = c

This defines both 'a' and 'b' as globals.

Global Variable Usage

Global variables can be used within functions without explicitly declaring them.

a = 12

def foo(c):
    return a + c

You may be explicit about a's scope using a 'global' statement

a = 12

def foo(c):
    global a
    return a + c

These two forms are equivalent, unless you also include an assignment expression with a on the LHS (left hand side):

a = 12

def foo(c):
    a = 13
    return a + c

is not the same as

a = 12

def foo(c):
    global a
    a = 13

as the former declares a new local, 'a', and leaves the global unchanged while the latter changes the global value.

Local Variable Usage

Python3 does whole-function analysis to figure out whether a name is local or not. If there is any assignment of a name within a function, that name references a local variable. Consider the following:

a = 12

def foo(c):
    b = a + c
    return b

def bar(c):
    b = a + c
    a = 1
    return b

The function 'foo' references the global named 'a', while the function 'bar' attempts to reference the local named 'a' before it has been assigned a value and, hence, generates an error.

Snek doesn't do this whole-function analysis, so 'bar' uses the global 'a' in the first statement as it hasn't yet reached the definition of 'a' as a local variable.

Augmented Assignments

Python Augmented Assignment statements are similar to C's Compound assignment operators — +=, *=, /=, etc. The Python reference has this to say about them:

"An augmented assignment expression like x += 1 can be rewritten as x = x + 1 to achieve a similar, but not exactly equal effect."

Because they work similar to assignment statements, they can declare a new variable in the current scope, if no such name has been included in previous assignment, global or non-local statements. Also, because they reference the variable on the RHS (right hand side), they need that variable to have already been defined before this statement executes.

Scoping in Snek

Because Snek doesn't do whole-function analysis, it can't 'see' later assignments in a function, and so a function with a use-before-assignment generates the following (non-Pythonic) result:

a = 12

def foo(c):
    b = a + c
    a = 1
    return b

> foo(13)
25

Fixing this would require additional tracking within the compiler, which I may add at some point, but for now, saving memory during compilation seems useful.

Snek Augmented Assignments

While Snek doesn't currently handle the general case of use-before-assignment involving separate statements, the simpler case with augmented assignments doesn't require saving any state during compilation and seems like something more useful to catch as without it, you would get:

a = 12

def foo(c):
    a += c
    return a

> foo(13)
25
> a
12

The value of 'a' is left as 12 because the augmented assignment fetches 'a' first, which finds the global variable 'a', but then when it assigns the resulting value, it creates a new local variable 'a', just as if this code looked like:

a = 12

def foo(c):
    b = a + c
    return b

Checking this case requires adding a special-case for augmented assignment within a function to see if the name has been declared or included in 'global' statement in the function.

Posted Sun May 26 18:02:06 2019 Tags:

ItsyBitsy Snek — snek on the Adafruit ItsyBitsy

I got an ItsyBitsy board from Adafruit a few days ago. This board is about as minimal an Arduino-compatible device as I can imagine. All it's got is an Atmel ATmega 32U4 SoC, one LED, and a few passive components.

I'd done a bit of work with the 32u4 under AltOS a few years ago when Bdale and I built a 'companion' board called TeleScience for TeleMetrum to try and measure rocket airframe temperatures in flight. So, I already had some basic drivers for some of the peripherals, including a USB driver.

USB Adventures

The 32u4 USB hardware is simple, and actually fairly easy to use. The AltOS driver used a separate thread to manage the setup messages on endpoint 0. I didn't imagine I'd have space for threading on this device, so I modified that USB driver to manage setup processing from the interrupt handler. I'd done that on a bunch of other USB parts, so while it took longer than I'd hoped, I did manage to get it working.

Then I spent a whole bunch of time reducing the code size of this driver. It started at about 2kB and is now almost down to 1kB. It's a bit less robust now; hosts sending odd setup messages may get unexpected results.

The last thing I did was to add a FIFO for OUT data. That's because we want to be able to see ^C keystrokes even while Snek is executing code.

Reset as longjmp

On the ATmega 328P, to reset Snek, I just reset the whole chip. Nice and clean. With integrated USB, I can't reset the chip without losing the USB connection, and that would be pretty annoying. Resetting Snek's state back to startup would take a pile of code, so instead, I gathered all of the snek-related .data and .bss variables by changing the linker script. Then, I wrote a reset function that does pretty much what the libc startup code does and then jumps back to main:

snek_poly_t
snek_builtin_reset(void)
{
    /* reset data */
    memcpy_P(&__snek_data_start__,
         (&__text_end__ + (&__snek_data_start__ - &__data_start__)),
          &__snek_data_end__ - &__snek_data_start__);

    /* reset bss */
    memset(&__snek_bss_start__, '\0', &__snek_bss_end__ - &__snek_bss_start__);

    /* and off we go! */
    longjmp(snek_reset_buf, 1);
    return SNEK_NULL;
}

I still need to write code to reset the GPIO pins.

Development Environment

To flash firmware to the device, I stuck the board into a proto board and ran jumpers from my AVRISP cable to the board.

Next, I hooked up a FTDI USB to Serial converter to the 32u4 TX/RX pins. Serial is always easier than USB, and this was certainly the case here.

Finally, I dug out my trusty Beagle USB analyzer. This lets me see every USB packet going between the host and the device and is invaluable for debugging USB issues.

You can see all of these pieces in the picture above. They're sitting on top of a knitting colorwork pattern of snakes and pyramids, which I may have to make something out of.

Current Status

Code for this part is on the master branch, which is available on my home machine as well as github:

I think this is the last major task to finish before I release snek version 1.0. I really wanted to see if I could get snek running on this tiny target. It's nearly there; I want to squeeze a few more things onto this chip.

Posted Mon May 20 00:17:45 2019 Tags:

Snek and Neopixels

(click on the picture to see the movie)

Adafruit sells a bunch of things using the Neopixel name that incorporate Worldsemi WS2812B full-color LEDs with built-in drivers. These devices use a 1-wire link to program a 24-bit rgb value and can be daisy-chained to connect as many devices as you like using only one GPIO.

Bit-banging Neopixels

The one-wire protocol used by Neopixels has three signals:

  • Short high followed by long low for a 0 bit
  • Long high followed by a short low for a 1 bit
  • Really long low for a reset code

Short pulses are about 400ns, long pulses are around 800ns. The reset pulse is anything over about 50us.

I'd like to use some nice clocked signal coming out of the part to generate these pulses. A SPI output would be ideal; set the bit rate to 400ns and then send three SPI bits for each LED bit, either 100 or 110. Alas, none of the boards I've got connect the Neopixels to a pin that can be used as for SPI MOSI.

As a fallback, I tried using DMAC to toggle the GPIO outputs. Alas, on the SAMD21G part included in these boards, the DMAC controller can't actually write to the GPIO control registers. There's a missing connection inside the chip.

So, like all of the examples I found, I fell back to driving the GPIO registers directly with the processor, relying on a carefully written sequence of operations to get the timing within the tolerance required by the Neopixels. I have to disable interrupts during this process to avoid messing up the timing though.

Current Snek Neopixel API

I looked at the Circuit Python Neopixel API to see if there was anything I could adapt for Snek. That API uses 3-element tuples for the R,G,B values, and then places those in a list, one for each pixel in the chain. That seemed like a good idea. However, that API also has a lot of allocation churn, with new colors being created in newly allocated lists. Doing that with Snek would probably be too slow as Snek uses a garbage collector for allocation.

So, we'll allow mutable lists inside of a list or tuple, then Neopixel colors can be changed by modifying the value within the per-Neopixel lists.

Snek doesn't have objects, so we'll just create a function to send color data for a list of Neopixels out a pin. We'll use the existing Snek GPIO function, talkto, to select the pin. Finally, I'm using color values from 0-1 instead of 0-255 to make this API work more like the other analog interfaces.

> pixels = ([0.2, 0, 0],)
> talkto(NEOPIXEL)
> neopixel(pixels)

That make the first Neopixel a not-quite-blinding red. Now we can turn it green with:

> pixels[0][0] = 0
> pixels[0][1] = 0.2
> neopixel(pixels)

You can, of course, use tuples like with Circuit Python:

> pixels = [(0.2, 0, 0)]
> talkto(NEOPIXEL)
> neopixel(pixels)
> pixels[0] = (0, 0.2, 0)
> neopixel(pixels)

This does allocate a new list though.

Snek on Circuit Playground Express

As you can see in the pictures above, Snek is running on the Adafruit Circuit Playground Express. This board has a bunch of built-in hardware. At this point, I've got the buttons, switches, lights and analog input sensors (temperature and light intensity) all working. I don't have the motion sensor or audio bits going. I'll probably leave those pieces until after Snek v1.0 has been released.

Posted Tue May 14 17:02:06 2019 Tags:

Snek and the Amusement Park

(you can click on the picture to watch the model in action)

Here's an update to my previous post about Snek in a balloon. We also hooked up a Ferris wheel and controlled them both with the same Arduino Duemilanove compatible board. This one has sound so you can hear how quiet the new Circuit Cube motors are.

Posted Fri May 10 16:45:16 2019 Tags:

Snek on the Arduino Mega 2560 Rev3

The Arduino Mega 2560 Rev3 is larger in almost all ways than the ATmega328P based Arduino boards. Based on the ATMega 2560 SoC, the Mega has 256K of flash, 8K of RAM and 4K of EEPROM. The processor and peripherals are compatible with the ATMega 328P making supporting this in Snek pretty easy.

ATMega238P to ATMega2560 changes

All that I needed to do for Snek to compile for the Mega was to adjust the serial port code to use the Mega register names. gcc-avr prefixes all of the USART registers with 'USART0' for the 2560 instead of 'USART'. With that change, Snek came right up on the board.

GPIO Changes

To get the Arduino Mega pins all working, I had to add definitions for all 70 of them. That's a lot of pins! I took the definitions from the Arduino sources and matched up all of the PWM outputs as well.

USB Serial Adventures

The Arduino Duemilanove uses an FTDI USB to Serial converter chip, while the Arduino Mega uses an ATmega 16u2 SoC. The FTDI exposes a custom USB device while the ATmega16u2 implements a standard CDC ACM device.

The custom USB device provides full serial control, including support for selecting XON/XOFF flow control. The CDC ACM standard only exposes configuration for RTS/CTS flow control, but doesn't provide any way to ask for XON/XOFF flow control.

The Arduino programming protocol requires a transparent 8-bit data path; because the CDC ACM standard doesn't provide a way to turn XON/XOFF on and off, the ATmega 16u2 never does XON/XOFF.

Snek needs XON/XOFF flow control to upload and download code over the serial link.

I was hoping to leave the ATmega 16u2 code and ATmega 2560 boot loader alone. This would let people use Snek on the Arduino Mega without needing a programming puck. And, in fact, Snek works just fine. But, you can't use Snekde with the Mega because getting and putting code to the device ends up with corrupted data.

So, I changed the ATmega 16u2 code to enable XON/XOFF whenever the baud rate is below 57600 baud, left Snek running at 38400 baud while the boot loader uses 115200 baud. The result is that when Snek runs, there is XON/XOFF flow control, and when the boot loader runs, there is not.

Results

With the extra ROM, I was able to include all of the math functions. With the extra RAM, the heap can be 6kB. So much space!

Posted Thu May 2 20:45:35 2019 Tags:

Snek Drives a Lego Car

(click on the picture to see the movie)

This is made from:

You can get everything other than the light sensors from various vendors.

More Pictures

Here's a picture from the front showing the light and light sensor mounted next to each other.

And here's the car from the rear showing the motor connections, the other light sensor/light combination and the battery pack:

Source Code

This program is a bit more verbose:

    mr = (MOTOR1A, MOTOR1B)
    ml = (MOTOR2A, MOTOR2B)

    pf = SIGNAL1
    pr = SIGNAL2

    f_speed = 0.5
    r_speed = 0.5
    t_speed_f = 0.6
    t_speed_s = 0.2

    def forw():
        talkto(mr)
        setpower(f_speed)
        setright()
        on()
        talkto(ml)
        setpower(f_speed)
        setleft()
        on()

    def back():
        talkto(mr)
        setpower(r_speed)
        setleft()
        on()
        talkto(ml)
        setpower(r_speed)
        setright()
        on()

    def left():
        talkto(mr)
        setpower(t_speed_f)
        setright()
        on()
        talkto(ml)
        setpower(t_speed_f)
        setright()
        on()

    def right():
        talkto(mr)
        setpower(t_speed_f)
        setleft()
        on()
        talkto(ml)
        setpower(t_speed_f)
        setleft()
        on()

    def stop():
        talkto(ml)
        setpower(0)
        off()
        talkto(mr)
        setpower(0)
        off()

    def go_forw():
        forw()
        listento(pf)
        while read() < .25:
            pass
        stop()

    def go_back():
        back()
        listento(pr)
        while read() < .25:
            pass
        stop()

    def bumper():
        while True:
            go_forw()
            back()
            time.sleep(0.5)
            stop()
            left()
            time.sleep(0.25)
            stop()
            go_forw()
            go_back()
            go_forw()

    bumper()
Posted Sun Apr 21 22:33:29 2019 Tags:

Snek and a Balloon

(you can click on the picture to watch the model in action)

This represents the scale of projects we typically do in our Lego class. A motor, a couple of sensors and some simple logic. Here's the Snek program driving the balloon:

# Make the balloon go up and down

motor = (D9, D8)
top = A0
bottom = A1

def up():
    talkto(motor)
    listento(top)
    setpower(0.5)
    setright()
    on()
    while read() < .8:
        pass
    off()

def down():
    talkto(motor)
    listento(bottom)
    setpower(0.3)
    setleft()
    on()
    while read() < .8:
        pass
    off()

def play():
    while True:
        up()
        time.sleep(10)
        down()
        time.sleep(10)

play()

Light Sensors and Lights

I like to use light sensors with robotics and wanted to make some new ones sensitive to visible light. I found these Vishay TEPT5600 photo-transistors which are sensitive to most visible light. Using those with a 470kΩ resistor generated a good range of outputs for indoor lights.

For a light source, I'm using Cree 5mm green LEDs with a 5V power supply and a 100Ω current limiting resistor, these draw about 20mA and generate a lot of light.

For both of these, I take a 1x4 brick and drill a 3/16" hole in one end and a 1/8" in the other. The 5mm device fits snugly in the larger hole and the wires thread out through the other hole. The 1/8W resistor is tucked inside the brick.

You can see both of these in action in the example — the white bricks contain LEDs and the red bricks contain light sensors. The path between the light and sensor is interrupted by the model, allowing the program to determine when the motion has completed.

Motors

This model uses the Circuit Cube motors that I discovered last month. There's one visible near the middle of the Ferris wheel and another one just behind the Duemilanove board driving the balloon mechanism.

These motors have a built-in gear reduction and so they offer low speed and high torque. For Lego modelers, that's a pretty useful combination as the older non-geared motors always involved a long gear-train or worm gear to provide a reasonable balance of speed and power. For the balloon, there is a string wrapping around an axle driven directly by one of these motors.

Simple Models with Simple Programs

This class uses Lego to build simple mechanical devices that are controlled with simple computer programs. The Snek environment is the latest in a long history of computer systems which started with Lego Logo on the Apple ][ over twenty years ago.

Posted Sat Apr 20 21:59:59 2019 Tags:

CrickitSnek — snek on the Adafruit Crickit

I got a Crickit FeatherWing from Adafruit today. This board is supposed to act as an I/O expander for all of the Feather boards, but it's a completely operational SAMD21 machine with a pile of useful GPIO bits:

  • 4 “Capacitive Touch” pins (which are just regular GPIOs)
  • 8 Analog input/digital output pins
  • 4 Digital I/O pins
  • 4 High-current 5V digital output pins
  • 2 H-bridge motor controllers
  • 1 Audio amplifier
  • 1 high current output designed for NeoPixels

It's also got a USB port and an on-board NeoPixel, plus headers to plug in a Feather board.

There's no Crystal on the Crickit

To save cost, the Crickit design doesn't include any crystal at all. That required re-configuring the SAMD21 clock configuration to synchronize the 48MHz system clock from USB instead of from the 32.768kHz crystal present on the Metro and Feather boards. Once I had done this, the Crickit board appeared on USB and Snek was running.

Naming the Crickit pins

There are a bunch of separate I/O groupings on the Crickit board, and I wanted to make it easy to remember how to use them. Providing convenient names for each pin seemed like the the best plan.

On the Metro and Duemilanove boards, I just used numbers for all of the pins; 0-13 for the digital pins and 14-19 for the analog pins. This matches the Arduino conventions, although it doesn't provide the convenient 0-5 numbering for analog input. Having names for these pins will also be nice.

So, I hacked up the Snek 'builtins' mechanism to include builtins with numeric values. Now you can have as many builtin values as you want. I first replaced the wacky lexer hacks for values like 'math.pi', 'True' and 'False' and then went and added names for the pins on all devices.

Snek vs TI DRV8833

The TI DRV8833 motor controller chip on the Crickit has two pins per motor -- you set one pin to ground and drive the other with a PWM signal, which pin you PWM selects the direction of the motor. This doesn't directly map to how I expected motor controllers to work in Snek. Snek expects to have one pin control direction and the other control speed.

I had to do a bit of magic to make this work, but the joy of having an interpreter between the application and the hardware is having the ability to hide these kinds of details from the application

Minor Crickit Schematics Error

The Crickit Schematics linked from the Crickit Downloads page have the DRIVE labels flipped -- DRIVEIN1 is actually hooked to PB10, DRIVEIN2 to PB11, DRIVEIN3 to PA12 and DRIVEIN4 to PA13. The Eagle schematics on github are correct; it would be nice to have the images updated as those don't require downloading proprietary software to view.

Status

All of these bits are in the Snek git repository and should be released in the next Snek version (0.97?).

Posted Sat Apr 20 00:45:59 2019 Tags:

SAMD21 USB Fixed on Windows 7

I pretty clearly missed some details when reviewing the USB traces for the SAMD21 driver because I didn't see the IN requests to the IN-Interrupt endpoint of the device. These are supposed to be NAK'd by the device because it never generates any data for this endpoint.

However, I managed to mis-configure the hardware registers controlling this end point and set it up as an OUT-Interrupt endpoint instead. This causes the hardware to simply ignore any IN requests directed at the end point, so the host never sees a NAK packet. All three operating systems (Linux, Mac OS X and Windows) eventually give up trying to communicate with the end point, which causes no ill effects on Linux and Mac OS X.

On Windows, it causes the driver to stop sending IN packets to the regular IN-Bulk endpoint after it receives one packet. “It's inconceivable” I hear you cry, but then all can say is “It's Windows”, where inconceivable becomes reality.

All Fixed.

With that minor mistake fixed, Snek on the Metro M0 Express board is running great with all three operating systems.

Posted Thu Apr 11 22:20:41 2019 Tags:

SAMD21 USB vs Windows 7

I'm mostly used to USB being really hard to get working on a new SoC, everything from generating a stable 48MHz clock to diving through thousands of register definitions to get the device programmed to receive that first SETUP packet. However, I'm used to having that part be the hardest section of the work, and once the first SETUP packet has been received and responded to successfully, it's usually down hill from there.

Not this time.

I've written about Snek on the SAMD21G18A before, and this is about the same board. USB on this device is medium-complicated, as the device supports both host and device modes, plus has a range of 'optimizations' which always makes simple operation harder. It took a few hours of hacking to get SETUP packets flowing, but after that (at least when talking to Linux and Mac OS X), the rest of the USB driver was pretty simple.

Enter Windows 7

I'm pushing towards a Snek 1.0 release and was testing snekde on Windows 7. It's working great with the classic Arduino Duemilanove, but when I plugged in the Metro M0 board, it got stuck after I typed one character. "That's Odd", I thought.

I figured it'd be a simple matter of a stuck interrupt or other minor mistake in the SAMD21 USB driver that I wrote. So, I broke out my trusty Beagle USB analyzer to see where the USB link was getting stuck.

IN-NAK ... IN DATAx ...

USB is an odd protocol; data from the device to the host has to sit in the device waiting for the host to come and ask for it. When the device is in use, the host polls for data by sending an IN packet. When there's no data to send back, the device sends a NAK reply. When there is data, the device sends a DATAx packet and the host replies with an ACK packet.

In my case, the host sends thousands of IN packets waiting for data, and the device responds with an equally huge number of NAK packets. The first time data was queued from the device to the host, the device responded to the IN packet with a DATAx packet and the host ACK'd that. After that, the host never sent another IN packet again. It would happily send it's own data using OUT packets, and the device would receive that data, and of course the usual stream of SOF (start of frame) packets were streaming along. But, not a single IN packet to be seen.

Differential Debugging

Well, I've got a lot of USB devices around here, so I hooked up one of our TeleBTv3.0 devices. That worked just fine, which was good as we've sold hundreds of those and it would kinda suck to discover that some Windows boxes weren't compatible.

A visual examination of the traces as seen captured by the Beagle analyzer didn't show anything obvious. But, it's often the little details that break things.

So, I hacked up the SAMD21 board to appear to be the same device as the TeleBT -- same VID/PID, same names, same serial number. Everything.

Now windows can't seem to tell the difference. It uses the same COM port for both at least.

I devised a simple test — plug-in the device, start PuTTY and then type two characters ('a', or 0x61). Because both devices echo whatever you send to them, this means I should get two characters back. Because they're typed separately, those two characters will be sent in separate OUT transactions, and the echos should be sent back in two IN transactions.

I captured traces from both devices:

TeleBT-v3.0 (STM32L151):

Metro M0 (SAMD21G18A):

The 'trimmed' versions elide timing and packet sequence information which can't be easily replicated exactly between the two tests; that "can't" matter, at least according to my understanding of USB. With those versions, I can do a text diff of the packet traces to find that, aside from a different number of SOF and IN-NAK transactions, the only difference appears at the end

$ diff -u stm32l.trim samd21.trim | tail +231
 0  1 B  01 04 OUT txn 61   
 1  3 B  01 04    OUT packet E1 01 BA   
 1  4 B  01 04    DATA0 packet C3 61 81 57   
 1  1 B  01 04    ACK packet D2   
-0  1 B  01 05 IN txn   [57536 POLL] 61   
-1    01 05    [57536 IN-NAK]    
+0  1 B  01 05 IN txn   [50387 POLL] 61   
+1    01 05    [50387 IN-NAK]    
 1  3 B  01 05    IN packet 69 81 0A   
 1  4 B  01 05    DATA0 packet C3 61 81 57   
 1  1 B  01 05    ACK packet D2   
-0      [1004 SOF]  [Frames: 853 - 1856]   
+0      [2000 SOF]  [Frames: 138 - 89] [Periodic Timeout]  
+0      [2000 SOF]  [Frames: 90 - 41] [Periodic Timeout]  
+0      [572 SOF]  [Frames: 42 - 613]   
 0  1 B  01 04 OUT txn 61   
 1  3 B  01 04    OUT packet E1 01 BA   
 1  4 B  01 04    DATA1 packet 4B 61 81 57   
 1  1 B  01 04    ACK packet D2   
-0  1 B  01 05 IN txn   [83901 POLL] 61   
-1    01 05    [83901 IN-NAK]    
-1  3 B  01 05    IN packet 69 81 0A   
-1  4 B  01 05    DATA1 packet 4B 61 81 57   
-1  1 B  01 05    ACK packet D2   
-0    01 01 [16 IN-NAK]  [Periodic Timeout]  
-0    01 05 [178185 IN-NAK]  [Periodic Timeout]  
-0      [2000 SOF]  [Frames: 1857 - 1808] [Periodic Timeout]  
-0    01 01 [16 IN-NAK]  [Periodic Timeout]  
-0    01 05 [147487 IN-NAK]  [Periodic Timeout]  
-0      [2000 SOF]  [Frames: 1809 - 1760] [Periodic Timeout]  
-0      [474 SOF]  [Frames: 1761 - 186]   
-0    01 05 [34876 IN-NAK]    
-0   ! 01 05 [1 ORPHANED]    
-1   U 01 05    [1 IN]    
-0    01 01 [16 IN-NAK]    
-0      Capture stopped  [Sun 31 Mar 2019 02:25:32 PM PDT]  
+0      [2000 SOF]  [Frames: 614 - 565] [Periodic Timeout]  
+0      [1163 SOF]  [Frames: 566 - 1728]   
+0      Capture stopped  [Sun 31 Mar 2019 02:36:23 PM PDT]  

You can see both boards receiving the first 'a' character and then send that back. Then both boards receive the second 'a' character, but only the stm32l gets the IN packets which it can respond with the DATAx packet containing the 'a' character. The samd21 board gets only SOF packets.

Next Steps?

I'm heading out of town on Tuesday to help with the NASA Student Launch, so I think I'll let this sit until I get back. Maybe I'll come up with a new debugging idea, or maybe I'll hear about a fancier USB monitoring device that might capture details that I'm missing.

Anyone with suggestions or comments is welcome to send them along; I'd like to get this bug squashed and finish the rest of the Snek 1.0 release process.

Posted Sun Mar 31 15:21:09 2019 Tags:

All Entries