Basic USB HID test failing...

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Basic USB HID test failing...

Post by fpp » Sat Sep 10, 2016 1:38 pm

I'm having no success using the pyboard as an USB HID (keyboard) device.

Even the simplest test I can think of fails :

Code: Select all

# boot.py -- run on boot-up
# can run arbitrary Python, but best to keep it minimal
import machine
import pyb
#~ pyb.main('main.py') # main script to run after this one
#~ pyb.usb_mode('CDC+MSC') # act as a serial and a storage device
pyb.usb_mode('CDC+HID', hid=pyb.hid_keyboard) # act as a serial device and a keyboard

Code: Select all

# main.py -- put your code here!
import pyb
kb = pyb.USB_HID()
def onSwitch():
    kb.send(bytearray(b'Hello World !'))
sw = pyb.Switch()
sw.callback(onSwitch)
After a reset, the USB mass storage disappears as expected.
But when I press the button, the window that has focus on the PC receives nothing,
and the serial console shows (part of) an error :

Code: Select all

MicroPython v1.8.2 on 2016-07-10; PYBv1.1 with STM32F405RG
Type "help()" for more information.
>>> Uncaught exception in ExtInt interrupt handler line 3
MemoryError:

Am I missing something obvious here ?... any hints welcome :-)

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Basic USB HID test failing...

Post by dhylands » Sat Sep 10, 2016 5:00 pm

The MemoryError inside the ExtInt handler is happening because you're trying to allocate memory from within an interrupt handler.

I recommend that you read through this: http://docs.micropython.org/en/latest/p ... =interrupt

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Basic USB HID test failing...

Post by dhylands » Sat Sep 10, 2016 5:05 pm

I see a couple of problems with your code:

1 - Instead of

Code: Select all

def onSwitch():
    kb.send(bytearray(b'Hello World !'))
you should assign a variable to the message you want outside the handler:

Code: Select all

msg = bytearray(b'Hello World !')
def onSwitch():
    kb.send(msg)
I don't know if kb.send tries to allocate memory or not, so I'm not 100% sure that this will work as rewritten.

2 - After assigning the callback, you exit main, which means that it will return to the REPL. I'm not sure that this is what you intended.

fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Re: Basic USB HID test failing...

Post by fpp » Sat Sep 10, 2016 7:46 pm

Thanks a lot for looking into this Dave !

1) was not at all obvious to me until I followed your pointer, thanks for that too.
I'll fix that and see what gives...
Now I understand better some remarks I saw in the forum, about the "culture shock" of writing in a well-known high-level language, but having to mind some very low-level, platform-dependent details...
Right now, I must admit that getting my upython code to work on the pyboard is actually more difficult than copy/pasting C++ (that I don't really try to understand) to an Arduino :-)
But it's a young platform, it will get better yet.

2) is definitely in obvious-land, but it's not what I intend *eventually*.
The goal is to use a keypad, by the usual method of scanning the 3 or 4 lines and cols inside a loop.
(I did this on a raspberry a while ago, but didn't find an example for upython devices)
What I wanted to assert here is the USB HID part, so seeing it work once with the user button will be enough :-)

Now back to the pyboard...

fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Re: Basic USB HID test failing...

Post by fpp » Sat Sep 10, 2016 8:30 pm

Well, after correcting 1) I no longer get the exception report in the REPL, but still nothing printed to the focused editor either...

I know the callback is working, as it also blinks a DEL and prints a trace to the REPL.
Maybe something missing in the pyb.USB_HID() call ?

fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Re: Basic USB HID test failing...

Post by fpp » Sat Sep 10, 2016 8:42 pm

More likely it's the "send" call :

viewtopic.php?t=2021

Seems I need to send one char at a time, not a string...

fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Re: Basic USB HID test failing...

Post by fpp » Sun Sep 11, 2016 10:06 am

As per the linked post (that is supposed to work now), main.py is now :

Code: Select all

# main.py -- put your code here!
import pyb

kb = pyb.USB_HID()
buf = bytearray(8)

def onSwitch():
    buf[2] = 0x04
    kb.send(buf)
    pyb.delay(10)
    buf[2] = 0x00
    kb.send(buf)

sw = pyb.Switch()
sw.callback(onSwitch)
No errors in REPL, but still nothing appears on the host PC...

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Basic USB HID test failing...

Post by dhylands » Sun Sep 11, 2016 6:11 pm

Calling delay from within an ISR is often problematic. Since you're in an ISR, some level of ISRs are disabled. Calling delay often requires some other ISR to run in order to work properly, and it might be that you're disabling it because of the ISR you're in.

I would try seeing if you can get a non-ISR based solution working first.(i.e. use a loop and call sw() to see if the switch is pressed. Then you can use all of the delays and stuff you like.

fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Re: Basic USB HID test failing...

Post by fpp » Sun Sep 11, 2016 7:34 pm

Thanks again Dave ! I will give this a try on my next tinkering slot :-)

I do seem to recall trying the above code without the delays, initially, with the same results.
But after all there's nothing to lose...

Come to think of it, I might also try without a loop, and just send a single char through USB on boot :-)

fpp
Posts: 64
Joined: Wed Jul 20, 2016 12:08 pm

Re: Basic USB HID test failing...

Post by fpp » Mon Sep 12, 2016 6:58 pm

Okay, so here is the new test bed without ISR/callback :

Code: Select all

# main.py -- put your code here!
import pyb

kb = pyb.USB_HID()
led = pyb.LED(1)
check = "btn press"
buf = bytearray(8)
sw = pyb.Switch()

while 1 :
    pyb.delay(100)
    if sw() :
        print(check)
        led.toggle()
        led.toggle()
        buf[2] = 0x04
        kb.send(buf)
        pyb.delay(10)
        buf[2] = 0x00
        kb.send(buf)
Results when pressing button :
LED blinks
"btn press" printed in the serial console
nothing in the focused window

...so I'm almost certainly missing something in the elusive USB_HID docs and/or example found above...

Post Reply