9 January 2009

USB Part 3 – Configuring the PicPack USB library

As a personal preference, I think that state machines are evil and should be avoided like the plague. Mostly this is because of my view the source code should show precisely what should happen. State machines are different, since they show what should happen under certain circumstances and they specifically hide the workings of the “machine” as a whole. It means that the understanding of how the whole system works is in fact “outside of the code”. You need to know something beyond what is written to comprehend what happens and why. This makes debugging these systems extremely difficult.

Despite my misgivings, state machines are excellent at enabling us to create hardware cheaply since it doesn’t need to understand about what it is doing or why – it just needs to respond quickly. This is (unfortunately) the world we find ourselves in when we start playing with USB.

Let’s have a look at how pic devices, in combination with the PicPack library handle the tangled web that is USB. Our first port of call is the config.h file, which is where the PicPack library finds all its configuration details – and the USB library is no exception. Let’s pull apart the USB section from the Joy Mouse demo.

#define USB_HIGHEST_EP 1

In order to configure the appropriate data structures, the library needs to know what the highest end point number will be. In this case, it’s endpoint 1.


Is the device powered from the USB supply? Select your option here. This changes what the pic reports upstream when queried.

#define USB_EP0_OUT_SIZE 8
#define USB_EP0_OUT_ADDR 0x0500
#define USB_EP0_IN_SIZE 8
#define USB_EP0_IN_ADDR 0x0508
  #define USB_EP1_IN_SIZE 8
#define USB_EP1_IN_ADDR 0x0510

Here it starts to get a little more complex. Each endpoint for IN and OUT transactions has its own buffer. For each endpoint IN and endpoint OUT you need to decide how big transactions can be, and where the buffer will be located. You’ll need to check out the datasheet for your particular pic. In the case of the 18f4550, 0x0500 is a good place to start all the buffers. You can see they run sequentially from there. Eight bytes is just plenty for a mouse. Since we have only an IN endpoint 1 (no OUT), we only declare the IN.

// if you define it, you'll need to include this routine in your code:
// void usb_SOF_callback(uns16 frame) {
// }

Each 1ms, the USB starts a new “frame”. If you want a nice clean 1ms wake up call without having to use timers, define USB_CALLBACK_ON_SOF and create a function called usb_SOF_callback in your code.

// if you define it, you'll need to include this routine in your code:
// void usb_device_configured_callback() {
// }

USB has a state called “configured”. It means that the host has chosen a particular configuration (usually it has a choice of just one) and the PicPack library has set up the endpoints ready for action. If you’d like to get notified when this state occurs, define USB_CALLBACK_ON_DEVICE_CONFIGURED in your code and declare usb_device_configured_callback() in your code.

// if you define it, you'll need to include these routines in your code:
//void usb_handle_class_ctrl_read_callback();
//void usb_handle_class_ctrl_write_callback(uns8 *data, uns16 count);
//void usb_handle_class_request_callback(setup_data_packet sdp);

A number of different types of devices are defined by the USB standard. These are known as class compliant devices. Just to keep things fun, USB handles some transactions for class devices over endpoint 0 using control transfers. While the Joy Mouse demo does indeed handle class control transfers, it doesn’t do a lot with them. For a more complex example, including how to send data back to the host after it has made a request using a control transfer and assuming class ownership of the control transfer, see the serial (CDC) PicPack demo which we’ll cover in the next tutorial.

If your device needs to handle class control transfers, then define USB_CALLBACK_ON_CLASS_CTRL and declare the appropriate functions. Note that usb_handle_class_request_callback will be called when a class request has been received and needs action; usb_handle_class_ctrl_read_callback will be called when a transaction sending data to the host (IN) has completed, and usb_handle_class_ctrl_write_callback will be called when a transaction receiving data from the host has occurred.

// if you define it, you'll need to include these routines in your code:
//void usb_ep_data_out_callback(uns8 end_point, uns8 *buffer_location, uns16 byte_count);
//void usb_ep_data_in_callback(uns8 end_point, uns16 byte_count);

To handle data transactions that occur over endpoints other than endpoint 0, that is, non-control transfers, define USB_EP_DATA_CALLBACK. When a successful data transaction has occurred that received data from the host (OUT), usb_ep_data_out_callback will be called. You’ll be told the endpoint number, where the buffer is and how many bytes were transferred. Note that the endpoint will not be re-primed (armed) until you return from this function. When a successful data transaction has occurred that sent data to the host (IN), usb_ep_data_in_callback will be called. The Joy Mouse demo doesn’t use either of these functions.

1 comment:

Unknown said...

hi could you tell config settings for sourceboost for 20mhz pic18f2550 self power mode . i am consistently getting enumeration failed . i tried your sample code but fails .