Descargar Pdf

Anuncio
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)
#include "system\usb\class\hid\hid.h"
#endif
Ver autofiles\usbcfg.h
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)
#include "system\usb\class\msd\msd.h"
#endif
Ver autofiles\usbcfg.h
Si USB_USE_CDC está definida se incluye la librería cdc.h
#if defined(USB_USE_CDC)
#include "system\usb\class\cdc\cdc.h"
#endif
Ver autofiles\usbcfg.h
2
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
9 Uso de la clase Almacenamiento masivo: #define USB_USE_MSD
9
9
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
#define MUID_USB9
#define MUID_HID
#define MUID_CDC
1.1.2.3.
0
1
2
3
Ninguna
USB9
Interfaz humana
Clase de comunicación del dispositivo
Distribución de los Endpoint
#define HID_INTF_ID
#define HID_UEP
0x00
UEP1
Identificación de la interfaz
Endpoints que se utlizan
3
Documento creado por Slalen para Electronics Strange World
#define
#define
#define
#define
HID_BD_OUT
HID_INT_OUT_EP_SIZE
HID_BD_IN
HID_INT_IN_EP_SIZE
#define HID_NUM_OF_DSC
#define HID_RPT01_SIZE
ep1Bo
3
ep1Bi
3
1
50
Buffer descriptor de salida
Tamaño de la interrupción del Endpoint de salida
Buffer descriptor de entrada
Tamaño de la interrupción del Endpoint de
entrada
Número de descriptores
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
Librerías C18 del USB
1.1.3.
USBDEFS_STD_DSC.H:
DESCRIPTORES:
DEFINICIONES
ESTÁNDAR
DE
LOS
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"
1.1.3.2.
Librería en la que se definen tipos de datos
Definiciones
Tipos de descriptores:
#define DSC_DEV
#define DSC_CFG
#define DSC_STR
#define DSC_INTF
#define DSC_EP
0x01
0x02
0x03
0x04
0x05
Descriptor del dispositivo
Descriptor de configuración
Descriptor de la secuencia
Descriptor de la interfaz
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
#define _EP01_IN
#define _EP02_OUT
#define _EP02_IN
#define _EP03_OUT
#define _EP03_IN
#define _EP04_OUT
#define _EP04_IN
#define _EP05_OUT
#define _EP05_IN
#define _EP06_OUT
#define _EP06_IN
#define _EP07_OUT
#define _EP07_IN
#define _EP08_OUT
#define _EP08_IN
#define _EP09_OUT
#define _EP09_IN
#define _EP10_OUT
#define _EP10_IN
#define _EP11_OUT
#define _EP11_IN
#define _EP12_OUT
#define _EP12_IN
#define _EP13_OUT
#define _EP13_IN
0x01
0x81
0x02
0x82
0x03
0x83
0x04
0x84
0x05
0x85
0x06
0x86
0x07
0x87
0x08
0x88
0x09
0x89
0x0A
0x8A
0x0B
0x8B
0x0C
0x8C
0x0D
0x8D
5
Documento creado por Slalen para Electronics Strange World
#define _EP14_OUT
#define _EP14_IN
#define _EP15_OUT
#define _EP15_IN
0x0E
0x8E
0x0F
0x8F
Atributos de configuración:
#define _DEFAULT
#define _SELF
#define _RWU
0x01<<7
0x01<<6
0x01<<5
Valor por defecto (El Bit 7 se activa)
Auto-alimentado (Mantener si está activo)
Reinicio remoto (Mantener si está activo)
Tipo de transferencia del Endpoint:
#define _CTRL
#define _ISO
#define _BULK
#define _INT
0x00
0x01
0x02
0x03
Transferencia de control
Transferencia síncrona
Transferencia Bulk
Transferencia interrupción
Tipo de sincronización del Endpoint de transferencia síncrona:
#define _NS
#define _AS
#define _AD
#define _SY
0x00<<2
0x01<<2
0x02<<2
0x03<<2
Sin sincronización
Asíncrona
Adaptivo
Síncrona
Utilización del Endpoint tipo síncrono:
#define _DE
#define _FE
#define _IE
1.1.3.3.
0x00<<4
0x01<<4
0x02<<4
Endpoint de datos
Endpoint retroalimentado
Endpoint de datos y retroalimentado
Estructuras
Estructura de los descriptores del dispositivo USB (ver usbdsc.c):
typedef struct _USB_DEV_DSC
{
Longitud;
Tipo de descriptor;
byte bLength;
byte bDscType;
Clase del dispositivo;
Subclase del dispositivo;
byte bDevCls;
byte bDevSubCls;
Tamaño máximo del paquete;
Identificador del fabricante;
producto;
byte bMaxPktSize0;
word idVendor;
Bcd del dsipositivo;
Información de la manufactura;
word bcdDevice;
byte iMFR;
Número de serie;
Número de configuración;
byte iSerialNum;
byte bNumCfg;
} USB_DEV_DSC;
Bcd del USB;
word bcdUSB;
Protocolo del dispositivo;
byte bDevProtocol;
Identificación
del
word idProduct;
Información del producto;
byte iProduct;
Estructura del descriptor de configuración del USB:
typedef struct _USB_CFG_DSC
{
Longitud;
Tipo de descriptor;
byte bLength;
byte bDscType;
Número de interfaz;
Valor de configuración;
configuración;
6
Longitud total;
word wTotalLength;
Información
de
Librerías C18 del USB
byte bNumIntf;
Atributos;
byte bmAttributes;
} USB_CFG_DSC;
byte bCfgValue;
Máxima energía;
byte bMaxPower;
byte iCfg;
Estructura de la interfaz del dispositivo USB:
typedef struct _USB_INTF_DSC
{
Longitud;
Tipo de descriptor;
byte bLength;
byte bDscType;
Configuración alterna;
Número de Endpoints;
byte bAltSetting;
byte bNumEPs;
Subclase de interfaz;
Protocolo de la interfaz;
byte bIntfSubCls;
byte bIntfProtocol;
} USB_INTF_DSC;
Número de interfaz;
byte bIntfNum;
Clase de interfaz;
byte bIntfCls;
Información de la interfaz;
byte iIntf;
Estructura del Descriptor del Endpoint del USB:
typedef struct _USB_EP_DSC
{
Longitud;
byte bLength;
Atributos;
byte bmAttributes;
} USB_EP_DSC;
Tipo de descriptor;
byte bDscType;
Tamaño máximo del paquete;
word wMaxPktSize;
7
Dirección del Endpoint;
byte bEPAdr;
Intervalo;
byte bInterval;
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
{
USB_CFG_DSC
cd01;
USB_INTF_DSC
i00a00;
USB_EP_DSC
ep01o_i00a00;
USB_EP_DSC
ep01i_i00a00;
} cfg01
1.1.4.3.
Configuración 01
Descriptor de configuración
Descriptor de la interfaz
Endpoint descriptor de salida
Endpoint descriptor de entrada
Externas
extern rom USB_DEV_DSC device_dsc;
extern CFG01;
extern rom struct{byte bLength;byte bDscType;word string[1];}sd000;
8
Librerías C18 del USB
1.1.5.
USBDEFS_EP0_BUFF.H:
ENDPOINT 0
DESCRIPCIONES
DEL
BUFFER
DEL
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;
byte bRequest;
word wValue;
word wIndex;
word wLength;
};
struct
{
unsigned :8;
unsigned :8;
WORD W_Value;
WORD W_Index;
WORD W_Length;
};
struct
{
unsigned Recipient:5;
unsigned RequestType:2;
unsigned DataDir:1;
unsigned :8;
Tipo de respuesta
Respuesta
Valor
Índice
Longitud
Valor
Índice
Longitud
Dispositivo, Interfaz, Endpoint, Otro
Estándar, Clase, Fabricante, Reservado
Host-al-dispositivo, Dispositivo-al-host
9
Documento creado por Slalen para Electronics Strange World
byte bFeature;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
byte bDscIndex;
byte bDscType;
word wLangID;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
BYTE bDevADR;
byte bDevADRH;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
byte bCfgValue;
byte bCfgRSD;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
byte bAltID;
byte bAltID_H;
byte bIntfID;
byte bIntfID_H;
unsigned :8;
unsigned :8;
};
Reinicio remoto, Paro del Endpoint
Sólo para configuración y String del descriptor
Dispositivo, Configuración, String
Identificación de idioma
Dirección del dispositivo 0-127
Tiene que ser cero
Valor de configuración 0-255
Tiene que ser cero (Reservado)
Valor alterno de configuración 0-255
Tiene que ser cero
Valor del número de interfaz 0-255
Tiene que ser cero
10
Librerías C18 del USB
struct
{
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
byte bEPID;
byte bEPID_H;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned EPNum:4;
unsigned :3;
unsigned EPDir:1;
unsigned :8;
unsigned :8;
unsigned :8;
};
} CTRL_TRF_SETUP;
Identificación del Endpoint ID (Número y Dirección)
Tiene que ser cero
Número del Endpoint 0-15
Dirección del Endpoint: 0-OUT, 1-IN
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
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
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
#define _DTSEN
#define _INCDIS
#define _KEN
0x04
0x08
0x10
0x20
#define _DAT0
#define _DAT1
#define _DTSMASK
#define _USIE
#define _UCPU
0x00
0x40
0x40
0x80
0x00
Parada del buffer activa
Dato de sincronización activo
Incremento de dirección desactivado
Guardado del buffer descriptor por el
SIE activo
Paquete DATA0 esperando el siguiente
Paquete DATA1 esperando el siguiente
Máscara DTS
El SIE controla el buffer
La CPU controla el buffer
Estados del dispositivo USB. Para utilizarlos con [byte usb_device_state]:
#define DETACHED_STATE
#define ATTACHED_STATE
#define POWERED_STATE
#define DEFAULT_STATE
#define ADR_PENDING_STATE
#define ADDRESS_STATE
#define CONFIGURED_STATE
Tipos de memoria
USB_DEVICE_STATUS:
0
1
2
3
4
5
6
para
Sin conexión
Conectado
Alimentado
Por defecto
Pendiente de dirección
Direccionado
Configurado
el
control
de
transferencias,
#define _RAM 0
#define _ROM 1
1.1.6.3.
Tipos
typedef union _USB_DEVICE_STATUS
{
byte _byte;
struct
Estado del dispositivo
13
utilizado
en
Documento creado por Slalen para Electronics Strange World
{
unsigned RemoteWakeup:1;
unsigned ctrl_trf_mem:1;
};
} USB_DEVICE_STATUS;
[0]Desactivado [1]Activado: Ver usbdrv.h, usb9.h
[0]RAM [1]ROM
typedef union _BD_STAT
{
byte _byte;
struct{
unsigned BC8:1;
unsigned BC9:1;
unsigned BSTALL:1;
unsigned DTSEN:1;
unsigned INCDIS:1;
unsigned KEN:1;
unsigned DTS:1;
unsigned UOWN:1;
};
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;
unsigned :2;
};
} BD_STAT;
Estado del buffer descriptor
typedef union _BDT
{
struct
{
BD_STAT Stat;
byte Cnt;
byte ADRL;
byte ADRH;
};
struct
{
unsigned :8;
unsigned :8;
Tabla del buffer descriptor
Parada del buffer activa
Dato de sincronización activo
Incremento de dirección desactivado
Guardado del buffer descriptor por el SIE activo
Valor del dato de sincronización
Propiedad del USB
Paquete de identificación
Dirección del buffer baja
Dirección del buffer alta
14
Librerías C18 del USB
byte* ADR;
};
} BDT;
1.1.6.4.
Dirección del Buffer
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;
extern volatile far BDT ep0Bi;
extern volatile far BDT ep1Bo;
extern volatile far BDT ep1Bi;
extern volatile far BDT ep2Bo;
extern volatile far BDT ep2Bi;
extern volatile far BDT ep3Bo;
extern volatile far BDT ep3Bi;
extern volatile far BDT ep4Bo;
extern volatile far BDT ep4Bi;
extern volatile far BDT ep5Bo;
extern volatile far BDT ep5Bi;
extern volatile far BDT ep6Bo;
extern volatile far BDT ep6Bi;
extern volatile far BDT ep7Bo;
extern volatile far BDT ep7Bi;
extern volatile far BDT ep8Bo;
extern volatile far BDT ep8Bi;
extern volatile far BDT ep9Bo;
extern volatile far BDT ep9Bi;
extern volatile far BDT ep10Bo;
extern volatile far BDT ep10Bi;
extern volatile far BDT ep11Bo;
extern volatile far BDT ep11Bi;
extern volatile far BDT ep12Bo;
extern volatile far BDT ep12Bi;
extern volatile far BDT ep13Bo;
extern volatile far BDT ep13Bi;
extern volatile far BDT ep14Bo;
extern volatile far BDT ep14Bi;
extern volatile far BDT ep15Bo;
extern volatile far BDT ep15Bi;
Buffer descriptor del Endpoint #0 Out
Buffer descriptor del Endpoint #0 In
Buffer descriptor del Endpoint #1 Out
Buffer descriptor del Endpoint #1 In
Buffer descriptor del Endpoint #2 Out
Buffer descriptor del Endpoint #2 In
Buffer descriptor del Endpoint #3 Out
Buffer descriptor del Endpoint #3 In
Buffer descriptor del Endpoint #4 Out
Buffer descriptor del Endpoint #4 In
Buffer descriptor del Endpoint #5 Out
Buffer descriptor del Endpoint #5 In
Buffer descriptor del Endpoint #6 Out
Buffer descriptor del Endpoint #6 In
Buffer descriptor del Endpoint #7 Out
Buffer descriptor del Endpoint #7 In
Buffer descriptor del Endpoint #8 Out
Buffer descriptor del Endpoint #8 In
Buffer descriptor del Endpoint #9 Out
Buffer descriptor del Endpoint #9 In
Buffer descriptor del Endpoint #10 Out
Buffer descriptor del Endpoint #10 In
Buffer descriptor del Endpoint #11 Out
Buffer descriptor del Endpoint #11 In
Buffer descriptor del Endpoint #12 Out
Buffer descriptor del Endpoint #12 In
Buffer descriptor del Endpoint #13 Out
Buffer descriptor del Endpoint #13 In
Buffer descriptor del Endpoint #14 Out
Buffer descriptor del Endpoint #14 In
Buffer descriptor del Endpoint #15 Out
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
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
#define _PPBM1
#define _PPBM2
#define _LS
#define _FS
#define _TRINT
#define _TREXT
#define _PUEN
#define _OEMON
#define _UTEYE
0x00
0x01
0x02
0x00
0x04
0x00
0x08
0x10
0x40
0x80
Buffer Ping-pong Modo 0
Buffer Ping-pong Modo 1
Buffer Ping-pong Modo 2
Modo USB Low-Speed
Modo USB Full-Speed
Transmisor-receptor interno
Transmisor-receptor externo
Usar resistencias pull-up internas
Usar el indicador de salida SIE
Usar el test “Patrón de ojo”
Parámetros de los Endpoint iniciales:
#define EP_CTRL
#define EP_OUT
#define EP_IN
#define EP_OUT_IN
#define HSHK_EN
0x06
Pipe de control
0x0C
Pipe de salida
0x0A
Pipe de entrada
0x0E
Pipe de entrada y salida
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
X:EP3:EP2:EP1:EP0:DIR:PPBI:X
dirección
de
los
EP
PICmicro:
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
#define IN
0
1
#define PIC_EP_NUM_MASK 0b01111000
#define PIC_EP_DIR_MASK 0b00000100
Número de máscara del Endpoint
Dirección de la máscara del Endpoint
16
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
#define EP00_IN
#define EP01_OUT
#define EP01_IN
#define EP02_OUT
#define EP02_IN
#define EP03_OUT
#define EP03_IN
#define EP04_OUT
#define EP04_IN
#define EP05_OUT
#define EP05_IN
#define EP06_OUT
#define EP06_IN
#define EP07_OUT
#define EP07_IN
#define EP08_OUT
#define EP08_IN
#define EP09_OUT
#define EP09_IN
#define EP10_OUT
#define EP10_IN
#define EP11_OUT
#define EP11_IN
#define EP12_OUT
#define EP12_IN
#define EP13_OUT
#define EP13_IN
#define EP14_OUT
#define EP14_IN
#define EP15_OUT
#define EP15_IN
((0x00<<3)|(OUT<<2))
((0x00<<3)|(IN<<2))
((0x01<<3)|(OUT<<2))
((0x01<<3)|(IN<<2))
((0x02<<3)|(OUT<<2))
((0x02<<3)|(IN<<2))
((0x03<<3)|(OUT<<2))
((0x03<<3)|(IN<<2))
((0x04<<3)|(OUT<<2))
((0x04<<3)|(IN<<2))
((0x05<<3)|(OUT<<2))
((0x05<<3)|(IN<<2))
((0x06<<3)|(OUT<<2))
((0x06<<3)|(IN<<2))
((0x07<<3)|(OUT<<2))
((0x07<<3)|(IN<<2))
((0x08<<3)|(OUT<<2))
((0x08<<3)|(IN<<2))
((0x09<<3)|(OUT<<2))
((0x09<<3)|(IN<<2))
((0x0A<<3)|(OUT<<2))
((0x0A<<3)|(IN<<2))
((0x0B<<3)|(OUT<<2))
((0x0B<<3)|(IN<<2))
((0x0C<<3)|(OUT<<2))
((0x0C<<3)|(IN<<2))
((0x0D<<3)|(OUT<<2))
((0x0D<<3)|(IN<<2))
((0x0E<<3)|(OUT<<2))
((0x0E<<3)|(IN<<2))
((0x0F<<3)|(OUT<<2))
((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
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;
buffer_dsc.Stat.DTS = !buffer_dsc.Stat.DTS;
buffer_dsc.Stat._byte |= _USIE|_DTSEN;
}
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
Guarda sólo el bit DTS
Cambia el bit DTS
Cambia la propiedad al SIE
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
#define CTRL_TRF_TX
#define CTRL_TRF_RX
0
1
2
Espera Setup
Transf. de control de transmisión
Transf. de control de recepción
0b00001101
0b00000001
0b00001001
Token setup
Token de salida
Token de entrada
Tipos de Tokens:
#define SETUP_TOKEN
#define OUT_TOKEN
#define IN_TOKEN
Definición de los tipos de respuesta:
#define HOST_TO_DEV
#define DEV_TO_HOST
#define STANDARD
#define CLASS
#define VENDOR
#define RCPT_DEV
#define RCPT_INTF
#define RCPT_EP
#define RCPT_OTH
1.1.8.3.
0
1
0x00
0x01
0x02
0
1
2
3
Host-al-Dispositivo
Dispositivo-al-Host
Clase
Fabricante
Dispositivo destinatario
Destinatario de la interfaz
Destinatario del Endpoint
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
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
#define CLR_FEATURE
#define SET_FEATURE
#define SET_ADR
#define GET_DSC
#define SET_DSC
#define GET_CFG
#define SET_CFG
#define GET_INTF
#define SET_INTF
#define SYNCH_FRAME
0
1
3
5
6
7
8
9
10
11
12
Obtiene estado
Borra característica
Fija característica
Fija dirección
Obtiene descriptor
Fija descriptor
Obtiene configuración
Fija configuración
Obtiene interfaz
Fija interfaz
Marco de sincronismo
Características de los selectores estándar:
#define DEVICE_REMOTE_WAKEUP
#define ENDPOINT_HALT
0x01
0x00
Reinicio remoto del dispositivo
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
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()
1.1.10.3.
usbgen_rx_len
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
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"
1.1.11.2.
Mapa de pines E/S
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
#define GET_MAX_LUN
0xff
0xfe
#define BLOCKLEN_512
0x0200
#define STMSDTRIS
#define STRUNTRIS
#define STMSDLED
#define STRUNLED
#define ToggleRUNLED()
TRISD0
TRISD1
LATDbits.LATD0
LATDbits.LATD1
STRUNLED = !STRUNLED;
Set de commandos de código de la subclase transparente SCSI:
#define INQUIRY
#define READ_FORMAT_CAPACITY
#define READ_CAPACITY
#define READ_10
#define WRITE_10
#define REQUEST_SENSE
#define MODE_SENSE
#define PREVENT_ALLOW_MEDIUM_REMOVAL
#define TEST_UNIT_READY
#define VERIFY
#define STOP_START
0x12
0x23
0x25
0x28
0x2A
0x03
0x1A
0x1E
0x00
0x2F
0x1B
Varios estados del Firmware de almacenamiento masivo:
#define MSD_WAIT
0
#define MSD_DATA_IN
2
#define MSD_DATA_OUT 3
Esperando para un CBW válido
Estado de datos IN (Dispositivo-> Host)
Estado de datos OUT (Host -> Device)
22
Librerías C18 del USB
#define MSD_CSW_SIZE 0x0d
#define MSD_CBW_SIZE 0x1f
#define INVALID_CBW
#define VALID_CBW
#define MAX_LUN
Datos CSW de 10 bytes CSW
Datos CSW de 31 bytes CBW
1
!INVALID_CBW
0
Clave de los códigos de error Sense
#define S_NO_SENSE
#define S_RECOVERED_ERROR
#define S_NOT_READY
#define S_MEDIUM_ERROR
#define S_HARDWARE_ERROR
#define S_ILLEGAL_REQUEST
#define S_UNIT_ATTENTION
#define S_DATA_PROTECT
#define S_BLANK_CHECK
#define S_VENDOR_SPECIFIC
#define S_COPY_ABORTED
#define S_ABORTED_COMMAND
#define S_OBSOLETE
#define S_VOLUME_OVERFLOW
#define S_MISCOMPARE
0x0
0x1
0x2
0x3
0X4
0x5
0x6
0x7
0x8
0x9
0xA
0xB
0xC
0xD
0xE
#define S_CURRENT
#define S_DEFERRED
0x70
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
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
{
dword dCBWSignature;
dword dCBWTag;
con el
31 bytes totales CBW
55 53 42 43h
Enviado por el host, el dispositivo se hace eco
valor en CSW (asociado a CSW con CBW)
24
Librerías C18 del USB
dword dCBWDataTransferLength;
transferir
byte bCBWFlags;
bits 0
byte bCBWLUN;
una
byte bCBWCBLength;
byte CBWCB[16];
} USB_MSD_CBW;
typedef struct {
escribir 10
Número de bytes de datos que el host espera
Flags CBW, bit 7 = 0 salida de datos del hostdispositivo; bit 7=1 dispositivo-host, el resto de
MS1bits son siempre cero, 0 en nuestro caso es
sola unidad lógica
MS3bits son cero
Bloque de comando que ejecuta el dispositivo
/Bloque de comando para leer 10 (0x28) y
(0x2a) comandos
byte Opcode;
byte Flags;
DWORD LBA;
byte GroupNumber;
WORD TransferLength;
byte Control;
} ReadWriteCB;
b7-b5 lectura protegida, b4 DPO, b3 FUA,
b2 Reservado, b1 FUA_NV, b0 Obsoleto
b4-b0 es el número de grupo el resto reservados
typedef struct {
byte Opcode;
byte EVPD;
byte PageCode;
word AllocationLength;
byte Control;
} InquiryCB;
Formato del comando Inquiry
typedef struct {
byte Opcode;
byte Reserved1;
dword LBA;
word Reserved2;
byte PMI;
byte Control;
} ReadCapacityCB;
capacidad de lectura 10
typedef struct {
byte Opcode;
byte Desc;
word Reserved;
byte AllocationLength;
byte Control;
} RequestSenseCB;
Respuesta Sense 0x03
typedef struct {
byte Opcode;
Modo Sense 0x1A
sólo b0 enable vital product data
Bloque de dirección lógico
Partial medium Indicator sólo b0
25
Documento creado por Slalen para Electronics Strange World
byte DBD;
byte PageCode;
código
Actualmente sólo se utiliza b3 como bloque
descriptor desactivado
b7,b6 PC=página de control, b5-b0 página de
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 {
byte Opcode;
byte Reserved[3];
byte Prevent;
byte Control;
} PreventAllowMediumRemovalCB;
Prevenir el permiso de retirada del medio 0x1E
typedef struct {
byte Opcode;
dword Reserved;
byte Control;
} TestUnitReadyCB;
Unidad de prueba disponible 0x00
typedef struct {
byte Opcode;
byte VRProtect;
Verificar 10 Comando 0x2F
dword LBA;
byte GroupNumber;
word VerificationLength;
byte Control;
} VerifyCB;
typedef struct {
byte Opcode;
byte Immed;
word Reserved;
byte Start;
Sólo se previenen b1-b0, el resto reservados
b7-b5 VRProtect, b4 DPO, b3-b2,Reservado,
b1 BYTCHK, b0 Obsoleto
Número del grupo b4-b0, el resto reservado
STOP_START 0x1B
b7-b4 Condición de energía, b3-b2 reservedo,
b1 LOEJ, b0 Start
byte Control;
} StopStartCB;
typedef struct _USB_MSD_CSW
{
dword dCSWSignature;
dword dCSWTag;
dword dCSWDataResidue;
CSW
55 53 42 53h firma del paquete de CSW
eco dCBWTag del paquete CBW
diferencia en los datos esperados
(dCBWDataTransferLength)
y la cantidad actual procesada/enviada
26
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;
byte Removble;
byte Version;
byte Response_Data_Format;
byte AdditionalLength;
byte Sccstp;
byte bqueetc;
byte CmdQue;
Clasificador del periférico:3;
Periférico_DevType:5;
medio removible bit7 = 0 medio no removible,
resto reservado
versión
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
longitud en bytes de los datos que quedan de la
indagación estándar
b7 SCCS, b6 ACC, b5-b4 TGPS, b3 3PC,
b2-b1 Reservado, b0 Protegido
b7 bque, b6- EncServ, b5-VS, b4-MultiP,
b3-MChngr, b2-b1 Obsoleto, b0-Addr16
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;
unsigned notused:2;
unsigned WP:1;
byte BlockDscLen;
} tModeParamHdr;
0 indica que no soporta los bits DPO y FUA
0 indica que no protege la escritura
Longitud del Bloque Descriptor
Modo corto del bloque descriptor LBA (ver Página 1009, SBC-2)
typedef struct {
byte NumBlocks[4];
byte Resv;
byte BlockLen[3];
} tBlockDescriptor;
reservado
/* Page_0 mode page format */
typedef struct {
unsigned PageCode:6;
unsigned SPF:1;
SPC-3 7.4.5
SubPageFormat=0 medio Page_0 formato
27
Documento creado por Slalen para Electronics Strange World
unsigned PS:1;
byte PageLength;
byte ModeParam[];
} tModePage;
Parámetros salvables
si 2..n bytes del modo parámetro PageLength=n-1
modo parámetros
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;
unsigned VALID:1;
byte Obsolete;
unsigned SenseKey:4;
unsigned Resv:1;
unsigned ILI:1;
unsigned EOM:1;
unsigned FILEMARK:1;
DWORD Information;
byte AddSenseLen;
DWORD CmdSpecificInfo;
byte ASC;
byte ASCQ;
byte FRUC;
byte SenseKeySpecific[3];
b6-b0 es el código de respuesta fijado o el
formato
del descriptor
Poner a 1 indica que el campo de información
tiene un valor válido
Referencia SPC-3 Sección 4.5.6
Indicador de la longitud incorrecta
Fin del medio
para los comandos READ y SPACE
Tipo de dispositivo o comando específico
(SPC-33.1.18)
Número de bytes sense adicionales que
siguen <=244
depende del comando de la excepción ocurrida
código sense adicional
código sense adicional sección clasificada
4.5.2.1 SPC-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
Librerías C18 del USB
1.1.11.4.
Externas
extern CSD gblCSDReg;
1.1.11.5.
declarado en sdcard.c
Prototipos públicos
void USBCheckMSDRequest(void);
void ProcessIO(void);
void SDCardInit(void);
void MSDInitEP(void);
29
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
#define GET_ENCAPSULATED_RESPONSE
#define SET_COMM_FEATURE
#define GET_COMM_FEATURE
#define CLEAR_COMM_FEATURE
#define SET_LINE_CODING
#define GET_LINE_CODING
#define SET_CONTROL_LINE_STATE
#define SEND_BREAK
0x00
0x01
0x02
0x03
0x04
0x20
0x21
0x22
0x23
Notificaciones
Nota: las notificaciones se obtienen de la interface de comunicación (Endpoint
Interrupción)
#define NETWORK_CONNECTION
#define RESPONSE_AVAILABLE
#define SERIAL_STATE
0x00
0x01
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
Librerías C18 del USB
#define COUNTRY_SETTING
0x02
Descriptores funcionales
Tipos de valor del campo bDscType
#define CS_INTERFACE
#define CS_ENDPOINT
0x24
0x25
bDscSubType en descriptores funcionales
#define DSC_FN_HEADER
#define DSC_FN_CALL_MGT
#define DSC_FN_ACM
0x00
0x01
0x02
#define DSC_FN_DLM
#define DSC_FN_TELEPHONE_RINGER
#define DSC_FN_RPT_CAPABILITIES
#define DSC_FN_UNION
#define DSC_FN_COUNTRY_SELECTION
#define DSC_FN_TEL_OP_MODES
#define DSC_FN_USB_TERMINAL
0x03
0x04
0x05
0x06
0x07
0x08
0x09
ACM – Administración de control
abstracta
DLM – Dirección de línea directa
Estados de tranferencia CDC Bulk IN
#define CDC_TX_READY
#define CDC_TX_BUSY
#define CDC_TX_BUSY_ZLP
#define CDC_TX_COMPLETING
0
1
2
3
ZLP: Paquete de longitud cero
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
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
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
typedef union _LINE_CODING
{
struct
{
byte _byte[LINE_CODING_LENGTH];
};
struct
{
DWORD
byte
byte
byte
};
} LINE_CODING;
0x07
dwDTERate; Estructura de datos compleja
bCharFormat;
bParityType;
bDataBits;
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
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
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
#define GET_IDLE
#define GET_PROTOCOL
#define SET_REPORT
#define SET_IDLE
#define SET_PROTOCOL
0x01
0x02
0x03
0x09
0x0A
0x0B
Obtener informe
Obtener reposo
Obtener protocolo
Fijar informe
Fijar reposo
Fijar protocolo
Tipos de clase de descriptor:
#define DSC_HID
#define DSC_RPT
#define DSC_PHY
0x21
0x22
0x23
Descriptor HID
Descriptor informe
0x00
0x01
Protocolo de inicio
Informe de protocolo
Selección de protocolo:
#define BOOT_PROTOCOL
#define RPT_PROTOCOL
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
#define HID_PROTOCOL_KEYBOAD
#define HID_PROTOCOL_MOUSE
0x00
0x01
0x02
Ninguno
Teclado
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
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()
1.1.13.3.
hid_rpt_rx_len
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
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
#define OUTPUT_PIN
1.1.14.3.
1
0
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
#define tris_usb_vmo
#define tris_usb_rcv
#define tris_usb_vp
#define tris_usb_vm
#define tris_usb_oe
TRISBbits.TRISB3
TRISBbits.TRISB2
TRISAbits.TRISA4
TRISCbits.TRISC5
TRISCbits.TRISC4
TRISCbits.TRISC1
Salida
Salida
Entrada
Entrada
Entrada
Salida
#define tris_usb_suspnd
TRISAbits.TRISA3
Salida
1.1.14.4.
LED
#define mInitAllLEDs()
#define mLED_1
#define mLED_2
#define mLED_3
#define mLED_4
#define mLED_1_On()
#define mLED_2_On()
#define mLED_3_On()
#define mLED_4_On()
#define mLED_1_Off()
#define mLED_2_Off()
LATD &= 0xF0; TRISD &= 0xF0;
LATDbits.LATD0
LATDbits.LATD1
LATDbits.LATD2
LATDbits.LATD3
mLED_1 = 1;
mLED_2 = 1;
mLED_3 = 1;
mLED_4 = 1;
mLED_1 = 0;
mLED_2 = 0;
37
Documento creado por Slalen para Electronics Strange World
#define mLED_3_Off()
#define mLED_4_Off()
#define mLED_1_Toggle()
#define mLED_2_Toggle()
#define mLED_3_Toggle()
#define mLED_4_Toggle()
1.1.14.5.
Interruptores
#define mInitAllSwitches()
#define mInitSwitch2()
#define mInitSwitch3()
//#define sw2
#define sw3
1.1.14.6.
mLED_3 = 0;
mLED_4 = 0;
mLED_1 = !mLED_1;
mLED_2 = !mLED_2;
mLED_3 = !mLED_3;
mLED_4 = !mLED_4;
TRISBbits.TRISB4=1;TRISBbits.TRISB5=1;
TRISBbits.TRISB4=1;
TRISBbits.TRISB5=1;
PORTBbits.RB4
PORTBbits.RB5
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
#define cs_temp_sensor
LATBbits.LATB2
#define tris_cs_sdmmc
TRISBbits.TRISB3
#define cs_sdmmc
LATBbits.LATB3
1.1.14.8.
Salida
Salida
SDMMC
#define TRIS_CARD_DETECT
#define CARD_DETECT
#define TRIS_WRITE_DETECT
#define WRITE_DETECT
TRISBbits.TRISB4
PORTBbits.RB4
TRISAbits.TRISA4
PORTAbits.RA4
38
Entrada
Entrada
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
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
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"
2.1.2.
Se necesita para USBCheckBusStatus()
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
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
#define USB_BUS_DETACHED
1
0
if(usb_bus_sense == USB_BUS_ATTACHED)
{
if(UCONbits.USBEN == 0)
USBModuleEnable();
}
else
{
if(UCONbits.USBEN == 1)
USBModuleDisable();
} end if(usb_bus_sense...)
¿Está el USB conectado?
¿Está el módulo apagado?
Está apagado, actívalo
¿Está el módulo encendido?
Está encendido, desactívalo
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;
UIE = 0;
USB
UIEbits.URSTIE = 1;
UIEbits.IDLEIE = 1;
usb_device_state = POWERED_STATE;
} end if
borrado
} end if(usb_device_state == ATTACHED_STATE)
Borra todas las interrupciones del USB
Enmascara todas las interrupciones del
Desenmascara la interrupción RESET
Desenmascara la interrupción IDLE
Lo demás espera hasta que SE0 esté
} 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
Librerías C18 del USB
UIE = 0;
UCONbits.USBEN = 1;
usb_device_state = ATTACHED_STATE;
} end USBModuleEnable
2.1.4.3.
Enmascara todas las interrupciones USB
Activa el modulo y une el bus
Definido en usbmmap.c y .h
void USBModuleDisable(void)
Esta rutina desactiva el modulo USB.
Sólo se puede llamar esta rutina desde USBCheckBusStatus().
void USBModuleDisable(void)
{
UCON = 0;
bus
UIE = 0;
usb_device_state = DETACHED_STATE;
} end USBModuleDisable
2.1.4.4.
Desactiva el modulo y desconecta del
Enmascara todas las interrupciones USB
Definido en usbmmap.c y .h
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
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
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)
48
4
MIP
12
1
Periodo señal RESUME (ms)
1,05
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
Documento creado por Slalen para Electronics Strange World
static word delay_count;
if(usb_stat.RemoteWakeup == 1)
función
{
USBWakeFromSuspend();
UCONbits.RESUME = 1;
Comprueba si el host a activado la
reinicio remoto
Reinicio del modo suspendido
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
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
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"
2.2.2.
Requerido para el estado auto-alimentado
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
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
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;
usb_stat.ctrl_trf_mem = _RAM;
LSB(wCount) = 1;
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.
Fija la fuente
Fija el tipo de memoria
Activa la cuenta de datos
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;
end if
end USBStdGetDscHandler
Fija el tipo de memoria
50
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;
CtrlTrfData._byte1 = 0;
Inicializa el contenido
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)
CtrlTrfData._byte0|=0b00000010;
}
usb_stat definido en usbmmap.c
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
Documento creado por Slalen para Electronics Strange World
if(ctrl_trf_session_owner == MUID_USB9)
{
pSrc.bRam = (byte*)&CtrlTrfData;
usb_stat.ctrl_trf_mem = _RAM;
LSB(wCount) = 2;
} end if(...)
} end USBStdGetStatusHandler
2.2.4.5.
Fija fuente
Fija el tipo de memoria
Activa la cuenta de datos
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_DE
V))
{
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
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;
byte ctrl_trf_session_owner;
POINTER pSrc;
POINTER pDst;
WORD wCount;
2.3.3.
Estado de la transferencia de control
Controlador de la sesión de transferencia actual
Puntero a la fuente de datos
Puntero al destino de los datos
Contador de datos
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)
USBCtrlTrfSetupHandler();
else
USBCtrlTrfOutHandler();
}
else if(USTAT == EP00_IN)
USBCtrlTrfInHandler();
} end USBCtrlEPService
EP0 SETUP
EP0 OUT
EP0 IN
53
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;
wCount._word = 0;
Fijar el dueño a NULL
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
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
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
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
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;
ep0Bo.Cnt = EP0_BUFF_SIZE;
ep0Bo.ADR = (byte*)&SetupPkt;
ep0Bo.Stat._byte = _USIE|_DAT0|_DTSEN;
usbmmap.h
ep0Bi.Stat._byte = _UCPU;
} end USBPrepareForNextSetupTrf
Ver usbctrltrf.h
Definido en usbcfg.h
Inicialización
EP0
buff
EP0 IN buffer inicialización
58
dsc,
ver
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
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
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),
DSC_DEV,
0x0200,
0x00,
0x00,
0x00,
EP0_BUFF_SIZE,
0x04D8,
0x0000,
Tamaño del descriptor en bytes
Descriptor tipo DEVICE
Número de versión del USB en formato BCD
Código de Clase
Código Subclase
Código Protocolo
Tamaño de paquete máximo para el EP0, ver usbcfg.h
ID Fabricante
ID Producto
61
Documento creado por Slalen para Electronics Strange World
};
0x0001,
0x01,
0x02,
0x00,
0x01
Descriptor de configuración 1
CFG01={
Descriptor de configuración
sizeof(USB_CFG_DSC),
DSC_CFG,
sizeof(cfg01),
1,
1,
0,
_DEFAULT|_RWU,
50,
Descriptor de la interfaz
sizeof(USB_INTF_DSC),
DSC_INTF,
0,
0,
1,
HID_INTF,
BOOT_INTF_SUBCLASS,
HID_PROTOCOL_MOUSE,
0,
Número de versión del dispositivo en formato BCD
String índice de fabricante
String índice del producto
String índice del número de serie del dispositivo
Número de configuraciones posible
Tamaño del descriptor en bytes
Tipo del descriptor CONFIGURACIÓN
Longitud total de datos de esta configuración
Número de interfaces en esta configuración
Valor del índice de esta configuración
String índice de configuración
Atributos, ver usbdefs_std_dsc.h
Consumo máximo de corriente (2X mA)
Tamaño del descriptor en bytes
Tipo de descriptor INTERFACE
Número de Interface
Número alterno de configuración
Número de Endpoints en esta interfaz
Código de la Clase
Código de la Subclase
Código del Protocolo
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
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
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.
2.
3.
4.
El ID de la interfaz USB
Los registros de control de los Endpoint (UEPn)
El registro BDT (ep<#>B<d>)
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
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 puertodual 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 (0x0000x05F).
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;
USB_DEVICE_STATUS usb_stat;
byte usb_active_cfg;
byte usb_alt_intf[MAX_NUM_INT];
2.5.3.
Estados del dispositivo: Desconectado, Conectado, ...
Flags globales del USB
Valor de la configuración actual
Matriz para guardar los datos de la configuración actual
alterna para cada ID interfaz
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
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;
volatile far BDT ep1Bi;
#endif
Endpoint #1 BD Out
Endpoint #1 BD In
#if(2 <= MAX_EP_NUMBER)
volatile far BDT ep2Bo;
volatile far BDT ep2Bi;
#endif
Endpoint #2 BD Out
Endpoint #2 BD In
#if(3 <= MAX_EP_NUMBER)
volatile far BDT ep3Bo;
volatile far BDT ep3Bi;
#endif
Endpoint #3 BD Out
Endpoint #3 BD In
#if(4 <= MAX_EP_NUMBER)
volatile far BDT ep4Bo;
volatile far BDT ep4Bi;
#endif
Endpoint #4 BD Out
Endpoint #4 BD In
#if(5 <= MAX_EP_NUMBER)
volatile far BDT ep5Bo;
volatile far BDT ep5Bi;
#endif
Endpoint #5 BD Out
Endpoint #5 BD In
#if(6 <= MAX_EP_NUMBER)
volatile far BDT ep6Bo;
volatile far BDT ep6Bi;
#endif
Endpoint #6 BD Out
Endpoint #6 BD In
#if(7 <= MAX_EP_NUMBER)
volatile far BDT ep7Bo;
volatile far BDT ep7Bi;
#endif
Endpoint #7 BD Out
Endpoint #7 BD In
#if(8 <= MAX_EP_NUMBER)
volatile far BDT ep8Bo;
volatile far BDT ep8Bi;
#endif
Endpoint #8 BD Out
Endpoint #8 BD In
#if(9 <= MAX_EP_NUMBER)
volatile far BDT ep9Bo;
volatile far BDT ep9Bi;
Endpoint #9 BD Out
Endpoint #9 BD In
66
Librerías C18 del USB
#endif
#if(10 <= MAX_EP_NUMBER)
volatile far BDT ep10Bo;
volatile far BDT ep10Bi;
#endif
Endpoint #10 BD Out
Endpoint #10 BD In
#if(11 <= MAX_EP_NUMBER)
volatile far BDT ep11Bo;
volatile far BDT ep11Bi;
#endif
Endpoint #11 BD Out
Endpoint #11 BD In
#if(12 <= MAX_EP_NUMBER)
volatile far BDT ep12Bo;
volatile far BDT ep12Bi;
#endif
Endpoint #12 BD Out
Endpoint #12 BD In
#if(13 <= MAX_EP_NUMBER)
volatile far BDT ep13Bo;
volatile far BDT ep13Bi
#endif
Endpoint #13 BD Out
Endpoint #13 BD In
#if(14 <= MAX_EP_NUMBER)
volatile far BDT ep14Bo;
volatile far BDT ep14Bi;
#endif
Endpoint #14 BD Out
Endpoint #14 BD In
#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
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;
USBGEN_BD_IN.Stat._byte = _UCPU|_DAT1;
Fija la dirección del buffer
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
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
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
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
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
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
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
bInterfaceSubClass
2.7.5.11.
con
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
RequestSenseResponse gblSenseData.
2.7.5.14.
Sense,
inicializando
la
estructura
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
Librerías C18 del USB
2.7.5.16.
void MSDDataOut(void)
Efectos
secundarios:
MSD_BD_OUT.ADR
se
incrementa
MSD_OUT_EP_SIZE (para leer los 64B siguientes en msd_buffer).
con
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
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;
POINTER pCDCSrc;
POINTER pCDCDst;
byte cdc_tx_len;
byte cdc_mem_type;
Estados definidos en cdc.h
Puntero dedicado a la fuente
Puntero dedicado al destino
Longitud total tx
_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.
2.8.4.1.
RESPUESTAS ESPECÍFICAS DE LA CLASE
void USBCheckCDCRequest(void)
Esta rutina chequea el paquete de datos setup para ver si este sabe como
manipularlo.
76
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
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
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;
byte hid_rpt_rx_len;
2.10.3.
[0] Protocolo de inicio [1] Protocolo de informe
PROTOTIPOS PRIVADOS
void HIDGetReportHandler(void);
void HIDSetReportHandler(void);
2.10.4.
DECLARACIONES
#pragma code
2.10.5.
2.10.5.1.
RESPUESTAS ESPECÍFICAS DE LA CLASE
void USBCheckHIDRequest(void)
Esta rutina chequea el paquete de datos específico para ver si sabe como
manipularlo.
2.10.6.
2.10.6.1.
API DEL USUARIO
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
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
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()
ProcessIO();
} end while
} end main
USB Tasks
Aqui se llama al programa del usuario
static void InitializeSystem(void)
81
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();
if(UCFGbits.UTEYE!=1)
USBDriverService();
se tiene que utilizar el método obtener
Método interrupción u obtener
} end USBTasks
82
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.
2.12.3.1.
DECLARACIONES
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
Descargar