Professional Documents
Culture Documents
Las libreras 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 lneas que dependen de la clase. Y en verde la parte de la librera que es cdigo, aunque el texto en rojo y en azul tambin es cdigo. Para realizar una conexin sin caractersticas especficas, lo recomendable es utilizar la clase genrica (GEN) ya que permite una velocidad ms alta que la clase CDC, aunque esta ltima se utiliza por resultar ms fcil la programacin del host. Para ello se copian todas las libreras de esta clase que suministra Microchip y se modifican las lneas que aqu aparecen en rojo. Lo ms importante es definir bien las interfaces y los Endpoints. Para realizar una aplicacin en una clase determinada, lo ms sencillo es copiar todas las libreras de esa clase, corregirlas y modificar las libreras user.h y las aqu comentadas. Haciendo esto, nos evitamos tener que modificar el cdigo al cambiar la clase del dispositivo. Para ms informacin visitar la pgina web de microchip, en la que hay ejemplos de cada clase.
1.1.1.
USB.H
Esta librera proporciona la forma de incluir todos los archivos necesarios del firmware del USB de Microchip. En realidad, es la nica librera que hay que incluir en el programa de inicio, ya que se encarga de aadir las dems. El orden de inclusin 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"
1.1.2.
USBCFG.H: CONFIGURACIN
Esta librera es la encargada de la configuracin del buffer por defecto, del Endpoint 0, de los Endpoints utilizados en la comunicacin Hay que modificarla en cada aplicacin.
1.1.2.1.
Definiciones
Valor de configuracin:
#define UCFG_VAL _PUEN|_TRINT|_FS|MODE_PP
E/S auto-alimentadas:
#define USE_SELF_POWER_SENSE_IO
Las dos definiciones anteriores se realizarn cuando sea necesario, siendo totalmente independiente una de la otra.
1.1.2.2.
MUID = Microchip USB Clase ID Se utiliza para identificar la clase del USB de la sesin actual de control de la transferencia del EP0:
#define MUID_NULL #define MUID_USB9 #define MUID_HID #define MUID_CDC 0 1 2 3 Ninguna USB9 Interfaz humana Clase de comunicacin del dispositivo
1.1.2.3.
Macros HID
Ver la direccin del descriptor HID:
#define mUSBGetHIDDscAdr(ptr) { if(usb_active_cfg == 1) ptr = (rom byte*)&cfg01.hid_i00a00; }
USBDEFS_STD_DSC.H: DESCRIPTORES:
1.1.3.
DEFINICIONES
ESTNDAR
DE
LOS
Mediante esta librara se crean las estructuras de los descriptores estndar, se definen constantes para realizar el cdigo ms rpidamente, etc. En general, no hay que modificar nada de la librera. En nuestra aplicacin copiaremos la que cede Microchip que corresponda con nuestra clase.
1.1.3.1. 1.1.3.2.
Incluye:
Librera en la que se definen tipos de datos
#include "system\typedefs.h"
Definiciones
0x01 0x02 0x03 0x04 0x05 Descriptor del dispositivo Descriptor de configuracin Descriptor de la secuencia Descriptor de la interfaz Descriptor del Endpoint
Tipos de descriptores:
#define DSC_DEV #define DSC_CFG #define DSC_STR #define DSC_INTF #define DSC_EP
Definicin de los Endpoint (slo 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
Atributos de configuracin:
#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)
1.1.3.3.
Estructuras
Bcd del USB; word bcdUSB; Protocolo del dispositivo; byte bDevProtocol; Identificacin del word idProduct; Informacin del producto; byte iProduct;
Nmero de interfaz; byte bIntfNum; Clase de interfaz; byte bIntfCls; Informacin de la interfaz; byte iIntf;
Tipo de descriptor; byte bDscType; Tamao mximo del paquete; word wMaxPktSize;
1.1.4.
USBDSC.H: DESCRIPTORES
Esta es una de las libreras ms importantes, ya que en ella se definen los descriptores. Como hemos visto anteriormente, los descriptores definen la interfaz, la clase, el fabricante, etc. Esta librera suele ser totalmente distinta en cada aplicacin.
1.1.4.1.
1.1.4.2.
Definiciones
Configuracin 01 Descriptor de configuracin Descriptor de la interfaz Endpoint descriptor de salida Endpoint descriptor de entrada
#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.
Externas
extern rom USB_DEV_DSC device_dsc; extern CFG01; extern rom struct{byte bLength;byte bDscType;word string[1];}sd000;
DESCRIPCIONES
DEL
BUFFER
DEL
La librera actual recopila las caractersticas del Endpoint 0 y de su buffer, no hay que modificarla ya que las variables se han declarado en otras libreras.
1.1.5.1.
Incluye
Dispositivo, Interfaz, Endpoint, Otro Estndar, Clase, Fabricante, Reservado Host-al-dispositivo, Dispositivo-al-host
Slo para configuracin y String del descriptor Dispositivo, Configuracin, String Identificacin de idioma
Valor alterno de configuracin 0-255 Tiene que ser cero Valor del nmero de interfaz 0-255 Tiene que ser cero
10
11
12
1.1.6.
USBMMAP.H
Esta librera define constantes y estructuras utilizadas por otras.
El programador, salvo excepcin, no tiene que modificarla utilizndola tal y como aparece.
1.1.6.1. 1.1.6.2.
Incluye Definiciones
0x04 0x08 0x10 0x20 0x00 0x40 0x40 0x80 0x00 Parada del buffer activa Dato de sincronizacin activo Incremento de direccin desactivado Guardado del buffer descriptor por el SIE activo Paquete DATA0 esperando el siguiente Paquete DATA1 esperando el siguiente Mscara DTS El SIE controla el buffer La CPU controla el buffer
#include "system\typedefs.h"
para
el
control
de
transferencias,
utilizado
en
1.1.6.3.
Tipos
Estado del dispositivo
13
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; typedef union _BDT { struct { BD_STAT Stat; byte Cnt; byte ADRL; byte ADRH; }; struct { unsigned :8; unsigned :8;
Parada del buffer activa Dato de sincronizacin activo Incremento de direccin desactivado Guardado del buffer descriptor por el SIE activo Valor del dato de sincronizacin Propiedad del USB
Paquete de identificacin
14
1.1.6.4.
Externas
extern byte usb_device_state; extern USB_DEVICE_STATUS usb_stat; extern byte usb_active_cfg; extern byte usb_alt_intf[MAX_NUM_INT]; extern volatile far BDT ep0Bo; 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
1.1.7.
Lo nico que hay que modificar es la correccin de la errata en la original de Microchip, como se comenta ms adelante.
1.1.7.1.
Incluye
1.1.7.2.
Definiciones
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 Patrn de ojo
Esto se utiliza cuando se comprueba el valor ledo 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"
16
NOTA: la librera tiene una errata en la definicin 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 definicin de UCFG_VAL est en autofiles\usbcfg.h Este registro determina: velocidad del USB Speed, seleccin de las resistencias pull-up del chip, seleccin del transmisor-receptor del chip, modo de chequeo patrn de ojo, buffer modo Ping-pong
17
void mDisableEP1to15()
Esta macro desactiva todos los Endpoints menos el 0. Hay que invocar esta macro cada vez que el host enve una seal 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)
Precondicin: 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; adems, cambia el bit DTS para sincronizacin.
#define mUSBBufferReady(buffer_dsc) { buffer_dsc.Stat._byte &= _DTSMASK; buffer_dsc.Stat.DTS = !buffer_dsc.Stat.DTS; buffer_dsc.Stat._byte |= _USIE|_DTSEN; }
Guarda slo el bit DTS Cambia el bit DTS Cambia la propiedad al SIE
1.1.7.3.
Prototipos pblicos
void USBCheckBusStatus(void); void USBDriverService(void); void USBRemoteWakeup(void); void USBSoftDetach(void); void ClearArray(byte* startAdr,byte count);
18
1.1.8.
Esta librera es la encargada de definir los tipos de transferencia. Se utiliza desde otras libreras al declarar la interfaz, la transferecia, etc. No hay que modificarla
1.1.8.1. 1.1.8.2.
Incluye Definiciones
0 1 2 Espera Setup Transf. de control de transmisin Transf. de control de recepcin
#include "system\typedefs.h"
Tipos de Tokens:
#define SETUP_TOKEN #define OUT_TOKEN #define IN_TOKEN 0b00001101 0b00000001 0b00001001 Token setup Token de salida Token de entrada
1.1.8.3.
Externas
extern byte ctrl_trf_session_owner; extern POINTER pSrc; extern POINTER pDst; extern WORD wCount;
1.1.8.4.
Prototipos pblicos
void USBCtrlEPService(void); void USBCtrlTrfTxService(void); void USBCtrlTrfRxService(void); void USBCtrlEPServiceComplete(void); void USBPrepareForNextSetupTrf(void);
19
1.1.9.
USB9.H
Gracias a esta librera obtenemos la direccin del dispositivo, entre otras caractersticas. No se tiene que modificar.
1.1.9.1. 1.1.9.2.
Incluye Definiciones
0 1 3 5 6 7 8 9 10 11 12 Obtiene estado Borra caracterstica Fija caracterstica Fija direccin Obtiene descriptor Fija descriptor Obtiene configuracin Fija configuracin Obtiene interfaz Fija interfaz Marco de sincronismo
#include "system\typedefs.h"
mUSBCheckAdrPendingState()
Rutina de chequeo especializado, comprueba si el dispositivo est en el estado Pendiente de direccin 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 pblicos
void USBCheckStdRequest(void);
20
1.1.10.
Esta es la librera de la clase genrica. Se definen las transferencias creando funciones para realizarlas. No hay que modificarla.
1.1.10.1. 1.1.10.2.
Incluye Definiciones
#include "system\typedefs.h"
(bit) mUSBGenRxIsBusy(void)
Esta macro se utiliza para comprobar que el Endpoint de salida est ocupado (lo controla el SIE) o no. Uso tpico: 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 tpico: 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 nmero de bytes copiados al buffer del usuario en la ltima llamada a la funcin USBGenRead.
#define mUSBGenGetRxLength() usbgen_rx_len
1.1.10.3. 1.1.10.4.
void USBGenInitEP(void); void USBGenWrite(byte *buffer, byte len); byte USBGenRead(byte *buffer, byte len);
21
1.1.11.
Esta es la librera de la clase MSD. Se definen las transferencias creando funciones para realizarlas. No hay que modificarla.
1.1.11.1.
Incluye
Mapa de pines E/S
1.1.11.2.
Definiciones
0x08
Comandos de la clase:
#define MSD_RESET #define GET_MAX_LUN #define BLOCKLEN_512 #define STMSDTRIS #define STRUNTRIS #define STMSDLED #define STRUNLED #define ToggleRUNLED() 0xff 0xfe 0x0200 TRISD0 TRISD1 LATDbits.LATD0 LATDbits.LATD1 STRUNLED = !STRUNLED;
22
1 !INVALID_CBW 0
Cdigos ASC ASCQ para datos (slo 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
23
(bit) mMSDRxIsBusy(void)
Esta macro se utiliza para comprobar si el Endpoint MSD OUT est ocupado (controlado por el SIE) o no. Uso tpico: 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 tpico: if(mMSDTxIsBusy())
#define mMSDTxIsBusy() MSD_BD_IN.Stat.UOWN
(bit) mMin(void)
Esta macro se utiliza para encontrar el menor de dos argumentos. Uso tpico: mMin(A, B)
#define mMin(A,B) (A<B)?A:B
1.1.11.3.
Estructuras
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
/Bloque de comando para leer 10 (0x28) y (0x2a) comandos b7-b5 lectura protegida, b4 DPO, b3 FUA, b2 Reservado, b1 FUA_NV, b0 Obsoleto b4-b0 es el nmero de grupo el resto reservados
capacidad de lectura 10
25
Verificar 10 Comando 0x2F b7-b5 VRProtect, b4 DPO, b3-b2,Reservado, b1 BYTCHK, b0 Obsoleto Nmero del grupo b4-b0, el resto reservado
STOP_START 0x1B
26
byte AdditionalLength; byte Sccstp; byte bqueetc; byte CmdQue; 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;
Clasificador del perifrico:3; Perifrico_DevType:5; medio removible bit7 = 0 medio no removible, resto reservado versin b7,b6 Obsoleto, b5 Acceso de control coordinado, b4 direccionamiento jerrquico 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 indagacin estndar 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
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 Pgina 1009, SBC-2)
typedef struct { byte NumBlocks[4]; byte Resv; byte BlockLen[3]; } tBlockDescriptor; /* Page_0 mode page format */ typedef struct { unsigned PageCode:6; unsigned SPF:1; SPC-3 7.4.5 SubPageFormat=0 medio Page_0 formato
reservado
27
b6-b0 es el cdigo de respuesta fijado o el formato del descriptor Poner a 1 indica que el campo de informacin tiene un valor vlido Referencia SPC-3 Seccin 4.5.6 Indicador de la longitud incorrecta Fin del medio para los comandos READ y SPACE Tipo de dispositivo o comando especfico (SPC-33.1.18) Nmero de bytes sense adicionales que siguen <=244 depende del comando de la excepcin ocurrida cdigo sense adicional cdigo sense adicional seccin clasificada 4.5.2.1 SPC-3 SKSV son los msb de la clave sense especfica de campo vlido fijado=>SKS vlido. Los 18-n bytes sense adicionales se pueden definir ms tarde de respuesta sense de formato fijado
18bytes }; } RequestSenseResponse;
28
1.1.11.4. 1.1.11.5.
Externas
declarado en sdcard.c
Prototipos pblicos
29
1.1.12.
Esta es la librera de la clase CDC. Se definen las transferencias creando funciones para realizarlas. No hay que modificarla.
1.1.12.1. 1.1.12.2.
Incluye Definiciones
0x00 0x01 0x02 0x03 0x04 0x20 0x21 0x22 0x23
#include "system\typedefs.h"
30
BOOL mUSBUSARTIsTxTrfReady(void)
Esta macro se utiliza para comprobar si la clase CDC est disponible para enviar mas datos. Uso tpico: 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 tpico: 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 tpico: if(mCDCUsartTxIsBusy())
#define mCDCUsartTxIsBusy() CDC_BULK_BD_IN.Stat.UOWN
byte mCDCGetRxLength(void)
Salida: devuelve cdc_rx_len mCDCGetRxLength se utiliza para recuperar el nmero de bytes que se han copiado al buffer del usuario en la ltima llamada a la funcin getsUSBUSART.
#define mCDCGetRxLength() cdc_rx_len
32
1.1.12.3.
Estructuras
0x07
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;
33
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
1.1.13.
Esta es la librera de la clase HID. Se definen las transferencias creando funciones para realizarlas. No hay que modificarla.
1.1.13.1. 1.1.13.2.
Incluye Definiciones
0x01 0x02 0x03 0x09 0x0A 0x0B Obtener informe Obtener reposo Obtener protocolo Fijar informe Fijar reposo Fijar protocolo
#include "system\typedefs.h"
Seleccin de protocolo:
#define BOOT_PROTOCOL #define RPT_PROTOCOL 0x00 0x01 Protocolo de inicio Informe de protocolo
(bit) mHIDRxIsBusy()
Esta macro comprueba si el Endpoint de salida del HID est ocupado (controlado por el SIE) o no. Aplicacin tpica: if(mHIDRxIsBusy())
35
(bit) mHIDTxIsBusy()
Esta macro comprueba si el Endpoint de entrada del HID est coupado (controlado por el SIE) o no. Aplicacin tpica: 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 nmero de bytes copindolos al buffer de usuario en orden de la ltima llamada a la funcin HIDRxReport.
#define mHIDGetRptRxLength() hid_rpt_rx_len
1.1.13.3.
Estructuras
typedef struct _USB_HID_DSC_HEADER Cabecera del descriptor HID { byte bDscType; Tipo de descriptor word wDscLength; Longitud del descriptor } USB_HID_DSC_HEADER; typedef struct _USB_HID_DSC Descriptor HID { Longitud Tipo de descriptor Bcd del HID byte bLength; byte bDscType; word bcdHID; Cdigo de territorio Nmero 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
1.1.13.5.
Prototipos pblicos
void HIDInitEP(void); void USBCheckHIDRequest(void); void HIDTxReport(char *buffer, byte len); byte HIDRxReport(char *buffer, byte len);
1.1.14.
IO_CFG.H
36
Libreras C18 del USB Si no se desea incluir hay que definir el apartado del USB ya que si no, la compilacin dara un error al no definir los puertos Bus Sense y Power Sense.
1.1.14.1. 1.1.14.2.
Incluye Tris
1 0
#include "autofiles\usbcfg.h"
1.1.14.3.
USB
TRISAbits.TRISA1 entrada
#define tris_usb_bus_sense
#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
1.1.14.4.
LED
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;
#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()
37
1.1.14.5.
Interruptores
TRISBbits.TRISB4=1;TRISBbits.TRISB5=1; TRISBbits.TRISB4=1; TRISBbits.TRISB5=1; PORTBbits.RB4 PORTBbits.RB5
#define mInitAllSwitches() #define mInitSwitch2() #define mInitSwitch3() //#define sw2 #define sw3
1.1.14.6.
Potencimetro
1.1.14.7.
#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.
SDMMC
TRISBbits.TRISB4 PORTBbits.RB4 TRISAbits.TRISA4 PORTAbits.RA4 Entrada Entrada
38
1.1.15.
INTERRUPT.H
En esta librera se incluye todo lo referente a las interrupciones. El usuario la modificar dependiendo de la aplicacin.
#include "system\typedefs.h"
39
1.1.16.1.
Incluye
1.1.16.2.
#if
(EP0_BUFF_SIZE != 8) && (EP0_BUFF_SIZE != 16) && (EP0_BUFF_SIZE != 32) && (EP0_BUFF_SIZE != 64) #error(Tamao 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 tamao 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 tamao del Endpoint de entrada de HID no puede ser mayor de 64, comprueba "autofiles\usbcfg.h") #endif #endif
1.2.
Al instalar el compilador MPLAB C18 se crea una carpeta llamada lkr, en la cual hay unos archivos que se pueden aadir al proyecto. Estos archivos definen todos los puertos, registros, bits del microprocesador que utilicemos en el proyecto. Es recomendable aadir este archivo ya que todas las libreras trabajan con las definiciones hechas en l.
40
2.
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 libreras. En stas hay un apartado llamado prototipos pblicos en los que se declara la macro como funcin. Las macros que no aparecen en el apartado de prototipos pblicos, 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 libreras, aparecen en rojo los datos que hay que modificar en cada aplicacin, en azul los referentes a la clase y en verde todo el cdigo fuente.
2.1.
En este archive el fabricante ha creado el cdigo relativo a la comunicacin inicial. En el cual se declaran los estados del USB, los comprueba y determina en cual est la aplicacin.
2.1.1.
INCLUYE
2.1.2. 2.1.3.
#pragma udata
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. 2.1.4.1.
#pragma code
41
Despus de activar el modulo USB, hay un retardo para que la tensin de las lneas D+ o D- se pongan en alto lo suficiente para que salga de la condicin SE0. La interrupcin de Reset del USB tiene que estar enmascarada hasta que la condicin 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) } end USBCheckBusStatus
Borra todas las interrupciones del USB Enmascara todas las interrupciones del Desenmascara la interrupcin RESET Desenmascara la interrupcin IDLE Lo dems espera hasta que SE0 est
2.1.4.2.
void USBModuleEnable(void)
Esta rutina activa el mdulo USB. Slo se puede llamar esta rutina desde USBCheckBusStatus().
void USBModuleEnable(void) { UCON = 0;
42
2.1.4.3.
void USBModuleDisable(void)
Esta rutina desactiva el modulo USB. Slo se puede llamar esta rutina desde USBCheckBusStatus().
void USBModuleDisable(void) { UCON = 0; bus UIE = 0; usb_device_state = DETACHED_STATE; } end USBModuleDisable
Desactiva el modulo y desconecta del Enmascara todas las interrupciones USB Definido en usbmmap.c y .h
2.1.4.4.
void USBSoftDetach(void)
Efectos secundarios: El dispositivo se tiene que reenumerar. USBSoftDetach desconecta elctricamente el dispositivo del bus. Se utiliza para dejar de suministrar tensin VUSB a las resistencias pull-up. Las resistencias pull-down en el lado del host pondrn las seales diferenciales en bajo y el host registrar el evento como una desconexin. Como el cable USB no se desconecta fsicamente, la energa suministrada a travs de l la puede detectar el dispositivo. Cuando se llame la funcin USBCheckBusStatus(), se reconectar el dispositivo al bus.
void USBSoftDetach(void) { USBModuleDisable(); } end USBSoftDetach
2.1.4.5.
void USBDriverService(void)
Esta rutina es el corazn del firmware. Controla las interrupciones USB. Nota: Las transiciones de estado del dispositivo son las siguientes: Desconectado->Conectado->Alimentado->Por defecto->Pendiente de direccin> ->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;
43
Tarea B: Servicio de la Interrupcin 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 despus 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();
2.1.4.6.
void USBSuspend(void)
void USBSuspend(void) { Nota: No borrar UIRbits.ACTVIF aqu Razn: ACTVIF slo se genera si IDLEIF se ha generado. Es un ratio de generacin de interrupcin de 1:1. Por cada IDLEIF, habr slo un ACTVIF sea cual sea el nmero de transacciones en el bus. Si el ACTIF se borra aqu, puede ocurrir un problema cuando: [ IDLE ][bus activity -> <--- 3 ms -----> ^ ^ ACTVIF=1
44
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 funcin la tiene que llamar el usuario cuando el dispositivo se despierte por un estmulo externo que no sea ACTIVIF. Nota: La seccin modificable en esta rutina se puede cambiar dependiendo de las especificaciones de la aplicacin. La implementacin actual bloquea temporalmente otras funciones de ejecucin en un periodo de 1-13ms dependiendo de la frecuencia del ncleo. De acuerdo con las especificaciones del USB 2.0 en la seccin 7.1.7.7, El reinicio remoto del dispositivo tiene que bloquear la seal al menos por 1ms y no ms de 15ms. La idea aqu es utilizar un retraso por contador, usando un valor comn que pueda trabajar con un gran rango de frecuencias del ncleo. Este valor es 1800. Ver la tabla de debajo:
Frec del ncleo (MHz) 48 4 MIP 12 1 Periodo seal RESUME (ms) 1,05 12,6
Estos tiempos pueden ser distintos si se utiliza la optimizacin o el cdigo de instrucciones entendido o cuando se tiene otra interrupcin activa. Asegurarse usando del Stopwatch del MPLAB SIM.
void USBRemoteWakeup(void) {
45
2.1.4.9.
void USB_SOF_Handler(void)
El host enva un paquete SOF a los dispositivos cada milisegundo. Esta interrupcin puede ser til en las pipes sncronas. Los diseadores pueden implementar una rutina de realimentacin como necesite.
void USB_SOF_Handler(void) { /* Rutina de realimentacin aqu */ UIRbits.SOFIF = 0; } end USB_SOF_Handler
2.1.4.10.
void USBStallHandler(void)
Precondicin: El SIE tiene que haber mandado un paquete STALL al host. El STALLIF se active cada vez que el SIE enva un paquete STALL siempre que un Endpoint lo provoque. Una transaccin Setup invalida la funcin 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 funcin STALL a un pipe Endpoint particular se desactivar automticamente (direccin especfica). 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 especfico.
46
Libreras C18 del USB Ejemplo: Clase de dispositivo de almacenamiento masivo Si el CBW no es vlido, 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 transaccin Setup, la CPU gobierna el EP0_OUT forzndolo por firmware. if(UEP0bits.EPSTALL == 1) { USBPrepareForNextSetupTrf(); UEP0bits.EPSTALL = 0; } UIRbits.STALLIF = 0; } end USBStallHandler
2.1.4.11.
void USBErrorHandler(void)
El propsito de esta interrupcin es slo por depuracin durante el desarrollo. Chequea UEIR para ver error ha causado la interrupcin.
void USBErrorHandler(void) { UIRbits.UERRIF = 0; } end USBErrorHandler
2.1.4.12.
void USBProtocolResetHandler(void)
Precondicin: Se tiene que haber recibido un reset del bus USB desde el host. Efectos secundarios: Esta rutina purga cualquier transaccin pendiente. Borra la FIFO USTAT. Hay que llamar esta rutina cuando el reset del bus USB se ha recibido. Resetea la direccin 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 interrupcin, desenmascara las interrupciones USB aplicables y reinicializa las variables internas de estado-mquina.
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 interrupcin USB UIE = 0b01111011; Activa todas las interrupciones menos ACTVIE UADDR = 0x00; Resetea a la direccin 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 transaccin pendiente UIRbits.TRNIF = 0; UCONbits.PKTDIS = 0; Se asegura de que el procesamiento de paquetes est activo
47
2.1.5.
FUNCIN AUXILIAR
void ClearArray(byte* startAdr,byte count) { *startAdr; while(count) { _asm clrf POSTINC0,0 _endasm count--; } end while } end ClearArray
2.2.
2.2.1.
USB9.C
Estas macros establecen la conexin.
INCLUYE
2.2.2. 2.2.3.
#pragma udata
2.2.4.
DECLARACIONES
#pragma code
48
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; Actualizacin de estado Ver USBCtrlTrfInHandler() en usbctrltrf.c para el prximo 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
2.2.4.2.
void USBStdGetDscHandler(void)
Esta rutina une la respuesta estndar GET_DESCRIPTOR. Utiliza tablas dinmicamente buscando el tamao del descriptor. Esta rutina no se debe modificar si las tablas usbdsc.c en estn 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
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 seccin 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; /* Seccin modificable */ BootInitEP(); /* Final de la seccin modificable */ } end if(SetupPkt.bcfgValue == 0) } end USBStdSetCfgHandler
2.2.4.4.
void USBStdGetStatusHandler(void)
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 mscara de bit CtrlTrfData._byte0=0x01; Activa bit0 break; end switch
51
2.2.4.5.
void USBStdFeatureReqHandler(void)
52
2.3.
2.3.1.
USBCTRLTRF.C
Estas macros controlan las transferencias.
INCLUYE
2.3.2.
VARIABLES
Estado de la transferencia de control Controlador de la sesin de transferencia actual Puntero a la fuente de datos Puntero al destino de los datos Contador de datos
#pragma udata byte ctrl_trf_state; byte ctrl_trf_session_owner; POINTER pSrc; POINTER pDst; WORD wCount;
2.3.3.
PROTOTIPOS PRIVADOS
2.3.4. 2.3.4.1.
#pragma code
Precondicin: USTAT est cargada con una direccin de Endpoint vlida. USBCtrlEPService chequea tres tipos de transacciones que conoce como tratarlas y lo hace: 1. EP0 SETUP 2. EP0 OUT 3. EP0 IN Ignora los dems 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 IN
53
2.3.4.2.
void USBCtrlTrfSetupHandler(void)
Precondicin: El buffer SetupPkt est cargado con un dato vlido de Setup. Esta rutina es una tarea para despachar y tiene tres estados. 1. Inicializa la transferencia de control de estados mquina. 2. Llama cada vez al mdulo que sabe como servir la respuesta Setup del host. Ejemplo de mdulo: USB9, HID, CDC, MSD, Se aade una nueva clase, la tabla ClassReqHandler en usbdsc.c se tiene que actualizar para llamar todas las clases de unin disponibles. 3. Una vez que el mdulo se arriesga a chequear si el responsable de servir la respuesta, en el estado 3 chequea la direccin 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 mquina: 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 parmetros 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.
{ byte i;
void USBCtrlTrfSetupHandler(void)
Estado 1 ctrl_trf_state = WAIT_SETUP; ctrl_trf_session_owner = MUID_NULL; wCount._word = 0; Estado 2 USBCheckStdRequest(); /* Seccin Modificable */
Ver system\usb9\usb9.c
Insertar otra respuesta de unin de clase de dispositivo USB aqu /* Fin de la seccin modificable */ Estado 3 USBCtrlEPServiceComplete(); } end USBCtrlTrfSetupHandler
2.3.4.4.
void USBCtrlTrfOutHandler(void)
Esta rutina une una transaccin OUT de acuerdo con el estado de la transferencia de control que est actualmente activa.
54
Libreras C18 del USB Nota: Si la transferencia de control es del host al dispositivo, hay que notificar el dueo de la sesin cada transaccin 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 transaccin IN de acuerdo con el estado de la transferencia de control que est actualmente activa. Nota: Si se fija la direccin 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 direccin es una transaccin IN. Por lo tanto se necesita para servir esta situacin cuando la condicin es correcta. La macro mUSBCheckAdrPendingState se define en usb9.h y est diseada para servir este evento.
void USBCtrlTrfInHandler(void) { mUSBCheckAdrPendingState();
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)
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 mltiples transacciones USB. Nota: Esta rutina trabaja con Endpoints sncronos mayores que 256bytes y aqu se muestra un ejemplo de cmo 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 envan. 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 nmero 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 versin del firmware.
void USBCtrlTrfRxService(void) { byte byte_to_read; byte_to_read = ep0Bo.Cnt; Acumula el nmero total de bytes ledos wCount._word = wCount._word + byte_to_read; pSrc.bRam = (byte*)&CtrlTrfData;
56
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 situacin dada. Hay tres: a. No hay unin 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 cmo 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 transaccin 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 sesin 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 terminacin temprana NOTA: Si algo va mal durante la transferencia de control, puede que el host no enve la ltima fase de estado. Cuando pasa esto, pueden ocurrir dos cosas dependiendo del host: a) El host enva un RESET
57
Documento creado por Slalen para Electronics Strange World b) El host puede mandar una nueva transaccin SETUP sin enviar primero un
RESET. Para que el caso b) comunique correctamente, el EP OUT tiene que configurarse para recibir una transaccin OUT de longitud cero o una nueva transaccin SETUP. Como la transaccin SETUP necesita que el bit DTS sea DAT0, el estado de longitud cero necesita que el bit DTS sea DAT1, la comprobacin del bit DTS por hardware tiene que desactivarse. En este caso el SIE puede aceptar cualquiera de las dos transacciones. Adems, el byte Cnt se tiene que fijar para prepararse para el dato SETUP (8bytes o mas), y el buffer de direccin 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 dueo. 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 finalizacin 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 transaccin 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 transaccin 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
58
2.4.
Este archivo contiene la informacin de los descriptores USB. Se utiliza junto al archivo usbdsc.h. Cuando se aade o remueve un descriptor del men de configuracin 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 tamao del descriptor, ej. sizeof(CFG01). Una configuracin tpica de los descriptores consiste en: La mnima configuracin del descriptor (USB_CFG_DSC) Uno o ms descriptores de interfaz (USB_INTF_DSC) Uno o ms descriptores de Endpoint (USB_EP_DSC) Nombres convenidos: Tipo USB_CFG_DSC se nombra cdxx, donde xx es el nmero de configuracin. Este nmero debera ser el mismo que el valor del ndice actual de esta configuracin. Tipo USB_INTF_DSC se nombra i<yy>a<zz>, donde yy es el nmero de la interfaz y zz es el nmero de la interfaz alterna. Tipo USB_EP_DSC se nombra ep<##><d>_i<yy>a<zz>, donde ## es el nmero del Endpoint y d es la direccin 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 configuracin, 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 USB_INTF_DSC USB_EP_DSC USB_EP_DSC USB_INTF_DSC USB_EP_DSC } cfg01 cd01; i00a00; ep01o_i00a00; ep01i_i00a00; i01a00; ep02i_i01a00;
Ver que la jerarqua de los descriptores sigue a las especificaciones de necesidad del USB. Todos los Endpoint que pertenecen a una interfaz se tienen que listar inmediatamente despus 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 configuracin tiene que tener la definicin _DEFAULT como mnimo. Se pueden aadir 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 parmetros son auto-explicativos. Especifican la longitud del descriptor del Endpoint (7) y el tipo de descriptor. El siguiente parmetro identifica el Endpoint, las definiciones se encuentran en usbdefs_std_dsc.h y tienen la siguiente convencin: _EP<##>_<dir> donde ## es el nmero del endpoint y dir es la direccin de la transferencia. dir tiene el valor de OUT o IN. El siguiente parmetro 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 opcin _ISO, se pueden aadir opciones adicionales. Ejemplo: _ISO|_AD|_FE Esto describe el Endpoint como una pipe sncrona con los atributos adoptivo y realimentacin. Ver usbdefs_std_dsc.h y las especificaciones del USB por ms detalles. El siguiente parmetro define el tamao del Endpoint. El ltimo parmetro es el intervalo de muestreo. Aadir 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 nmero 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 carcter como un tipo de letra. Todo el texto string se declara como una matriz de letras con el nmero 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
Libreras C18 del USB Un proyecto USB puede que tenga varios strings y el firmware soporta el control de mltiples strings como una bsqueda en tabla. La bsqueda en tabla se define: rom const unsigned char *rom USB_SD_Ptr[]={&sd000,&sd001,&sd002}; La declaracin de arriba tiene 3 strings, sd000, sd001 y sd002. Los strings se pueden aadir o borrar. sd000 es un string descriptor especial, define el idioma, normalmente es ingls americano (US English (0x0409)). El ndice del string debe ser igual que el ndice de posicin de la matriz USB_SD_Ptr, &sd000 tiene que estar en la posicin USB_SD_Ptr[0], &sd001 tiene que estar en la posicin USB_SD_Ptr[1] y as sucesivamente. La bsqueda en tabla USB_SD_Ptr la utiliza la funcin de unin string en usb9.c. El esquema de bsqueda en tabla tambin se aplica a la descriptor de configuracin. Un dispositivo USB puede tener varios descriptores de configuraciones, ej. CFG01, CFG02, etc. Para aadir un descriptor de configuracin, el usuario tiene que implementar una estructura similar a CFG01. El siguiente paso es aadir el nombre del descriptor de configuracin, ej. cfg01, cfg02; a la bsqueda en tabla USB_CD_Ptr. USB_CD_Ptr[0] es muy fcil poner el titular ya que la configuracin 0 es el estado no configurado de acuerdo con las especificaciones del USB. Los tipos de descriptor especficos se definen en: system\usb\usbdefs\usbdefs_std_dsc.h La informacin de configuracin se define en: autofiles\usbcfg.h
2.4.1.
INCLUYE
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,
Tamao del descriptor en bytes Descriptor tipo DEVICE Nmero de versin del USB en formato BCD Cdigo de Clase Cdigo Subclase Cdigo Protocolo Tamao de paquete mximo para el EP0, ver usbcfg.h ID Fabricante ID Producto
61
};
Descriptor de configuracin 1 CFG01={ Descriptor de configuracin 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,
Tamao del descriptor en bytes Tipo del descriptor CONFIGURACIN Longitud total de datos de esta configuracin Nmero de interfaces en esta configuracin Valor del ndice de esta configuracin String ndice de configuracin Atributos, ver usbdefs_std_dsc.h Consumo mximo de corriente (2X mA)
Tamao del descriptor en bytes Tipo de descriptor INTERFACE Nmero de Interface Nmero alterno de configuracin Nmero de Endpoints en esta interfaz Cdigo de la Clase Cdigo de la Subclase Cdigo del Protocolo String ndice de interfaz
}; 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',' ',
Descriptor de Clase Especfica HID sizeof(USB_HID_DSC), Tamao del descriptor en bytes DSC_HID, Tipo del descriptor HID 0x0101, Nmero de versin especfica HID en formato BCD 0x00, Cdigo del pas (0x00 en los no soportados) HID_NUM_OF_DSC, Nmero de la clase del descriptor, ver usbcfg.h DSC_RPT, Tipo del informe del descriptor sizeof(hid_rpt01), Tamao del informe del descriptor Descriptor del Endpoint sizeof(USB_EP_DSC),DSC_EP,_EP01_IN,_INT,HID_INT_IN_EP_SIZE,0x0A
62
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 compilacin de usbcfg.h instantneamente 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 especfica 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 estn conectadas en el chip. Al hacerlas instantneas, 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 ejecucin y se reduce el tamao de programa. Los Endpoints se definen con el nmero de Endpoint y la direccin de transferencia. Para simplificar, usbmmap.c slo utiliza el nmero del Endpoint del esquema de direccionamiento de los registros BDT. Con este mtodo si MAX_EP_NUMBER es 1, tenemos cuatro BDTs instantneamente: uno para EP0IN, otro para EP0OUT, que se tiene que inicializar instantneamente para las transferencias de control por defecto, y otros dos para EP1IN y EP1OUT. El nombre convenido es ep<#>B<d> donde # es el nmero del Endpoint y d es la direccin 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 instantneamente. Representa el nmero mximo de Endpoints que se direccionan, no cuantos Endpoints se utilizan. Como los BDTs para los Endpoints tienen la direccin 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 aplicacin 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 decisin final la tiene el usuario. El paso siguiente es asignar los BDTs instantneos a las distintas funciones del USB. El firmware asume que cada funcin 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 nmero. La asignacin de los Endpoints de las funciones del USB se gobiernan en usbcfg.h. Esto ayuda a prevenir errores de tener ms de una funcin USB con el mismo Endpoint. La seccin Distribucin de los Endpoints en usbcfg.h proporciona un ejemplo de cmo distribuir los Endpoints del USB con funciones USB. Se puede cambiar la configuracin en esta seccin. No hay una forma correcta de configuracin y los usuarios tienen que elegir el mtodo ms adecuado para la aplicacin. Normalmente, un usuario mapear lo siguiente para una funcin 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 tamao 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 #define FOO_UEP #define FOO_BD_OUT #define FOO_BD_IN #define FOO_EP_SIZE 0x00 UEP1 ep1Bo ep1Bi 64
64
Libreras 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 cdigo 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 tamao del Endpoint definido en el archivo usbcfg.h se utiliza de nuevo en el archivo usbmmap.c. Esto muestra que los dos archivos estn muy relacionados. El buffer del Endpoint para cada funcin USB se localiza en el rea del puertodual RAM y como despus se tiene que hacer instantneos los BDTs. Un ejemplo de declaracin es: volatile far unsigned char[FOO_EP_SIZE] data; La palabra volatile dice al compilador que no funcione ningn cdigo de optimizacin 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 definicin externa, como extern volatile far unsigned char[FOO_EP_SIZE] data; Conclusin: 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 cdigo de programa ms rpido y pequeo.
2.5.1.
INCLUYE
2.5.2.
#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.
#pragma udata usbram4=0x400 Ver, usb4: 0x400-0x4FF(256-byte) Seccin A: Tabla del Buffer Descriptor - 0x400 - 0x4FF(max)
65
66
#if(13 <= MAX_EP_NUMBER) volatile far BDT ep13Bo; volatile far BDT ep13Bi #endif #if(14 <= MAX_EP_NUMBER) volatile far BDT ep14Bo; volatile far BDT ep14Bi; #endif
#if(15 <= MAX_EP_NUMBER) volatile far BDT ep15Bo; Endpoint #15 BD Out volatile far BDT ep15Bi; Endpoint #15 BD In #endif Seccin B: Espacio del Buffer del EP0 - Dos areas definidas para el buffer: A. CTRL_TRF_SETUP - Tamao = 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 - Tamao = 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; Seccin 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
2.6.
En este archivo se han creado todas las funciones de transferencia de los datos que desee el usuario en la clase genrica.
2.6.1.
INCLUYE
2.6.2.
VARIABLES
#pragma code
USBGenInitEP inicializa Endpoints genricos, buffer de los descriptores, estados mquina internos y variables. Hay que llamarla despus 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. Razn: El nmero de bytes enviados al host vara de una transaccin a otra. Cnt tiene que ser igual al nmero exacto de bytes a transmitir en una transaccin IN dada. Este nmero de bytes slo se conoce una vez que los datos hayan sido enviados. USBGEN_BD_OUT.Cnt = sizeof(usbgen_out); Fija el tamao del buffer USBGEN_BD_OUT.ADR = (byte*)&usbgen_out; Fija la direccin 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; } end USBGenInitEP Fija la direccin del buffer Fija el estado del buffer
2.6.4.2.
68
Libreras C18 del USB El valor de len tiene que ser igual o menor que USBGEN_EP_SIZE. Para un Endpoint interrupcin/bulk, el tamao mximo del buffer es de 64bytes. Entrada: buffer: Puntero a la localizacin de inicio de los bytes de datos. len: Nmero de bytes a transmitir. Esta macro se utiliza para transferir datos de la memoria de datos. Aplicacin tpica: 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 comprobacin fuerza que se cumpla la precondicin. 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.
Precondicin: El valor del argumento de entrada len tiene que ser menor que el tamao mximo del Endpoint responsable de la recepcin 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 nmero de bytes copiados al buffer. Efectos secundarios: el acceso a la variable pblica usbgen_rx_len se actualiza con el nmero de bytes copiados al buffer. Una vez llamado USBGenRead, la recuperacin de usbgen_rx_len se puede hacer llamando la macro mUSBGenGetRxLength(). USBGenRead copia un string de los bytes recibidos a travs de un Endpoint OUT a una localizacin especificada por el usuario. Es una funcin que espera a recibir los datos si no estn disponibles. Devuelve 0 para notificar que no hay datos disponibles. Nota: Si el nmero actual de bytes recibidos es mayor que el nmero de bytes esperados (len), slo se copian el nmero de bytes esperados al buffer. Si el nmero de bytes recibidos es menor que el nmero 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 nmero de bytes que se esperan al nmero 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 prximo transaccin 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
2.7.
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
2.7.2.
VARIABLES
Toma valores MSD_WAIT, MSD_DATA_IN o SD_DATA_OUT
USB_MSD_CBW gblCBW; byte gblCBWLength; SDCSTATE gblFlag; RequestSenseResponse gblSenseData; byte *ptrNextData;
El nmero 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;
2.7.3.
PROTORIPOS PRIVADOS
71
#pragma code
Esta rutina une el RESET estndar y el comando de repuesta recibido en el EP0 de control GET_MAX_LUN.
2.7.5.2.
void ProcessIO(void)
Precondicin: 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
Libreras C18 del USB Todos los comandos de transporte Bulk en el Endpoit 1 se unen aqu: MSD_State contiene el estado actual del mdulo de almacenamiento masivo. En el estado MSD_WAIT: Espera al bloque de comando de cubierta (CBW) del Endpoint1. Si se recibe un CBW vlido y significativo, dependiendo del comando recibido MSD_State cambia a MSD_DATA_IN si el dato se enva al host (para todos comandos adems del WRITE_10). MSD_DATA_OUT si el host est esperando a mandar datos (slo en el caso de WRITE_10). Al finalizar el comando de estado de transferencia de datos de cubierta (CSW) se enva 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 Tamao = 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 Inicializacin. MSD_State se fija a MAD_WAIT. Esta rutina se llama desde InitializeSystem() en main.c. Inicializa la tarjeta SD y si tiene algn problema en la inicializacin todos los LEDs se encienced. Tambin fija MSD_State = MSD_WAIT
2.7.5.5.
void MSDCommandHandler(void)
Esta rutina se llama desde ProcessIO() cuando MSD_State=MSD_WAIT. Esta funcin 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 funcin enva el CSW y fija el estado a MSD_WAIT. Tambin 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.
2.7.5.8.
void MSDDataIn(void)
Esta funcin enva 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 envan son menores que MSD_EP:SIZE y cuando se comprueba la condicin de error bCSWStatus=0x01. En caso de error 0 se llenan y se envan los datos del tamao esperado por el host dCBWDataTransferLength is sent.
73
2.7.5.9.
void IsValidCBW()
Comprueba si el CBW es vlido de acuerdo con las especificaciones de la clase almacenamiento masivo. Se considera un CSW vlido 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 vlido soportado por el dispositivo 3. bCBWCBLength y CBWCB tienen concordancia bInterfaceSubClass
con
2.7.5.11.
void PrepareCSWData()
Esto prepara el dato de estado del CSW copiando el dCSWTag del CBWTage y fijando la firma de vlido CSW=53425355h
2.7.5.12.
void MSDInquiryHandler(void)
Esta funcin 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)
Sense, inicializando la estructura
2.7.5.14.
void MSDReadCapacityHandler()
Esta funcin procesa el dato del registro CSD (leido durante la inicializacin de la tarjeta SD) para encontrar el nmero 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 (nmero 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 envan al host en trozos de 64B (MSD_IN_EP_SIZE) (ver MSDDataIN()). Esto se repite para el nmero 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 cdigo apropiado ASC, ASCQ.
74
2.7.5.16.
void MSDDataOut(void)
con
Efectos secundarios: MSD_BD_OUT.ADR se incrementa MSD_OUT_EP_SIZE (para leer los 64B siguientes en msd_buffer). Esta funcin 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 (nmero 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 funcin 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 cdigo apropiado ASC, ASCQ.
2.7.5.18.
void MSDRequestSenseHandler(void)
Esta funcin 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 funcin prepara para responder al comando Modo Sense. Se implementa una respuesta bsica en esta versin del cdigo 00h y 0x03 es el tamao del dato (en bytes) que sigue.
2.7.5.20.
void MSDMediumRemovalHandler()
Esta funcin prepara la respuesta al comando Prevent Allow Medium Removal. No se espera una respuesta de datos slo se espera un CSW con comando de ejecucin de estado. Como no se puede controlar la retirada del medio, repondemos con un Success CSW.
2.7.5.21.
void MSDTestUnitReadyHandler()
Esta funcin prepara la respuesta al comando Test Unit Ready. No se espera respuesta de datos, slo se enva 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 funcin prepara la respuesta al comando Verify. No se espera respuesta de datos, respondemos con un CSW satisfactorio. El comando no se procesa en esta versin del cdigo.
2.7.5.23.
void MSDStopStartHandler()
Esta funcin 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 versin del cdigo.
75
2.8.
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
2.8.2.
VARIABLES
Longitud total rx Estados definidos en cdc.h Puntero dedicado a la fuente Puntero dedicado al destino Longitud total tx _ROM, _RAM
#pragma udata byte cdc_rx_len; byte cdc_trf_state; POINTER pCDCSrc; POINTER pCDCDst; byte cdc_tx_len; byte cdc_mem_type;
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.
Esta rutina chequea el paquete de datos setup para ver si este sabe como manipularlo.
76
2.9.
2.9.1.1.
CDCInitEP inicializa los Endpoints CDC, buffer descriptores, estados internos mquina y variables. Se tiene que llamar despus de que el host haya enviado una repuesta SET_CONFIGURATION. Ver USBStdSetCfgHandler() en usb9.c para ejemplos.
2.9.1.2.
Precondicin: El valor del argumento de entrada len tiene que ser menor que el tamao mximo del Endpoint responsable de la recepcin 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 tamao especificado por len. Entrada: Buffer: Puntero a donde se guardan los datos recibidos. len: El nmero de bytes esperados. Salida: El nmero de bytes copiados al buffer. Efectos secundarios: Se actualiza la variable de acceso pblico cdc_rx_len con el nmero de bytes copiados al buffer. Para recuperar esta variable llamamos a la macro mCDCGetRxLength(). getsUSBUSART copia un string de bytes recibidos a travs del Endpoint OUT CDC Bulk a una localizacin especificada por el usuario. Es una funcin de no bloqueo. No espera a los datos si no estn disponibles. Devuelve un 0 para notificar que no hay datos disponibles. Nota: Si el nmero actual de bytes recibidos es mayor que el nmero de bytes esperados (len), slo se copian el nmero de bytes esperados. En cambio, si es menor el nmero de los recibidos, se copian todos.
2.9.1.3.
Precondicin: cdc_trf_state tiene que estar en el estado CDC_TX_READY. 255bytes. Entrada: data: Puntero a un string de datos terminado con nulo. Si no se encuentra, se envan 255bytes al host. putsUSBUSART escribe un string de datos al USB incluyendo caracteres nulos. Utilizar esta versin, puts, para transferir datos localizados en la memoria de datos. Nota: El mecanismo de transferencia para dispositivo-a-host (put) es ms flexible que el de host-a-dispositivo (get). Puede manipular un string de datos mayor que el tamao mximo del Endpoint In bulk. Se utiliza un estado mquina para transferir un long string de datos a travs de mltiples transacciones USB. Ver CDCTxService() para ms detalles.
2.9.1.4.
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 envan 255bytes al host. putrsUSBUSART escribe un string de datos al USB incluidos los caracteres nulos. Utilizar esta versin, puts, para transferir datos localizados en la memoria de programa. Nota: El mecanismo de transferencia para dispositivo-a-host (put) es ms flexible que el de host-a-dispositivo (get). Puede manipular un string de datos mayor que el tamao mximo del Endpoint In bulk. Se utiliza un estado mquina para transferir un long string de datos a travs de mltiples transacciones USB. Ver CDCTxService() para ms detalles.
2.9.1.5.
void CDCTxService(void)
CDCTxService une las transacciones dispositivo-a-host. Hay que llamar a esta funcin una vez por cada loop del programa Main.
78
2.10.
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
2.10.2.
VARIABLES
2.10.3.
PROTOTIPOS PRIVADOS
2.10.4.
DECLARACIONES
#pragma code
2.10.5. 2.10.5.1.
Esta rutina chequea el paquete de datos especfico para ver si sabe como manipularlo.
2.10.6. 2.10.6.1.
HIDInitEP inicializa los Endpoints HID, buffer descriptores, estados internos mquina y variables. Se tiene que llamar despus de que el host haya enviado una repuesta SET_CONFIGURATION. Ver USBStdSetCfgHandler() en usb9.c para ejemplos.
79
2.10.6.2.
Precondicin: mHIDTxIsBusy() tiene que devolver falso. El valor de len tiene que ser menor o igual que HID_INT_IN_EP_SIZE. Para un Endpoint interrupcin, el tamao del buffer mximo es de 64bytes. Entrada: buffer: Puntero al comienzo de la localizacin de bytes de datos. len: Nmero de bytes que se van a transferir. Utilizar esta macro para tranferir datos localizados en la memoria de datos. Aplicacin tpica:
if(!mHIDTxIsBusy()) HIDTxReport(buffer, 3);
2.10.6.3.
Precondicin: El valor del arguemento de entrada len tiene que ser menor que el tamao mximo del Endpoint responsable de la recepcin de datos del host USB para la clase HID. El argumento de entrada buffer tiene que apuntar a un rea mayor o igual al tamao especificado por len. Entrada: buffer: Puntero al lugar donde se guardan los datos recibidos. len: Nmero de bytes que se esperan. Salida: Nmero de bytes copiados al buffer. Efectos secundarios: Se actualiza la variable de acceso pblico hid_rpt_rx_len con el nmero de bytes copiados al buffer. Para recuperar esta variable llamamos a la macro mHIDGetRptRxLength(). HIDRxReport copia un string de bytes recibidos a travs del Endpoint OUT HID a una localizacin especificada por el usuario. Es una funcin de no bloqueo. No espera a los datos si no estn disponibles. Devuelve un 0 para notificar que no hay datos disponibles. Nota: Si el nmero actual de bytes recibidos es mayor que el nmero de bytes esperados (len), slo se copian el nmero de bytes esperados. En cambio, si es menor el nmero de los recibidos, se copian todos.
80
2.11.
MAIN.C
Este es el archivo de inicio. En l se incluyen las funciones necesariar para establecer la comunicacin USB y las relativas a la aplicacin del usuario.
2.11.1.
INCLUYE
Requerido Requerido Requerido
Opcional Modificable
2.11.2. 2.11.3.
#pragma udata
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.
#pragma code
Declaraciones
void main(void)
void main(void) { InitializeSystem(); while(1) { USBTasks() ProcessIO(); } end while } end main
81
Documento creado por Slalen para Electronics Strange World InitializeSystem es una rutina centralizada de inicializacin. Todas las rutinas de inicializacin se llaman desde aqu.
static void InitializeSystem(void) { ADCON1 |= 0x0F;
#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(); UserInit(); } end InitializeSystem Ver usbdrv.h inicializacin del usuario
void USBTasks(void)
Precondicin: 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(); } end USBTasks se tiene que utilizar el mtodo obtener Mtodo interrupcin u obtener
82
2.12.
INTERRUPT.C
En este archivo se declaran la parte del programa que se ejecuta durante una interrupcin.
2.12.1.
INCLUYE
2.12.2.
VECTORES DE INTERRUPCIN
#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.
2.12.3.2.
void low_isr(void)
83