Dominando la Placa PSoC 6 Pioneer con Shield IoT Add-On: Guía para Desarrolladores
Introducción
El PSoC 6 es la última incorporación a la poderosa serie PSoC de procesadores de Cypress. El Shield IoT Add-On Pioneer es la herramienta de desarrollo asociada a esta línea de procesadores, que incluye un depurador integrado, headers compatibles con Arduino, widgets CapSense y más, todo vinculado a un procesador PSoC 6. El procesador es un dispositivo de doble núcleo, con un Cortex-M0+ de bajo consumo y un Cortex-M4 de alto rendimiento unidos mediante periféricos compartidos y espacio de memoria.
Este tutorial te muestra cómo empezar con la Pioneer Board, usando el Pioneer Add-on Shield para expandir las capacidades del dispositivo PSoC 6. Te mostraremos cómo comunicarte con una Raspberry Pi mediante BLE y WiFi (usando un módulo XBee WiFi), así como cómo comunicar una PSoC 4 BLE Pioneer Board con la PSoC 6 Pioneer Board vía BLE.
Materiales Requeridos
Los ejemplos de este tutorial están diseñados para usar con el PSoC 6 Pioneer Kit, que puede comprarse directamente de Cypress o Digi-Key.
Obviamente, también necesitarás un Pioneer Add-on Shield. También necesitarás un Módulo XBee WiFi. Hay algunas opciones de XBee WiFi según tu configuración: Trace, Conector RP-SMA con antena externa 2,4GHz, o Wire. Lo más fácil sería conseguir XBee con antena de alambre.
También necesitarás el Kit de Inicio Raspberry Pi 3. Este será tu objetivo de comunicación desde la PSoC6 Pioneer Board. Por supuesto, puedes comprar la Pi 3 por separado junto con una protoboard, cables jumper, resistencias y LEDs, pero creemos que el kit de inicio es una oferta excepcional y bien vale la pena conseguirlo.
Visión General del Hardware
Repasemos en detalle las características del Pioneer Kit IoT Add-on Board.
- Ranura para Tarjeta MicroSD —Los pines de esta ranura se mapean al periférico SPI en la mayoría de placas compatibles con Arduino, incluida la PSoC 6 BLE Pioneer Board.
- Header XBee —Este header está espaciado para aceptar la huella estándar XBee. Es compatible con todos los módulos XBee oficiales.
- Conector Qwiic —Este conector añade soporte para todos los módulos Qwiic de SparkFun. Suministra 3,3V.
- Conector de Alimentación MicroB USB —Las líneas de datos en este conector no están conectadas a nada. Proporciona 5V al regulador de 3,3V para el módulo XBee, anulando los 5V que vienen del header Arduino y permitiendo que módulos XBee de alta potencia (celulares, wifi, o modelos Pro) funcionen correctamente.
- Botones D7 y D9 —Dos botones de usuario vinculados a pines D7 y D9 (P0.2 y P13.1 en el PSoC 6, o P1.0 y P0.4 en PSoC 4 BLE).
- Regulador 3,3V —Regulador de modo conmutado de 3,3V capaz de suministrar hasta 1,5A, dependiendo de la capacidad de la fuente aguas arriba. Toma energía de la alimentación 5V en pines Arduino o conector de alimentación MicroB. Suministra energía solo al header XBee.
- Buffer de Cambio de Nivel —Convierte señales de 5V a 3,3V. Permite usar la placa en sistemas de 3,3V o 5V.
- Circuito de Cambio de Nivel I2C —Convierte señales I2C de 3,3V a 5V, si es necesario.
- Jumper de Selección de Voltaje —Selecciona el nivel al que el circuito de cambio de nivel I2C traduce. Por defecto en 3,3V. Configura a 5V para uso con sistemas de 5V. Tanto las placas Pioneer BLE PSoC 4 como PSoC 6 son sistemas de 3,3V.
- LED XBee DIO5 —DIO5 por defecto tiene funciones útiles, especialmente en el módulo WiFi, donde muestra conectividad a la red WiFi configurada.
Ejemplo: WiFi a Raspberry Pi Usando el PSoC 6 Pioneer Kit
Este ejemplo demuestra cómo enviar una señal a una Raspberry Pi vía WiFi. Te muestra cómo acceder a un módulo XBee WiFi, comunicación entre procesos entre los dos núcleos del PSoC 6, y cómo recibir y analizar comandos con una Raspberry Pi.
Seguir este ejemplo requiere configuración, así que recorramos eso ahora.
Configuración PSoC 6 Pioneer Kit: Hardware
La configuración del lado del Pioneer Kit es trivial: inserta el módulo XBee WiFi en el Pioneer IoT Add-on Shield e inserta el shield en el header Arduino de la Pioneer Kit Board.
El lado de la Raspberry Pi requiere más explicación. Necesitarás configurar tanto hardware como software en la Raspberry Pi.
Configuración PSoC 6 Pioneer Kit: Software
Nota: El soporte para PSoC 6 solo está disponible en Creator 4.2 o posterior. El proyecto de software para el Pioneer Kit está disponible en GitHub.
DESCARGA DE SOFTWARE PSOC 6 PIONEER KIT
Una vez descargado y extraído el archivo, puedes abrir el ejemplo (XBee_WiFi_Example) en PSoC Creator.
Antes de hacer nada más, necesitas abrir el archivo "main_cm4.c" y hacer un par de cambios. Encontrarás una sección de código que se ve así:
char ssid[] = "your_ssid_here";
char rpi_ip[] = "raspi_ip_here";
char ssid_pw[] = "wifi_pw_here";
int dest_port = 5000;
char encrypt_mode = WPA2;
Espero que sea obvio qué hacer: cambia estos ajustes para que coincidan con tu configuración de red. El valor encrypt_mode puede ser WPA, WEP, WPA2, o (¡ojalá que no!) NO_SECURITY. rpi_ip es una dirección IP (ej. "10.8.253.193") que puedes obtener escribiendo "ifconfig" en una ventana de comandos en tu Raspberry Pi (ver abajo para instrucciones sobre abrir una ventana de comandos) y mirando la sección "wlan0".
Para programar la placa, conéctala a tu PC mediante el cable USB-A a USB-C incluido. Luego, haz clic en el botón "Program" en la barra de herramientas (como se muestra abajo) para compilar automáticamente el proyecto y programar la placa.
Puede aparecer una ventana pidiéndote elegir un objetivo a programar. No importa qué entrada elijas bajo el elemento "KitProg2", cualquiera programará el flash correctamente.
Configuración Raspberry Pi: Hardware
Primero, veamos cómo está conectado el hardware:
Como puedes ver, hemos conectado un LED (con resistencia de 330 ohm) a los pines 3 (GPIO 2) y 6 (ground) de la Raspberry Pi. Esto nos permitirá alternar GPIO2 y ver el resultado en el LED.
Configuración Raspberry Pi: Software
Asumiremos que tienes una Raspberry Pi configurada con la última versión de Raspbian (la instalación completa, no la lite) corriendo, y que está conectada a teclado, ratón, monitor y red WiFi local. Si no es el caso, tómate unos momentos para configurarlo. Puedes revisar nuestro tutorial sobre configuración de la Pi aquí.
Empecemos desde el escritorio de la Raspberry Pi. Deberías tener una pantalla que se vea algo así:
Necesitarás hacer clic en el pequeño logo en la parte superior de la pantalla (mostrado abajo) para abrir una línea de comandos. El resto de este tutorial asumirá que tienes esa línea de comandos abierta.
Eso abrirá una ventana de línea de comandos. Esto te permite decirle a la Raspberry Pi que ejecute comandos directamente.
Empezaremos ejecutando el comando para instalar Flask. Flask es un framework web para Python que te permite crear un front-end web que ejecuta scripts de Python en el backend del servidor de forma bastante trivial. Escribe el siguiente comando, luego pulsa "Enter".
sudo pip install flask
Un montón de cosas sucederán en la ventana de línea de comandos y al final, Flask estará instalado en tu Raspberry Pi.
El siguiente paso es instalar el software que hemos escrito para soportar este proyecto desde GitHub. El comando para hacerlo es:
git clone https://github.com/sparkfun/Flask_Tutorial
De nuevo, verás texto desplazarse por la línea de comandos, y cuando vuelva el prompt, esa será tu indicación de que el proceso de instalación ha terminado. Una vez completado, ejecuta este comando:
sudo python Flask_Tutorial/Python/app.py
Eso lanzará la app y comenzará a escuchar entrada sobre TCP/IP desde la Pioneer board. Ahora deberías poder encender y apagar el LED conectado a la Raspberry Pi presionando los botones D7 y D9 en el IoT Shield. ¡Genial!
¿Qué Está Pasando Aquí? Pt. 1: El Pioneer Kit
Veamos qué está pasando exactamente, empezando desde una vista de alto nivel del proyecto de software PSoC 6. Mira el frame Workspace Explorer en el lado izquierdo de la pantalla. Recorreremos ese frame, destacando los archivos importantes y cómo se relacionan con el proyecto general.
¿Difícil ver el Workspace Explorer? Haz clic en la imagen para ver más de cerca.
El nivel superior del proyecto tiene seis entradas: el esquema ("TopDesign.sch"), los Recursos de Diseño Global ("XBee_WiFi_Example.cydwr"), los archivos fuente asociados al núcleo Cortex-M0+ ("CM0p (Core 0)"), los archivos fuente asociados al núcleo Cortex-M4 ("CM4 (Core 1)"), archivos para compartir entre los dos ("Shared Files"), y archivos de soporte generados por el IDE ("Generated_Source").
El esquema para este proyecto es muy simple, teniendo un par de LEDs, un par de interruptores, y el UART usado para transferir datos hacia y desde el módulo XBee WiFi. Los LEDs en realidad no se usan en la implementación actual del proyecto.
Nos saltaremos el contenido del archivo .cydwr. Este archivo contiene las asignaciones de pines para las señales usadas en el esquema, la generación de reloj, y constantes de configuración de núcleo. Si quieres investigar más, siéntete libre de indagar. Gran parte debería ser autoexplicativo.
Bajando en la lista, llegamos a nuestros archivos fuente Cortex-M0+. Notarás que el nivel superior en este subdominio tiene cinco entradas: "Header Files", "Source Files", y tres otros archivos. Solo necesitamos preocuparnos por el contenido de los subdominios "Header Files" y "Source Files", y de hecho, solo con un archivo en esos: el archivo "main_cm0p.c". Aquí es donde vive la función main() para el código que corre en el procesador Cortex-M0+.
Como habrás adivinado por la estructura del workspace, hay dos bases de código completamente separadas corriendo para los dos núcleos diferentes. "main_cm0p.c" es el punto de entrada para el código del núcleo Cortex-M0+, y luego ese núcleo inicia el núcleo Cortex-M4. Existe un subdominio similar para el núcleo Cortex-M4 con archivos similares y de nuevo, solo necesitamos preocuparnos por los subdominios "Header Files" y "Source Files".
Finalmente, tenemos la sección "Shared Files". La mayoría de estos archivos son generados automáticamente, salvo los archivos "ipc_common.c" y "ipc_common.h". Estos archivos son helpers para comunicación entre procesos desarrollados para este proyecto.
El Archivo Main del Cortex-M0+
Ahora que hemos destacado los contenidos importantes, echemos un vistazo a los bits importantes del código, un archivo a la vez, empezando con el archivo "main_cm0p.c". Este archivo maneja toda la actividad que el núcleo Cortex-M0+ hace para el sistema: monitorizar los dos pulsadores y enviar una señal al Cortex-M4 cuando uno u otro es presionado.
Sin embargo, esto no es tan directo como parece, ya que el Cortex-M4 necesita poder borrar la señal una vez que la ha tratado, y eso significa múltiples procesos accediendo a los mismos datos. Cada vez que tienes múltiples procesos trabajando en el mismo conjunto de datos, necesitas considerar los efectos de una colisión de escritura. ¿Qué pasa si un proceso intenta cambiar los datos en medio de que el otro proceso intenta cambiar los mismos datos? Para lidiar con esto usamos un sistema de lecturas y escrituras protegidas, configurado en los archivos "ipc_common".
Para entender cómo funciona, primero hay que entender el concepto de un canal IPC. Los canales IPC usan semáforos para escribir datos de un proceso a otro garantizando que no habrá colisión entre los dos núcleos. Al comienzo de la ejecución de la aplicación para cada núcleo debes establecer endpoints para los canales IPC a usar durante la ejecución. Considera estas dos líneas de código:
IPC_STRUCT_Type *D9IpcHandle;
D9IpcHandle = Cy_IPC_Drv_GetIpcBaseAddress(7);
La primera crea un puntero para un struct que define las características de un canal IPC. La segunda realmente establece ese struct para apuntar a una ubicación de memoria específica, la del canal IPC del sistema 7. Usamos el canal 7 porque los canales 0-6 están reservados para uso del sistema.
Luego debemos, por supuesto, decirle al otro núcleo qué dirección de memoria está asociada con este canal IPC. Eso es lo que hace esta llamada a función:
while(Cy_IPC_Drv_SendMsgPtr(D9IpcHandle, CY_IPC_NO_NOTIFICATION, &D9Button) != CY_IPC_DRV_SUCCESS);
D9Button es una variable configurada antes en el código. La llamada a función está encerrada en un bucle while() porque queremos repetir la llamada hasta recibir verificación de que el otro proceso (es decir, el código corriendo en el núcleo Cortex-M4) ha recibido esta información. También queremos esperar hasta que el bloqueo en la variable se libere, indicando que el Cortex-M4 ha terminado de leer el valor del puntero.
while(Cy_IPC_Drv_IsLockAcquired(D9IpcHandle));
Finalmente, caemos en nuestro bucle infinito para la aplicación, donde las funciones personalizadas ReadSharedVar() y WriteSharedVar() manejan la actualización de las variables compartidas que comunican el estado de los botones con el otro núcleo. Profundizaremos en esas funciones más tarde.
El Archivo Main del Cortex-M4
En la función main() del Cortex-M4, repetimos algunas de las mismas operaciones que hicimos en la función main() del Cortex-M0+ respecto a la configuración del canal IPC.
IPC_STRUCT_Type *D9IpcHandle;
D9IpcHandle = Cy_IPC_Drv_GetIpcBaseAddress(7);
Una vez completado eso, debemos llamar a algún código para "capturar" el mensaje que fue enviado desde el proceso Cortex-M0+, conteniendo la dirección de la variable compartida a acceder.
while (Cy_IPC_Drv_ReadMsgPtr(D9IpcHandle, (void *)&D9Button) != CY_IPC_DRV_SUCCESS);
De nuevo, encerramos esta llamada en un bucle while() para que se llame continuamente hasta que el mensaje sea enviado desde el Cortex-M0+. Luego debemos liberar el bloqueo en ese canal IPC para que el proceso Cortex-M0+ sepa que puede continuar operación y usar el canal IPC en el futuro. No hay necesidad de encerrar esto en un bucle while() porque es abierto: la llamada solo necesita emitirse una vez para liberar el bloqueo, versus verificar que el bloqueo ha sido liberado, lo cual debe repetirse hasta que el bloqueo se libere.
Cy_IPC_Drv_LockRelease(D9IpcHandle, CY_IPC_NO_NOTIFICATION);
Una vez completado todo esto, debemos configurar el shield XBee WiFi para acceder a nuestra red local. No duplicaremos todo ese código aquí, ya que está bien documentado en el ejemplo.
En el bucle infinito que ejecuta el código de la aplicación, volvemos a llamar a las funciones personalizadas ReadSharedVar() y WriteSharedVar() para acceder a las variables que mantienen el estado de los botones, que se comparten con el núcleo Cortex-M0+. Echemos un vistazo más de cerca a qué hacen estas funciones.
Leer Más Información……
Usando la PSoC 6 Pioneer Board con el Pioneer IoT Add-on Shield
Proceso de manufactura
- Integre su estación meteorológica con CWOP: Guía práctica
- Integrar radar pulsado Acconeer A111 con Raspberry Pi: guía práctica
- Primeros pasos con IoT y MQTT: tutorial ESP8266 sin código
- Construye un robot inteligente con Bridge Shield – Integración Raspberry Pi y Arduino
- Extensión de GoPiGo v2 en Windows 10 IoT Core para Raspberry Pi 3
- Desatando el Poder de los Datos Visuales en el Ecosistema IoT
- IoT revoluciona el servicio de campo: Mantenimiento predictivo y mayor ROI
- Cómo las smart cities aprovechan IoT, microservicios y dashboards para gestión eficiente de activos
- IoT World: Dentro de la solución Big-Data de Vertica para analítica IoT
- Plataforma IoT Lumada de Hitachi: Unificando Insight Industrial para Manufactura Inteligente
- IoT Empresarial: Desbloqueando 36x el Valor del Internet Actual