revisar c18usb

83
1. LIBRERÍAS DEL USB Las librerías que aquí aparecen son un ejemplo. Dependiendo de la clase (HID, MSD, GEN, BOOT o CDC) hay algunas variaciones. En rojo aparecen los datos que hay que cambiar en cada firmware. En azul las líneas que dependen de la clase. Y en verde la parte de la librería que es código, aunque el texto en rojo y en azul también es código. Para realizar una conexión sin características específicas, lo recomendable es utilizar la clase genérica (GEN) ya que permite una velocidad más alta que la clase CDC, aunque esta última se utiliza por resultar más fácil la programación del host. Para ello se copian todas las librerías de esta clase que suministra Microchip y se modifican las líneas que aquí aparecen en rojo. Lo más importante es definir bien las interfaces y los Endpoints. Para realizar una aplicación en una clase determinada, lo más sencillo es copiar todas las librerías de esa clase, corregirlas y modificar las librerías user.h y las aquí comentadas. Haciendo esto, nos evitamos tener que modificar el código al cambiar la clase del dispositivo. Para más información visitar la página web de microchip, en la que hay ejemplos de cada clase. 1.1.1. USB.H Esta librería proporciona la forma de incluir todos los archivos necesarios del firmware del USB de Microchip. En realidad, es la única librería que hay que incluir en el programa de inicio, ya que se encarga de añadir las demás. El orden de inclusión es importante, ya que se resuelven los conflictos de dependencia con el orden correcto: #include "autofiles\usbcfg.h" #include "system\usb\usbdefs\usbdefs_std_dsc.h" #include "autofiles\usbdsc.h" #include "system\usb\usbdefs\usbdefs_ep0_buff.h" #include "system\usb\usbmmap.h" #include "system\usb\usbdrv\usbdrv.h" #include "system\usb\usbctrltrf\usbctrltrf.h" #include "system\usb\usb9\usb9.h" Si USB_USE_HID está definida se incluye la librería hid.h #if defined(USB_USE_HID) Ver autofiles\usbcfg.h #include "system\usb\class\hid\hid.h" #endif

Transcript of revisar c18usb

Page 1: revisar c18usb

1. LIBRERÍAS DEL USB Las librerías que aquí aparecen son un ejemplo. Dependiendo de la clase (HID,

MSD, GEN, BOOT o CDC) hay algunas variaciones.

En rojo aparecen los datos que hay que cambiar en cada firmware. En azul las líneas que dependen de la clase. Y en verde la parte de la librería que es código, aunque el texto en rojo y en azul también es código.

Para realizar una conexión sin características específicas, lo recomendable es utilizar la clase genérica (GEN) ya que permite una velocidad más alta que la clase CDC, aunque esta última se utiliza por resultar más fácil la programación del host. Para ello se copian todas las librerías de esta clase que suministra Microchip y se modifican las líneas que aquí aparecen en rojo. Lo más importante es definir bien las interfaces y los Endpoints.

Para realizar una aplicación en una clase determinada, lo más sencillo es copiar todas las librerías de esa clase, corregirlas y modificar las librerías user.h y las aquí comentadas. Haciendo esto, nos evitamos tener que modificar el código al cambiar la clase del dispositivo.

Para más información visitar la página web de microchip, en la que hay ejemplos de cada clase.

1.1.1. USB.H Esta librería proporciona la forma de incluir todos los archivos necesarios del

firmware del USB de Microchip.

En realidad, es la única librería que hay que incluir en el programa de inicio, ya que se encarga de añadir las demás.

El orden de inclusión es importante, ya que se resuelven los conflictos de dependencia con el orden correcto:

#include "autofiles\usbcfg.h" #include "system\usb\usbdefs\usbdefs_std_dsc.h" #include "autofiles\usbdsc.h" #include "system\usb\usbdefs\usbdefs_ep0_buff.h" #include "system\usb\usbmmap.h" #include "system\usb\usbdrv\usbdrv.h" #include "system\usb\usbctrltrf\usbctrltrf.h" #include "system\usb\usb9\usb9.h"

Si USB_USE_HID está definida se incluye la librería hid.h

#if defined(USB_USE_HID) Ver autofiles\usbcfg.h #include "system\usb\class\hid\hid.h" #endif

Page 2: revisar c18usb

Documento creado por Slalen para Electronics Strange World

Si USB_USE_MSD está definida se incluye la librería msd.h

#if defined(USB_USE_MSD) Ver autofiles\usbcfg.h #include "system\usb\class\msd\msd.h" #endif

Si USB_USE_CDC está definida se incluye la librería cdc.h

#if defined(USB_USE_CDC) Ver autofiles\usbcfg.h #include "system\usb\class\cdc\cdc.h" #endif

2

Page 3: revisar c18usb

Librerías C18 del USB

1.1.2. USBCFG.H: CONFIGURACIÓN Esta librería es la encargada de la configuración del buffer por defecto, del

Endpoint 0, de los Endpoints utilizados en la comunicación… Hay que modificarla en cada aplicación.

1.1.2.1. Definiciones Tamaño del buffer del Endpoint 0 (8, 16 32 ó 64):

#define EP0_BUFF_SIZE 8

Número máximo de interrupciones:

#define MAX_NUM_INT 1

Definición de parámetros descritos en usbdrv.h:

Modo Ping-Pong:

#define MODE_PP _PPBM0

Valor de configuración:

#define UCFG_VAL _PUEN|_TRINT|_FS|MODE_PP

E/S auto-alimentadas:

#define USE_SELF_POWER_SENSE_IO

E/S dependientes del bus USB:

#define USE_USB_BUS_SENSE_IO

Las dos definiciones anteriores se realizarán cuando sea necesario, siendo totalmente independiente una de la otra.

1.1.2.2. Uso de la clase del dispositivo Dependiendo de la aplicación hay que definir la clase que vamos a utilizar.

Uso de la interfaz humana del dispositivo USB: #define USB_USE_HID Uso del CDC del dispositivo: #define USB_USE_CDC Uso de la clase Almacenamiento masivo: #define USB_USE_MSD

MUID = Microchip USB Clase ID

Se utiliza para identificar la clase del USB de la sesión actual de control de la transferencia del EP0:

#define MUID_NULL 0 Ninguna #define MUID_USB9 1 USB9 #define MUID_HID 2 Interfaz humana #define MUID_CDC 3 Clase de comunicación del dispositivo

1.1.2.3. Distribución de los Endpoint #define HID_INTF_ID 0x00 Identificación de la interfaz #define HID_UEP UEP1 Endpoints que se utlizan

3

Page 4: revisar c18usb

Documento creado por Slalen para Electronics Strange World

#define HID_BD_OUT ep1Bo Buffer descriptor de salida #define HID_INT_OUT_EP_SIZE 3 Tamaño de la interrupción del Endpoint de salida #define HID_BD_IN ep1Bi Buffer descriptor de entrada #define HID_INT_IN_EP_SIZE 3 Tamaño de la interrupción del Endpoint de entrada #define HID_NUM_OF_DSC 1 Número de descriptores #define HID_RPT01_SIZE 50 Tamaño del informe

Macros HID Ver la dirección del descriptor HID:

#define mUSBGetHIDDscAdr(ptr) { if(usb_active_cfg == 1) ptr = (rom byte*)&cfg01.hid_i00a00; }

Ver la dirección del informe del descriptor HID:

#define mUSBGetHIDRptDscAdr(ptr) { if(usb_active_cfg == 1) ptr = (rom byte*)&hid_rpt01; }

Ver el tamaño del informe del descriptor HID:

#define mUSBGetHIDRptDscSize(count) { if(usb_active_cfg == 1) count = sizeof(hid_rpt01); }

Número máximo de Endpoints:

#define MAX_EP_NUMBER 1 //UEP1

4

Page 5: revisar c18usb

Librerías C18 del USB

1.1.3. USBDEFS_STD_DSC.H: DEFINICIONES ESTÁNDAR DE LOS DESCRIPTORES:

Mediante esta libraría se crean las estructuras de los descriptores estándar, se definen constantes para realizar el código más rápidamente, etc.

En general, no hay que modificar nada de la librería. En nuestra aplicación copiaremos la que cede Microchip que corresponda con nuestra clase.

1.1.3.1. Incluye: #include "system\typedefs.h" Librería en la que se definen tipos de datos

1.1.3.2. Definiciones Tipos de descriptores:

#define DSC_DEV 0x01 Descriptor del dispositivo #define DSC_CFG 0x02 Descriptor de configuración #define DSC_STR 0x03 Descriptor de la secuencia #define DSC_INTF 0x04 Descriptor de la interfaz #define DSC_EP 0x05 Descriptor del Endpoint

Definición de los Endpoint (sólo usarse con los descriptores, para cualquier otro uso utilizar los definidos en usbdrv.h):

#define _EP01_OUT 0x01 #define _EP01_IN 0x81 #define _EP02_OUT 0x02 #define _EP02_IN 0x82 #define _EP03_OUT 0x03 #define _EP03_IN 0x83 #define _EP04_OUT 0x04 #define _EP04_IN 0x84 #define _EP05_OUT 0x05 #define _EP05_IN 0x85 #define _EP06_OUT 0x06 #define _EP06_IN 0x86 #define _EP07_OUT 0x07 #define _EP07_IN 0x87 #define _EP08_OUT 0x08 #define _EP08_IN 0x88 #define _EP09_OUT 0x09 #define _EP09_IN 0x89 #define _EP10_OUT 0x0A #define _EP10_IN 0x8A #define _EP11_OUT 0x0B #define _EP11_IN 0x8B #define _EP12_OUT 0x0C #define _EP12_IN 0x8C #define _EP13_OUT 0x0D #define _EP13_IN 0x8D

5

Page 6: revisar c18usb

Documento creado por Slalen para Electronics Strange World

#define _EP14_OUT 0x0E #define _EP14_IN 0x8E #define _EP15_OUT 0x0F #define _EP15_IN 0x8F

Atributos de configuración:

#define _DEFAULT 0x01<<7 Valor por defecto (El Bit 7 se activa) #define _SELF 0x01<<6 Auto-alimentado (Mantener si está activo) #define _RWU 0x01<<5 Reinicio remoto (Mantener si está activo)

Tipo de transferencia del Endpoint:

#define _CTRL 0x00 Transferencia de control #define _ISO 0x01 Transferencia síncrona #define _BULK 0x02 Transferencia Bulk #define _INT 0x03 Transferencia interrupción

Tipo de sincronización del Endpoint de transferencia síncrona:

#define _NS 0x00<<2 Sin sincronización #define _AS 0x01<<2 Asíncrona #define _AD 0x02<<2 Adaptivo #define _SY 0x03<<2 Síncrona

Utilización del Endpoint tipo síncrono:

#define _DE 0x00<<4 Endpoint de datos #define _FE 0x01<<4 Endpoint retroalimentado #define _IE 0x02<<4 Endpoint de datos y retroalimentado

1.1.3.3. Estructuras Estructura de los descriptores del dispositivo USB (ver usbdsc.c):

typedef struct _USB_DEV_DSC { Longitud; Tipo de descriptor; Bcd del USB; byte bLength; byte bDscType; word bcdUSB; Clase del dispositivo; Subclase del dispositivo; Protocolo del dispositivo; byte bDevCls; byte bDevSubCls; byte bDevProtocol; Tamaño máximo del paquete; Identificador del fabricante; Identificación del producto; byte bMaxPktSize0; word idVendor; word idProduct; Bcd del dsipositivo; Información de la manufactura; Información del producto; word bcdDevice; byte iMFR; byte iProduct; Número de serie; Número de configuración; byte iSerialNum; byte bNumCfg; } USB_DEV_DSC;

Estructura del descriptor de configuración del USB:

typedef struct _USB_CFG_DSC { Longitud; Tipo de descriptor; Longitud total; byte bLength; byte bDscType; word wTotalLength; Número de interfaz; Valor de configuración; Información de configuración;

6

Page 7: revisar c18usb

Librerías C18 del USB

byte bNumIntf; byte bCfgValue; byte iCfg; Atributos; Máxima energía; byte bmAttributes; byte bMaxPower; } USB_CFG_DSC;

Estructura de la interfaz del dispositivo USB:

typedef struct _USB_INTF_DSC { Longitud; Tipo de descriptor; Número de interfaz; byte bLength; byte bDscType; byte bIntfNum; Configuración alterna; Número de Endpoints; Clase de interfaz; byte bAltSetting; byte bNumEPs; byte bIntfCls; Subclase de interfaz; Protocolo de la interfaz; Información de la interfaz; byte bIntfSubCls; byte bIntfProtocol; byte iIntf; } USB_INTF_DSC;

Estructura del Descriptor del Endpoint del USB:

typedef struct _USB_EP_DSC { Longitud; Tipo de descriptor; Dirección del Endpoint; byte bLength; byte bDscType; byte bEPAdr; Atributos; Tamaño máximo del paquete; Intervalo; byte bmAttributes; word wMaxPktSize; byte bInterval; } USB_EP_DSC;

7

Page 8: revisar c18usb

Documento creado por Slalen para Electronics Strange World

1.1.4. USBDSC.H: DESCRIPTORES Esta es una de las librerías más importantes, ya que en ella se definen los

descriptores.

Como hemos visto anteriormente, los descriptores definen la interfaz, la clase, el fabricante, etc.

Esta librería suele ser totalmente distinta en cada aplicación.

1.1.4.1. Librerías que incluye #include "system\typedefs.h" #include "autofiles\usbcfg.h" #include "system\usb\usb.h"

1.1.4.2. Definiciones #define CFG01 rom struct Configuración 01 { USB_CFG_DSC cd01; Descriptor de configuración USB_INTF_DSC i00a00; Descriptor de la interfaz USB_EP_DSC ep01o_i00a00; Endpoint descriptor de salida USB_EP_DSC ep01i_i00a00; Endpoint descriptor de entrada } cfg01

1.1.4.3. Externas extern rom USB_DEV_DSC device_dsc; extern CFG01; extern rom struct{byte bLength;byte bDscType;word string[1];}sd000;

8

Page 9: revisar c18usb

Librerías C18 del USB

1.1.5. USBDEFS_EP0_BUFF.H: DESCRIPCIONES DEL BUFFER DEL ENDPOINT 0

La librería actual recopila las características del Endpoint 0 y de su buffer, no hay que modificarla ya que las variables se han declarado en otras librerías.

1.1.5.1. Incluye #include "system\typedefs.h" #include "autofiles\usbcfg.h"

Control de transferencias setup Cada paquete setup tiene 8bytes. Sin embargo, el tamaño del buffer del Endpoint

0 es el especificado en la librería usbcfg.h.

El tamaño del buffer puede ser de 8, 16, 32 ó 64.

Los primeros 8bytes se definen para direccionarse directamente para mejorar la velocidad y reducir el tamaño del código. El resto de bytes se direccionan indirectamente.

typedef union _CTRL_TRF_SETUP { Matriz para el direccionamiento indirecto struct { byte _byte[EP0_BUFF_SIZE]; }; Respuestas estándar del dispositivo struct { byte bmRequestType; Tipo de respuesta byte bRequest; Respuesta word wValue; Valor word wIndex; Índice word wLength; Longitud }; struct { unsigned :8; unsigned :8; WORD W_Value; Valor WORD W_Index; Índice WORD W_Length; Longitud }; struct { unsigned Recipient:5; Dispositivo, Interfaz, Endpoint, Otro unsigned RequestType:2; Estándar, Clase, Fabricante, Reservado unsigned DataDir:1; Host-al-dispositivo, Dispositivo-al-host unsigned :8;

9

Page 10: revisar c18usb

Documento creado por Slalen para Electronics Strange World

byte bFeature; Reinicio remoto, Paro del Endpoint unsigned :8; unsigned :8; unsigned :8; unsigned :8; unsigned :8; }; struct { unsigned :8; unsigned :8; byte bDscIndex; Sólo para configuración y String del descriptor byte bDscType; Dispositivo, Configuración, String word wLangID; Identificación de idioma unsigned :8; unsigned :8; }; struct { unsigned :8; unsigned :8; BYTE bDevADR; Dirección del dispositivo 0-127 byte bDevADRH; Tiene que ser cero unsigned :8; unsigned :8; unsigned :8; unsigned :8; }; struct { unsigned :8; unsigned :8; byte bCfgValue; Valor de configuración 0-255 byte bCfgRSD; Tiene que ser cero (Reservado) unsigned :8; unsigned :8; unsigned :8; unsigned :8; }; struct { unsigned :8; unsigned :8; byte bAltID; Valor alterno de configuración 0-255 byte bAltID_H; Tiene que ser cero byte bIntfID; Valor del número de interfaz 0-255 byte bIntfID_H; Tiene que ser cero unsigned :8; unsigned :8; };

10

Page 11: revisar c18usb

Librerías C18 del USB

struct { unsigned :8; unsigned :8; unsigned :8; unsigned :8; byte bEPID; Identificación del Endpoint ID (Número y Dirección) byte bEPID_H; Tiene que ser cero unsigned :8; unsigned :8; }; struct { unsigned :8; unsigned :8; unsigned :8; unsigned :8; unsigned EPNum:4; Número del Endpoint 0-15 unsigned :3; unsigned EPDir:1; Dirección del Endpoint: 0-OUT, 1-IN unsigned :8; unsigned :8; unsigned :8; }; } CTRL_TRF_SETUP;

Control de transferencia de datos typedef union _CTRL_TRF_DATA { Matriz para el direccionamiento indirecto: struct { byte _byte[EP0_BUFF_SIZE]; }; Los primeros 8bytes direccionables directamente: struct { byte _byte0; byte _byte1; byte _byte2; byte _byte3;

11

Page 12: revisar c18usb

Documento creado por Slalen para Electronics Strange World

byte _byte4; byte _byte5; byte _byte6; byte _byte7; }; struct { word _word0; word _word1; word _word2; word _word3; }; } CTRL_TRF_DATA;

12

Page 13: revisar c18usb

Librerías C18 del USB

1.1.6. USBMMAP.H Esta librería define constantes y estructuras utilizadas por otras.

El programador, salvo excepción, no tiene que modificarla utilizándola tal y como aparece.

1.1.6.1. Incluye #include "system\typedefs.h"

1.1.6.2. Definiciones Parámetros de inicialización del descriptor del registro estado:

#define _BSTALL 0x04 Parada del buffer activa #define _DTSEN 0x08 Dato de sincronización activo #define _INCDIS 0x10 Incremento de dirección desactivado #define _KEN 0x20 Guardado del buffer descriptor por el SIE activo #define _DAT0 0x00 Paquete DATA0 esperando el siguiente #define _DAT1 0x40 Paquete DATA1 esperando el siguiente #define _DTSMASK 0x40 Máscara DTS #define _USIE 0x80 El SIE controla el buffer #define _UCPU 0x00 La CPU controla el buffer

Estados del dispositivo USB. Para utilizarlos con [byte usb_device_state]:

#define DETACHED_STATE 0 Sin conexión #define ATTACHED_STATE 1 Conectado #define POWERED_STATE 2 Alimentado #define DEFAULT_STATE 3 Por defecto #define ADR_PENDING_STATE 4 Pendiente de dirección #define ADDRESS_STATE 5 Direccionado #define CONFIGURED_STATE 6 Configurado

Tipos de memoria para el control de transferencias, utilizado en USB_DEVICE_STATUS:

#define _RAM 0 #define _ROM 1

1.1.6.3. Tipos typedef union _USB_DEVICE_STATUS Estado del dispositivo { byte _byte; struct

13

Page 14: revisar c18usb

Documento creado por Slalen para Electronics Strange World

{ unsigned RemoteWakeup:1; [0]Desactivado [1]Activado: Ver usbdrv.h, usb9.h unsigned ctrl_trf_mem:1; [0]RAM [1]ROM }; } USB_DEVICE_STATUS; typedef union _BD_STAT Estado del buffer descriptor { byte _byte; struct{ unsigned BC8:1; unsigned BC9:1; unsigned BSTALL:1; Parada del buffer activa unsigned DTSEN:1; Dato de sincronización activo unsigned INCDIS:1; Incremento de dirección desactivado unsigned KEN:1; Guardado del buffer descriptor por el SIE activo unsigned DTS:1; Valor del dato de sincronización unsigned UOWN:1; Propiedad del USB }; struct{ unsigned BC8:1; unsigned BC9:1; unsigned PID0:1; unsigned PID1:1; unsigned PID2:1; unsigned PID3:1; unsigned :1; unsigned UOWN:1; }; struct{ unsigned :2; unsigned PID:4; Paquete de identificación unsigned :2; }; } BD_STAT; typedef union _BDT Tabla del buffer descriptor { struct { BD_STAT Stat; byte Cnt; byte ADRL; Dirección del buffer baja byte ADRH; Dirección del buffer alta }; struct { unsigned :8; unsigned :8;

14

Page 15: revisar c18usb

Librerías C18 del USB

byte* ADR; Dirección del Buffer }; } BDT;

1.1.6.4. Externas extern byte usb_device_state; extern USB_DEVICE_STATUS usb_stat; extern byte usb_active_cfg; extern byte usb_alt_intf[MAX_NUM_INT]; extern volatile far BDT ep0Bo; Buffer descriptor del Endpoint #0 Out extern volatile far BDT ep0Bi; Buffer descriptor del Endpoint #0 In extern volatile far BDT ep1Bo; Buffer descriptor del Endpoint #1 Out extern volatile far BDT ep1Bi; Buffer descriptor del Endpoint #1 In extern volatile far BDT ep2Bo; Buffer descriptor del Endpoint #2 Out extern volatile far BDT ep2Bi; Buffer descriptor del Endpoint #2 In extern volatile far BDT ep3Bo; Buffer descriptor del Endpoint #3 Out extern volatile far BDT ep3Bi; Buffer descriptor del Endpoint #3 In extern volatile far BDT ep4Bo; Buffer descriptor del Endpoint #4 Out extern volatile far BDT ep4Bi; Buffer descriptor del Endpoint #4 In extern volatile far BDT ep5Bo; Buffer descriptor del Endpoint #5 Out extern volatile far BDT ep5Bi; Buffer descriptor del Endpoint #5 In extern volatile far BDT ep6Bo; Buffer descriptor del Endpoint #6 Out extern volatile far BDT ep6Bi; Buffer descriptor del Endpoint #6 In extern volatile far BDT ep7Bo; Buffer descriptor del Endpoint #7 Out extern volatile far BDT ep7Bi; Buffer descriptor del Endpoint #7 In extern volatile far BDT ep8Bo; Buffer descriptor del Endpoint #8 Out extern volatile far BDT ep8Bi; Buffer descriptor del Endpoint #8 In extern volatile far BDT ep9Bo; Buffer descriptor del Endpoint #9 Out extern volatile far BDT ep9Bi; Buffer descriptor del Endpoint #9 In extern volatile far BDT ep10Bo; Buffer descriptor del Endpoint #10 Out extern volatile far BDT ep10Bi; Buffer descriptor del Endpoint #10 In extern volatile far BDT ep11Bo; Buffer descriptor del Endpoint #11 Out extern volatile far BDT ep11Bi; Buffer descriptor del Endpoint #11 In extern volatile far BDT ep12Bo; Buffer descriptor del Endpoint #12 Out extern volatile far BDT ep12Bi; Buffer descriptor del Endpoint #12 In extern volatile far BDT ep13Bo; Buffer descriptor del Endpoint #13 Out extern volatile far BDT ep13Bi; Buffer descriptor del Endpoint #13 In extern volatile far BDT ep14Bo; Buffer descriptor del Endpoint #14 Out extern volatile far BDT ep14Bi; Buffer descriptor del Endpoint #14 In extern volatile far BDT ep15Bo; Buffer descriptor del Endpoint #15 Out extern volatile far BDT ep15Bi; Buffer descriptor del Endpoint #15 In extern volatile far CTRL_TRF_SETUP SetupPkt; extern volatile far CTRL_TRF_DATA CtrlTrfData; #if defined(USB_USE_HID) Si está definido USB_USE_HID extern volatile far unsigned char hid_report_out[HID_INT_OUT_EP_SIZE]; extern volatile far unsigned char hid_report_in[HID_INT_IN_EP_SIZE]; #endif

15

Page 16: revisar c18usb

Documento creado por Slalen para Electronics Strange World

1.1.7. USBDRV.H: DRIVER DEL USB Esta librería es la encargada de definir la configuración inicial.

Lo único que hay que modificar es la corrección de la errata en la original de Microchip, como se comenta más adelante.

1.1.7.1. Incluye #include "system\typedefs.h" #include "system\usb\usb.h"

1.1.7.2. Definiciones Parámetros de configuración iniciales:

#define _PPBM0 0x00 Buffer Ping-pong Modo 0 #define _PPBM1 0x01 Buffer Ping-pong Modo 1 #define _PPBM2 0x02 Buffer Ping-pong Modo 2 #define _LS 0x00 Modo USB Low-Speed #define _FS 0x04 Modo USB Full-Speed #define _TRINT 0x00 Transmisor-receptor interno #define _TREXT 0x08 Transmisor-receptor externo #define _PUEN 0x10 Usar resistencias pull-up internas #define _OEMON 0x40 Usar el indicador de salida SIE #define _UTEYE 0x80 Usar el test “Patrón de ojo”

Parámetros de los Endpoint iniciales:

#define EP_CTRL 0x06 Pipe de control #define EP_OUT 0x0C Pipe de salida #define EP_IN 0x0A Pipe de entrada #define EP_OUT_IN 0x0E Pipe de entrada y salida #define HSHK_EN 0x10 Activar paquetes de protocolo Los paquetes de protocolo se tienen que desactivar en la síncronas

Definiciones de los Endpoints PICmicro El formato de la dirección de los EP PICmicro:

X:EP3:EP2:EP1:EP0:DIR:PPBI:X

Esto se utiliza cuando se comprueba el valor leído de la USTAT.

NOTA: estas definiciones no se usan en los descriptores porque tienen distinto formato. Se definen en : "system\usb\usbdefs\usbdefs_std_dsc.h"

#define OUT 0 #define IN 1 #define PIC_EP_NUM_MASK 0b01111000 Número de máscara del Endpoint #define PIC_EP_DIR_MASK 0b00000100 Dirección de la máscara del Endpoint

16

Page 17: revisar c18usb

Librerías C18 del USB

NOTA: la librería tiene una errata en la definición de los Endpoints, lo correcto es:

#define EP00_OUT ((0x00<<3)|(OUT<<2)) #define EP00_IN ((0x00<<3)|(IN<<2)) #define EP01_OUT ((0x01<<3)|(OUT<<2)) #define EP01_IN ((0x01<<3)|(IN<<2)) #define EP02_OUT ((0x02<<3)|(OUT<<2)) #define EP02_IN ((0x02<<3)|(IN<<2)) #define EP03_OUT ((0x03<<3)|(OUT<<2)) #define EP03_IN ((0x03<<3)|(IN<<2)) #define EP04_OUT ((0x04<<3)|(OUT<<2)) #define EP04_IN ((0x04<<3)|(IN<<2)) #define EP05_OUT ((0x05<<3)|(OUT<<2)) #define EP05_IN ((0x05<<3)|(IN<<2)) #define EP06_OUT ((0x06<<3)|(OUT<<2)) #define EP06_IN ((0x06<<3)|(IN<<2)) #define EP07_OUT ((0x07<<3)|(OUT<<2)) #define EP07_IN ((0x07<<3)|(IN<<2)) #define EP08_OUT ((0x08<<3)|(OUT<<2)) #define EP08_IN ((0x08<<3)|(IN<<2)) #define EP09_OUT ((0x09<<3)|(OUT<<2)) #define EP09_IN ((0x09<<3)|(IN<<2)) #define EP10_OUT ((0x0A<<3)|(OUT<<2)) #define EP10_IN ((0x0A<<3)|(IN<<2)) #define EP11_OUT ((0x0B<<3)|(OUT<<2)) #define EP11_IN ((0x0B<<3)|(IN<<2)) #define EP12_OUT ((0x0C<<3)|(OUT<<2)) #define EP12_IN ((0x0C<<3)|(IN<<2)) #define EP13_OUT ((0x0D<<3)|(OUT<<2)) #define EP13_IN ((0x0D<<3)|(IN<<2)) #define EP14_OUT ((0x0E<<3)|(OUT<<2)) #define EP14_IN ((0x0E<<3)|(IN<<2)) #define EP15_OUT ((0x0F<<3)|(OUT<<2)) #define EP15_IN ((0x0F<<3)|(IN<<2))

mInitializeUSBDriver() Configura el modulo USB.

La definición de UCFG_VAL está en autofiles\usbcfg.h

Este registro determina: velocidad del USB Speed, selección de las resistencias pull-up del chip, selección del transmisor-receptor del chip, modo de chequeo “patrón de ojo”, buffer modo Ping-pong

17

Page 18: revisar c18usb

Documento creado por Slalen para Electronics Strange World

#define mInitializeUSBDriver() {UCFG = UCFG_VAL; usb_device_state = DETACHED_STATE; usb_stat._byte = 0x00; usb_active_cfg = 0x00; }

void mDisableEP1to15() Esta macro desactiva todos los Endpoints menos el 0.

Hay que invocar esta macro cada vez que el host envíe una señal de RESET o una respuesta a SET_CONFIGURATION

#define mDisableEP1to15() ClearArray((byte*)&UEP1,15);

O lo que es lo mismo:

#define mDisableEP1to15() UEP1=0x00;UEP2=0x00;UEP3=0x00; UEP4=0x00;UEP5=0x00;UEP6=0x00;UEP7=0x00; UEP8=0x00;UEP9=0x00;UEP10=0x00;UEP11=0x00; UEP12=0x00;UEP13=0x00;UEP14=0x00;UEP15=0x00;

mUSBBufferReady(buffer_dsc) Precondición: Endpoint IN: El buffer está cargado y listo para enviar.

Endpoint OUT: El buffer puede escribir al SIE.

Entrada: byte buffer_dsc: Nombre del grupo del buffer descriptor (e.j. ep0Bo, ep1Bi) declarado en usbmmap.h. Los nombres se pueden cambiar por legibilidad; ver los ejemplos en usbcfg.h (#define HID_BD_OUT ep1Bo)

Esta macro se tiene que llamar cada vez que ocurra:

1. Que se llene un buffer de un Endpoint, que no sea el EP0, con datos. 2. Que se lea un buffer de un Endpoint, que no sea el EP0.

Esta macro convierte la propiedad del buffer al SIE para dar servicio; además, cambia el bit DTS para sincronización.

#define mUSBBufferReady(buffer_dsc) { buffer_dsc.Stat._byte &= _DTSMASK; Guarda sólo el bit DTS buffer_dsc.Stat.DTS = !buffer_dsc.Stat.DTS; Cambia el bit DTS buffer_dsc.Stat._byte |= _USIE|_DTSEN; Cambia la propiedad al SIE }

1.1.7.3. Prototipos públicos void USBCheckBusStatus(void); void USBDriverService(void); void USBRemoteWakeup(void); void USBSoftDetach(void); void ClearArray(byte* startAdr,byte count);

18

Page 19: revisar c18usb

Librerías C18 del USB

1.1.8. USBCTRLTRF.H: CONTROL DE TRANSFERENCIAS DEL USB Esta librería es la encargada de definir los tipos de transferencia. Se utiliza desde

otras librerías al declarar la interfaz, la transferecia, etc.

No hay que modificarla

1.1.8.1. Incluye #include "system\typedefs.h"

1.1.8.2. Definiciones Estado de las transferencias de control

#define WAIT_SETUP 0 Espera Setup #define CTRL_TRF_TX 1 Transf. de control de transmisión #define CTRL_TRF_RX 2 Transf. de control de recepción

Tipos de Tokens:

#define SETUP_TOKEN 0b00001101 Token setup #define OUT_TOKEN 0b00000001 Token de salida #define IN_TOKEN 0b00001001 Token de entrada

Definición de los tipos de respuesta:

#define HOST_TO_DEV 0 Host-al-Dispositivo #define DEV_TO_HOST 1 Dispositivo-al-Host #define STANDARD 0x00 #define CLASS 0x01 Clase #define VENDOR 0x02 Fabricante #define RCPT_DEV 0 Dispositivo destinatario #define RCPT_INTF 1 Destinatario de la interfaz #define RCPT_EP 2 Destinatario del Endpoint #define RCPT_OTH 3

1.1.8.3. Externas extern byte ctrl_trf_session_owner; extern POINTER pSrc; extern POINTER pDst; extern WORD wCount;

1.1.8.4. Prototipos públicos void USBCtrlEPService(void); void USBCtrlTrfTxService(void); void USBCtrlTrfRxService(void); void USBCtrlEPServiceComplete(void); void USBPrepareForNextSetupTrf(void);

19

Page 20: revisar c18usb

Documento creado por Slalen para Electronics Strange World

1.1.9. USB9.H Gracias a esta librería obtenemos la dirección del dispositivo, entre otras

características.

No se tiene que modificar.

1.1.9.1. Incluye #include "system\typedefs.h"

1.1.9.2. Definiciones Códigos de respuesta estándar:

#define GET_STATUS 0 Obtiene estado #define CLR_FEATURE 1 Borra característica #define SET_FEATURE 3 Fija característica #define SET_ADR 5 Fija dirección #define GET_DSC 6 Obtiene descriptor #define SET_DSC 7 Fija descriptor #define GET_CFG 8 Obtiene configuración #define SET_CFG 9 Fija configuración #define GET_INTF 10 Obtiene interfaz #define SET_INTF 11 Fija interfaz #define SYNCH_FRAME 12 Marco de sincronismo

Características de los selectores estándar:

#define DEVICE_REMOTE_WAKEUP 0x01 Reinicio remoto del dispositivo #define ENDPOINT_HALT 0x00 Paro del Endpoint

mUSBCheckAdrPendingState() Rutina de chequeo especializado, comprueba si el dispositivo está en el estado

“Pendiente de dirección” y le da servicio si está.

#define mUSBCheckAdrPendingState() if(usb_device_state==ADR_PENDING_STATE) { UADDR = SetupPkt.bDevADR._byte; if(UADDR > 0) usb_device_state=ADDRESS_STATE; else usb_device_state=DEFAULT_STATE; }

1.1.9.3. Prototipos públicos void USBCheckStdRequest(void);

20

Page 21: revisar c18usb

Librerías C18 del USB

1.1.10. USBGEN.H: USB GENÉRICO Esta es la librería de la clase genérica. Se definen las transferencias creando

funciones para realizarlas.

No hay que modificarla.

1.1.10.1. Incluye #include "system\typedefs.h"

1.1.10.2. Definiciones

(bit) mUSBGenRxIsBusy(void) Esta macro se utiliza para comprobar que el Endpoint de salida está ocupado (lo

controla el SIE) o no.

Uso típico: if(mUSBGenRxIsBusy())

#define mUSBGenRxIsBusy() USBGEN_BD_OUT.Stat.UOWN

(bit) mUSBGenTxIsBusy(void) Esta macro se utiliza para comprobar que el Endpoint de entrada está ocupado

(lo controla el SIE) o no.

Uso típico: if(mUSBGenTxIsBusy())

#define mUSBGenTxIsBusy() USBGEN_BD_IN.Stat.UOWN

byte mUSBGenGetRxLength(void) Salida: mUSBGenGetRxLength devuelve usbgen_rx_len (longitude de Rx).

mUSBGenGetRxLength se utiliza para recuperar el número de bytes copiados al buffer del usuario en la última llamada a la función USBGenRead.

#define mUSBGenGetRxLength() usbgen_rx_len

1.1.10.3. Externas extern byte usbgen_rx_len;

1.1.10.4. Prototipos Públicos void USBGenInitEP(void); void USBGenWrite(byte *buffer, byte len); byte USBGenRead(byte *buffer, byte len);

21

Page 22: revisar c18usb

Documento creado por Slalen para Electronics Strange World

1.1.11. MSD.H: ALMACENAMIENTO MASIVO Esta es la librería de la clase MSD. Se definen las transferencias creando

funciones para realizarlas.

No hay que modificarla.

1.1.11.1. Incluye #include "system\typedefs.h" #include "io_cfg.h" Mapa de pines E/S

1.1.11.2. Definiciones Código de la clase de interfaz MSD:

#define MSD_INTF 0x08

Código de la subclase de la interfas de clase MSD:

#define MSD_INTF_SUBCLASS 0x06

Código de protocolo de la clase de la interfaz MSD:

#define MSD_PROTOCOL 0x50

Comandos de la clase:

#define MSD_RESET 0xff #define GET_MAX_LUN 0xfe #define BLOCKLEN_512 0x0200 #define STMSDTRIS TRISD0 #define STRUNTRIS TRISD1 #define STMSDLED LATDbits.LATD0 #define STRUNLED LATDbits.LATD1 #define ToggleRUNLED() STRUNLED = !STRUNLED;

Set de commandos de código de la subclase transparente SCSI:

#define INQUIRY 0x12 #define READ_FORMAT_CAPACITY 0x23 #define READ_CAPACITY 0x25 #define READ_10 0x28 #define WRITE_10 0x2A #define REQUEST_SENSE 0x03 #define MODE_SENSE 0x1A #define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E #define TEST_UNIT_READY 0x00 #define VERIFY 0x2F #define STOP_START 0x1B

Varios estados del Firmware de almacenamiento masivo:

#define MSD_WAIT 0 Esperando para un CBW válido #define MSD_DATA_IN 2 Estado de datos IN (Dispositivo-> Host) #define MSD_DATA_OUT 3 Estado de datos OUT (Host -> Device)

22

Page 23: revisar c18usb

Librerías C18 del USB

#define MSD_CSW_SIZE 0x0d Datos CSW de 10 bytes CSW #define MSD_CBW_SIZE 0x1f Datos CSW de 31 bytes CBW #define INVALID_CBW 1 #define VALID_CBW !INVALID_CBW #define MAX_LUN 0

Clave de los códigos de error Sense

#define S_NO_SENSE 0x0 #define S_RECOVERED_ERROR 0x1 #define S_NOT_READY 0x2 #define S_MEDIUM_ERROR 0x3 #define S_HARDWARE_ERROR 0X4 #define S_ILLEGAL_REQUEST 0x5 #define S_UNIT_ATTENTION 0x6 #define S_DATA_PROTECT 0x7 #define S_BLANK_CHECK 0x8 #define S_VENDOR_SPECIFIC 0x9 #define S_COPY_ABORTED 0xA #define S_ABORTED_COMMAND 0xB #define S_OBSOLETE 0xC #define S_VOLUME_OVERFLOW 0xD #define S_MISCOMPARE 0xE #define S_CURRENT 0x70 #define S_DEFERRED 0x71

Códigos ASC ASCQ para datos (sólo el que vamos a utilizar)

Con una respuesta de clave sense ilegal de un comando no soportado:

#define ASC_INVALID_COMMAND_OPCODE 0x20 #define ASCQ_INVALID_COMMAND_OPCODE 0x00

Con una respuesta de clave sense ilegal para probar si la unidad está disponible:

#define ASC_LOGICAL_UNIT_NOT_SUPPORTED 0x25 #define ASCQ_LOGICAL_UNIT_NOT_SUPPORTED 0x00

Con una clave sense Not ready

#define ASC_LOGICAL_UNIT_DOES_NOT_RESPOND 0x05 #define ASCQ_LOGICAL_UNIT_DOES_NOT_RESPOND 0x00 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASCQ_MEDIUM_NOT_PRESENT 0x00 #define ASC_LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE 0x04 #define ASCQ_LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE 0x00

23

Page 24: revisar c18usb

Documento creado por Slalen para Electronics Strange World

#define ASC_LOGICAL_UNIT_IN_PROCESS 0x04 #define ASCQ_LOGICAL_UNIT_IN_PROCESS 0x01 #define ASC_LOGICAL_UNIT_NOT_READY_INIT_REQD 0x04 #define ASCQ_LOGICAL_UNIT_NOT_READY_INIT_REQD 0x02 #define ASC_LOGICAL_UNIT_NOT_READY_INTERVENTION_REQD 0x04 #define ASCQ_LOGICAL_UNIT_NOT_READY_INTERVENTION_REQD 0x03 #define ASC_LOGICAL_UNIT_NOT_READY_FORMATTING 0x04 #define ASCQ_LOGICAL_UNIT_NOT_READY_FORMATTING 0x04 #define ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 #define ASCQ_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x00 #define ASC_WRITE_PROTECTED 0x27 #define ASCQ_WRITE_PROTECTED 0x00

(bit) mMSDRxIsBusy(void) Esta macro se utiliza para comprobar si el Endpoint MSD OUT está ocupado

(controlado por el SIE) o no.

Uso típico: if(mMSDRxIsBusy())

#define mMSDRxIsBusy() MSD_BD_OUT.Stat.UOWN

(bit) mMSDTxIsBusy(void) Esta macro se utiliza para comprobar si el Endpoint MSD IN está ocupado

(controlado por el SIE) o no.

Uso típico: if(mMSDTxIsBusy())

#define mMSDTxIsBusy() MSD_BD_IN.Stat.UOWN

(bit) mMin(void) Esta macro se utiliza para encontrar el menor de dos argumentos.

Uso típico: mMin(A, B)

#define mMin(A,B) (A<B)?A:B

1.1.11.3. Estructuras typedef struct _USB_MSD_CBW 31 bytes totales CBW { dword dCBWSignature; 55 53 42 43h dword dCBWTag; Enviado por el host, el dispositivo se hace eco con el valor en CSW (asociado a CSW con CBW)

24

Page 25: revisar c18usb

Librerías C18 del USB

dword dCBWDataTransferLength; Número de bytes de datos que el host espera transferir byte bCBWFlags; Flags CBW, bit 7 = 0 salida de datos del host- dispositivo; bit 7=1 dispositivo-host, el resto de bits 0 byte bCBWLUN; MS1bits son siempre cero, 0 en nuestro caso es una sola unidad lógica byte bCBWCBLength; MS3bits son cero byte CBWCB[16]; Bloque de comando que ejecuta el dispositivo } USB_MSD_CBW; typedef struct { /Bloque de comando para leer 10 (0x28) y escribir 10 (0x2a) comandos byte Opcode; byte Flags; b7-b5 lectura protegida, b4 DPO, b3 FUA, b2 Reservado, b1 FUA_NV, b0 Obsoleto DWORD LBA; byte GroupNumber; b4-b0 es el número de grupo el resto reservados WORD TransferLength; byte Control; } ReadWriteCB; typedef struct { Formato del comando Inquiry byte Opcode; byte EVPD; sólo b0 enable vital product data byte PageCode; word AllocationLength; byte Control; } InquiryCB; typedef struct { capacidad de lectura 10 byte Opcode; byte Reserved1; dword LBA; Bloque de dirección lógico word Reserved2; byte PMI; Partial medium Indicator sólo b0 byte Control; } ReadCapacityCB; typedef struct { Respuesta Sense 0x03 byte Opcode; byte Desc; word Reserved; byte AllocationLength; byte Control; } RequestSenseCB; typedef struct { Modo Sense 0x1A byte Opcode;

25

Page 26: revisar c18usb

Documento creado por Slalen para Electronics Strange World

byte DBD; Actualmente sólo se utiliza b3 como bloque descriptor desactivado byte PageCode; b7,b6 PC=página de control, b5-b0 página de código Página de Control bits 00=> valor actual, 01=>valores modificables,10=>valor por defecto, 11=>valores guardados byte SubPageCode; byte AllocationLength; byte Control; } ModeSenseCB; typedef struct { Prevenir el permiso de retirada del medio 0x1E byte Opcode; byte Reserved[3]; byte Prevent; Sólo se previenen b1-b0, el resto reservados byte Control; } PreventAllowMediumRemovalCB; typedef struct { Unidad de prueba disponible 0x00 byte Opcode; dword Reserved; byte Control; } TestUnitReadyCB; typedef struct { Verificar 10 Comando 0x2F byte Opcode; byte VRProtect; b7-b5 VRProtect, b4 DPO, b3-b2,Reservado, b1 BYTCHK, b0 Obsoleto dword LBA; byte GroupNumber; Número del grupo b4-b0, el resto reservado word VerificationLength; byte Control; } VerifyCB; typedef struct { STOP_START 0x1B byte Opcode; byte Immed; word Reserved; byte Start; b7-b4 Condición de energía, b3-b2 reservedo, b1 LOEJ, b0 Start byte Control; } StopStartCB; typedef struct _USB_MSD_CSW CSW { dword dCSWSignature; 55 53 42 53h firma del paquete de CSW dword dCSWTag; eco dCBWTag del paquete CBW dword dCSWDataResidue; diferencia en los datos esperados (dCBWDataTransferLength) y la cantidad actual procesada/enviada

26

Page 27: revisar c18usb

Librerías C18 del USB

byte bCSWStatus; 00h Comando aprobado, 01h Comando Fallido, 02h Error de fase, el resto obsoleto/reservado } USB_MSD_CSW; typedef struct { byte Peripheral; Clasificador del periférico:3; Periférico_DevType:5; byte Removble; medio removible bit7 = 0 medio no removible, resto reservado byte Version; versión byte Response_Data_Format; b7,b6 Obsoleto, b5 Acceso de control coordinado, b4 direccionamiento jerárquico soportado b3:0 respuesta al formato de datos 2 indica que la respuesta esta en el formato definido por spec byte AdditionalLength; longitud en bytes de los datos que quedan de la indagación estándar byte Sccstp; b7 SCCS, b6 ACC, b5-b4 TGPS, b3 3PC, b2-b1 Reservado, b0 Protegido byte bqueetc; b7 bque, b6- EncServ, b5-VS, b4-MultiP, b3-MChngr, b2-b1 Obsoleto, b0-Addr16 byte CmdQue; b7-b6 Obsoleto, b5-WBUS, b4-Sync, b3-Linked, b2 Obsoleto, b1 Cmdque, b0-VS char vendorID[8]; char productID[16]; char productRev[4]; } InquiryResponse; typedef struct { byte ModeDataLen; byte MediumType; unsigned Resv:4; unsigned DPOFUA:1; 0 indica que no soporta los bits DPO y FUA unsigned notused:2; unsigned WP:1; 0 indica que no protege la escritura byte BlockDscLen; Longitud del Bloque Descriptor } tModeParamHdr;

Modo corto del bloque descriptor LBA (ver Página 1009, SBC-2)

typedef struct { byte NumBlocks[4]; byte Resv; reservado byte BlockLen[3]; } tBlockDescriptor; /* Page_0 mode page format */ typedef struct { unsigned PageCode:6; SPC-3 7.4.5 unsigned SPF:1; SubPageFormat=0 medio Page_0 formato

27

Page 28: revisar c18usb

Documento creado por Slalen para Electronics Strange World

unsigned PS:1; Parámetros salvables byte PageLength; si 2..n bytes del modo parámetro PageLength=n-1 byte ModeParam[]; modo parámetros } tModePage; typedef struct { tModeParamHdr Header; tBlockDescriptor BlockDsc; tModePage modePage; } ModeSenseResponse;

Formato fijado si el bit Desc de la respuesta sense CBW es 0

typedef union { struct { byte _byte[18]; }; struct { unsigned ResponseCode:7; b6-b0 es el código de respuesta fijado o el formato del descriptor unsigned VALID:1; Poner a 1 indica que el campo de información tiene un valor válido byte Obsolete; unsigned SenseKey:4; Referencia SPC-3 Sección 4.5.6 unsigned Resv:1; unsigned ILI:1; Indicador de la longitud incorrecta unsigned EOM:1; Fin del medio unsigned FILEMARK:1; para los comandos READ y SPACE DWORD Information; Tipo de dispositivo o comando específico (SPC-33.1.18) byte AddSenseLen; Número de bytes sense adicionales que siguen <=244 DWORD CmdSpecificInfo; depende del comando de la excepción ocurrida byte ASC; código sense adicional byte ASCQ; código sense adicional sección clasificada 4.5.2.1 SPC-3 byte FRUC; byte SenseKeySpecific[3]; SKSV son los msb de la clave sense específica de campo válido fijado=>SKS válido. Los 18-n bytes sense adicionales se pueden definir más tarde 18bytes de respuesta sense de formato fijado }; } RequestSenseResponse;

28

Page 29: revisar c18usb

Librerías C18 del USB

1.1.11.4. Externas extern CSD gblCSDReg; declarado en sdcard.c

1.1.11.5. Prototipos públicos void USBCheckMSDRequest(void); void ProcessIO(void); void SDCardInit(void); void MSDInitEP(void);

29

Page 30: revisar c18usb

Documento creado por Slalen para Electronics Strange World

1.1.12. CDC.H: DISPOSITIVOS DE COMUNICACIÓN Esta es la librería de la clase CDC. Se definen las transferencias creando

funciones para realizarlas.

No hay que modificarla.

1.1.12.1. Incluye #include "system\typedefs.h"

1.1.12.2. Definiciones Repuesta de clase específica:

#define SEND_ENCAPSULATED_COMMAND 0x00 #define GET_ENCAPSULATED_RESPONSE 0x01 #define SET_COMM_FEATURE 0x02 #define GET_COMM_FEATURE 0x03 #define CLEAR_COMM_FEATURE 0x04 #define SET_LINE_CODING 0x20 #define GET_LINE_CODING 0x21 #define SET_CONTROL_LINE_STATE 0x22 #define SEND_BREAK 0x23

Notificaciones

Nota: las notificaciones se obtienen de la interface de comunicación (Endpoint Interrupción)

#define NETWORK_CONNECTION 0x00 #define RESPONSE_AVAILABLE 0x01 #define SERIAL_STATE 0x20

Código de la clase del dispositivo:

#define CDC_DEVICE 0x02

Código de la clase de la interfaz de comunicación

#define COMM_INTF 0x02

Código de la subclase de la interfaz de comunicación

#define ABSTRACT_CONTROL_MODEL 0x02

Código del protocolo de control de la clase de la interfaz de comunicación

#define V25TER 0x01 Comandos comunes AT ("Hayes(TM)")

Código de la clase de la interfaz de datos

#define DATA_INTF 0x0A

Código del protocolo de la clase de la interfaz de datos

#define NO_PROTOCOL 0x00 No necesita un protrocolo de clase específico

Código selector de las características de la comunicación

#define ABSTRACT_STATE 0x01

30

Page 31: revisar c18usb

Librerías C18 del USB

#define COUNTRY_SETTING 0x02

Descriptores funcionales

Tipos de valor del campo bDscType

#define CS_INTERFACE 0x24 #define CS_ENDPOINT 0x25

bDscSubType en descriptores funcionales

#define DSC_FN_HEADER 0x00 #define DSC_FN_CALL_MGT 0x01 #define DSC_FN_ACM 0x02 ACM – Administración de control abstracta #define DSC_FN_DLM 0x03 DLM – Dirección de línea directa #define DSC_FN_TELEPHONE_RINGER 0x04 #define DSC_FN_RPT_CAPABILITIES 0x05 #define DSC_FN_UNION 0x06 #define DSC_FN_COUNTRY_SELECTION 0x07 #define DSC_FN_TEL_OP_MODES 0x08 #define DSC_FN_USB_TERMINAL 0x09

Estados de tranferencia CDC Bulk IN

#define CDC_TX_READY 0 #define CDC_TX_BUSY 1 #define CDC_TX_BUSY_ZLP 2 ZLP: Paquete de longitud cero #define CDC_TX_COMPLETING 3

BOOL mUSBUSARTIsTxTrfReady(void) Esta macro se utiliza para comprobar si la clase CDC está disponible para enviar

mas datos.

Uso típico: if(mUSBUSARTIsTxTrfReady())

#define mUSBUSARTIsTxTrfReady() (cdc_trf_state == CDC_TX_READY)

(bit) mCDCUsartRxIsBusy(void) Esta macro se utiliza para comprobar si el Endpoint CDC Bulk OUT está

ocupado (controlado por el SIE) o no.

Uso típico: if(mCDCUsartRxIsBusy())

#define mCDCUsartRxIsBusy() CDC_BULK_BD_OUT.Stat.UOWN

(bit) mCDCUsartTxIsBusy(void) Esta macro se utiliza para comprobar si el Endpoint CDC Bulk IN está ocupado

(controlado por el SIE) o no.

31

Page 32: revisar c18usb

Documento creado por Slalen para Electronics Strange World

Uso típico: if(mCDCUsartTxIsBusy())

#define mCDCUsartTxIsBusy() CDC_BULK_BD_IN.Stat.UOWN

byte mCDCGetRxLength(void) Salida: devuelve cdc_rx_len

mCDCGetRxLength se utiliza para recuperar el número de bytes que se han copiado al buffer del usuario en la última llamada a la función getsUSBUSART.

#define mCDCGetRxLength() cdc_rx_len

void mUSBUSARTTxRam(byte *pData, byte len) Precondición: cdc_trf_state tiene que estar en el estado CDC_TX_READY.

El valor de ‘len’ tiene que se igual o menor de 255bytes.

Entrada: pDdata: Puntero al comienzo de la localización de los bytes de datos.

len: número de bytes que se van a transferir.

Esta macro se utiliza para transferir datos localizados en la memoria de datos.

Utilizar esta macro cuando:

1. La longitud de la transferencia se conoce 2. Los datos no terminan con uno nulo

Nota: Esta macro sólo manipula la transferencia setup. La transferencia actual la manipula CDCTxService().

#define mUSBUSARTTxRam(pData,len) { pCDCSrc.bRam = pData; cdc_tx_len = len; cdc_mem_type = _RAM; cdc_trf_state = CDC_TX_BUSY; }

void mUSBUSARTTxRom(rom byte *pData, byte len) Precondición: cdc_trf_state tiene que estar en el estado CDC_TX_READY.

El valor de ‘len’ tiene que se igual o menor de 255bytes.

Entrada: pDdata: Puntero al comienzo de la localización de los bytes de datos.

len: número de bytes que se van a transferir.

Esta macro se utiliza para transferir datos localizados en la memoria de programa.

Utilizar esta macro cuando:

3. La longitud de la transferencia se conoce 4. Los datos no terminan con uno nulo

Nota: Esta macro sólo manipula la transferencia setup. La transferencia actual la manipula CDCTxService().

32

Page 33: revisar c18usb

Librerías C18 del USB

#define mUSBUSARTTxRom(pData,len) { pCDCSrc.bRom = pData; cdc_tx_len = len; cdc_mem_type = _ROM; cdc_trf_state = CDC_TX_BUSY; }

1.1.12.3. Estructuras Estructura de la línea de codificación

#define LINE_CODING_LENGTH 0x07 typedef union _LINE_CODING { struct { byte _byte[LINE_CODING_LENGTH]; }; struct { DWORD dwDTERate; Estructura de datos compleja byte bCharFormat; byte bParityType; byte bDataBits; }; } LINE_CODING; typedef union _CONTROL_SIGNAL_BITMAP { byte _byte; struct { unsigned DTE_PRESENT; [0] No Presente [1] Presente unsigned CARRIER_CONTROL; [0] Desactiva [1] Activa }; } CONTROL_SIGNAL_BITMAP;

Descriptor de cabecera funcional

typedef struct _USB_CDC_HEADER_FN_DSC { byte bFNLength; byte bDscType; byte bDscSubType; word bcdCDC; } USB_CDC_HEADER_FN_DSC;

Descriptor funcional de dirección de control abstracto

typedef struct _USB_CDC_ACM_FN_DSC

33

Page 34: revisar c18usb

Documento creado por Slalen para Electronics Strange World

{ byte bFNLength; byte bDscType; byte bDscSubType; byte bmCapabilities; } USB_CDC_ACM_FN_DSC;

Descriptor funcional de unión

typedef struct _USB_CDC_UNION_FN_DSC { byte bFNLength; byte bDscType; byte bDscSubType; byte bMasterIntf; byte bSaveIntf0; } USB_CDC_UNION_FN_DSC;

Descriptor funcional de control de llamadas

typedef struct _USB_CDC_CALL_MGT_FN_DSC { byte bFNLength; byte bDscType; byte bDscSubType; byte bmCapabilities; byte bDataInterface; } USB_CDC_CALL_MGT_FN_DSC;

1.1.12.4. Externas extern byte cdc_rx_len; extern byte cdc_trf_state; extern POINTER pCDCSrc; extern byte cdc_tx_len; extern byte cdc_mem_type;

1.1.12.5. Prototipos publicos void USBCheckCDCRequest(void); void CDCInitEP(void); byte getsUSBUSART(char *buffer, byte len); void putrsUSBUSART(const rom char *data); void putsUSBUSART(char *data); void CDCTxService(void); #endif CDC_H

34

Page 35: revisar c18usb

Librerías C18 del USB

1.1.13. HID.H: DISPOSITIVO INTERFAZ CON HUMANOS Esta es la librería de la clase HID. Se definen las transferencias creando

funciones para realizarlas.

No hay que modificarla.

1.1.13.1. Incluye #include "system\typedefs.h"

1.1.13.2. Definiciones Repuestas de clase específicas:

#define GET_REPORT 0x01 Obtener informe #define GET_IDLE 0x02 Obtener reposo #define GET_PROTOCOL 0x03 Obtener protocolo #define SET_REPORT 0x09 Fijar informe #define SET_IDLE 0x0A Fijar reposo #define SET_PROTOCOL 0x0B Fijar protocolo

Tipos de clase de descriptor:

#define DSC_HID 0x21 Descriptor HID #define DSC_RPT 0x22 Descriptor informe #define DSC_PHY 0x23

Selección de protocolo:

#define BOOT_PROTOCOL 0x00 Protocolo de inicio #define RPT_PROTOCOL 0x01 Informe de protocolo

Código de clase de interfaz HID:

#define HID_INTF 0x03 Interfaz HID

Código de subclase de interfaz HID:

#define BOOT_INTF_SUBCLASS 0x01

Código de protocolo de clase de interfaz:

#define HID_PROTOCOL_NONE 0x00 Ninguno #define HID_PROTOCOL_KEYBOAD 0x01 Teclado #define HID_PROTOCOL_MOUSE 0x02 Ratón

(bit) mHIDRxIsBusy() Esta macro comprueba si el Endpoint de salida del HID está ocupado

(controlado por el SIE) o no.

Aplicación típica: if(mHIDRxIsBusy())

35

Page 36: revisar c18usb

Documento creado por Slalen para Electronics Strange World

#define mHIDRxIsBusy() HID_BD_OUT.Stat.UOWN

(bit) mHIDTxIsBusy() Esta macro comprueba si el Endpoint de entrada del HID está coupado

(controlado por el SIE) o no.

Aplicación típica: if(mHIDTxIsBusy())

#define mHIDTxIsBusy() HID_BD_IN.Stat.UOWN

byte mHIDGetRptRxLength() Salida: mHIDGetRptRxLength devuelve un informe de la longitud del receptor

HID (hid_rpt_rx_len).

La mHIDGetRptRxLength se utiliza para recuperar el número de bytes copiándolos al buffer de usuario en orden de la última llamada a la función HIDRxReport.

#define mHIDGetRptRxLength() hid_rpt_rx_len

1.1.13.3. Estructuras typedef struct _USB_HID_DSC_HEADER Cabecera del descriptor HID { byte bDscType; Tipo de descriptor word wDscLength; Longitud del descriptor } USB_HID_DSC_HEADER; typedef struct _USB_HID_DSC Descriptor HID { Longitud Tipo de descriptor Bcd del HID byte bLength; byte bDscType; word bcdHID; Código de territorio Número del descriptor byte bCountryCode; byte bNumDsc; USB_HID_DSC_HEADER hid_dsc_header[HID_NUM_OF_DSC]; HID_NUM_OF_DSC se define en autofiles\usbcfg.h } USB_HID_DSC;

1.1.13.4. Externas extern byte hid_rpt_rx_len;

1.1.13.5. Prototipos públicos void HIDInitEP(void); void USBCheckHIDRequest(void); void HIDTxReport(char *buffer, byte len); byte HIDRxReport(char *buffer, byte len);

1.1.14. IO_CFG.H En esta librería se definen los puertos utilizados en la aplicación USB.

36

Page 37: revisar c18usb

Librerías C18 del USB

Si no se desea incluir hay que definir el apartado del USB ya que si no, la compilación daría un error al no definir los puertos Bus Sense y Power Sense.

1.1.14.1. Incluye #include "autofiles\usbcfg.h"

1.1.14.2. Tris #define INPUT_PIN 1 #define OUTPUT_PIN 0

1.1.14.3. USB #define tris_usb_bus_sense TRISAbits.TRISA1 entrada #if defined(USE_USB_BUS_SENSE_IO) #define usb_bus_sense PORTAbits.RA1 #else #define usb_bus_sense 1 #endif #define tris_self_power TRISAbits.TRISA2 entrada #if defined(USE_SELF_POWER_SENSE_IO) #define self_power PORTAbits.RA2 #else #define self_power 1 #endif

Interfaz del transmisor externo

#define tris_usb_vpo TRISBbits.TRISB3 Salida #define tris_usb_vmo TRISBbits.TRISB2 Salida #define tris_usb_rcv TRISAbits.TRISA4 Entrada #define tris_usb_vp TRISCbits.TRISC5 Entrada #define tris_usb_vm TRISCbits.TRISC4 Entrada #define tris_usb_oe TRISCbits.TRISC1 Salida #define tris_usb_suspnd TRISAbits.TRISA3 Salida

1.1.14.4. LED #define mInitAllLEDs() LATD &= 0xF0; TRISD &= 0xF0; #define mLED_1 LATDbits.LATD0 #define mLED_2 LATDbits.LATD1 #define mLED_3 LATDbits.LATD2 #define mLED_4 LATDbits.LATD3 #define mLED_1_On() mLED_1 = 1; #define mLED_2_On() mLED_2 = 1; #define mLED_3_On() mLED_3 = 1; #define mLED_4_On() mLED_4 = 1; #define mLED_1_Off() mLED_1 = 0; #define mLED_2_Off() mLED_2 = 0;

37

Page 38: revisar c18usb

Documento creado por Slalen para Electronics Strange World

#define mLED_3_Off() mLED_3 = 0; #define mLED_4_Off() mLED_4 = 0; #define mLED_1_Toggle() mLED_1 = !mLED_1; #define mLED_2_Toggle() mLED_2 = !mLED_2; #define mLED_3_Toggle() mLED_3 = !mLED_3; #define mLED_4_Toggle() mLED_4 = !mLED_4;

1.1.14.5. Interruptores #define mInitAllSwitches() TRISBbits.TRISB4=1;TRISBbits.TRISB5=1; #define mInitSwitch2() TRISBbits.TRISB4=1; #define mInitSwitch3() TRISBbits.TRISB5=1; //#define sw2 PORTBbits.RB4 #define sw3 PORTBbits.RB5

1.1.14.6. Potenciómetro #define mInitPOT() TRISAbits.TRISA0=1;ADCON0=0x01;ADCON2=0x3C;

1.1.14.7. SPI: Líneas de Chip Select #define tris_cs_temp_sensor TRISBbits.TRISB2 Salida #define cs_temp_sensor LATBbits.LATB2 #define tris_cs_sdmmc TRISBbits.TRISB3 Salida #define cs_sdmmc LATBbits.LATB3

1.1.14.8. SDMMC #define TRIS_CARD_DETECT TRISBbits.TRISB4 Entrada #define CARD_DETECT PORTBbits.RB4 #define TRIS_WRITE_DETECT TRISAbits.TRISA4 Entrada #define WRITE_DETECT PORTAbits.RA4

38

Page 39: revisar c18usb

Librerías C18 del USB

1.1.15. INTERRUPT.H En esta librería se incluye todo lo referente a las interrupciones. El usuario la

modificará dependiendo de la aplicación.

1.1.15.1. Incluye #include "system\typedefs.h"

1.1.15.2. Definiciones #define mEnableInterrupt() INTCONbits.GIE = 1;

1.1.15.3. Prototipos void low_isr(void); void high_isr(void);

39

Page 40: revisar c18usb

Documento creado por Slalen para Electronics Strange World

1.1.16. USB_COMPILE_TIME_VALIDATION.H: VALIDACIÓN DEL TIEMPO DE COMPILADO

Esta librería se utiliza para comprobar errores en la compilación. Es totalmente opcional.

1.1.16.1. Incluye #include "system\typedefs.h" #include "system\usb\usb.h"

1.1.16.2. Validación del USB #if (EP0_BUFF_SIZE != 8) && (EP0_BUFF_SIZE != 16) && (EP0_BUFF_SIZE != 32) && (EP0_BUFF_SIZE != 64) #error(Tamaño del buffer del Endpoint 0 incorrecto, comprueba "autofiles\usbcfg.h") #endif #if defined(HID_INT_OUT_EP_SIZE) #if (HID_INT_OUT_EP_SIZE > 64) #error(El tamaño del Endpoint de salida de HID no puede ser mayor de 64, comprueba "autofiles\usbcfg.h") #endif #endif #ifdef HID_INT_IN_EP_SIZE #if (HID_INT_IN_EP_SIZE > 64) #error(El tamaño del Endpoint de entrada de HID no puede ser mayor de 64, comprueba "autofiles\usbcfg.h") #endif #endif

1.2. LIBRERÍAS DEL MICROPROCESADOR Al instalar el compilador MPLAB C18 se crea una carpeta llamada lkr, en la

cual hay unos archivos que se pueden añadir al proyecto.

Estos archivos definen todos los puertos, registros, bits… del microprocesador que utilicemos en el proyecto.

Es recomendable añadir este archivo ya que todas las librerías trabajan con las definiciones hechas en él.

40

Page 41: revisar c18usb

Librerías C18 del USB

2. MACROS DEL COMPILADOR C18 Una macro es un conjunto de funciones declaradas en un programa. Se declaran

por ser funciones muy utilizadas para ahorrar tiempo al programar.

Para poder trabajar con las funciones definidas en las macros, hay que definir las librerías. En éstas hay un apartado llamado prototipos públicos en los que se declara la macro como función.

Las macros que no aparecen en el apartado de prototipos públicos, son funciones internas que no se pueden llamar desde otro archivo.

En este punto se comentan las macros de Microchip relativas al puerto USB.

Como en las librerías, aparecen en rojo los datos que hay que modificar en cada aplicación, en azul los referentes a la clase y en verde todo el código fuente.

2.1. USBDRV.C: DRIVERS USB En este archive el fabricante ha creado el código relativo a la comunicación

inicial. En el cual se declaran los estados del USB, los comprueba y determina en cual está la aplicación.

2.1.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h" #include "io_cfg.h" Se necesita para USBCheckBusStatus()

2.1.2. VARIABLES #pragma udata

2.1.3. PROTOTIPOS PRIVADOS void USBModuleEnable(void); void USBModuleDisable(void); void USBSuspend(void); void USBWakeFromSuspend(void); void USBProtocolResetHandler(void); void USB_SOF_Handler(void); void USBStallHandler(void); void USBErrorHandler(void);

2.1.4. DECLARACIONES #pragma code

2.1.4.1. void USBCheckBusStatus(void) Esta rutina activa/desactiva el módulo USB comprobado la señal de energía.

41

Page 42: revisar c18usb

Documento creado por Slalen para Electronics Strange World

void USBCheckBusStatus(void) {

Detección de la conexión/desconexión del bus

usb_bus_sense es un puerto de E/S definido en io_cfg.h

#define USB_BUS_ATTACHED 1 #define USB_BUS_DETACHED 0 if(usb_bus_sense == USB_BUS_ATTACHED) ¿Está el USB conectado? { if(UCONbits.USBEN == 0) ¿Está el módulo apagado? USBModuleEnable(); Está apagado, actívalo } else { if(UCONbits.USBEN == 1) ¿Está el módulo encendido? USBModuleDisable(); Está encendido, desactívalo } end if(usb_bus_sense...)

Después de activar el modulo USB, hay un retardo para que la tensión de las líneas D+ o D- se pongan en alto lo suficiente para que salga de la condición SE0.

La interrupción de Reset del USB tiene que estar enmascarada hasta que la condición SE0 esté borrada. Esto ayuda a prevenir que el firmware confunda este evento con un reset del host.

if(usb_device_state == ATTACHED_STATE) { if(!UCONbits.SE0) { UIR = 0; Borra todas las interrupciones del USB UIE = 0; Enmascara todas las interrupciones del USB UIEbits.URSTIE = 1; Desenmascara la interrupción RESET UIEbits.IDLEIE = 1; Desenmascara la interrupción IDLE usb_device_state = POWERED_STATE; } end if Lo demás espera hasta que SE0 esté borrado } end if(usb_device_state == ATTACHED_STATE) } end USBCheckBusStatus

2.1.4.2. void USBModuleEnable(void) Esta rutina activa el módulo USB.

Sólo se puede llamar esta rutina desde USBCheckBusStatus().

void USBModuleEnable(void) { UCON = 0;

42

Page 43: revisar c18usb

Librerías C18 del USB

UIE = 0; Enmascara todas las interrupciones USB UCONbits.USBEN = 1; Activa el modulo y une el bus usb_device_state = ATTACHED_STATE; Definido en usbmmap.c y .h } end USBModuleEnable

2.1.4.3. void USBModuleDisable(void) Esta rutina desactiva el modulo USB.

Sólo se puede llamar esta rutina desde USBCheckBusStatus().

void USBModuleDisable(void) { UCON = 0; Desactiva el modulo y desconecta del bus UIE = 0; Enmascara todas las interrupciones USB usb_device_state = DETACHED_STATE; Definido en usbmmap.c y .h } end USBModuleDisable

2.1.4.4. void USBSoftDetach(void) Efectos secundarios: El dispositivo se tiene que reenumerar.

USBSoftDetach desconecta eléctricamente el dispositivo del bus. Se utiliza para dejar de suministrar tensión VUSB a las resistencias pull-up. Las resistencias pull-down en el lado del host pondrán las señales diferenciales en bajo y el host registrará el evento como una desconexión.

Como el cable USB no se desconecta físicamente, la energía suministrada a través de él la puede detectar el dispositivo. Cuando se llame la función USBCheckBusStatus(), se reconectará el dispositivo al bus.

void USBSoftDetach(void) { USBModuleDisable(); } end USBSoftDetach

2.1.4.5. void USBDriverService(void) Esta rutina es el corazón del firmware. Controla las interrupciones USB.

Nota: Las transiciones de estado del dispositivo son las siguientes:

Desconectado->Conectado->Alimentado->Por defecto->Pendiente de dirección-> ->Direccionado->Configurado->Listo

void USBDriverService(void) { Punto para continuar dando servicio si el cable del USB no está unido. if(usb_device_state == DETACHED_STATE) return;

Tarea A: Servicio de la interrupción de actividad

if(UIRbits.ACTVIF && UIEbits.ACTVIE) USBWakeFromSuspend();

43

Page 44: revisar c18usb

Documento creado por Slalen para Electronics Strange World

Punto para continuar dando servicio si el dispositivo está en modo suspendido. if(UCONbits.SUSPND==1) return;

Tarea B: Servicio de la Interrupción Reset del Bus.

Cuando se recibe un reset del bus durante el modo suspendido, lo primero hay que activar ACTVIF, una vez que UCONbits.SUSPND esté borrado, entonces el bit URSTIF se reafirmará. Esto es porque URSTIF se chequea después de ACTVIF.

El flag de reset USB se enmascara cuando el USB está en estado desconectado o conectado, por lo que no se puede provocar un estado de reset del USB en estos dos estados.

if(UIRbits.URSTIF && UIEbits.URSTIE) USBProtocolResetHandler();

Tarea C: Servicio de otras interrupciones.

if(UIRbits.IDLEIF && UIEbits.IDLEIE) USBSuspend(); if(UIRbits.SOFIF && UIEbits.SOFIE) USB_SOF_Handler(); if(UIRbits.STALLIF && UIEbits.STALLIE) USBStallHandler(); if(UIRbits.UERRIF && UIEbits.UERRIE) USBErrorHandler(); Punto para continuar dando servicio si el bus no ha enviado un reset del bus. Al recibir el reset del bus, el dispositivo cambia al estado por defecto y está listo para comunicarse. if(usb_device_state < DEFAULT_STATE) return;

Tarea D: Servicio de una interrupción de transacción completa

if(UIRbits.TRNIF && UIEbits.TRNIE) { USBCtrlEPService sólo maneja las transacciones del EP0, ignora todas las transacciones de los otros EP. USBCtrlEPService(); Los demás Endpoint se pueden determinar después respondiendo a la clase del firmware. Cada driver del dispositivo sabe cuando una transacción OUT o IN está disponible comprobando el bit de propiedad del buffer. Un EP OUT lo debe controlar siempre el SIE hasta que el dato esté disponible. Un EP IN lo debe controlar siempre la CPU hasta que el dato esté disponible. Por esta lógica, no es necesario guardar el valor de USTAT de una transacción de un Endpoint distinto del 0 (non-EP0). UIRbits.TRNIF = 0; } end if(UIRbits.TRNIF && UIEbits.TRNIE) } end USBDriverService

2.1.4.6. void USBSuspend(void) void USBSuspend(void) { Nota: No borrar UIRbits.ACTVIF aquí Razón: ACTVIF sólo se genera si IDLEIF se ha generado. Es un ratio de generación de interrupción de 1:1. Por cada IDLEIF, habrá sólo un ACTVIF sea cual sea el número de transacciones en el bus. Si el ACTIF se borra aquí, puede ocurrir un problema cuando: [ IDLE ][bus activity -> <--- 3 ms -----> ^ ^ ACTVIF=1

44

Page 45: revisar c18usb

Librerías C18 del USB

IDLEIF=1 # # # # (#=Banderas de programa de interrogación) ^ Este ciclo de pregunta mira IDLEIF=1 y ACTVIF=1. Sin embargo, el programa sirve primero IDLEIF porque ACTIVIE=0. Si esta rutina borra el único ACTIVIF, puede que no salga nunca del modo suspendido. UIEbits.ACTVIE = 1; Activa las interrupciones del bus UIRbits.IDLEIF = 0; UCONbits.SUSPND = 1; Pone el modulo USB en el modo reserva de energía, el reloj SIE inactivo. En este punto el PIC puede ponerse en sleep, reposo, cambiar a un reloj más lento, etc. /* Sección modificable */ /* Final de la sección modificable */ } end USBSuspend

2.1.4.7. void USBWakeFromSuspend(void) void USBWakeFromSuspend(void) { Si se cambia la frecuencia de reloj, en este lugar se vuelve a poner la frecuencia original. UCONbits.SUSPND = 0; UIEbits.ACTVIE = 0; UIRbits.ACTVIF = 0; } end USBWakeFromSuspend

2.1.4.8. void USBRemoteWakeup(void) Esta función la tiene que llamar el usuario cuando el dispositivo se despierte por

un estímulo externo que no sea ACTIVIF.

Nota: La sección modificable en esta rutina se puede cambiar dependiendo de las especificaciones de la aplicación. La implementación actual bloquea temporalmente otras funciones de ejecución en un periodo de 1-13ms dependiendo de la frecuencia del núcleo.

De acuerdo con las especificaciones del USB 2.0 en la sección 7.1.7.7, “El reinicio remoto del dispositivo tiene que bloquear la señal al menos por 1ms y no más de 15ms.” La idea aquí es utilizar un retraso por contador, usando un valor común que pueda trabajar con un gran rango de frecuencias del núcleo. Este valor es 1800. Ver la tabla de debajo:

Frec del núcleo (MHz) MIP Periodo señal RESUME (ms) 48 12 1,05 4 1 12,6

Estos tiempos pueden ser distintos si se utiliza la optimización o el código de instrucciones entendido o cuando se tiene otra interrupción activa. Asegurarse usando del Stopwatch del MPLAB SIM.

void USBRemoteWakeup(void) {

45

Page 46: revisar c18usb

Documento creado por Slalen para Electronics Strange World

static word delay_count; if(usb_stat.RemoteWakeup == 1) Comprueba si el host a activado la función { reinicio remoto USBWakeFromSuspend(); Reinicio del modo suspendido UCONbits.RESUME = 1; Comienzo de la señal RESUME /* Sección modificable */ /* Final de la sección modificable */ UCONbits.RESUME = 0; } endif } end USBRemoteWakeup

2.1.4.9. void USB_SOF_Handler(void) El host envía un paquete SOF a los dispositivos cada milisegundo. Esta

interrupción puede ser útil en las pipes síncronas. Los diseñadores pueden implementar una rutina de realimentación como necesite.

void USB_SOF_Handler(void) { /* Rutina de realimentación aquí */ UIRbits.SOFIF = 0; } end USB_SOF_Handler

2.1.4.10. void USBStallHandler(void) Precondición: El SIE tiene que haber mandado un paquete STALL al host.

El STALLIF se active cada vez que el SIE envía un paquete STALL siempre que un Endpoint lo provoque. Una transacción Setup invalida la función STALL. Un Endpoint paralizado para el STALL cuando recibe un paquete setup. En este caso, el SIE aceptará el paquete Setup y activa la bandera TRNIF para informar el firmware. Una función STALL a un pipe Endpoint particular se desactivará automáticamente (dirección específica).

Hay varios motivos para que un Endpoint se paralice:

1. Cuando se recibe una repuesta no soportada por el USB.

Ejemplo: GET_DESCRIPTOR(DEVICE_QUALIFIER)

2. Cuando un Endpoint está actualmente parado 3. Cuando la clase del dispositivo especifica que Endpoint tiene que

paralizarse en repuesta a un evento específico.

46

Page 47: revisar c18usb

Librerías C18 del USB

Ejemplo: Clase de dispositivo de almacenamiento masivo

Si el CBW no es válido, el dispositivo parará la pipe Bulk de entrada.

Nota: UEPn.EPSTALL tiene que escanear que Endpoint provoca el evento STALL.

void USBStallHandler(void) { Todos los buffer descriptores del Endpoint 0 los controla el SIE, pero al recibir una transacción Setup, la CPU gobierna el EP0_OUT forzándolo por firmware. if(UEP0bits.EPSTALL == 1) { USBPrepareForNextSetupTrf(); UEP0bits.EPSTALL = 0; } UIRbits.STALLIF = 0; } end USBStallHandler

2.1.4.11. void USBErrorHandler(void) El propósito de esta interrupción es sólo por depuración durante el desarrollo.

Chequea UEIR para ver error ha causado la interrupción.

void USBErrorHandler(void) { UIRbits.UERRIF = 0; } end USBErrorHandler

2.1.4.12. void USBProtocolResetHandler(void) Precondición: Se tiene que haber recibido un reset del bus USB desde el host.

Efectos secundarios: Esta rutina purga cualquier transacción pendiente. Borra la FIFO USTAT.

Hay que llamar esta rutina cuando el reset del bus USB se ha recibido. Resetea la dirección del dispositivo a cero, desactiva todos los Endpoints menos el cero, inicializa el EP0 para que esté disponible las comunicaciones por defecto, borra todas los flags de interrupción, desenmascara las interrupciones USB aplicables y reinicializa las variables internas de estado-máquina.

void USBProtocolResetHandler(void) { UEIR = 0; Borra todas los flags de error del USB UIR = 0; Borra todas las interrupciones USB UEIE = 0b10011111; Desenmascara todos los errores de interrupción USB UIE = 0b01111011; Activa todas las interrupciones menos ACTVIE UADDR = 0x00; Resetea a la dirección por defecto mDisableEP1to15(); Resetea todos los registros UEPn non-EP0 UEP0 = EP_CTRL|HSHK_EN; Inicializa el EP0 como EP Ctrl, ver usbdrv.h while(UIRbits.TRNIF == 1) Borra cualquier transacción pendiente UIRbits.TRNIF = 0; UCONbits.PKTDIS = 0; Se asegura de que el procesamiento de paquetes esté activo

47

Page 48: revisar c18usb

Documento creado por Slalen para Electronics Strange World

USBPrepareForNextSetupTrf(); Declarado en usbctrltrf.c usb_stat.RemoteWakeup = 0; Desactiva el flag de estado por defecto usb_active_cfg = 0; Borra la configuración activa usb_device_state = DEFAULT_STATE; } end USBProtocolResetHandler

2.1.5. FUNCIÓN AUXILIAR void ClearArray(byte* startAdr,byte count) { *startAdr; while(count) { _asm clrf POSTINC0,0 _endasm count--; } end while } end ClearArray

2.2. USB9.C Estas macros establecen la conexión.

2.2.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h" #include "io_cfg.h" Requerido para el estado auto-alimentado

2.2.2. VARIABLES #pragma udata

2.2.3. PROTOTIPOS PRIVADOS void USBStdGetDscHandler(void); void USBStdSetCfgHandler(void); void USBStdGetStatusHandler(void); void USBStdFeatureReqHandler(void);

2.2.4. DECLARACIONES #pragma code

48

Page 49: revisar c18usb

Librerías C18 del USB

2.2.4.1. void USBCheckStdRequest(void) Esta rutina chequea el paquete de datos setup para ver si sabe cuando conectarse.

void USBCheckStdRequest(void) { if(SetupPkt.RequestType != STANDARD) return; switch(SetupPkt.bRequest) { case SET_ADR: ctrl_trf_session_owner = MUID_USB9; usb_device_state = ADR_PENDING_STATE; Actualización de estado Ver USBCtrlTrfInHandler() en usbctrltrf.c para el próximo paso break; case GET_DSC: ctrl_trf_session_owner = MUID_USB9; if(SetupPkt.bDscType == DSC_DEV) { pSrc.bRom = (rom byte*)&device_dsc; wCount._word = sizeof(device_dsc); Activa la cuenta de datos } else if(SetupPkt.bDscType == DSC_CFG) { pSrc.bRom = (rom byte*)&cfg01; wCount._word = sizeof(cfg01); Activa la cuenta de datos } else if(SetupPkt.bDscType == DSC_STR) { pSrc.bRom = (rom byte*)&sd000; wCount._word = sizeof(sd000); Activa la cuenta de datos } else Esto se necesita para parar la respuesta DEVICE_QUALIFIER ctrl_trf_session_owner = MUID_NULL; usb_stat.ctrl_trf_mem = _ROM; Fija el tipo de memoria break; case SET_CFG: USBStdSetCfgHandler(); break; case GET_CFG: ctrl_trf_session_owner = MUID_USB9; pSrc.bRam = (byte*)&usb_active_cfg; Fija la fuente usb_stat.ctrl_trf_mem = _RAM; Fija el tipo de memoria LSB(wCount) = 1; Activa la cuenta de datos break; case GET_STATUS: USBStdGetStatusHandler(); break; case CLR_FEATURE: case SET_FEATURE: USBStdFeatureReqHandler(); break;

49

Page 50: revisar c18usb

Documento creado por Slalen para Electronics Strange World

case GET_INTF: ctrl_trf_session_owner = MUID_USB9; pSrc.bRam = (byte*)&usb_alt_intf+SetupPkt.bIntfID; Fija la fuente usb_stat.ctrl_trf_mem = _RAM; Fija el tipo de memoria LSB(wCount) = 1; Activa la cuenta de datos break; case SET_INTF: ctrl_trf_session_owner = MUID_USB9; usb_alt_intf[SetupPkt.bIntfID] = SetupPkt.bAltID; break; case SET_DSC: case SYNCH_FRAME: default: break; } end switch } end USBCheckStdRequest

2.2.4.2. void USBStdGetDscHandler(void) Esta rutina une la respuesta estándar GET_DESCRIPTOR. Utiliza tablas

dinámicamente buscando el tamaño del descriptor. Esta rutina no se debe modificar si las tablas usbdsc.c en están declaradas correctamente.

void USBStdGetDscHandler(void) { if(SetupPkt.bmRequestType == 0x80) { switch(SetupPkt.bDscType) { case DSC_DEV: ctrl_trf_session_owner = MUID_USB9; pSrc.bRom = (rom byte*)&device_dsc; wCount._word = sizeof(device_dsc); Activa la cuenta de datos break; case DSC_CFG: ctrl_trf_session_owner = MUID_USB9; pSrc.bRom = *(USB_CD_Ptr+SetupPkt.bDscIndex); wCount._word = *(pSrc.wRom+1); Activa la cuenta de datos break; case DSC_STR: ctrl_trf_session_owner = MUID_USB9; pSrc.bRom = *(USB_SD_Ptr+SetupPkt.bDscIndex); wCount._word = *pSrc.bRom; Activa la cuenta de datos break; } end switch usb_stat.ctrl_trf_mem = _ROM; Fija el tipo de memoria } end if } end USBStdGetDscHandler

50

Page 51: revisar c18usb

Librerías C18 del USB

2.2.4.3. void USBStdSetCfgHandler(void) Esta rutina primero desactiva todos los Endpoints borrando los registros UEP.

Configura (inicializa) los Endpoints especificados en la sección modificable.

void USBStdSetCfgHandler(void) { ctrl_trf_session_owner = MUID_USB9; mDisableEP1to15(); Ver usbdrv.h ClearArray((byte*)&usb_alt_intf,MAX_NUM_INT); usb_active_cfg = SetupPkt.bCfgValue; if(SetupPkt.bCfgValue == 0) usb_device_state = ADDRESS_STATE; else { usb_device_state = CONFIGURED_STATE; /* Sección modificable */ BootInitEP(); /* Final de la sección modificable */ } end if(SetupPkt.bcfgValue == 0) } end USBStdSetCfgHandler

2.2.4.4. void USBStdGetStatusHandler(void) Esta rutina une la respuesta estándar GET_STATUS.

void USBStdGetStatusHandler(void) { CtrlTrfData._byte0 = 0; Inicializa el contenido CtrlTrfData._byte1 = 0; switch(SetupPkt.Recipient) { case RCPT_DEV: ctrl_trf_session_owner = MUID_USB9; _byte0: bit0: Estado auto-alimentado [0] Alimentado por el bus [1] auto-alimentado bit1: Reinicio remoto [0] Desactivado [1] Activado if(self_power == 1) Auto-alimentado definido en io_cfg.h CtrlTrfData._byte0|=0b000000001; Activa bit0 if(usb_stat.RemoteWakeup == 1) usb_stat definido en usbmmap.c CtrlTrfData._byte0|=0b00000010; Activa bit1 break; case RCPT_INTF: ctrl_trf_session_owner = MUID_USB9; No hay datos a actualizar break; case RCPT_EP: ctrl_trf_session_owner = MUID_USB9; _byte0: bit0: Estado parado [0] No parado [1] Parado pDst.bRam = (byte*)&ep0Bo+(SetupPkt.EPNum*8)+(SetupPkt.EPDir*4); if(*pDst.bRam & _BSTALL) Usar _BSTALL como máscara de bit CtrlTrfData._byte0=0x01; Activa bit0 break; } end switch

51

Page 52: revisar c18usb

Documento creado por Slalen para Electronics Strange World

if(ctrl_trf_session_owner == MUID_USB9) { pSrc.bRam = (byte*)&CtrlTrfData; Fija fuente usb_stat.ctrl_trf_mem = _RAM; Fija el tipo de memoria LSB(wCount) = 2; Activa la cuenta de datos } end if(...) } end USBStdGetStatusHandler

2.2.4.5. void USBStdFeatureReqHandler(void) Esta rutina une las repuestas estándar SET y CLEAR FEATURES.

void USBStdFeatureReqHandler(void) { if((SetupPkt.bFeature==DEVICE_REMOTE_WAKEUP)&&(SetupPkt.Recipient==RCPT_DEV)) { ctrl_trf_session_owner = MUID_USB9; if(SetupPkt.bRequest == SET_FEATURE) usb_stat.RemoteWakeup = 1; else usb_stat.RemoteWakeup = 0; } end if if((SetupPkt.bFeature==ENDPOINT_HALT)&&(SetupPkt.Recipient==RCPT_EP)&& (SetupPkt.EPNum!=0)) { ctrl_trf_session_owner = MUID_USB9; Se tiene que calcular la dirección en este punto pDst.bRam = (byte*)&ep0Bo+(SetupPkt.EPNum*8)+(SetupPkt.EPDir*4); if(SetupPkt.bRequest == SET_FEATURE) *pDst.bRam = _USIE|_BSTALL; else { if(SetupPkt.EPDir == 1) // IN *pDst.bRam = _UCPU; else *pDst.bRam = _USIE|_DAT0|_DTSEN; } end if } end if } end USBStdFeatureReqHandler

52

Page 53: revisar c18usb

Librerías C18 del USB

2.3. USBCTRLTRF.C Estas macros controlan las transferencias.

2.3.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h"

2.3.2. VARIABLES #pragma udata byte ctrl_trf_state; Estado de la transferencia de control byte ctrl_trf_session_owner; Controlador de la sesión de transferencia actual POINTER pSrc; Puntero a la fuente de datos POINTER pDst; Puntero al destino de los datos WORD wCount; Contador de datos

2.3.3. PROTOTIPOS PRIVADOS void USBCtrlTrfSetupHandler(void); void USBCtrlTrfOutHandler(void); void USBCtrlTrfInHandler(void);

2.3.4. DECLARACIONES #pragma code

2.3.4.1. void USBCtrlEPService(void) Precondición: USTAT está cargada con una dirección de Endpoint válida.

USBCtrlEPService chequea tres tipos de transacciones que conoce como tratarlas y lo hace:

1. EP0 SETUP 2. EP0 OUT 3. EP0 IN

Ignora los demás tipos.

void USBCtrlEPService(void) { if(USTAT == EP00_OUT) { if(ep0Bo.Stat.PID == SETUP_TOKEN) EP0 SETUP USBCtrlTrfSetupHandler(); else EP0 OUT USBCtrlTrfOutHandler(); } else if(USTAT == EP00_IN) EP0 IN USBCtrlTrfInHandler(); } end USBCtrlEPService

53

Page 54: revisar c18usb

Documento creado por Slalen para Electronics Strange World

2.3.4.2. void USBCtrlTrfSetupHandler(void) Precondición: El buffer SetupPkt está cargado con un dato válido de Setup.

Esta rutina es una tarea para despachar y tiene tres estados.

1. Inicializa la transferencia de control de estados máquina. 2. Llama cada vez al módulo que sabe como servir la respuesta Setup del

host. Ejemplo de módulo: USB9, HID, CDC, MSD,… Se añade una nueva clase, la tabla ClassReqHandler en usbdsc.c se tiene que actualizar para llamar todas las clases de unión disponibles.

3. Una vez que el módulo se arriesga a chequear si el responsable de servir la respuesta, en el estado 3 chequea la dirección de la transferencia para determinar como preparar el EP0 para la transferencia de control.

Nota: El firmware del USB de Microchip tiene tres estados distintos para el control de los estados máquina:

1. WAIT_SETUP 2. CTRL_TRF_TX 3. CTRL_TRF_RX

Mirar en el manual del firmware como cambia de un estado a otro.

Una transferencia de control se compone de varias transacciones USB. Cuando se transfieren datos con muchas transacciones, es importante guardar los datos fuente, datos destino y cuenta de datos. Estos tres parámetros se guardan en pSrc, pDst y wCount. Un flag se utiliza para ver si la fuente de los datos es de la RAM o de la ROM.

2.3.4.3. void USBCtrlTrfSetupHandler(void) { byte i; Estado 1 ctrl_trf_state = WAIT_SETUP; ctrl_trf_session_owner = MUID_NULL; Fijar el dueño a NULL wCount._word = 0; Estado 2 USBCheckStdRequest(); Ver system\usb9\usb9.c /* Sección Modificable */ Insertar otra respuesta de unión de clase de dispositivo USB aquí /* Fin de la sección modificable */ Estado 3 USBCtrlEPServiceComplete(); } end USBCtrlTrfSetupHandler

2.3.4.4. void USBCtrlTrfOutHandler(void) Esta rutina une una transacción OUT de acuerdo con el estado de la transferencia

de control que está actualmente activa.

54

Page 55: revisar c18usb

Librerías C18 del USB

Nota: Si la transferencia de control es del host al dispositivo, hay que notificar el dueño de la sesión cada transacción OUT para dar servicio a los datos recibidos.

void USBCtrlTrfOutHandler(void) { if(ctrl_trf_state == CTRL_TRF_RX) { USBCtrlTrfRxService(); No preocuparse de reescribir el bit _KEEP porque si está activo, TRNIF no se generará en primer lugar. if(ep0Bo.Stat.DTS == 0) ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN; else ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN; } else CTRL_TRF_TX USBPrepareForNextSetupTrf(); } end USBCtrlTrfOutHandler

2.3.4.5. void USBCtrlTrfInHandler(void) Esta rutina une una transacción IN de acuerdo con el estado de la transferencia

de control que está actualmente activa.

Nota: Si se fija la dirección de respuesta no modificará la actual hasta que se complete la transferencia de control. El final de la transferencia de control para una repuesta de cambio de dirección es una transacción IN. Por lo tanto se necesita para servir esta situación cuando la condición es correcta. La macro mUSBCheckAdrPendingState se define en usb9.h y está diseñada para servir este evento.

void USBCtrlTrfInHandler(void) { mUSBCheckAdrPendingState(); Se tiene que comprobar si está en ADR_PENDING_STATE if(ctrl_trf_state == CTRL_TRF_TX) { USBCtrlTrfTxService(); if(ep0Bi.Stat.DTS == 0) ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN; else ep0Bi.Stat._byte = _USIE|_DAT0|_DTSEN; } else CTRL_TRF_RX USBPrepareForNextSetupTrf(); } end USBCtrlTrfInHandler

2.3.4.6. void USBCtrlTrfTxService(void) Precondición: pSrc, wCount, y usb_stat.ctrl_trf_mem están configurados

correctamente.

55

Page 56: revisar c18usb

Documento creado por Slalen para Electronics Strange World

Hay que llamar esta rutina en dos casos. Uno desde USBCtrlEPServiceComplete() y otro desde USBCtrlTrfInHandler(). Hay que tener cuidado con el control de una transferencia sobre múltiples transacciones USB.

Nota: Esta rutina trabaja con Endpoints síncronos mayores que 256bytes y aquí se muestra un ejemplo de cómo tratar BC9 y BC8. En realidad, un Endpoint de control no puede ser mayor de 64bytes.

void USBCtrlTrfTxService(void) { byte byte_to_send; Primero, hay que calcular cuantos bytes de datos se envían. if(wCount._word < EP0_BUFF_SIZE) byte_to_send = wCount._word; else byte_to_send = EP0_BUFF_SIZE; ep0Bi.Cnt = byte_to_send; Resta el número de bytes enviados a los del total. wCount._word -= byte_to_send; pDst.bRam = (byte*)&CtrlTrfData; Fija el puntero destino while(byte_to_send) { if(usb_stat.ctrl_trf_mem == _ROM) { *pDst.bRam = *pSrc.bRom; pSrc.bRom++; } else { *pDst.bRam = *pSrc.bRam; pSrc.bRam++; }//end if else pDst.bRam++; byte_to_send--; } end while } end USBCtrlTrfTxService

2.3.4.7. void USBCtrlTrfRxService(void) Precondiciones: pDst y wCount tienen que estar configurados correctamente.

pSrc siempre es &CtrlTrfData y usb_stat.ctrl_trf_mem es _RAM. wCount tiene que estar configurado como 0 al principio de cada transferencia de control.

Esta rutina no está completada. Comprueba una nueva versión del firmware.

void USBCtrlTrfRxService(void) { byte byte_to_read; byte_to_read = ep0Bo.Cnt; Acumula el número total de bytes leídos wCount._word = wCount._word + byte_to_read; pSrc.bRam = (byte*)&CtrlTrfData;

56

Page 57: revisar c18usb

Librerías C18 del USB

while(byte_to_read) { *pDst.bRam = *pSrc.bRam; pDst.bRam++; pSrc.bRam++; byte_to_read--; } end while(byte_to_read) } end USBCtrlTrfRxService

2.3.4.8. void USBCtrlEPServiceComplete(void) Esta rutina consigue que la tarea en servicio sea una repuesta setup. Esta tarea

sirve para configurar los controles del Endpoint apropiadamente para una situación dada.

Hay tres:

a. No hay unión para la respuesta, in este caso hay que mandar un STALL.

b. El host ha respondido con una lectura de transferencia de control, los Endpoints se necesitan para determinar el camino.

c. El host ha respondido con una escritura de transferencia de control o no se necesita un estado de control de datos, los Endpoints se necesitan para determinar el camino.

Se resume el procesamiento del paquete borrando el bit PKTDIS.

void USBCtrlEPServiceComplete(void) { if(ctrl_trf_session_owner == MUID_NULL) { Si ninguno sabe cómo dar servicio a esta respuesta, entonces se para. * If no one knows how to service this request then stall. Tiene que preparar el EP0 para que reciba la siguiente transacción SETUP. ep0Bo.Cnt = EP0_BUFF_SIZE; ep0Bo.ADR = (byte*)&SetupPkt; ep0Bo.Stat._byte = _USIE|_BSTALL; ep0Bi.Stat._byte = _USIE|_BSTALL; } else El modulo demanda el control de la sesión de transferencia. { if(SetupPkt.DataDir == DEV_TO_HOST) { if(SetupPkt.wLength < wCount._word) wCount._word = SetupPkt.wLength; USBCtrlTrfTxService(); ctrl_trf_state = CTRL_TRF_TX; Control de lectura: <SETUP[0]><IN[1]><IN[0]>...<OUT[1]> | <SETUP[0]> 1. Prepara EP OUT para responder a una terminación temprana NOTA: Si algo va mal durante la transferencia de control, puede que el host no envíe la última fase de estado. Cuando pasa esto, pueden ocurrir dos cosas dependiendo del host:

a) El host envía un RESET

57

Page 58: revisar c18usb

Documento creado por Slalen para Electronics Strange World

b) El host puede mandar una nueva transacción SETUP sin enviar primero un RESET.

Para que el caso b) comunique correctamente, el EP OUT tiene que configurarse para recibir una transacción OUT de longitud cero o una nueva transacción SETUP. Como la transacción SETUP necesita que el bit DTS sea DAT0, el estado de longitud cero necesita que el bit DTS sea DAT1, la comprobación del bit DTS por hardware tiene que desactivarse. En este caso el SIE puede aceptar cualquiera de las dos transacciones. Además, el byte Cnt se tiene que fijar para prepararse para el dato SETUP (8bytes o mas), y el buffer de dirección tiene que apuntar al SetupPkt. ep0Bo.Cnt = EP0_BUFF_SIZE; ep0Bo.ADR = (byte*)&SetupPkt; ep0Bo.Stat._byte = _USIE; Nota: DTSEN es 0 2. Prepara el EP IN para una transferencia de datos, Cnt tiene que estar inicializado para ser el responsable de una respuesta de dueño. ep0Bi.ADR = (byte*)&CtrlTrfData; ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN; } else (SetupPkt.DataDir = HOST_TO_DEV) { ctrl_trf_state = CTRL_TRF_RX; Control Escritura: <SETUP[0]><OUT[1]><OUT[0]>...<IN[1]> | <SETUP[0]> 1. Prepara el EP IN para responder ante una finalización temprana. Es lo mismo que una respuesta a un paquete de longitud cero para una transferencia de control sin fase de datos. ep0Bi.Cnt = 0; ep0Bi.Stat._byte = _USIE|_DAT1|_DTSEN; 2. Prepara el EP OUT para recibir datos. ep0Bo.Cnt = EP0_BUFF_SIZE; ep0Bo.ADR = (byte*)&CtrlTrfData; ep0Bo.Stat._byte = _USIE|_DAT1|_DTSEN; } end if(SetupPkt.DataDir == DEV_TO_HOST) } end if(ctrl_trf_session_owner == MUID_NULL) El bit PKTDIS se activa cuando se recibe una transacción Setup. Borrar para resumir el procesamiento del paquete. UCONbits.PKTDIS = 0; } end USBCtrlEPServiceComplete

2.3.4.9. void USBPrepareForNextSetupTrf(void) La rutina fuerza al EP0 OUT que esté listo para una nueva transacción Setup, y

fuerza a que la CPU controle el EP0 IN.

void USBPrepareForNextSetupTrf(void) { ctrl_trf_state = WAIT_SETUP; Ver usbctrltrf.h ep0Bo.Cnt = EP0_BUFF_SIZE; Definido en usbcfg.h ep0Bo.ADR = (byte*)&SetupPkt; ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN; Inicialización EP0 buff dsc, ver usbmmap.h ep0Bi.Stat._byte = _UCPU; EP0 IN buffer inicialización } end USBPrepareForNextSetupTrf

58

Page 59: revisar c18usb

Librerías C18 del USB

2.4. USBDSC.C: DESCRIPTORES USB Este archivo contiene la información de los descriptores USB. Se utiliza junto al

archivo usbdsc.h. Cuando se añade o remueve un descriptor del menú de configuración de los descriptores, ej. CFG01, el usuario debe cambiar la estructura del descriptor definida en el archivo usbdsc.h. La estructura se utiliza para calcular el tamaño del descriptor, ej. sizeof(CFG01).

Una configuración típica de los descriptores consiste en:

La mínima configuración del descriptor (USB_CFG_DSC)

Uno o más descriptores de interfaz (USB_INTF_DSC)

Uno o más descriptores de Endpoint (USB_EP_DSC)

Nombres convenidos:

Tipo USB_CFG_DSC se nombra cdxx, donde xx es el número de configuración. Este número debería ser el mismo que el valor del índice actual de esta configuración.

Tipo USB_INTF_DSC se nombra i<yy>a<zz>, donde yy es el número de la interfaz y zz es el número de la interfaz alterna.

Tipo USB_EP_DSC se nombra ep<##><d>_i<yy>a<zz>, donde ## es el número del Endpoint y d es la dirección de transferencia.

El nombre de la interfaz se tiene que listar como un sufijo para identificar que interfaz pertenece al Endpoint.

Ejemplo:

Si un dispositivo tiene una configuración, dos interfaces, la interfaz 0 tiene dos Endpoints (IN y OUT), y la interfaz 1 tiene un Endpoint (IN). Entonces la estructura en usbdsc.h tiene que ser:

#define CFG01 rom struct

{ USB_CFG_DSC cd01;

USB_INTF_DSC i00a00;

USB_EP_DSC ep01o_i00a00;

USB_EP_DSC ep01i_i00a00;

USB_INTF_DSC i01a00;

USB_EP_DSC ep02i_i01a00;

} cfg01

Ver que la jerarquía de los descriptores sigue a las especificaciones de necesidad del USB. Todos los Endpoint que pertenecen a una interfaz se tienen que listar inmediatamente después que la interfaz.

Rellenar los valores del descriptor en el archivo usbdsc.c:

[Descriptor de Configuration (USB_CFG_DSC)]

59

Page 60: revisar c18usb

Documento creado por Slalen para Electronics Strange World

El atributo de configuración tiene que tener la definición _DEFAULT como mínimo. Se pueden añadir opciones adicionales al tributo _DEFAULT. Las opciones disponibles son _SELF y _RWU.

Estas definiciones se encuentran en el archivo usbdefs_std_dsc.h. El _SELF dice al host del USB que este dispositivo es autoalimentado. El _RWU dice al host del USB que el dispositivo soporta el reinicios remoto.

[Descriptor del Endpoint (USB_EP_DSC)]

Suponer el siguiente ejemplo:

sizeof(USB_EP_DSC),DSC_EP,_EP01_OUT,_BULK,64,0x00

Los dos primeros parámetros son auto-explicativos. Especifican la longitud del descriptor del Endpoint (7) y el tipo de descriptor. El siguiente parámetro identifica el Endpoint, las definiciones se encuentran en usbdefs_std_dsc.h y tienen la siguiente convención:

_EP<##>_<dir>

donde ## es el número del endpoint y dir es la dirección de la transferencia. dir tiene el valor de ‘OUT’ o ‘IN’.

El siguiente parámetro especifica el tipo de Endpoint. Las opciones disponibles son _BULK, _INT, _ISO, y _CTRL. El _CTRL no se utiliza normalmente porque el Endpoint de transferencia de control por defecto no se define en los descriptores USB. Cuando se utiliza la opción _ISO, se pueden añadir opciones adicionales. Ejemplo:

_ISO|_AD|_FE

Esto describe el Endpoint como una pipe síncrona con los atributos adoptivo y realimentación. Ver usbdefs_std_dsc.h y las especificaciones del USB por más detalles. El siguiente parámetro define el tamaño del Endpoint. El último parámetro es el intervalo de muestreo.

Añadir un String al USB

Una matriz de string descriptor debe tener el siguiente formato:

rom struct{byte bLength;byte bDscType;word string[size];}sdxxx={

sizeof(sdxxx),DSC_STR,<text>};

La estructura proporciona un medio al compilador de C para calcular la longitud del string descriptor sdxxx, donde xxx es el número de índice. Los dos primeros bytes del descriptor son su longitud y tipo. El resto <text> son strings de texto que tienen que estar en formato unicode. El formato unicode se obtiene declarando cada carácter como un tipo de letra. Todo el texto string se declara como una matriz de letras con el número de caracteres igual a <size>. <size> se tiene que contar manualmente y meter en las declaraciones de la matriz. Ejemplo:

Si el string es “USB”, entonces el string descriptor debe ser:

(Utilizando índice 02)

rom struct{byte bLength;byte bDscType;word string[3];}sd002={

sizeof(sd002),DSC_STR,'U','S','B'};

60

Page 61: revisar c18usb

Librerías C18 del USB

Un proyecto USB puede que tenga varios strings y el firmware soporta el control de múltiples strings como una búsqueda en tabla.

La búsqueda en tabla se define:

rom const unsigned char *rom USB_SD_Ptr[]={&sd000,&sd001,&sd002};

La declaración de arriba tiene 3 strings, sd000, sd001 y sd002. Los strings se pueden añadir o borrar. sd000 es un string descriptor especial, define el idioma, normalmente es inglés americano (US English (0x0409)). El índice del string debe ser igual que el índice de posición de la matriz USB_SD_Ptr, &sd000 tiene que estar en la posición USB_SD_Ptr[0], &sd001 tiene que estar en la posición USB_SD_Ptr[1] y así sucesivamente.

La búsqueda en tabla USB_SD_Ptr la utiliza la función de unión string en usb9.c.

El esquema de búsqueda en tabla también se aplica a la descriptor de configuración. Un dispositivo USB puede tener varios descriptores de configuraciones, ej. CFG01, CFG02, etc. Para añadir un descriptor de configuración, el usuario tiene que implementar una estructura similar a CFG01.

El siguiente paso es añadir el nombre del descriptor de configuración, ej. cfg01, cfg02…; a la búsqueda en tabla USB_CD_Ptr. USB_CD_Ptr[0] es muy fácil poner el titular ya que la configuración 0 es el estado no configurado de acuerdo con las especificaciones del USB.

Los tipos de descriptor específicos se definen en:

system\usb\usbdefs\usbdefs_std_dsc.h

La información de configuración se define en:

autofiles\usbcfg.h

2.4.1. INCLUYE #include "system\typedefs.h" #include "system\usb\usb.h"

2.4.2. CONSTANTES #pragma romdata Descriptor del dispositivo rom USB_DEV_DSC device_dsc= { sizeof(USB_DEV_DSC), Tamaño del descriptor en bytes DSC_DEV, Descriptor tipo DEVICE 0x0200, Número de versión del USB en formato BCD 0x00, Código de Clase 0x00, Código Subclase 0x00, Código Protocolo EP0_BUFF_SIZE, Tamaño de paquete máximo para el EP0, ver usbcfg.h 0x04D8, ID Fabricante 0x0000, ID Producto

61

Page 62: revisar c18usb

Documento creado por Slalen para Electronics Strange World

0x0001, Número de versión del dispositivo en formato BCD 0x01, String índice de fabricante 0x02, String índice del producto 0x00, String índice del número de serie del dispositivo 0x01 Número de configuraciones posible }; Descriptor de configuración 1 CFG01={ Descriptor de configuración sizeof(USB_CFG_DSC), Tamaño del descriptor en bytes DSC_CFG, Tipo del descriptor CONFIGURACIÓN sizeof(cfg01), Longitud total de datos de esta configuración 1, Número de interfaces en esta configuración 1, Valor del índice de esta configuración 0, String índice de configuración _DEFAULT|_RWU, Atributos, ver usbdefs_std_dsc.h 50, Consumo máximo de corriente (2X mA) Descriptor de la interfaz sizeof(USB_INTF_DSC), Tamaño del descriptor en bytes DSC_INTF, Tipo de descriptor INTERFACE 0, Número de Interface 0, Número alterno de configuración 1, Número de Endpoints en esta interfaz HID_INTF, Código de la Clase BOOT_INTF_SUBCLASS, Código de la Subclase HID_PROTOCOL_MOUSE, Código del Protocolo 0, String índice de interfaz Descriptor de Clase Específica HID sizeof(USB_HID_DSC), Tamaño del descriptor en bytes DSC_HID, Tipo del descriptor HID 0x0101, Número de versión específica HID en formato BCD 0x00, Código del país (0x00 en los no soportados) HID_NUM_OF_DSC, Número de la clase del descriptor, ver usbcfg.h DSC_RPT, Tipo del informe del descriptor sizeof(hid_rpt01), Tamaño del informe del descriptor Descriptor del Endpoint sizeof(USB_EP_DSC),DSC_EP,_EP01_IN,_INT,HID_INT_IN_EP_SIZE,0x0A }; rom struct{byte bLength;byte bDscType;word string[1];}sd000={ sizeof(sd000),DSC_STR,0x0409}; rom struct{byte bLength;byte bDscType;word string[25];}sd001={ sizeof(sd001),DSC_STR, 'M','i','c','r','o','c','h','i','p',' ', 'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'}; rom struct{byte bLength;byte bDscType;word string[22];}sd002={ sizeof(sd002),DSC_STR, 'M','o','u','s','e',' ','I','n',' ','a',' ',

62

Page 63: revisar c18usb

Librerías C18 del USB

'C','i','r','c','l','e',' ','D','e','m','o'}; rom struct{byte report[HID_RPT01_SIZE];}hid_rpt01={ 0x05, 0x01, Página de uso (Escritorio genérico) 0x09, 0x02, Uso (Ratón) 0xA1, 0x01, Colección (Aplicación) 0x09, 0x01, Uso (Puntero) 0xA1, 0x00, Colección (Física) 0x05, 0x09, Página de uso (Botones) 0x19, 0x01, Uso mínimo (01) 0x29, 0x03, Uso máximo (03) 0x15, 0x00, Mínimo lógico (0) 0x25, 0x01, Máximo lógico (0) 0x95, 0x03, Cuenta del informe (3) 0x75, 0x01, Tamaño del informe (1) 0x81, 0x02, Entrada (Dato, Variable, Absoluto) 0x95, 0x01, Cuenta del informe (1) 0x75, 0x05, Tamaño del informe (5) 0x81, 0x01, Entrada (Constante); 5 bit de relleno 0x05, 0x01, Uso de página (Escritorio genérico) 0x09, 0x30, Uso (X) 0x09, 0x31, Uso (Y) 0x15, 0x81, Mínimo lógico (-127) 0x25, 0x7F, Máximo lógico (127) 0x75, 0x08, Tamaño del informe (8) 0x95, 0x02, Cuenta del informe (2) 0x81, 0x06, Entrada (Dato, Variable, Relativo) 0xC0, 0xC0}; Fin de la colección rom const unsigned char *rom USB_CD_Ptr[]={&cfg01,&cfg01}; rom const unsigned char *rom USB_SD_Ptr[]={&sd000,&sd001,&sd002}; rom pFunc ClassReqHandler[1]= { &USBCheckHIDRequest }; #pragma code

2.5. USBMMAP.C Este archivo es el que controla la memoria del USB, sirve para asignar la

memoria en cada instante a los Endpoint. Utiliza los tiempos de compilación de usbcfg.h instantáneamente para los Endpoints y sus buffers.

Cada Endpoint necesita fijar un registro del buffer descriptor (BDT). Un BDT tiene 4bytes de longitud y una memoria específica en la RAM para cada Endpoint. El BDT del EP0 OUT está entre las direcciones 0x400 a 0x403, el BDT del EP0 IN en 0x404 a0x407, el del EP1 OUT 0x408 a 0x40B y así sucesivamente. Estas localizaciones son correctas con el Buffer Ping-Pong en Modo 0. Estas localizaciones

63

Page 64: revisar c18usb

Documento creado por Slalen para Electronics Strange World

están conectadas en el chip. Al hacerlas instantáneas, ej. volatile far BDT ep0Bo, es para proporcionar al compilador de C un camino para direccionar cada variable directamente. Esto es muy importante porque cuando se puede acceder a un registro directamente, se ahorra tiempo de ejecución y se reduce el tamaño de programa.

Los Endpoints se definen con el número de Endpoint y la dirección de transferencia. Para simplificar, usbmmap.c sólo utiliza el número del Endpoint del esquema de direccionamiento de los registros BDT. Con este método si MAX_EP_NUMBER es 1, tenemos cuatro BDTs instantáneamente: uno para EP0IN, otro para EP0OUT, que se tiene que inicializar instantáneamente para las transferencias de control por defecto, y otros dos para EP1IN y EP1OUT. El nombre convenido es ep<#>B<d> donde # es el número del Endpoint y d es la dirección de transferencia, que puede ser <i> o <o>.

El control de la memoria USB utiliza MAX_EP_NUMBER, definido en usbcfg.h, para saber que Endpoints se necesitan instantáneamente. Representa el número máximo de Endpoints que se direccionan, no cuantos Endpoints se utilizan. Como los BDTs para los Endpoints tienen la dirección asignada en el Bank 4 en hardware, configurar este valor con un dato muy grande puede que se utilice inadecuadamente la RAM. Por ejemplo, en una aplicación se utiliza los EP0 y EP4, el MAX_EP_NUMBER es 4, y no 2. Los Endpoints del medio (EP1, EP2 y EP3) no se utilizan, y los 24bytes de memoria asociados se pierden. No tiene mucho sentido saltar Endpoints, pero la decisión final la tiene el usuario.

El paso siguiente es asignar los BDTs instantáneos a las distintas funciones del USB. El firmware asume que cada función del USB sabe que Endpoint utiliza, ej. la transferencia de control por defecto sabe que utiliza el EP0IN y el EP0OUT. Una clase HID puede elegir que Endpoint utiliza, pero una vez elegido tiene que saber el número.

La asignación de los Endpoints de las funciones del USB se gobiernan en usbcfg.h. Esto ayuda a prevenir errores de tener más de una función USB con el mismo Endpoint. La sección “Distribución de los Endpoints” en usbcfg.h proporciona un ejemplo de cómo distribuir los Endpoints del USB con funciones USB.

Se puede cambiar la configuración en esta sección. No hay una forma correcta de configuración y los usuarios tienen que elegir el método más adecuado para la aplicación.

Normalmente, un usuario mapeará lo siguiente para una función de interfaz:

1. El ID de la interfaz USB 2. Los registros de control de los Endpoint (UEPn) 3. El registro BDT (ep<#>B<d>) 4. El tamaño del Endpoint.

Ejemplo: Suponer una clase de dispositivo “foo”, que utiliza un Endpoint de salida de 64bytes y un Endpoint de entrada de 64bytes, entonces:

#define FOO_INTF_ID 0x00

#define FOO_UEP UEP1

#define FOO_BD_OUT ep1Bo

#define FOO_BD_IN ep1Bi

#define FOO_EP_SIZE 64

64

Page 65: revisar c18usb

Librerías C18 del USB

El mapeo anterior elige la clase “foo” para utilizarse con el Endpoint 1. El nombre es arbitrario y se puede elegir otro que no sea FOO_???????. Como idea abstracta, el código para la clase “foo” se tiene que usar en las definiciones abstractas de FOO_BD_OUT,FOO_BD_IN y o ep1Bo o ep1Bi.

Ver que el tamaño del Endpoint definido en el archivo usbcfg.h se utiliza de nuevo en el archivo usbmmap.c. Esto muestra que los dos archivos están muy relacionados.

El buffer del Endpoint para cada función USB se localiza en el área del puerto-dual RAM y como después se tiene que hacer instantáneos los BDTs. Un ejemplo de declaración es: volatile far unsigned char[FOO_EP_SIZE] data;

La palabra ‘volatile’ dice al compilador que no funcione ningún código de optimización en esta variable porque el contenido lo tiene que modificar el hardware. La palabra ‘far’ dice que la variable no se localiza en el área de RAM Accesible (0x000-0x05F).

Para que la variable sea accesible globalmente con otros ficheros, se tiene que declarar en el archivo de cabecera usbmmap.h como una definición externa, como extern volatile far unsigned char[FOO_EP_SIZE] data;

Conclusión:

Las dependencias entre usbcfg y usbmmap se pueden mostrar como:

usbcfg[MAX_EP_NUMBER] -> usbmmap

usbmmap[ep<#>B<d>] -> usbcfg

usbcfg[EP size] -> usbmmap

usbcfg[abstract ep definitions] -> usb9/hid/cdc/etc class code

usbmmap[endpoint buffer variable] -> usb9/hid/cdc/etc class code

El mapeo proporciona una manera directa de direccionado de BDT y un buffer del Enpoint. Esta forma utiliza menos punteros, y se equipara con un código de programa más rápido y pequeño.

2.5.1. INCLUYE #include "system\typedefs.h" #include "system\usb\usb.h"

2.5.2. VARIABLES GLOBALES DEL USB #pragma udata byte usb_device_state; Estados del dispositivo: Desconectado, Conectado, ... USB_DEVICE_STATUS usb_stat; Flags globales del USB byte usb_active_cfg; Valor de la configuración actual byte usb_alt_intf[MAX_NUM_INT]; Matriz para guardar los datos de la configuración actual alterna para cada ID interfaz

2.5.3. LOCALIZACIONES DE VARIABLES FIJAS DEL USB #pragma udata usbram4=0x400 Ver, usb4: 0x400-0x4FF(256-byte) Sección A: Tabla del Buffer Descriptor - 0x400 - 0x4FF(max)

65

Page 66: revisar c18usb

Documento creado por Slalen para Electronics Strange World

- MAX_EP_NUMBER se define en autofiles\usbcfg.h - BDT data type se define en system\usb\usbmmap.h #if(0 <= MAX_EP_NUMBER) volatile far BDT ep0Bo; Endpoint #0 BD Out volatile far BDT ep0Bi; Endpoint #0 BD In #endif #if(1 <= MAX_EP_NUMBER) volatile far BDT ep1Bo; Endpoint #1 BD Out volatile far BDT ep1Bi; Endpoint #1 BD In #endif #if(2 <= MAX_EP_NUMBER) volatile far BDT ep2Bo; Endpoint #2 BD Out volatile far BDT ep2Bi; Endpoint #2 BD In #endif #if(3 <= MAX_EP_NUMBER) volatile far BDT ep3Bo; Endpoint #3 BD Out volatile far BDT ep3Bi; Endpoint #3 BD In #endif #if(4 <= MAX_EP_NUMBER) volatile far BDT ep4Bo; Endpoint #4 BD Out volatile far BDT ep4Bi; Endpoint #4 BD In #endif #if(5 <= MAX_EP_NUMBER) volatile far BDT ep5Bo; Endpoint #5 BD Out volatile far BDT ep5Bi; Endpoint #5 BD In #endif #if(6 <= MAX_EP_NUMBER) volatile far BDT ep6Bo; Endpoint #6 BD Out volatile far BDT ep6Bi; Endpoint #6 BD In #endif #if(7 <= MAX_EP_NUMBER) volatile far BDT ep7Bo; Endpoint #7 BD Out volatile far BDT ep7Bi; Endpoint #7 BD In #endif #if(8 <= MAX_EP_NUMBER) volatile far BDT ep8Bo; Endpoint #8 BD Out volatile far BDT ep8Bi; Endpoint #8 BD In #endif #if(9 <= MAX_EP_NUMBER) volatile far BDT ep9Bo; Endpoint #9 BD Out volatile far BDT ep9Bi; Endpoint #9 BD In

66

Page 67: revisar c18usb

Librerías C18 del USB

#endif #if(10 <= MAX_EP_NUMBER) volatile far BDT ep10Bo; Endpoint #10 BD Out volatile far BDT ep10Bi; Endpoint #10 BD In #endif #if(11 <= MAX_EP_NUMBER) volatile far BDT ep11Bo; Endpoint #11 BD Out volatile far BDT ep11Bi; Endpoint #11 BD In #endif #if(12 <= MAX_EP_NUMBER) volatile far BDT ep12Bo; Endpoint #12 BD Out volatile far BDT ep12Bi; Endpoint #12 BD In #endif #if(13 <= MAX_EP_NUMBER) volatile far BDT ep13Bo; Endpoint #13 BD Out volatile far BDT ep13Bi Endpoint #13 BD In #endif #if(14 <= MAX_EP_NUMBER) volatile far BDT ep14Bo; Endpoint #14 BD Out volatile far BDT ep14Bi; Endpoint #14 BD In #endif #if(15 <= MAX_EP_NUMBER) volatile far BDT ep15Bo; Endpoint #15 BD Out volatile far BDT ep15Bi; Endpoint #15 BD In #endif Sección B: Espacio del Buffer del EP0 - Dos areas definidas para el buffer: A. CTRL_TRF_SETUP - Tamaño = EP0_BUFF_SIZE definido en autofiles\usbcfg.h - La estructura de datos detallada permite el direccionamiento directo de bits y bytes. B. CTRL_TRF_DATA - Tamaño = EP0_BUFF_SIZE definido en autofiles\usbcfg.h - La estructura de datos detallada permite el direccionamiento directo de los 8 bytes primeros. - Los dos tipos se definen en system\usb\usbdefs\usbdefs_ep0_buff.h volatile far CTRL_TRF_SETUP SetupPkt; volatile far CTRL_TRF_DATA CtrlTrfData; Sección C: Buffer CDC #pragma udata usbram5a=0x500 //See Linker Script,usb5:0x500- #if defined(USB_USE_CDC) volatile far unsigned char cdc_notice[CDC_INT_EP_SIZE]; volatile far unsigned char cdc_data_rx[CDC_BULK_OUT_EP_SIZE]; volatile far unsigned char cdc_data_tx[CDC_BULK_IN_EP_SIZE]; #endif #pragma udata

67

Page 68: revisar c18usb

Documento creado por Slalen para Electronics Strange World

2.6. USBGEN.C: USB GENÉRICO En este archivo se han creado todas las funciones de transferencia de los datos

que desee el usuario en la clase genérica.

2.6.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h" #ifdef USB_USE_GEN

2.6.2. VARIABLES #pragma udata byte usbgen_rx_len;

2.6.3. DECLARACIONES #pragma code

2.6.4. API DEL USUARIO

2.6.4.1. void USBGenInitEP(void) USBGenInitEP inicializa Endpoints genéricos, buffer de los descriptores,

estados máquina internos y variables. Hay que llamarla después de que el host haya enviado una repuesta SET_CONFIGURATION.

Ver USBStdSetCfgHandler() en usb9.c como ejemplo.

void USBGenInitEP(void) { usbgen_rx_len = 0; USBGEN_UEP = EP_OUT_IN|HSHK_EN; Activa 2 pipes de datos No hay que iniciar Cnt para las pipes de entrada. Razón: El número de bytes enviados al host varía de una transacción a otra. Cnt tiene que ser igual al número exacto de bytes a transmitir en una transacción IN dada. Este número de bytes sólo se conoce una vez que los datos hayan sido enviados. USBGEN_BD_OUT.Cnt = sizeof(usbgen_out); Fija el tamaño del buffer USBGEN_BD_OUT.ADR = (byte*)&usbgen_out; Fija la dirección del buffer USBGEN_BD_OUT.Stat._byte = _USIE|_DAT0|_DTSEN; Fija el estado USBGEN_BD_IN.ADR = (byte*)&usbgen_in; Fija la dirección del buffer USBGEN_BD_IN.Stat._byte = _UCPU|_DAT1; Fija el estado del buffer } end USBGenInitEP

2.6.4.2. void USBGenWrite(byte *buffer, byte len) Precondición: mUSBGenTxIsBusy() tiene que devolver “falso”.

68

Page 69: revisar c18usb

Librerías C18 del USB

El valor de ‘len’ tiene que ser igual o menor que USBGEN_EP_SIZE.

Para un Endpoint interrupción/bulk, el tamaño máximo del buffer es de 64bytes.

Entrada: buffer: Puntero a la localización de inicio de los bytes de datos.

len: Número de bytes a transmitir.

Esta macro se utiliza para transferir datos de la memoria de datos.

Aplicación típica:

if(!mUSBGenTxIsBusy())

USBGenWrite(buffer, 3); void USBGenWrite(byte *buffer, byte len) { byte i; El valor de ‘len’ tiene que ser igual o menor que USBGEN_EP_SIZE. Esta comprobación fuerza que se cumpla la precondición. if(len > USBGEN_EP_SIZE) len = USBGEN_EP_SIZE; Copia de los datos del buffer del usuario al buffer de la ram-dual. for (i = 0; i < len; i++) usbgen_in[i] = buffer[i]; USBGEN_BD_IN.Cnt = len; mUSBBufferReady(USBGEN_BD_IN); } end USBGenWrite

2.6.4.3. byte USBGenRead(byte *buffer, byte len) Precondición: El valor del argumento de entrada ‘len’ tiene que ser menor que

el tamaño máximo del Endpoint responsable de la recepción del informe de datos del host para la clase HID.

El argumento de entrada ‘buffer’ debe apuntar al área de buffer que sea mayor o igual que ‘len’.

69

Page 70: revisar c18usb

Documento creado por Slalen para Electronics Strange World

Salida: El número de bytes copiados al buffer.

Efectos secundarios: el acceso a la variable pública usbgen_rx_len se actualiza con el número de bytes copiados al buffer. Una vez llamado USBGenRead, la recuperación de usbgen_rx_len se puede hacer llamando la macro mUSBGenGetRxLength().

USBGenRead copia un string de los bytes recibidos a través de un Endpoint OUT a una localización especificada por el usuario. Es una función que espera a recibir los datos si no están disponibles. Devuelve ‘0’ para notificar que no hay datos disponibles.

Nota: Si el número actual de bytes recibidos es mayor que el número de bytes esperados (len), sólo se copian el número de bytes esperados al buffer.

Si el número de bytes recibidos es menor que el número de bytes esperados (len), se copian los bytes recibidos al buffer.

byte USBGenRead(byte *buffer, byte len) { usbgen_rx_len = 0; if(!mUSBGenRxIsBusy()) { Ajusta el número de bytes que se esperan al número de bytes recibidos. if(len > USBGEN_BD_OUT.Cnt) len = USBGEN_BD_OUT.Cnt; Copia los datos de la ram-dual al buffer del usuario for(usbgen_rx_len = 0; usbgen_rx_len < len; usbgen_rx_len++) buffer[usbgen_rx_len] = usbgen_out[usbgen_rx_len]; Prepara la ram-dual para la próximo transacción OUT. USBGEN_BD_OUT.Cnt = sizeof(usbgen_out); mUSBBufferReady(USBGEN_BD_OUT); } end if return usbgen_rx_len; } end USBGenRead #endif def USB_USE_GEN

70

Page 71: revisar c18usb

Librerías C18 del USB

2.7. MSD.C: USB ALMACENAMIENTO MASIVO En este archivo se han creado todas las funciones de transferencia de los datos

que desee el usuario en la clase MSD.

2.7.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h" #include<string.h> #ifdef USB_USE_MSD

2.7.2. VARIABLES #pragma udata byte MSD_State; Toma valores MSD_WAIT, MSD_DATA_IN o SD_DATA_OUT USB_MSD_CBW gblCBW; byte gblCBWLength; SDCSTATE gblFlag; RequestSenseResponse gblSenseData; byte *ptrNextData;

El número de bloques o la longitud son globales porque para cada comando READ_10 y WRITE_10 se tiene que verificar que el último LBA es menor que gblNumBLKS.

DWORD gblNumBLKS=0x00,gblBLKLen=0x00;

Respuesta estándar para saber que commando está en la ROM.

const rom InquiryResponse inq_resp = { 0x00, Dispositivo periférico conectado, acceso directo al bloque del 0x80, dispositivo removible. 0x04, versión = 00=> no cumple ningún estándar, 4=> SPC-2 0x02, respuesta en formato especificado por SPC-2 0x20, n-4 = 36-4=32= 0x20 0x00, sccs etc. 0x00, bque=1 y cmdque=0, indica que la cola simple 00 está obsoleta, pero en el caso de otro dispositivo, usamos 00 0x00, 00 obsoleto, 0x80 para tareas básicas de cola "Microchp", este es el T10 asignado ID del fabricante "Mass Storage ", "0001" };

2.7.3. PROTORIPOS PRIVADOS void MSDCommandHandler(void); void MSDInquiryHandler(void);

71

Page 72: revisar c18usb

Documento creado por Slalen para Electronics Strange World

void MSDReadCapacityHandler(void); void MSDReadHandler(void); void MSDWriteHandler(void); void MSDModeSenseHandler(void); void MSDMediumRemovalHandler(void); void MSDRequestSenseHandler(void); void MSDTestUnitReadyHandler(void); void MSDVerifyHandler(void); void MSDStopStartHandler(void); byte IsMeaningfulCBW(void); byte IsValidCBW(void); void PrepareCSWData(void); void SendData(byte*, byte); void SendCSW(void); void ResetSenseData(void); void MSDDataIn(void); void MSDDataOut(void); extern SDC_Error MediaInitialize(SDCSTATE*); extern void SocketInitialize(void); extern SDC_Error SectorRead(dword, byte*); extern SDC_Error SectorWrite(dword, byte*); extern SDC_Error CSDRead(void); extern int DetectSDCard (void); extern byte IsWriteProtected(void);

2.7.4. DECLARACIONES #pragma code

2.7.5. RESPUESTAS ESPECÍFICAS DE LA CLASE

2.7.5.1. void USBCheckMSDRequest(void) Esta rutina une el RESET estándar y el comando de repuesta recibido en el EP0

de control GET_MAX_LUN.

2.7.5.2. void ProcessIO(void) Precondición: Se han llamado MSDInitEP() y SDCardInit().

MSDInitEP() se llama desde USBStdSetCfgHandler(void)(usb9.c)

SDCardInit() se llama desde InitializeSystem() en main.c

Esta rutina se llama desde loop continuos de main.c.

72

Page 73: revisar c18usb

Librerías C18 del USB

Todos los comandos de transporte Bulk en el Endpoit 1 se unen aquí: MSD_State contiene el estado actual del módulo de almacenamiento masivo.

En el estado MSD_WAIT: Espera al bloque de comando de cubierta (CBW) del Endpoint1. Si se recibe un CBW válido y significativo, dependiendo del comando recibido MSD_State cambia a MSD_DATA_IN si el dato se envía al host (para todos comandos además del WRITE_10).

MSD_DATA_OUT si el host está esperando a mandar datos (sólo en el caso de WRITE_10). Al finalizar el comando de estado de transferencia de datos de cubierta (CSW) se envía llamando SendCSW().

2.7.5.3. void MSDInitEP(void) Esta rutina se llama desde USBStdSetCfgHandler(void) inicializa Bulk-IN y

Bulk-OUT, los Endpoints MSD_BD_IN y MSD_BD_OUT Tamaño = 64B (Ver usbmmap.c y usbdefs_std_dsc.h para las definiciones de los Enspoints.

2.7.5.4. void SDCardInit(void) Efectos secundarios: gblFlag se actualiza de acuerdo con la Inicialización.

MSD_State se fija a MAD_WAIT.

Esta rutina se llama desde InitializeSystem() en main.c. Inicializa la tarjeta SD y si tiene algún problema en la inicialización todos los LEDs se encienced. También fija MSD_State = MSD_WAIT

2.7.5.5. void MSDCommandHandler(void) Esta rutina se llama desde ProcessIO() cuando MSD_State=MSD_WAIT. Esta

función decodifica el comando CBW y actua consecuentemente. Si el CBW no está soportado se fija el dato Sense, el estado de CSW se pone en comando fallido (bCSWStatus=01h).

2.7.5.6. void SendCSW(void) Esta función envía el CSW y fija el estado a MSD_WAIT. También cambia

MSD_BD_OUT para que apunte a msd_csw (estructura para leer CSW). Notar que esto ha cambiado en el estado MSD_DATA_OUT para que apunte a msd_buffer para que lea datos del host.

2.7.5.7. void SendData(byte* dataAddr, byte dataSize) Esta función envía “dataSize” bytes de datos empezando en la dirección

“dataAddr”.

2.7.5.8. void MSDDataIn(void) Esta función envía 512B de datos en el msd_buffer al host en trozos de 64B

usando MSD_BD_IN. Hay varias condiciones; cuando los datos que se envían son menores que MSD_EP:SIZE y cuando se comprueba la condición de error bCSWStatus=0x01. En caso de error 0 se llenan y se envían los datos del tamaño esperado por el host dCBWDataTransferLength is sent.

73

Page 74: revisar c18usb

Documento creado por Slalen para Electronics Strange World

2.7.5.9. void IsValidCBW() Comprueba si el CBW es válido de acuerdo con las especificaciones de la clase

almacenamiento masivo. Se considera un CSW válido si:

1. Se recibe en estado MS_WAIT 2. La longitud de CBW es 1Fh (MSD_CBW_SIZE) 3. dCBWSignature es igual a 0x43425355h

2.7.5.10. void IsMeaningfulCBW() Comprueba si el CBW recibido es significativo de acuerdo con las

especificaciones de la clase almacenamiento masivo. Un CSW se considera significativo si:

1. No se fijan bits reservados 2. bCBWLUN contiene un LUN válido soportado por el dispositivo 3. bCBWCBLength y CBWCB tienen concordancia con

bInterfaceSubClass

2.7.5.11. void PrepareCSWData() Esto prepara el dato de estado del CSW copiando el dCSWTag del CBWTage y

fijando la firma de válido CSW=53425355h

2.7.5.12. void MSDInquiryHandler(void) Esta función prepara la repuesta del comando INQUIRY. La repuesta se copia

de la ROM al msd_buffer y CSWStatus, se fijan los valores CSWDataResidue.

2.7.5.13. void ResetSenseData(void) Esta rutina resetean el dato Sense, inicializando la estructura

RequestSenseResponse gblSenseData.

2.7.5.14. void MSDReadCapacityHandler() Esta función procesa el dato del registro CSD (leido durante la inicialización de

la tarjeta SD) para encontrar el número de bloques (gblNumBLKS) y la longitud del bloque (gblBLKLen). Este dato se copia a msd_buffer y se prepara para responder al comando Leer Capacidad.

2.7.5.15. void MSDReadHandler(void) Decodifica el CBWCB del comando READ(10) para calcular el inicio LBA y la

longitud de la transferencia (número de bloques a leer). Leyendo bloques de 512B de datos de la tarjeta SD en msd_buffer (llamando SectorRead). Si se lee satisfactoriamente (sdcValid), los datos se envían al host en trozos de 64B (MSD_IN_EP_SIZE) (ver MSDDataIN()). Esto se repite para el número de bloques TransferLength. En el caso de error bCSWStatus se fija a 0x01 y dato Sense con la clave de dato NOT READY y se prepara el código apropiado ASC, ASCQ.

74

Page 75: revisar c18usb

Librerías C18 del USB

2.7.5.16. void MSDDataOut(void) Efectos secundarios: MSD_BD_OUT.ADR se incrementa con

MSD_OUT_EP_SIZE (para leer los 64B siguientes en msd_buffer).

Esta función lee 64B (MSD_OUT_EP_SIZE) de EP1 OUT MSD_BD_OUT.

2.7.5.17. void MSDWriteHandler() Decodifica el CBWCB del comando WRITE(10) para calcular el comienzo de

LBA y la longitud de la transferencia (número de bloques que se escriben). Lee los bloques TransferLength de datos, 1 bloque=512B en un momento en msd_buffer. Los datos del host, 64B en MSD_BD_OUT, se reciben en el msd_buffer (ver MSDDataOut()).

El puntero MSD_BD_OUT.ADR se manipula para llenar los 512B del msd_buffer y cuando todos los datos se escriben en la tarjeta SD llamando la función Sector Write(…) (ver sdcard.c). En caso de error bCSWStatus se fija a 0x01 y dato Sense con la clave de dato NOT READY se prepara el código apropiado ASC, ASCQ.

2.7.5.18. void MSDRequestSenseHandler(void) Esta función prepara el Dato Sense para responder al comando Respuesta Sense.

El contenido de la estructura RequestSenseResponse se copia a msd_buffer y se fija un satisfactorio bCSWStatus=0x00.

2.7.5.19. void MSDModeSenseHandler() Esta función prepara para responder al comando Modo Sense. Se implementa

una respuesta básica en esta versión del código 00h y 0x03 es el tamaño del dato (en bytes) que sigue.

2.7.5.20. void MSDMediumRemovalHandler() Esta función prepara la respuesta al comando Prevent Allow Medium Removal.

No se espera una respuesta de datos sólo se espera un CSW con comando de ejecución de estado. Como no se puede controlar la retirada del medio, repondemos con un Success CSW.

2.7.5.21. void MSDTestUnitReadyHandler() Esta función prepara la respuesta al comando Test Unit Ready. No se espera

respuesta de datos, sólo se envía un CSW basado en el estado actual de la tarjeta SD se fija un valor de estado de error o de satisfactorio.

2.7.5.22. void MSDVerifyHandler() Esta función prepara la respuesta al comando Verify. No se espera respuesta de

datos, respondemos con un CSW satisfactorio. El comando no se procesa en esta versión del código.

2.7.5.23. void MSDStopStartHandler() Esta función prepara la respuesta al comando Start Stop Unit. No se espera

respuesta de datos, respondemos con un CSW satisfactorio. El comando no se procesa en esta versión del código.

75

Page 76: revisar c18usb

Documento creado por Slalen para Electronics Strange World

2.8. CDC.C: USB DISPOSITIVO DE COMUNICACIÓN En este archivo se han creado todas las funciones de transferencia de los datos

que desee el usuario en la clase CDC.

2.8.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h" #ifdef USB_USE_CDC

2.8.2. VARIABLES #pragma udata byte cdc_rx_len; Longitud total rx byte cdc_trf_state; Estados definidos en cdc.h POINTER pCDCSrc; Puntero dedicado a la fuente POINTER pCDCDst; Puntero dedicado al destino byte cdc_tx_len; Longitud total tx byte cdc_mem_type; _ROM, _RAM LINE_CODING line_coding; Buffer para almacenar líneas de información CONTROL_SIGNAL_BITMAP control_signal_bitmap;

SEND_ENCAPSULATED_COMMAND y GET_ENCAPSULATED_RESPONSE se necesitan para responder de acuerdo a las especificaciones CDC. Sin embargo, realmente no se empieza a usar aquí, se utiliza un buffer por comodidad.

#define dummy_length 0x08 byte dummy_encapsulated_cmd_response[dummy_length];

2.8.3. DECLARACIONES #pragma code

2.8.4. RESPUESTAS ESPECÍFICAS DE LA CLASE

2.8.4.1. void USBCheckCDCRequest(void) Esta rutina chequea el paquete de datos setup para ver si este sabe como

manipularlo.

76

Page 77: revisar c18usb

Librerías C18 del USB

2.9. API DEL USUARIO

2.9.1.1. void CDCInitEP(void) CDCInitEP inicializa los Endpoints CDC, buffer descriptores, estados internos

máquina y variables. Se tiene que llamar después de que el host haya enviado una repuesta SET_CONFIGURATION. Ver USBStdSetCfgHandler() en usb9.c para ejemplos.

2.9.1.2. byte getsUSBUSART(char *buffer, byte len) Precondición: El valor del argumento de entrada ‘len’ tiene que ser menor que

el tamaño máximo del Endpoint responsable de la recepción de datos bulk del host para la clase CDC.

El argumento de entrada ‘buffer’ tiene que apuntar a un área mayor o igual que el tamaño especificado por ‘len’.

Entrada: Buffer: Puntero a donde se guardan los datos recibidos.

len: El número de bytes esperados.

Salida: El número de bytes copiados al buffer.

Efectos secundarios: Se actualiza la variable de acceso público cdc_rx_len con el número de bytes copiados al buffer. Para recuperar esta variable llamamos a la macro mCDCGetRxLength().

getsUSBUSART copia un string de bytes recibidos a través del Endpoint OUT CDC Bulk a una localización especificada por el usuario. Es una función de no bloqueo. No espera a los datos si no están disponibles. Devuelve un ‘0’ para notificar que no hay datos disponibles.

Nota: Si el número actual de bytes recibidos es mayor que el número de bytes esperados (len), sólo se copian el número de bytes esperados. En cambio, si es menor el número de los recibidos, se copian todos.

2.9.1.3. void putsUSBUSART(char *data) Precondición: cdc_trf_state tiene que estar en el estado CDC_TX_READY.

El string de caracteres que apunta ‘data’ tiene que ser igual o menor de 255bytes.

Entrada: data: Puntero a un string de datos terminado con nulo. Si no se encuentra, se envían 255bytes al host.

putsUSBUSART escribe un string de datos al USB incluyendo caracteres nulos. Utilizar esta versión, ‘puts’, para transferir datos localizados en la memoria de datos.

Nota: El mecanismo de transferencia para dispositivo-a-host (put) es más flexible que el de host-a-dispositivo (get). Puede manipular un string de datos mayor que el tamaño máximo del Endpoint In bulk. Se utiliza un estado máquina para transferir un long string de datos a través de múltiples transacciones USB. Ver CDCTxService() para más detalles.

2.9.1.4. void putrsUSBUSART(const rom char *data) Precondición: cdc_trf_state tiene que estar en el estado CDC_TX_READY.

77

Page 78: revisar c18usb

Documento creado por Slalen para Electronics Strange World

El string de caracteres que apunta ‘data’ tiene que ser igual o menor de 255bytes.

Entrada: data: Puntero a un string de datos terminado con nulo. Si no se encuentra, se envían 255bytes al host.

putrsUSBUSART escribe un string de datos al USB incluidos los caracteres nulos. Utilizar esta versión, ‘puts’, para transferir datos localizados en la memoria de programa.

Nota: El mecanismo de transferencia para dispositivo-a-host (put) es más flexible que el de host-a-dispositivo (get). Puede manipular un string de datos mayor que el tamaño máximo del Endpoint In bulk. Se utiliza un estado máquina para transferir un long string de datos a través de múltiples transacciones USB. Ver CDCTxService() para más detalles.

2.9.1.5. void CDCTxService(void) CDCTxService une las transacciones dispositivo-a-host. Hay que llamar a esta

función una vez por cada loop del programa Main.

78

Page 79: revisar c18usb

Librerías C18 del USB

2.10. HID.C: USB INTERFAZ CON HUMANOS En este archivo se han creado todas las funciones de transferencia de los datos

que desee el usuario en la clase HID.

2.10.1. INCLUYE #include <p18cxxx.h> #include "system\typedefs.h" #include "system\usb\usb.h" #ifdef USB_USE_HID

2.10.2. VARIABLES #pragma udata byte idle_rate; byte active_protocol; [0] Protocolo de inicio [1] Protocolo de informe byte hid_rpt_rx_len;

2.10.3. PROTOTIPOS PRIVADOS void HIDGetReportHandler(void); void HIDSetReportHandler(void);

2.10.4. DECLARACIONES #pragma code

2.10.5. RESPUESTAS ESPECÍFICAS DE LA CLASE

2.10.5.1. void USBCheckHIDRequest(void) Esta rutina chequea el paquete de datos específico para ver si sabe como

manipularlo.

2.10.6. API DEL USUARIO

2.10.6.1. void HIDInitEP(void) HIDInitEP inicializa los Endpoints HID, buffer descriptores, estados internos

máquina y variables. Se tiene que llamar después de que el host haya enviado una repuesta SET_CONFIGURATION. Ver USBStdSetCfgHandler() en usb9.c para ejemplos.

79

Page 80: revisar c18usb

Documento creado por Slalen para Electronics Strange World

2.10.6.2. void HIDTxReport(char *buffer, byte len) Precondición: mHIDTxIsBusy() tiene que devolver falso. El valor de ‘len’ tiene

que ser menor o igual que HID_INT_IN_EP_SIZE. Para un Endpoint interrupción, el tamaño del buffer máximo es de 64bytes.

Entrada: buffer: Puntero al comienzo de la localización de bytes de datos.

len: Número de bytes que se van a transferir.

Utilizar esta macro para tranferir datos localizados en la memoria de datos.

Aplicación típica: if(!mHIDTxIsBusy()) HIDTxReport(buffer, 3);

2.10.6.3. byte HIDRxReport(char *buffer, byte len) Precondición: El valor del arguemento de entrada ‘len’ tiene que ser menor que

el tamaño máximo del Endpoint responsable de la recepción de datos del host USB para la clase HID. El argumento de entrada ‘buffer’ tiene que apuntar a un área mayor o igual al tamaño especificado por ‘len’.

Entrada: buffer: Puntero al lugar donde se guardan los datos recibidos.

len: Número de bytes que se esperan.

Salida: Número de bytes copiados al buffer.

Efectos secundarios: Se actualiza la variable de acceso público hid_rpt_rx_len con el número de bytes copiados al buffer. Para recuperar esta variable llamamos a la macro mHIDGetRptRxLength().

HIDRxReport copia un string de bytes recibidos a través del Endpoint OUT HID a una localización especificada por el usuario. Es una función de no bloqueo. No espera a los datos si no están disponibles. Devuelve un ‘0’ para notificar que no hay datos disponibles.

Nota: Si el número actual de bytes recibidos es mayor que el número de bytes esperados (len), sólo se copian el número de bytes esperados. En cambio, si es menor el número de los recibidos, se copian todos.

80

Page 81: revisar c18usb

Librerías C18 del USB

2.11. MAIN.C Este es el archivo de inicio. En él se incluyen las funciones necesariar para

establecer la comunicación USB y las relativas a la aplicación del usuario.

2.11.1. INCLUYE #include <p18cxxx.h>

#include "system\typedefs.h" Requerido

#include "system\usb\usb.h" Requerido

#include "io_cfg.h" Requerido

#include "system\usb\usb_compile_time_validation.h" Opcional

#include "user\user_mouse.h" Modificable

2.11.2. VARIABLES #pragma udata

2.11.3. PROTOTIPOS PRIVADOS static void InitializeSystem(void); void USBTasks(void);

2.11.3.1. Remapeo de vectores extern void _startup (void); #pragma code _RESET_INTERRUPT_VECTOR = 0x000800 void _reset (void) { _asm goto _startup _endasm }

2.11.3.2. Declaraciones #pragma code

void main(void) void main(void) { InitializeSystem(); while(1) { USBTasks() USB Tasks ProcessIO(); Aqui se llama al programa del usuario } end while } end main

static void InitializeSystem(void)

81

Page 82: revisar c18usb

Documento creado por Slalen para Electronics Strange World

InitializeSystem es una rutina centralizada de inicialización. Todas las rutinas de inicialización se llaman desde aquí.

static void InitializeSystem(void) { ADCON1 |= 0x0F; Por defecto todos los pines en digital #if defined(USE_USB_BUS_SENSE_IO) tris_usb_bus_sense = INPUT_PIN; Ver io_cfg.h #endif #if defined(USE_SELF_POWER_SENSE_IO) tris_self_power = INPUT_PIN; #endif mInitializeUSBDriver(); Ver usbdrv.h UserInit(); inicialización del usuario } end InitializeSystem

void USBTasks(void) Precondición: Se tiene que haber llamado InitializeSystem

Da vueltas dando servicio a las tareas USB.

void USBTasks(void) {

Da servicio al Hardware

USBCheckBusStatus(); se tiene que utilizar el método obtener if(UCFGbits.UTEYE!=1) USBDriverService(); Método interrupción u obtener } end USBTasks

82

Page 83: revisar c18usb

Librerías C18 del USB

2.12. INTERRUPT.C En este archivo se declaran la parte del programa que se ejecuta durante una

interrupción.

2.12.1. INCLUYE #include <p18cxxx.h> #include "system/typedefs.h" #include "system/interrupt/interrupt.h"

2.12.2. VECTORES DE INTERRUPCIÓN #pragma code high_vector=0x08 void interrupt_at_high_vector(void) { _asm goto high_isr _endasm } #pragma code #pragma code low_vector=0x18 void interrupt_at_low_vector(void) { _asm goto low_isr _endasm } #pragma code

2.12.3. DECLARACIONES

2.12.3.1. void high_isr(void) #pragma interrupt high_isr void high_isr(void) { }

2.12.3.2. void low_isr(void) void low_isr(void) { } #pragma code

83