Monday, January 19, 2015

Controlling Microchips 18F4550 as HID Custom USB device using python pyUSB

The MLA( Microchip Libraries for Applications ) ships with a MPLABX project for 18F4550 that makes the chip behave like a HID Custom device. i built the project, burnt the hex file, and was also able to test it using the plug_and_play executable provided for Linux

As per this project, there is 1 interface with 2 endpoints.
One is IN, other is OUT. Both are of type INTERRUPT.
( See usb_descriptors.c )

For the commands, see app_device_custom_hid.c.
The commands are :
  • COMMAND_TOGGLE_LED = 0x80 -- LED on RD0
  • COMMAND_GET_BUTTON_STATUS = 0x81 -- Button on RB4, pressing should bring it to Ground
  • COMMAND_READ_POTENTIOMETER = 0x37 -- ADC_CHANNEL_0

Commands should be sent on the OUT endpoint, and data received on the IN.


i wanted to write my own code to control the device. came across the pyusb framework, which looked easy to use.

Here is working code for the first 2 commands :
import usb.core
import usb.util
import sys

# find our device
dev = usb.core.find(idVendor=0x04d8, idProduct=0x003f)

# was it found?
if dev is None:
    raise ValueError('Device not found')

interface = 0

if dev.is_kernel_driver_active(interface) is True:
            print "but we need to detach kernel driver"
            dev.detach_kernel_driver(interface)

# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()

# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]

for cfg in dev:
    sys.stdout.write("ConfigurationValue:" + str(cfg.bConfigurationValue) + '\n')
    for intf in cfg:
        #print vars(intf)
        sys.stdout.write('\t' + \
                         "InterfaceNumber:" + str(intf.bInterfaceNumber) + \
                         ',' + \
                         "AlternateSetting:" + str(intf.bAlternateSetting) + \
                         '\n')
        for ep in intf:
            #print vars(ep)
            sys.stdout.write('\t\t' + \
                             "EndpointAddress:" + str(ep.bEndpointAddress) + \
                             '\n')

assert ep is not None

# toggle the led. COMMAND_TOGGLE_LED
# args : ep, value, timeout
dev.write( 1, chr(128), 100)

# read the button state. COMMAND_GET_BUTTON_STATUS
# first send the command on EP_OUT
dev.write( 1, chr(129), 100)
# read on EP_IN
ret = dev.read( 129, 100)
print "Received: %d,%d", ret[0], ret[1]
print "Button Status : " + "Released" if ret[1] == 1 else "Pressed"


Thursday, January 15, 2015

PIC Programmer using a USB to Serial Converter - HVP

Background


This is a follow up to my earlier post by the same name, for LVP. Please read that first, since it discusses the basics. In this one, i will discuss HVP.


Current Status

I am able to program the PIC12F675 in HVP mode. As expected its quite slow, takes around 2-3 mins to burn a 500 byte program.

Hardware

Obtaining a High voltage > 9V from USB

i wanted to investigate whether a high voltage could be obtained from the USB port. There are voltage-pump/ charge-pump ICs like LM2623, MAX660,
mc34063a etc. I could obtain ADM660 for Rs 175. Later i also found mc34063a which is cheaper, but i don't know if it is locally available. With just two 1uF capacitors, ADM660 delivers double the input voltage, and i was able to get 10V from the 5V of the USB port.

The problem with Txd and flip-flop at 10V

i planned to supply the 10V to the flip-flop as supply, and use the flip-flops output to drive the VPP. However, i ran into an issue here. Txd, which drove the CLK of the flip-flop, was still at 5V, and while it could reset the flip-flop, it could not set it. Hence i kept the flip-flop at 5V, and added a NPN transistor to provide the 10V.
The VCC of the transistor was 10V from the ADM660. Output of the flip-flop was fed as input to base. emitter to ground. The Output from collector now provided the high voltage to VPP. Rbase=Rload=10k.


The working circuit

The circuit is powered by the usb port on the right. The Flip-flop with the LED indicating its output state is on the left. Next comes the transistor which changes the fip-flop output from 5V to 10V. Next comes the ADM660 voltage-doubler which provides the VCC of 10V for the transistor. Last is the PIC12F675, which gets its VPP from the transistor output.



Software

This time, i tried out a new software : pickle( old version is called k8048) from kewl.org, written in C. (This site also has a nice list of PICs that support LVP.) It supports a lot of PICs and modes, and is simple and easy to modify. I had to modify it, since it depends on the usb-serial-port to support the BREAK functionality, which my adapter does not.
The change is to introduce a new config param( bit-rule) VPP_TOGGLE_ON_PULSE, and alter the set_vpp() method so that it when VPP_TOGGLE_ON_PULSE is true, it sends a single 0 instead of the BREAK functionality.

The .k8048 file should be created in the home directory, and has the config.

the ktest command helps to check whether the pins have correct voltages.
 
For serial-port option, the connections are fixed in the code, not in the .k8048 file. So DTR->PGD, PGD->CTS,RTS->CLK and Txd->Vpp. You need to follow these exactly. 
 
The common reason for "device not detected" is that Vpp is not properly applied. Confirm that you have a Vpp > VDD + 3.5 V. Check whether it turns on and off correctly. Put an LED with a 10k resistor as an indicator on it. It should be low before programming, and will go high/low during programming, and go low after its finished.
 
The command to use for programming depends on the instruction-set of the chip. For 12f675, i used k14, since it has a 14-bit instructions set.
For validating device id, i use "k14 id".

For programming, k14 program <hexfile>

Do not set any flags(bitrules), unless you understand them.
 
The zip with the modified files is available as k8048_vpp_pulsed.zip under http://milunsagle.in/webroot/downloads/

More to come...