J. Mike Rollins (Sparky) [rollins@wfu.edu]
Hyperbola New
My Cats New
Kitty New
Mike is on
Green Cycle Design Group
  My Stuff  
  My Truck  
   AC Inverter
   Taz (My EV)
   PIC Switch
   LM3524 Motor Control
      18F Setup
      18F Firmware
      18F USB Driver
   SMP with 317
   Power Supply
   Function Gen
   Simulator: Zener
   Charge Controller
   IR Audio
   PWM with 555
   Entertainment Center
   GPS & WD-C2401P
Jacob's Ladder
My House
My Cars
My Cats New
My Jokes
Pi Poetry
Toro Mower
Speed of a Piston
Not a Pipe

Disclaimer:The following are my notes. As I am learning electronics, I am making my notes available. I hope they will be of benefit. However, I do not guarantee the accuracy of my work. I recommend the reader exercise critical thinking.
18F USB Driver

PIC18F4550 Driver

Please review the PIC18 Setup and PIC18 Firmware page before reading this page.

This page will cover the creation of the driver for the REPING program

REPING: A Linux server program constructs a packet of data and sends it to the PIC18F4550 microcontroller using USB communications. The microcontroller reverse the order of the bytes in the packet and send the new packet back to the server. I call this program "reping".

OS Commands

The lsusb command shows the devices connected to the USB bus. The new PIC18F4550 device shows up as "Microchip Technology Inc," with and ID of 04d8:000c. The ID portion is defined within the USB_DESCRIPTOR_DEVICE section of the usb_descriptors.c file.
 > lsusb
 Bus 001 Device 011: ID 04d8:000c Microchip Technology Inc.
The text is defined later using a USB_DESCRIPTOR_STRING descriptor.


    0x12,         // Size of this descriptor in bytes
    USB_DESCRIPTOR_DEVICE,  // DEVICE descriptor type
    . . . 
    0x04D8,       // Vendor ID 
    0x000C,       // Product ID 
    . . . 

More information about the usb device can be obtained with the the -v and the -s options of the lsusb command. The lsusb command identifies one interface, interface number 0, with two end points (EP). The first EP is an OUT end point, with address 0x01 and is configured for Bulk transfer mode. The second EP is in IN end point, with address 0x81 and is configured for Bulk transfer mode. You can compare the lsusb output with the definitions in the usb_descriptors.c code.

lsusb -v -s 001:011
  Configuration Descriptor:
    bLength                 9
    . . .
    bNumInterfaces          1
    . . .
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bNumEndpoints           2
      . . . 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               none
        wMaxPacketSize         64
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               none
        wMaxPacketSize         64
        bInterval               1
  /* Configuration 1 Descriptor */
  ROM BYTE configDescriptor1[]={
    /* Configuration Descriptor */
    . . .
    /* Interface Descriptor */
    . . . 
    0,            // Interface Number
    0,            // Alternate Setting Number
    2,         // Number of endpoints in this intf
    0x00,         // Class code
    . . . 
    /* Endpoint Descriptor */
    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP01_OUT,                  //EndpointAddress
    _BULK,                      //Attributes
    USBGEN_EP_SIZE,0x00,        //size
    1,                          //Interval
    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP01_IN,                   //EndpointAddress
    _BULK,                      //Attributes
    USBGEN_EP_SIZE,0x00,        //size
    1                           //Interval

The wMaxPacketSize corresponds to the USBGEN_EP_SIZE field. The macro USBGEN_EP_SIZE is defined in usb_config.h with a value 64.

The Microchip USB Framework provides pre-defined values for end point addresses. The EP used in the example firmware code is EP number 01. However, we reference the EP by its address. Section 9.6.6 (page 269) of the USB 2.0 Specifications defines an Endpoint Address as follows: Bit 7: Direction (0 = OUT, 1 = IN); Bit 6...4: Reserved, reset to zero; and Bit 3...0: The endpoint number.

  Bit 7 Bit 6...4 Bit 3...0  
  0 = OUT / 1 = IN Reserved EP Number  
EP Number: 1
Type: Bulk
Direction: IN
= 0x81
EP Number: 1
Type: Bulk
Direction: OUT
= 0x01

The USB Framework file \Microchip\Include\Usb\usb_device.h defines _EP01_OUT as 0x01 and _EP01_IN as 0x81. This seems to explain the origin of the EP01 addresses.

LibUSB client (user-space)

This driver is written using libusb and runs in user space. The first task of the program is to find how to reference the USB end points. This is fairly complex. The rest of the program is devoted to sending and receiving information from the USB device. reping.c

Here is the command to compile this program. The program will need to be run as the root user.

  wget http://www.camotruck.net/rollins/electronics/reping.c
  gcc -o reping.exe reping.c -lusb

Kernel Module and SYSFS

This next example is a kernel module that provides a sys filesystem interface. This module is derived from examples provided by Greg Kroah-Hartman: usbled.c and usb-skeleton.c. Also, the sysfs documentation by Patrick Mochel gave me a better understanding about sysfs.

I don't know all the tricks about adding kernel modules, but I found a way to add this module to a kernel source tree. This example assumes you have the linux-2.6.18 source. Here are the steps.

Unpack the kernel source
tar xvzf linux-2.6.18.tar.gz

Modify Kconfig
cd linux-2.6.18/drivers
Open the file Kconfig
Add the line, source "drivers/reping/Kconfig" at the end of the file, just before the endmenu tag.

Modify Makefile
cd linux-2.6.18/drivers (you should already be in this directory>
Open the file Makefile
Add the following to the end of this file:

    obj-$(CONFIG_REPING)            += reping/

Add the REPING kernel module code
Download the kernel module and install it into the directory linux-2.6.18/drivers.

  wget http://www.camotruck.net/rollins/electronics/reping.tar.gz
  tar xvzf reping.tar.gz
Now you can compile the kernel modules as usual.
  cd linux-2.6.18
  make oldconfig
  make modules
  make modules_install
To test the device, connect the USB device to the computer and insert the module.
  insmod /lib/modules/2.6.18/kernel/drivers/reping/reping.ko
Navigating through the /sys filesystem, you will find the interface for the reping module.
    [root@host]# ls -l /sys/bus/usb/drivers/reping

    total 0
    lrwxrwxrwx 1 root root    0 Jul  4 13:49 1-2:1.0 -> ../../../../devices/pci0000:0...
    --w------- 1 root root 4096 Jul  4 13:50 bind
    lrwxrwxrwx 1 root root    0 Jul  4 13:50 module -> ../../../../module/reping
    --w------- 1 root root 4096 Jul  4 13:50 new_id
    --w------- 1 root root 4096 Jul  4 13:50 unbind
A simpler way to find the interface is with the following command:
   [root@host]# ls -l /sys/bus/usb/drivers/reping/*/reping

   -rw-r--r-- 1 root root 0 Jul  4 13:51 /sys/bus/usb/drivers/reping/1-2:1.0/reping
Now we can test the device.
    [root@host]# echo "Countdown: 5 4 3 2 1" > /sys/bus/usb/drivers/reping/1-2:1.0/reping

    [root@host]# cat /sys/bus/usb/drivers/reping/1-2:1.0/reping

    1 2 3 4 5 :nwodtnuoC