Empezando con el USB modo CDC
1. Introducción:
El modo de funcionamiento CDC (Communication Devices Class) emula un puerto serie a través del USB.
Es decir, en administrador de dispositivos del PC, detectará nuestro microcontrolador como un puerto COMx virtual.
La forma de funcionar está definica en el AN1164.
2. Empezando:
Lo primero que haremos será abrir el ejemplo (USB Device - DCD -Basic) del directorio MLA para ver qué ficheros son necesarios:

2.1.Ficheros importantes:
En el datasheet AN1164, nos describen las funcionalidades de cada fichero:

Ficheros:
- "app_device_cdc_basic.h" y "app_device_cdc_basic.c": contienen las funciones para inicializar la comunicación y el "task" al que debemos llamar periódicamente para mantener funcionando el stack.
- "app_led_usb_status.h" y "app_led_usb_status.c": gestiona el led que indica el estado del usb. Si la conexión usb no se ha realizado, el led parpadea lento; una vez realizada, pasa a parpadear más rápido.
- usb_descriptors.c: definen las variables necesarias para la comunicación USB.
- usb_config.h: define el modo de funcionamiento de la conexión USB.
- system.h y system.c: configuración de los fuses.
- fixed_address_memory.h: definición de las direcciones de memoria para los buffers IN y Out.
- Ficheros ubicados en la carpeta "bsp": habilita los led y pulsadores de nuestra placa.
2.2.Funciones importantes:
Lo primero que se hace es inicializar el puerto USB; para esto se llama a la función "USBInitialize()", esta función habilita el USB.
La función "USBTask()" gestiona los estados del USB y maneja los eventos. Esta función debe llamarse periódicamente para mantener el USB funcionando.
La declaración de las estructuras descriptoras está en el fichero "usb_ch9.h", y se definen sus valores en el fichero "usb_descriptors.c":




2.3.USB Stack options:
La configuración se define en el fichero "usb_config.h":
- USB_DEV_HIGHEST_EP_NUMBER: Esta opción afecta a la memoria reservada. Indica el número de endpoints usados.
- USB_DEV_EP0_MAX_PACKET_SIZE: Define la memoria reservada para el endpoint 0.
- CDC_CONFIG_NUM: Define el número de configuración para la función CDC.
- CDC_COMM_INTF_ID: Define el número de la interface de la clase comunicación.
- CDC_INT_EP_NUM: Define el número de la interrupción para el endpoint.
- CDC_INT_EP_SIZE: Define el buffer de la interrupción para el endpoint.
- CDC_DATA_INTF_ID: Identifica la interface para transmitir los datos.
- CDC_BULK_EP_NUM: Define el número de endpoint para transmisión bulk.
- CDC_BULK_OUT_EP_SIZE: Define el tamaño del buffer bulk para el endpoint de recepción.
- CDC_BULK_IN_EP_SOZE: Define el tamaño del buffer bulk para el endpoint de transmisión.
Líneas de configuración que el CDC Serial pasa al host:
- CDC_DEFAULT_BPS: Bits por segundo
- CDC_DEFAULT_FORMAT: Stop bits
- CDC_DEFAULT_PARITY: Parity
- CDC_DEFAULT_NUM_BITS: Bits por palabra
2.4.Ejemplo funciones recibir y enviar:

- USBUSARTRxIsReady(): Comprueba si el puerto está ocupado recibiendo datos.
- USBUSARTRx(gBuffer, BUFFER_SIZE): Guarda lo recibido en el buffer "gBuffer".
- USBUSARTRxGetLength() > 0: Comprueba si se ha guardado algo en el buffer. Así es como identifica que hemos recibido algo.
- USBUSARTTxIsReady(): Comprueba si estamos preparados para transmitir. Si se está enviando datos y no ha terminado, nos dará como puerto ocupado y debemos esperar.
- USBUSARTTx(gBuffer, gSize): Escribe en el buffer de salida.

- USBUSARTGets(): Recibe cadena de texto del puerto.
- USBUSARTPuts(): Envía cadena de texto.
3. Creando un proyecto nuevo para modificar:
Empezamos abriendo el ejemplo:
File -> Open Project y buscamos en el directorio de instalación de las MLA lo siguiente: \Mla\v2016_11_07\apps\usb\device\cdc_basic\firmware\picdem_fs_usb.x

Lo establecemos como proyecto principal y vemos que compila sin problemas.
3.1. Copiando el proyecto:
Con el botón derecho sobre el proyecto, seleccionamos la opción "Copy". Así podremos tener una copia en nuestro directorio de pruebas para modificar.

Lo establecemos como proyecto principal y al intentar compilar falla. Este fallo se debe a que está buscando una serie de ficheros que no encuentra.

- Como vemos en la imagen anterior, busca ficheros en los siguientes directorios de la MLA:
- /demo_src
- /framework/usb/inc
- /bsp/picdem_fs_usb
- .
- El siguiente paso será copiar estos directorios al directorio de nuestro proyecto y apuntamos:
- C:\Program Files (x86)\Microchip\Mla\v2016_11_07\bsp\picdem_fs_usb y renombramos a bsp
- C:\Program Files (x86)\Microchip\Mla\v2016_11_07\framework\usb dejando nombrado como usb
- C:\Program Files (x86)\Microchip\Mla\v2016_11_07\apps\usb\device\cdc_basic\firmware\demo_src renombrado a src
Quedando así el directorio de nuestro proyecto:

Hay ficheros que se mantienen apuntando a los directorios anteriores. Esto lo sabemos porque al posicionar el puntero sobre ellos, nos sale un mensaje indicando el "Storage path".

Con el secundario escogemos "Remove from project" y añadimos los que tenemos en nuestro directorio usando la opción del botón secundario "Add Existing Items From Folder"
También debemos añadir las rutas en XC8Compiler:

Ahora podemos compilar sin errores.
Con esto conseguimos que copiando el directorio del proyecto, podamos compilarlo sin tener instaladas las MLA.
4. Adaptando a nuestra placa:
Para adaptar el proyecto a nuestra placa debemos realizar los siguientes cambios:
En el directorio bsp, añadimos los ficheros que habíamos creado en proyectos anteriores:

Reemplazando buttons.c, buttons.h, led.c y led.h en el proyecto. Las funciones son las mismas por lo tanto no hay problema.
Al compilar nos saldrá error porque los nombres de los ficheros no coinciden. Debemos corregirlo:

También debemos configurar los fuses; para esto modificamos el fichero "system.c" dejándolo de la siguiente forma:

El último paso es reservar la memoria para el bootloader:

Compilamos y cargamos.
Cuando conectemos nuesta placa al pc por USB, será reconocida como un nuevo puerto COM en Administrador de Dispositivos:

- Si no están instalados los drivers, los pedirá (C:\Program Files (x86)\Microchip\Mla\v2016_11_07\apps\usb\device\cdc_basic\utilities\inf):
- mchpcdc.cat
- mchpcdc.inf
Usando un terminal como puede ser "Hercules", nos conectamos. Los parámetros de la conexión están definidos en el fichero App_device_cdc_basic.c:


5. Ejemplos:
Presentaremos dos ejercicios de prueba.
5.1. Pulsadores y led:
En este ejemplo, monitorizaremos todos los botones y controlaremos los led a través de comandos.
Se pulsa un botón y no se envía mensaje hasta que se suelta.
Para hacer toggle de los led debemos enviar: "led8", "led7", "led6" o "led5"
La primera modificación es en el fichero "system.c" para habilitar cuatro led más (8, 7, 6 y 5) y los 3 pulsadores restantes:

Ahora modificaremos el fichero app_device_cdc_basic.c:



- Pic18f4550 usb CDC monitorizar pulsadores y control de led:
5.2. Lcd por USB
Modificaremos el ejemplo del lcd por uart para que funcione a través del usb.
Lo primero es añadir las librerías necesarias:

Ahora las incluiremos. Estas librerías llamaban a "config.h" que es dónde estaba configurado el "#define _XTAL_FREQ 48000000".
Como ahora estamos realizando la configuración desde el "system.h", lo cambiamos en "lcd.h".

Deshabilitamos los led usados con la función toggle ya que serán usador por el lcd en el fichero "system.c":

Estado final del fichero "app_device_cdc_basic.c":



Envío desde la aplicación "Hércules":

Resultado:

- Pic18f4550 usb CDC escribir en LCD:
6. Conclusiones:
Comentarios a destacar.
6.1. Limitación del Buffer:
El buffer de recepción es limitado a 64 bytes; por lo tanto si enviamos cadenas mayores no serán escritas completas.
El display tiene capacidad para 80 caracteres repartidos en 4 líneas.
El tamaño del buffer se define en el fichero "usb_config.h":

Los posibles tamaños son: 8, 16, 34 y 64:

La solución sería desarrollar un protocolo para dividir la información en paquetes de 64 bytes.
6.2. Pid, Vid:
Estos valores se usan para identificar los dispositivos USB en el mercado. En caso de realizar una comunicación emulando un puerto COM, es más sencillo usar integrados como el FTDI232 y así no tener que adquirir las licencias.
La comunicación con este integrado se hace a través del puerto UART.
7. Descargas:
- Ejemplo control led y pulsadores desde termminal serie.
- Ejemplo control display lcd desde terminal serie.