mis primeros pasos con el 18f4550

Upload: eledu-divididos

Post on 10-Jul-2015

597 views

Category:

Documents


2 download

TRANSCRIPT

Mis Primeros pasos con el 18F4550 (http://www.unpocodelectronica.netau.net/mis-primeros-pasos-con-el18f4550) Introduccin Etapa Osciladora Conociendo el PiN1 MCLR PORTx vs LATx Mdulo CAD o ADC (I) Mdulo CAD o ADC (II) Primera Prctica: PiCUSB USB CDC (I) USB CDC (II) Monitorear el puerto COM virtual Detectando el HOST (I) Detectando el HOST (II) Primera Aplicacin CDC Conociendo al SnoopyPRO mpusbapi.dll (I) mpusbapi.dll (II) mpusbapi.dll (III) mpusbapi.dll (parte 4) mpusbapi.dll (parte 5) mpusbapi.dll (Primera Aplicacin) Agradecimientos y Mritos Correspondientes

Estudio de mpusbapi.dll (parte I)vamos a estudiar en forma la transmisin USB usando la biblioteca de vnculo dinmico mpusbapi.dll y que mejor que empezar con el ejemplo de J1M. hay que tener una idea de porque Jaime utiliz esas llamadas a los drivers y que hace cada una de ellas. hay muchas preguntas en cuanto a este tipo de transmisin, por ejemplo: podemos transmitir a 12Mbits/seg en lenguaje C? si estamos ejecutando un proceso de muestreo, podremos llegar a esa velocidad? las posibles respuestas a estas, sin nimo de desilusionar a nadie (incluyndome) vean esto (mitos y realidades pgina 9 de 858_USB.pdf):

Mitos y verdades acerca del USB una cosa que hay que tener en consideracin y sobre todo para lo que estudiamos esto en lenguaje de alto nivel, el protocolo de transmisin USB tambin lo llaman la pila USB

reas Implementadas de la pila USB observen que tiene cierto parecido al modelo OSI. en las capas superiores tenemos las funciones bsicas que el usuario puede realizar (comunicacin lgica). esto a su vez va a parar a la segunda capa y luego a la tercera capa(comunicacin fsica) que involucra el aspecto elctrico. En nuestro caso estaramos directamente metidos en la capa superior, pero algunas veces entrando en las otras dos: primera capa(superior): programacin bsica en C. segunda capa(intermedio): llamados a los drivers que trae el compilador de C. tercera capa(inferior): llamados a los drivers que trae el compilador de C (procesos dentro de los drivers) y conexin del mdulo USB al HOST.

esta tema es fascinante pero a la vez extenso, as que hay que ir por partes para no perdernos.

ESTUDIO DEL LADO DEL PIC:por lo pronto lo que hay que hacer, es estudiar los drivers que trae el CCS (que es el compilador de C que uso), estos son: - pic18_usb.h - PicUSB.h - usb.c - usb.h tratando de meter un poco de teora a cada lnea que nos encontremos y siguiendo el mismo mtodo anterior: analizando el cdigo a la inversa. veamos el cdigo reza as: //// PicUSB.c //// //// //// //// Este ejemplo muestra como desarrollar un sencillo dispositivo //// //// USB con el PIC18F2550, aunque puede ser facilmente adaptado //// //// para la serie 18Fxx5x. Se suministra el PicUSB.exe, as como //// //// su cdigo fuente para Visual C# 2005, podris encontrar tb //// //// los drivers para el dispositivo. No se suministra esquema de //// //// conexin puesto que est pensado para ser usado en el GTP USB, //// //// cualquiera de las tres versiones disponibles, si aun no teneis //// //// el programador, podeis utilizar el esquema de ese proyecto. //// //// //// //// Cuando el dispositivo sea conectado al PC, saldr el asistente //// //// para la instalacin del driver. Instala el suministrado junto //// //// a este ejemplo, lo encontrareis dentro de la carpeta Driver. //// //// Una vez instalado podreis usar el PicUSB.exe para encender o //// //// apagar el led bicolor del GTP USB, y para realizar la suma de //// //// dos nmeros introducidos. //// //// //// //// Realizado con el compilador CCS PCWH 3.227 //// //// //// //// Por: Jaime Fernndez-Caro Belmonte [email protected] //// //// //// //// http://www.hobbypic.com //// ///////////////////////////////////////////////////////////////////////// #include //#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL3,CPUDIV1,VRE GEN

#fuses XTPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDI V1,VREGEN,NOPBADEN // el fuse // modificado para USB -> VREGEN #use delay(clock=48000000) ///////////////////////////////////////////////////////////////////////////// // // CCS Library dynamic defines. For dynamic configuration of the CCS Library // for your application several defines need to be made. See the comments // at usb.h for more information // ///////////////////////////////////////////////////////////////////////////// #define USB_HID_DEVICE FALSE //deshabilitamos el uso de las directivas HID #define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on EP1(EndPoint1) for IN bulk/interrupt transfers #define USB_EP1_RX_ENABLE USB_ENABLE_BULK //turn on EP1(EndPoint1) for OUT bulk/interrupt transfers #define USB_EP1_TX_SIZE 1 //size to allocate for the tx endpoint 1 buffer #define USB_EP1_RX_SIZE 3 //size to allocate for the rx endpoint 1 buffer ///////////////////////////////////////////////////////////////////////////// // // If you are using a USB connection sense pin, define it here. If you are // not using connection sense, comment out this line. Without connection // sense you will not know if the device gets disconnected. // (connection sense should look like this: // 100k // VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC) // | // +----/\/\/\/\/\-----GND // 100k // (where VBUS is pin1 of the USB connector) // ///////////////////////////////////////////////////////////////////////////// //#define USB_CON_SENSE_PIN PIN_B2 //CCS 18F4550 development kit has optional conection sense pin ///////////////////////////////////////////////////////////////////////////// // // Include the CCS USB Libraries. See the comments at the top of these // files for more information // ///////////////////////////////////////////////////////////////////////////// #include //Microchip PIC18Fxx5x Hardware layer for CCS's PIC USB driver #include //Configuracin del USB y los descriptores para este dispositivo

#include

//handles usb setup tokens and get descriptor reports

///////////////////////////////////////////////////////////////////////////// // // Al conectar el PicUSB al PC encendemos el Led Rojo hasta que el dispositivo // halla sido configurado por el PC, en ese momento encederemos el Led Verde. // Esperaremos hasta que se reciba un paquete proveniente del PC. Comprobaremos // el primer byte del paquete recibido para comprobar si queremos entrar en el // modo Suma, donde se realizar una suma de dos operandos, que corresponderan // con los dos bytes restantes del paquete recibido; una vez realizada la suma // enviaremos el paquete con el resultado de vuelta al PC. Si entramos en el // modo Led comprobaremos el segundo byte del paquete recibido para comprobar // si deberemos apagar los leds, encender el verder o el rojo. // ///////////////////////////////////////////////////////////////////////////// #define LEDV PIN_B6 #define LEDR PIN_B7 #define LED_ON output_high #define LED_OFF output_low #define modo recibe[0] #define param1 recibe[1] #define param2 recibe[2] #define resultado envia[0] void main(void) { int8 recibe[3]; int8 envia[1]; LED_OFF(LEDV); LED_ON(LEDR); usb_init(); //declaramos variables //encendemos led rojo //inicializamos el USB

usb_task(); //habilita periferico usb e interrupciones usb_wait_for_enumeration(); //esperamos hasta que el PicUSB sea configurado por el host LED_OFF(LEDR); LED_ON(LEDV); while (TRUE) { if(usb_enumerated()) { if (usb_kbhit(1)) { //encendemos led verde

//si el PicUSB est configurado //si el endpoint de salida contiene datos del host

usb_get_packet(1, recibe, 3); //cojemos el paquete de tamao 3bytes del EP1 y almacenamos en recibe if (modo == 0) // Modo_Suma { resultado = param1 + param2; //hacemos la suma usb_put_packet(1, envia, 1, USB_DTS_TOGGLE); //enviamos el paquete de tamao 1byte del EP1 al PC } if (modo == 1) // Modo_Led { if (param1 == 0) {LED_OFF(LEDV); LED_OFF(LEDR);} //apagamos los leds if (param1 == 1) {LED_ON(LEDV); LED_OFF(LEDR);} //encendemos led verde if (param1 == 2) {LED_OFF(LEDV); LED_ON(LEDR);} //encendemos led rojo } } } } } all estn las funciones usb_task(), usb_init() que ya las vimos por encimita, la novedad son las funciones: usb_wait_for_enumeration(), usb_get_packet y usb_put_packet tambin estn las definiciones USB_EP1_TX_ENABLE USB_ENABLE_BULK comencemos por el principio (lgico no? ) -------------------------------------------------------------------------------#define USB_HID_DEVICE FALSE //deshabilitamos el uso de las directivas HID

Qu significa HID?HID es acrnimo en espaol de Dispositivo de Interfaz Humana como bien lo describe Diego en su artculo EL USB DESENCADENADO : HID USB y resulta que en los drivers del CCS viene activado por defecto. si lo vamos a usar, no colocamos nada. si NO lo usaremos, lo negamos en el define (est programado al revs, digo yo ) #define USB_EP1_TX_ENABLE USB_ENABLE_BULK //turn on EP1(EndPoint1) for IN bulk/interrupt transfers que es eso de endpoint? bulk/interrup transfers?

voy a colocar aqu una explicacin que me pareci excelente tomada de un proyecto especial de grado link Capitulo 3: Bus Serie Universal, funcionamiento Pg. 38 cita: ... "Los dispositivos (o mejor dicho, las funcionas) tienen asociados unos canales lgicos unidireccionales (llamados pipes) que conectan al host controlador con una entidad lgica en el dispositivo llamada endpoint. Los datos son enviados en paquetes de largo variable (potencia de 2). Tpicamente estos paquetes son de 64, 128 o ms bytes. Estos endpoints (y sus respectivos pipes) son numerados del 0 al 15 en cada direccin, por lo cual un dispositivo puede tener hasta 32 endpoints (16 de entrada y 16 de salida). La direccin se considera siempre desde el punto de vista del host controlador. As un endpoint de salida ser un canal que transmite datos desde el host controlador al dispositivo. Un endpoint solo puede tener una nica direccin. El endpoint 0 (en ambas direcciones) est reservado para el control del bus." ... Se puede decir que los endpoint son buffer temporales de datos de entrada/salida en cada tipo. En el mdulo USB existen 16 de salida (OUT) y 16 de entrada (IN) pero agrupados en forma bidirecional, de acuerdo a un par de bits de configuracin (ver Pg. 171). Ojo un endpoint es unidireccional. para quien tenga dudas con el pipe, una imagen representativa:

Flujo de Comunicacin del USB respecto a la otra pregunta, existen 4 tipos de transferencias: transferencias de control: usado para comandos (y respuestas) cortos y simples. Es el tipo de transferencia usada por el pipe 0 transferencias iscronas:

proveen un ancho de banda asegurado pero con posibles prdidas de datos. Usado tpicamente para audio y video en tiempo real transferencias interruptivas: para dispositivos que necesitan una respuesta rpida (poca latencia), por ejemplo, mouse y otros dispositivos de interaccin humana. transferencias masivas (BULK): para transferencias grandes y espordicas utilizando todo el ancho de banda disponible, pero sin garantas de velocidad o latencia. Por ejemplo, transferencias de archivos. entonces nosotros debemos definir que tipo de transferencia vamos a realizar. en el ejemplo de Jaime se estn declarando 2 endpoints (1 bidirecionales) como transferencia masiva o BULK. #define USB_EP1_TX_SIZE 1 //size to allocate for the tx endpoint 1 buffer

podemos definir el tamao del buffer en bytes, el lmite lo tendremos que buscar en el driver correspondiente (con FS hasta 64 bytes por transaccin). nota: no confundir FS con HS, con High Speed se llega hasta 480Mbps, el mdulo USB del pic soporta Full Speed = 12Mbps usb_wait_for_enumeration() segn el concepto que dan en el driver, hace lo mismo que usb_enumerated(). La diferencia est en que el primero se queda en un bucle indefinido hasta que el HOST le d la orden de habilitacin. para propsitos donde queramos hacer otras actividades en el PIC, usaremos el segundo. ahora hablaremos de como se hace para transmitir y recibir datos. para eso estn usb_put_packet(,,) y usb_get_packet(,,) ambas necesitan de 3 argumentos. vamos con put_packet: ... /* usb_put_packet(endpoint,*ptr,len,toggle) /* /* Input: endpoint - endpoint to send packet to /* ptr - points to data to send /* len - amount of data to send /* toggle - whether to send data with a DATA0 pid, a DATA1 pid, or toggle from the last DATAx pid. /* /* Output: TRUE if data was sent correctly, FALSE if it was not. The only reason it will /* return FALSE is if because the TX buffer is still full from the last time you /* tried to send a packet. /* /* Summary: Sends one packet out the EP to the host. Notice that there is a difference /* between a packet and a message. If you wanted to send a 512 byte message you /* would accomplish this by sending 8 64-byte packets, followed by a 0 length packet. /* If the last (or only packet) being sent is less than the max packet size defined /* in your descriptor then you do not need to send a 0 length packet to identify /* an end of message.

... el 1 argumento endpoint ya se explic. - el 2 argumento apunta a la direccin del dato a enviar (es una variable declarada por nosotros). - el 3 argumento es el tamao del paquete en bytes. - el 4 argumento habla sobre DATA1, DATA2, toggle. y eso que es? como parte de su protocolo, nos encontraremos entre otras cosas que USB maneja la transmisin de datos por paquetes, llamados TOKEN en la cul el HOST es el iniciador de todas las transferencias que se producen en el BUS [2]

Los paquetes de datos pues bien en la parte de transmisin de datos USB, los paquetes de datos se encuentran en grupos de paquetes de datos, y dentro de estos, existen unos llamados DATA0, DATA1. hay un proceso llamado sincronizacin del data toggle. a grandes rasgos esto no es mas que un mtodo de validacin de paquetes, y lo que hace es enviar alternadamente a DATA0 y DATA1 en una secuencia seguido de su ACK respectivo. todo con el objetivo de mantener la sincronizacin transmisor receptor.

Transacciones Consecutivas

ese tercer argumento definido en el cdigo ejemplo: USB_DTS_TOGGLE enum USB_DTS_BIT {USB_DTS_DATA1=1, USB_DTS_TOGGLE=2, USB_DTS_DATA0=0, USB_DTS_STALL=3, USB_DTS_USERX=4}; segn la pgina 174 de 39632c.pdf el data toggle est definido por un bit llamado DTSEN y es mas, all lo explican.

Bit DTSEN en recepcin de paquetes hay toda una teora en lo relacionado a los grupos de paquetes, no lo mencionar para no salirme del objetivo principal. seguro alguien preguntar, y si yo no quiero usar la sincronizacin del data toggle? esto depende del tipo de transferencia a usar, hay casos donde es recomendable usarlo. ej: transferencias de mltiples transacciones y casos donde no se puede usar. para mayor informacin ver paginas 56 y 232 de usb_20.pdf usb_get_packet() / ********************************************************************** ********* /* usb_get_packet(endpoint, *ptr, max) /* /* Input: endpoint - endpoint to get data from /* ptr - where to save data to local PIC RAM /* max - max amount of data to receive from buffer /* /* Output: the amount of data taken from the buffer. /* /* NOTE - IF THERE IS NO PACKET TO GET YOU WILL GET INVALID RESULTS! /* VERIFY WITH USB_KBHIT() BEFORE YOU CALL USB_GET_PACKET()! /* /* Summary: Gets a packet of data from the USB buffer and puts into local PIC RAM. /* Until you call usb_get_packet() the data will sit in the endpoint /* buffer and the PC will get NAKs when it tries to write more data /* to the endpoint.

... el argumento 1 es el buffer de datos de entrada, donde llega el paquete de datos. el argumento 2 es el apuntador adonde guardaremos ese dato. el argumento 3 es el tamao de paquete en bytes. -vaya- se fue todo en pura teora, entonces en la prxima parte veremos si hacemos el estudio del lado del HOST mediante mpusbapi.dll y como hacerla funcionar por ej: en VB a travs de una Interfaz de Programacin de Aplicaciones API

Estudio de mpusbapi.dll (parte II)para hacer este estudio vamos a ver unos ejemplos de Slalen(programa1) y Ernesto Mozota Navarro(programa2). Este ltimo lo pueden bajar de http://www.hobbypic.com/ ambos sirven para el firmware que escribi Jaime J1M, el programa2 tambin aade otras posibilidades (PWM, CAD) lo primero, probar el cdigo. Claro! jeje y grabar el firmware PICusb en el PIC. Esto ya lo hice varios post atrs, pero no lo expliqu y ahora le toca el turno al Visual Basic usando el programa1. como mencion anteriormente, para usar nuestra aplicacin corriendo en VB, tenemos que hacer uso de unas llamadas a la librera mpusbapi.dll (apis).Public Declare Function MPUSBGetDLLVersion Lib "mpusbapi.dll" () As Long Public Declare Function MPUSBGetDeviceCount Lib "mpusbapi.dll" (ByVal pVID_PID As String) As Long Public Declare Function MPUSBOpen Lib "mpusbapi.dll" (ByVal instance As Long, ByVal pVID_PID As String, ByVal pEP As String, ByVal dwDir As Long, ByVal dwReserved As Long) As Long Public Declare Function MPUSBClose Lib "mpusbapi.dll" (ByVal handle As Long) As Long Public Declare Function MPUSBRead Lib "mpusbapi.dll" (ByVal handle As Long, ByVal pData As Long, ByVal dwLen As Long, ByRef pLength As Long, ByVal dwMilliseconds As Long) As Long Public Declare Function MPUSBWrite Lib "mpusbapi.dll" (ByVal handle As Long, ByVal pData As Long, ByVal dwLen As Long, ByRef pLength As Long, ByVal dwMilliseconds As Long) As Long Public Declare Function MPUSBReadInt Lib "mpusbapi.dll" (ByVal handle As Long, ByVal pData As Long, ByVal dwLen As Long, ByRef pLength As Long, ByVal dwMilliseconds As Long) As Long

aqu aparecen 7 ,yo cont unas 10 en el cdigo fuente. parece que estas 7 son las necesarias para hacer transacciones a la funcin. nota: funcin = dispositivo = mdulo USB del PIC, en adelante me referir a dispositivo para no confundir cuando hable de funciones en C.

la api mas sencilla aqu, parecer ser la de mostrar la versin veamos que dice la traduccin que nos pas Slalen:MPUSBGetDLLVersion(Void) Lee el nivel de revision del MPUSAPi.dll. Es un nivel de revision de 32bits. Esta funcion no devuelve la version del codigo, no realiza nada con el USB.

yo le agregara que devuelve un dato de 32 bits, la versin de la dll en formato MMMMmmmm. vamos agregar un procedimiento para ver que hace:Private Sub Command2_Click() Dim version_dll As Long version_dll = Hex(MPUSBGetDLLVersion) MsgBox Str(version_dll) End Sub

Mostrar la versin de mpusbapi.dll nos arroja 10000, y pienso que como hay 8 dgitos, ya que la versin es en hexa (8 nibbles = 32bits) -> versin dll = 1.0.0.0.0 si quieren mas informacin acerca de estas funciones, visitar estas direcciones: - La mpusbapi.dll desencadenada: PC PIC va USB en Delphi - Traduccin de mpusbapi.doc de lo que si voy hablar es como podemos usar esas apis en VB. veamos: cuando arrancamos esta aplicacin, primero se debe ejecutar el form_loadPrivate Sub Form_Load() OpenMPUSBDevice 'abre comunicaciones End Sub

quin es openMPUSBDevice? R: ste llama a MPUSBOpen:Sub OpenMPUSBDevice() myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) salida myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) entrada End Sub 'como 'como

configura el conducto(pipe) de acceso a cada endpoint, uno de salida y uno de entrada. para outpipe tenemos operacin de escritura -> MP_WRITE=0 y para inpipe -> MP_READ=1. El resultado de esta llamada se guardar en my(In/Out)Pipe si para ambos tenemos como resultado -1 -> entonces quiere decir que no se pudo establecer el enlace lgico con el dispositivo. INVALID_HANDLE_VALUE = -1 si observan el programa2 notaran que hay comprobaciones en casi todas partes, preguntando si hay enlace. para terminar la aplicacin, debemos cerrar el enlace (igual como se hace en RS-232) mediante:Sub CloseMPUSBDevice() MPUSBClose (myOutPipe) MPUSBClose (myInPipe) End Sub

esto es parecido al sistema de mensajeria de windows, donde el resultado de una api, es utilizada por otra (handle) para ejecutar otros procesos. nota: es bueno aadirle el mtodo debug.print a cada api para poder analizar cada lnea ejecutada:Sub OpenMPUSBDevice() myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) Debug.Print "myOutPipe= " & myOutPipe entrada End Sub myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) Debug.Print "myInPipe= " & myInPipe 'como salida 'como

vamos a escribir un cdigo para abrir y cerrar un enlace virtual con el dispositivo. les parece?

Option Explicit Private Declare Function MPUSBOpen Lib "mpusbapi.dll" (ByVal instance As Long, ByVal pVID_PID As String, ByVal pEP As String, ByVal dwDir As Long, ByVal dwReserved As Long) As Long Private Declare Function MPUSBClose Lib "mpusbapi.dll" (ByVal handle As Long) As Long Const INVALID_HANDLE_VALUE = -1 Const MPUS_FAIL = 0 Const MPUSB_SUCCESS = 1 Const vid_pid = "vid_04d8&pid_0011" ' Vendor id (Microchip) y Periferico id Const out_pipe = "\MCHP_EP1" ' endpoint 1 Const in_pipe = "\MCHP_EP1" ' endpoint 1 Const MP_WRITE = 0 Const MP_READ = 1 Public myInPipe As Long Public myOutPipe As Long ' ' para guardar el manejador

Private Sub cmdabrir_Click() ' abrir enlace o pipe myOutPipe = MPUSBOpen(0, vid_pid, out_pipe, 0, 0) 'como salida Debug.Print "myOutPipe= " & myOutPipe ' para monitoreo If myOutPipe = INVALID_HANDLE_VALUE Then ' si es -1 lblpipeout = "Fallo el enlace de salida" Else lblpipeout = "Enlace salida establecido" End If entrada myInPipe = MPUSBOpen(0, vid_pid, in_pipe, 1, 0) Debug.Print "myInPipe= " & myInPipe If myInPipe = INVALID_HANDLE_VALUE Then lblpipein = "Fallo el enlace de entrada" Else lblpipein = "Enlace entrada establecido" End If End Sub Private Sub cmdcerrar_Click() ' cerrar enlace pipe Dim resul_o As Long: Dim resul_i As Long resul_o = MPUSBClose(myOutPipe) Debug.Print "MPUSBClose(myOutPipe)= " & resul_o If resul_o = MPUSB_SUCCESS Then lblpipeout.Caption = "Enlace salida cerrado" Else lblpipeout.Caption = "Error al cerrar el enlace salida, puede que este cerrado" End If resul_i = MPUSBClose(myInPipe) Debug.Print "MPUSBClose(myInPipe)= " & resul_i If resul_i = MPUSB_SUCCESS Then 'como

Else

lblpipein.Caption = "Enlace entrada cerrado"

lblpipein.Caption = "Error al cerrar el enlace entrada, puede que este cerrado" End If End Sub

algunas pantallas de nuestro programilla abriendo y cerrando pipes

Casos de abrir y cerrar PiPES

Casos de abrir y cerrar PiPES

Casos de abrir y cerrar PiPES

Casos de abrir y cerrar PiPES ya tenemos una idea de como se usa la api MPUSBOpen.

Estudio de mpusbapi.dll (parte III)veremos las apis mas importantes de la biblioteca mpusbapi.dll. Me refiero a:

MPUSBRead MPUSBWrite

- como hizo el programa1 para encender un led? R: en el botn verde, tenemos:Private Sub Command1_Click(Index As Integer) Send_Buf(0) = 1 'Para que reconozca que se encienden o apagan Leds Send_Buf(1) = Index Send Send_Buf, 2 End Sub

aj ya empezaron las dudas, vamos a ver quien es Send_Buf:Dim Send_Buf(0 To 2) As Byte ... ' Funcin enviar Function Send(ByRef SendData() As Byte, bytes As Integer) As Long Dim SentDataLength As Long Call MPUSBWrite(myOutPipe, VarPtr(SendData(0)), bytes, VarPtr(bytes), 1000) 'VarPtr()= puntero a la variable End Function

es lgico pensar que como se trabaja con bytes, entonces para varios datos es necesario crear arrays de bytes. y eso es precisamente lo que hace Send_Buf() aqu hay una sentencia curiosa VarPtr(), yo nunca la haba visto, adems no pertenece al VB en s, leyendo por aqu, por ac, consegu:Declare Function VarPtrAny Lib "vb40032.dll" Alias "VarPtr" (lpObject As Any) As Long

'The VarPtr-function retrieves the memory handle of an object. ' lpObject ' Handle that identifies the object

-ahh- conque viene del runtime! hurgando en la biblioteca MSDN, aparecen tres mtodos NO documentados sobre usar direccionamiento en VB, VarPtr, ObjPtr y StrPtr esto si es un descubrimiento para mi, el uso de punteros en basic (bajo ciertas condiciones). volviendo a la api MPUSBWrite, el segundo argumento: pData -> salida: puntero al buffer que contiene los datos que se van a escribir para explicar un momento el uso del puntero en este caso, este argumento lo que necesita es la direccin donde est alojado el dato que queremos enviar el problema que tiene visual basic es que no podemos usar punteros, pero con el mtodo varptr podemos tomar dicha direccin, y esto no es lo mejor de todo, lase bien. Lo mejor es que gracias a que en un array de bytes las direcciones de esos datos son contiguos, entonces con solo tener la direccin del primer byte de datos es lo necesario que debe tener la api para hacer el recorrido en memoria. para demostrar esto que estoy diciendo, voy a escribir un cdigo donde: - guardar un dato (byte) en 2 variables - tomar la direccin de esas 2 variables mediante varptr - luego llamando una api CopyMemory, recuperar el valor que hay en esas direcciones que vienen siendo el mismo dato.' mediante el uso de Varptr y CopyMemory ' Varptr(dato): devuelve la direccion (Long) donde se almacena la variable dato ' con CopyMemory podemos recuperar el dato en memoria a partir de su direccion ' por: Pedro - PalitroqueZ. Option Explicit Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Long, ByVal ByteLen As Long) Dim d(0 To 1) As Byte, dato(0 To 1) As Byte, r1 As Long, r2 As Long Private Sub Command1_Click() d(0) = 25 ' un valor cualquiera Debug.Print "d(0)= " & d(0) d(1) = 97 ' un valor cualquiera Debug.Print "d(1)= " & d(1) r1 = VarPtr(d(0)) ' en r1 se guarda la direccion donde esta almacenado d(0) Debug.Print "r1= " & r1 23-feb-2007 10:19AM

r2 = VarPtr(d(1)) Debug.Print "r2= " & r2 ' ahora se procede a recuperar el dato, usando CopyMemory CopyMemory ByVal VarPtr(dato(0)), ByVal r1, 2 ' debe usarse byval OBLIGATORIO para que se pueda copiar el dato en vez de la direccion ' el ultimo argumento corresponde a la longitud del dato en bytes ' si se coloca 2, es para que tome la direccion del dato contiguo ' es decir, dato(1). ' como dato(0), dato(1) -> se almacenan en direcciones contiguas ' entonces CopyMemory almacenara el par de bytes de datos, en dato(0) ' y dato(1) mediante sus direcciones respectivas Debug.Print "dato(0)= " & dato(0) Debug.Print "dato(1)= " & dato(1) MsgBox "se recuper d(0)=" & Str(dato(0)) & " y d(1)=" & Str(dato(1)) Unload Me End Sub

una imagen del debugger:

Usando punteros en Visual Basic 6 as pues, donde veamos el varptr ya sabemos a que se est refiriendo, adems el argumento de la api tambin lo delata con la letra p ej: pData, pLenght

esto es la parte complicada de entender el uso de la api, para MPUSBRead es similar y al revs, el segundo argumento es el puntero de una variable previamente declarada por nosotros para que se alojen los datos que vayan llegando del USB. como vern esta es otra aplicacin del concepto del puntero, por un lado tenemos la casilla(direccin de almacenamiento) y por el otro tenemos el valor del dato almacenado. el resto de los argumentos es fcil de entender, como la longitud del dato (en bytes). esto depende de como configuremos el envo desde el dispositivo el tiempo en milisegundos: es para que la api no se quede en un bucle infinito si llegara a ocurrir un problema y por supuesto el pipe, o mejor dicho el handle del pipe, que se puede decir que es un puntero representado en VB como un long (ver fuentes consultadas) bueno volviendo al uso de la funcin SendLeds Send_Buf(0) = 1 Send_Buf(1) = Index Send Send_Buf, 2 'Para que reconozca que se encienden o apagan

esto interpretado desde el punto de vista del micro, es un paquete de datos, donde hay 2 bytes. en el primer byte se guarda el modo (modo_led) y el en otro byte se guarda el paraml que es la accin para ambos leds (apagado, on, off -> led rojo y verde) luego el array de bytes se enva a la funcin sendFunction Send(ByRef SendData() As Byte, bytes As Integer) As Long Dim SentDataLength As Long Call MPUSBWrite(myOutPipe, VarPtr(SendData(0)), bytes, VarPtr(bytes), 1000) 'VarPtr()= puntero a la variable End Function

observen el VarPtr(SendData(0)), es lo mismo que habl hace rato, se toma la direccin del primer byte es lo nico que necesita pData para tomar el resto del array de datos el que falta, la suma:Dim a As Byte 'buffer de datos intermedio

Send_Buf(0) = 0 'Para que reconozca que es una suma a = CByte(sumando(0).Text) 'convierte el texto a byte Send_Buf(2) = a Send_Buf(0) = 0 a = CByte(sumando(1).Text) Send_Buf(1) = a Send_Buf(0) = 0 Send Send_Buf, 3 'enva los sumandos recibir (a) 'recibe el resultado resultado.Caption = CStr(rec) 'convierte el dato a string

el Send ya lo hablamos, falta la funcin recibir:Dim SentDataLength As Long Call MPUSBRead(myInPipe, VarPtr(s), 1, 1, 1000) rec = s 'guardo el dato recibido en una variable intermedia

aqu sucede lo contrario, es decir, la api MPUSBRead necesita la direccin del byte s para almacenar el dato que viene del PIC (que en este caso es 1 byte de longitud). esto fue el anlisis realizado al programa1 y programa2. vamos a usar el estupendo SnoopyPro para ver los bferes del USB jijiji abrimos y ejecutamos las siguientes acciones en secuencia: 1.- led rojo = ON 2.- led verde = ON 3.- apaga leds 4.- 1 + 0 = 1 5.- 1 + 7 = 8 6.- 12 + 7 = 19

Capturas con SnoopyPro a ver que tenemos all:

Transaccin Recibida tenemos un paquete de 2 bytes, en el primer el modo = 1 (modo led). y en el segundo paraml = 2 (led rojo ON)

Transaccin Recibida tenemos un paquete de 2 bytes, en el primer el modo = 1 (modo led). y en el segundo paraml = 1 (led verde ON)

Transaccin Recibida tenemos un paquete de 2 bytes, en el primer el modo = 1 (modo led). y en el segundo paraml = 0 (led rojo y verde off)

Transaccin Recibida tenemos un paquete de 3 bytes, en el primer el modo = 0 (modo suma). y en el segundo y tercer byte tenemos 0 y 1 que son los operandos de la suma. ojo vean que esto es un paquete down , que transmite HOST -> PIC. un poco mas abajo:

Contenido paquete tenemos un paquete de PIC -> HOST de 1 byte y que trae? nada mas y nada menos que el resultado de la suma. el par de sumas que faltan:

analizando paquetes

analizando paquetes observaciones: - despus de haber visto varias veces el cdigo de Jaime hasta ahora es que me doy cuenta que el led verde es RB6 y led rojo RB7 yo lo tena invertido. pero lo extrao de todo es que con el programa PicUSBDelphi.exe de Diego se ejecuta OK con los leds invertido. ?? - faltara implementar un algoritmo de validacin, porque si ocurre un problema, hay que resetear tanto al programa como al pic para normalizar. - tengo que instalar el driver wdmstub.sys cada vez que conecto el cable USB en un puerto distinto, no se supone que esos conectores son compartidos? esto tambin sucede con la clase CDC.

Estudio de mpusbapi.dll (parte IV)quisiera hacer unas observaciones, varios mensaje atrs hablando sobre la api MPUSBGetDLLVersion() escrib: cita:nos arroja 10000, y pienso que como hay 8 dgitos, ya que la versin es en hexa (8 nibbles = 32bits) -> versin dll = 1.0.0.0.0

bueno, ahora no estoy tan seguro que eso sea cierto (despus de todo es una suposicin), ahora me baso en lo siguiente: - que dicha api, devuelve un puntero que contiene la versin de la librera mpusbapi.dll - si esto es cierto, entonces la versin correcta es 0.0.1.0 aqu est un adjunto con un programa en visual basic que hace lo que digo. est planteado as al momento de escribir esto, pudindose cambiar por la versin correcta posteriormente (dado el caso).

voy a tomar el ejemplo del CDC explicado con anterioridad y lo voy a modificar para usarlo con la librera mpusbapi.dll - lo primero, hacer la deteccin del lado del dispositivo - lo segundo hacer la deteccin del lado del Host Deteccin del lado del dispositivo: es de la misma forma que para la clase CDC estudiada, mediante el USB_CON_SENSE_PIN el cdigo con la modificacin:/* ejemplo7_parte4.c se pretende hacer la deteccion de conexion al puerto USB, mediante la mpusbapi.dll mostrando en una pantalla LCD 2x16 el estado. Este codigo es un hibrido del cual se tomo partes de: - PicUSB.c de J1M - RRCdcUSB de RedPic - probando_USB.c del ejemplo6_parte5 de PalitroqueZ Pedro - PalitroqueZ 07-Mar-2007. Hora: 3:54 PM */

#include #fuses XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,N OPBADEN #use delay(clock=48000000) #define use_portb_lcd TRUE #define USB_HID_DEVICE FALSE las directivas HID #define USB_EP1_TX_ENABLE USB_ENABLE_BULK for IN bulk/interrupt transfers #define USB_EP1_RX_ENABLE USB_ENABLE_BULK for OUT bulk/interrupt transfers #define USB_EP1_TX_SIZE 1 tx endpoint 1 buffer #define USB_EP1_RX_SIZE 1 rx endpoint 1 buffer #define USB_CON_SENSE_PIN PIN_E3 #include CCS's PIC USB driver #include "PicUSB.h" para este dispositivo #include reports #include //Microchip PIC18Fxx5x Hardware layer for //Configuracin del USB y los descriptores //handles usb setup tokens and get descriptor //deshabilitamos el uso de //turn on EP1(EndPoint1) //turn on EP1(EndPoint1) //size to allocate for the //size to allocate for the

void mostrar_estado_usb(); void main(){ int envia[1]; int recibe[1]; envia[0]='a'; usb_init_cs(); // inicializa el USB y lo desactiva lcd_init(); // llamadas necesarias para iniciar la LCD while(true){ usb_task(); //habilita periferico usb e interrupciones mostrar_estado_usb(); if(usb_enumerated()){ // primer if if(usb_kbhit(1)){ // segundo if //si el endpoint de salida contiene datos del host usb_get_packet(1, recibe, 1); //cojemos el paquete de tamao 1bytes del EP1 y almacenamos en recibe if(recibe[0]=='a'){ // tercer if usb_put_packet(1, envia, 1, USB_DTS_TOGGLE); //enviamos el paquete de tamao 1byte del EP1 al PC lcd_gotoxy(1,1); lcd_putc("llego una a "); delay_ms(500); } // fin del tercer if } // fin del segundo if } // fin del primer if lcd_gotoxy(1,1); lcd_putc("otros procesos"); delay_ms(500); } // fin del ciclo while }

/************************************************ // esta llamada imprime en la LCD los estados de conectado // y desconectado del USB dependiendo de la bandera // estado_usb //***********************************************/ void mostrar_estado_usb(){ lcd_gotoxy(10,2); if(usb_attached()){ lcd_putc(" USB:On"); }else{ lcd_putc("USB:Off"); } // delay_ms(500); }

voy a hacer unas observaciones sobre este programa, porque pas un buen rato tratando de que funcionara. - en usb_kbhit(1), el 1 es el endpoint de datos (el argumento es requerido). - sustitu a usb_init por usb_init_cs porque? R: aqu entra el simulador paso a paso del MPLAB. la funcin:void usb_init(void) { usb_init_cs(); do { usb_task(); } while (usb_state != USB_STATE_POWERED); }

se queda en un bucle eterno a menos que el dispositivo sea conectado, pero mi interes es hacer que el pic haga otras actividades independientemente si est presente no, el HOST. usb_init_cs() -> inicializa el mdulo USB y lo desactiva, est bien as que se desactive por defecto (menos consumo para el circuito). para encender el modulo est usb_task() dentro del bucle eterno del while(true), en cada instante l preguntar por el USB_CON_SENSE_PIN y dependiendo del Vusb en este pin, l activar/desactivar. ven lo importante que es el USB_CON_SENSE_PIN, basicamente es una deteccin por hardware, se est sensando si llega voltaje del HOST (Vusb). - elimin la bandera estado_usb, porque es igual que preguntar por usb_attached(), me ahorro 1 bit de memoria (que mezquino jaja). Adems que no hay que modificar el driver original pic18_usb.h - el resto del cdigo queda igual, solo ajustar los paquetes de datos a 1 byte, usando un eco. el HOST le enva un carcter (a) y el dispositivo se lo devuelve.

Estudio de mpusbapi.dll (parte V)empezaremos hacer modificaciones al ejemplo de Slalen:' ' ' ' ' ' este programa envia un caracter y recibe un eco del dispositivo para confirmacion. adaptacion del programa original de Slalen Pedro-PalitroqueZ 07-Mar-2007 Hora: 7:51 PM

Option Explicit Dim Send_Buf(0) As Byte Const verde = &HFF00& Const rojo = &HFF& Private Sub cmdversiondll_Click() Dim version_dll As Long, digitos(4) As Byte, cad As String, t As Integer version_dll = VarPtr(MPUSBGetDLLVersion) 'toma el puntero de la version For t = 0 To 3 digitos(t) = 0 ' limpiar variables Next t CopyMemory ByVal VarPtr(digitos(0)), ByVal version_dll, 5 ' recupera de la memoria los digitos de la version y lo copia en digitos() cad = "" For t = 0 To 3 ' concatena los digitos en una cadena cad = cad & Str(digitos(t)) & "." Next t lblversiondll.ForeColor = &HFFFF& lblversiondll.Caption = Left$(cad, Len(cad) - 1) ' muestra la version End Sub Private Sub Command2_Click() Dim eco As Byte, dato As Long Timer1.Enabled = False Send_Buf(0) = Asc("a") 'envia la "a" OpenMPUSBDevice 'abre comunicaciones Send Send_Buf, 1 dato = recibir(eco) If eco = 97 Then lblrespuesta.Caption = "El dispositivo respondio Exitosamente" Else lblrespuesta.Caption = "No hubo respuesta del Dispositivo" End If CloseMPUSBDevice 'cierra comunicaciones Timer1.Enabled = True End Sub Private Sub Form_Load() Timer1.Interval = 50 Timer1.Enabled = True End Sub Private Sub Form_Unload(Cancel As Integer) CloseMPUSBDevice 'cierra comunicaciones

End Sub Private Sub Timer1_Timer() OpenMPUSBDevice 'abre comunicaciones If (myOutPipe INVALID_HANDLE_VALUE) And (myInPipe INVALID_HANDLE_VALUE) Then shpestado.FillColor = verde Else shpestado.FillColor = rojo End If CloseMPUSBDevice 'cierra comunicaciones End Sub

como ven lo adapt para transferencias de paquetes de datos de 1 byte, y como siempre mi empeo en agregarle un sensor de estado del dispositivo, muy similar que con la clase CDC: un timer abriendo y cerrando el pipe cada 50 mS y preguntando si hubo enlace. cabe decir que el cdigo del PIC es el mismo del ejemplo anterior y funciona igual. en los ensayos en el protoboard - reconexin de la extensin USB. - abriendo y cerrando el programa en VB - incluso se desconect/conect la alimentacin al PIC y los resultados fueron satisfactorios.

Estudio de mpusbapi.dll (Aplicacin)se acuerdan del ejemplo donde usamos el CAD y hacamos transferencias y otras actividades? bien vamos a tomar ese ejemplo, pero con la biblioteca mpusbapi.dll y con los conocimientos aprendidos en el tema Estudio de Grficos en VB vamos a visualizar los datos obtenidos. los paquetes de datos se mantienen en 1 byte, hice pruebas con 64 bytes, y los resultados fueron casi los mismos. el cdigo del dispositivo:/* ejemplo8_parte1.c adaptacin del ejemplo6parte6. transmision del resultado del CAD al PC al puerto USB, mediante la mpusbapi.dll mostrando en una pantalla LCD 2x16 el resultado del CAD y el estado USB. Este cdigo es un hbrido del cul se tom partes de: - PicUSB.c de J1M - RRCdcUSB de RedPic - probando_USB.c del ejemplo6_parte5 de PalitroqueZ Pedro - PalitroqueZ 08-Mar-2007. Hora: 9:01 AM

*/ #include #DEVICE ADC=8 // cad a 8 bits #fuses XTPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,N OPBADEN #use delay(clock=48000000) #define use_portb_lcd TRUE #define USB_HID_DEVICE FALSE las directivas HID #define USB_EP1_TX_ENABLE USB_ENABLE_BULK for IN bulk/interrupt transfers #define USB_EP1_RX_ENABLE USB_ENABLE_BULK for OUT bulk/interrupt transfers #define USB_EP1_TX_SIZE 1 tx endpoint 1 buffer #define USB_EP1_RX_SIZE 1 rx endpoint 1 buffer #define USB_CON_SENSE_PIN PIN_E3 #define DERECHA 0 #include CCS's PIC USB driver #include "PicUSB.h" para este dispositivo #include reports #include //Microchip PIC18Fxx5x Hardware layer for //Configuracin del USB y los descriptores //handles usb setup tokens and get descriptor //deshabilitamos el uso de //turn on EP1(EndPoint1) //turn on EP1(EndPoint1) //size to allocate for the //size to allocate for the

void mostrar_estado_usb(); void config_adcon2(short justificacion); int value;

void main(){ int i; int envia[1]; int recibe[1]; set_tris_a(0x1); // Ra[0]=entradas, los demas=salida

usb_init_cs(); // inicializa el USB y lo desactiva lcd_init(); // llamadas necesarias para iniciar la LCD setup_adc_ports( AN0 || VSS_VDD ); // canal AN0, Vref+ = Vdd, Vref= Vss config_adcon2(DERECHA); // justificacin derecha, Tacq= 2Tad while(true){ usb_task(); //habilita periferico usb e interrupciones mostrar_estado_usb(); envia[0]= read_adc(); for(i=0;i 1 Then dato(Int((cx / n) + 2)) = Int(cy - valor * (cy / maximo)) Else dato(Int((cx / n)) + 1) = Int(cy - valor * (cy / maximo)) End If For i = 0 To cx ' pregunta si i no ha llegado a cx Picture1.Line (x, dato(i))-(j, dato(i + 1)), vbBlack x = j j = j + n ' para lograr el ajuste time-division dato(i) = dato(i + 1) ' rellenar el dato(n) : 0 < n < cx Next i Label1.Caption = "CAD= " & Round(valor * (5 / maximo), 3) & " volts -> 0x" & Hex(valor) End Sub Function ajustar_tiempo(time_division As Integer) If time_division > 1 Then Timer1.Interval = 3 * time_division Timer2.Interval = 3 * time_division Else Timer1.Interval = 1 Timer2.Interval = 1 End If End Function Private Sub Timer3_Timer() Send_Buf(0) = Asc("a") OpenMPUSBDevice 'abre el pipe (si se puede)

If (myOutPipe INVALID_HANDLE_VALUE) And (myInPipe INVALID_HANDLE_VALUE) Then shpestado.FillColor = verde Else shpestado.FillColor = rojo End If Send Send_Buf, 1 recibir (te) If rec = 0 Then valor = 1 ' para ajustar el grfico Else

valor = rec End If CloseMPUSBDevice 'cierra comunicaciones

End Sub Private Sub cmdayuda_Click() Dim mensaje As String mensaje = "Este programa recoge los datos enviado desde un" & vbCrLf mensaje = mensaje & "dispositivo (PIC18F4550) y grafica la seal correspondiente" & vbCrLf mensaje = mensaje & "al resultado de una conversion analogica-digital" & vbCrLf mensaje = mensaje & "a 8 bits de resolucin" MsgBox mensaje, vbInformation, "Informacion" End Sub

el Timer3_Timer() es primordial, porque cumple triple propsito: enva el dato de confirmacin (el ECO). recibe el dato del dispositivo. sensa el estado de conexin del dispositivo, ya que ante cada ejecucin y transferencia abre y cierra el pipe.

en base a mis experiencias, debo decir que trabajar con mpusbapi.dll como que es la mejor opcin, mucho mas rpido y prctico (conociendo la programacin). pero para no subestimar a la clase CDC, entonces: - de acuerdo a la situacin dada, se debe escoger que es conveniente: CDC mpusbapi.dll - eso depender del programador que tendr que decidir cul es mejor.