Adición de conectividad Ethernet a un STM32-Nucleo

Un inconveniente del ecosistema Nucleo es la falta de una versión con conectividad Ethernet o un escudo dedicado oficialmente soportado por ST. Hay 90 MCU STM32 diferentes disponibles que proporcionan una interfaz MAC de Ethernet (esto significa que solo un transceptor Ethernet externo, también llamado phyter) , y se requieren algunas otras cosas para llevar su MCU al mundo de IoT. STM32Cube (la HAL soportada oficialmente por ST) también brinda soporte para lwIPapilar. Sin embargo, todas las placas Nucleo actuales están diseñadas con una MCU sin una interfaz Ethernet (creo que la razón principal es que solo hay dos MCU STM32 con Ethernet MAC disponibles en el paquete LQFP-64 y las placas Nucleo están diseñadas para ser conectadas directamente). -pin compatible entre sus lanzamientos – L0, F1, etc).Esto significa que sin un escudo de expansión dedicado es imposible agregar conectividad de red a nuestro Nucleo. Y esto es un pecado teniendo en cuenta lo que MCU puede hacer.

En el mundo de Arduino, el Escudo de Ethernet oficial es la solución más popular para agregar conectividad de Internet a Arduino. El escudo de Ethernet se basa en un procesador de red que se ha hecho muy popular gracias a su difusión en la comunidad Arduino: W5100 de WIZnet .

WIZNet es una empresa coreana especializada en la producción de procesadores de red monolíticos. Un procesador de red es una especie de caja negra que proporciona capacidades de hardware (por ejemplo, un ethernet pyther) y toda la pila de red necesaria para conectar una MCU a Internet. La MCU interactúa con el procesador de red a través de una interfaz de bus. SPI es la solución más utilizada, ya que casi todas las MCU proporcionan al menos una interfaz maestra SPI.

Desde un punto de vista teórico, la forma en que la MCU interactúa con el procesador de red es realmente simple. Al enviar conjuntos específicos de comandos y cambiar algunos registros internos, el procesador de red puede configurar los parámetros de IP (dirección IP, máscara de red, etc.), abrir sockets y establecer conexiones a pares remotos, ya sea mediante TCP o UDP. Todos los detalles de la implementación de la pila TCP / IP están “codificados” dentro de la MCU. Los programadores deben “solo” hacerse cargo de la lógica de la aplicación y de cómo intercambiar datos con el par remoto mediante sockets TCP o UDP. Este enfoque tiene varios beneficios clave:

  • Diseño de hardware simplificado : estos chips se desarrollan de manera que solo se requieren en la placa algunos pasivos externos y un puerto Ethernet con magnetismo.
  • Reducción del tamaño del firmware : dado que toda la pila TCP / IP se incluye dentro del procesador de red, el firmware ocupa una cantidad menor de bytes; esto permite seleccionar una MCU con menos flash y menos capacidades de hardware, lo que reduce el costo de la lista de materiales.
  • Rápido tiempo de comercialización : el trabajo de los programadores se simplifica por el hecho de que no hay necesidad de luchar contra los detalles de implementación de TCP / IP; todo el trabajo sucio lo realizan los procesadores de red, y pueden centrarse en la aplicación específica (esta es la razón principal del éxito de la familia PIC18 y PIC32, según mi opinión, y la pila TCP / IP relacionada que proporcionó Microchip). ).

Sin embargo, en los primeros días de los chips W5100 (y luego del IC derivado como el W5200, etc.) fue realmente complejo lidiar con estos IC. La documentación oficial solo se redujo en una hoja de datos detamaño pequeño  (que también contiene varios errores …). La mejor biblioteca “C” fue solo la biblioteca Arduino Ethernet, diseñada para trabajar con la familia ATMega8 de AVR. Sin embargo, WIZNet trabajó arduamente en los últimos años para mejorar la calidad de su código oficial (pero aún falta una buena documentación). Recientemente lanzaron una biblioteca completa, llamada ioLibrary , en su cuenta de github. La biblioteca fue diseñada para ser lo suficientemente genérica para trabajar con varias HAL, y es posible usarla con la HAL STM32Cube con un esfuerzo muy pequeño. La biblioteca proporciona soporte para las funcionalidades de “bajo nivel” de los chips W5x00 (configuración de IP, sockets, etc.), así como la implementación de algunos protocolos de red populares como el HTTP.

En esta primera parte de la serie, mostraré cómo usar el protector Arduino Ethernet en una placa Nucleo STM32. Mostraré todos los pasos de configuración de hardware requeridos. También mostraré cómo importar la biblioteca de WIZNet dentro de un nuevo proyecto STM32 nuevo y cómo configurar la biblioteca para comenzar a trabajar con este escudo. En un próximo artículo veremos cómo habilitar un cliente DHCP y crearemos un servidor web simple que permita interactuar con nuestro Nucleo mediante una interfaz web.

Requisitos de hardware y software

En este post asumiré que tienes:

  • Una de las placas STM32Nucleo disponibles en el mercado: he probado con éxito el código tanto en una placa Nucleo-F401RE como en una placa Nucleo-F103RB.
  • Un Arduino Ethernet Shield , o uno de sus clones disponibles en eBay por menos de $ 10.
  • Algunos cables de conexión para redireccionar los pines ICSP de Arduino a los encabezados Núcleo Morpho, más sobre esto más adelante.
  • Una completa cadena de herramientas Eclipse / GCC ARM con los complementos necesarios como se describe en esta publicación . Asumiré que toda la cadena de herramientas está instalada en C: \ STM32Toolchain o ~ / STM32Toolchain si tiene un sistema similar a UNIX.
  • Un proyecto de prueba básico para su versión Nucleo como se describe en esta publicación .

No mostraré los pasos necesarios para crear un proyecto básico utilizando Eclipse y la última versión de HAL de ST, porque ya he cubierto este aspecto varias veces en mi blog. Puede encontrar estas publicaciones buscando las más populares en el lado izquierdo de esta página.

Más sobre el chip W5100

Como he dicho antes, el chip W5100 es un controlador Ethernet integrado TCP / IP en red que simplifica el proceso de agregar conectividad Ethernet a una MCU. W5100 proporciona en un solo chip un Ethernet 10/100 MAC, un phyter y una pila TCP / IP completa con soporte para TCP, UDP, IPv4, ICMP, ARP, IGMP y PPPoE. El W5100 utiliza un búfer interno de 16 bytes para intercambiar datos entre la memoria interna del chip y la MCU. Es posible utilizar 4 sockets de hardware independientes simultáneamente. Para cada socket, el usuario puede definir la cantidad de memoria de búfer para TX y RX. BUS (Directo e Indirecto) y SPI (Interfaz Periférica Serial) se proporcionan para una fácil integración con la MCU externa.

El proceso de programación de un chip W5100 implica estos pasos:

  • Configure el bus SPI de acuerdo con las especificaciones MCU y W5100. El W5100 funciona como dispositivo esclavo SPI y admite los modos más comunes: Modo SPI 0 
    y 3. 
  • Configure la dirección MAC, la dirección IP, la máscara de red y la puerta de enlace. Como veremos en un próximo artículo, W5100 no admite por sí solo el protocolo DHCP, pero WIZnet proporciona una biblioteca que usa sockets RAW para implementar el protocolo de descubrimiento DHCP.
  • Configure los buffers internos de socket para TX y RX. El usuario puede decidir expandir esta memoria independientemente de 0K a 8K. Tenga en cuenta que la memoria para TX y RX se comparte entre los 4 zócalos, y 8K es la cantidad total para cada búfer (8K para TX y 8K para RX). La configuración predeterminada utiliza 2K bytes para cada socket, tanto para buffers de TX como de RX.
  • Configure los sockets que necesitamos en nuestra aplicación. Esto significa decidir el tipo de socket (TCP, UDP, IP RAW, etc.) y así sucesivamente.
  • Utilice los comandos de emisión de socket que ponen el socket en un estado determinado de acuerdo con este diagrama de estado

Afortunadamente, no necesitamos lidiar con estos aspectos de bajo nivel del chip W5100. Gracias al ioLibrary de WIZNet y un poco de “pegamento” para adaptarlo a la HAL STM32Cube, podemos desarrollar aplicaciones IoT con nuestro MCU STM32 favorito de una manera realmente simple.

Configuración de hardware

Desafortunadamente, podemos usar el Arduino Ethernet Shield en nuestro Núcleo STM32 fácilmente. La razón es que el escudo utiliza el conector Arduino ICSP como fuente para los pines SPI (MISO, MOSI y SCK – SS se asigna al pin D10), como se muestra en la siguiente imagen.

arduino-eth-shield-schema

El Nucleo no proporciona ese conector. Esto significa que necesitamos “redireccionar” esos pines a otros pines. Mirando al pinout Nucleo-F401RE, podemos usar los pines en el conector morfo asociado al periférico SPI2, como se muestra a continuación.

xnucleo64_revc_f401re_mbed_pinout_v2_morpho.png.pagespeed.ic.-vtjy5PI6L

Sí, tenemos que hacer esta asociación:

  1. Arduino ICSP PIN 1 (MISO) to Nucleo PIN PB_14.
  2. Arduino ICSP PIN 4 (MOSI) to Nucleo PIN PB_15.
  3. Arduino ICSP PIN 3 (SCK) to Nucleo PIN PB_13.
  4. Arduino D10 PIN (SS) a Nucleo PIN PB_12 .

El siguiente esquema de división puede ayudar a comprender la conexión.

eth shield_bb

He usado 4 parches (los que se usan para conexiones de tablero de pruebas) como se muestra en la siguiente imagen.

2015-08-13 15.12.44

Importando el ioLibrary en Eclipse

De acuerdo. Vamos a empezar la parte divertida. Primero, necesitamos un proyecto de huesos desnudos para empezar. Si no sabe cómo generar uno, puede seguir este tutorial . A continuación, debemos descargar la última ioLibrary del repositorio de github de WIZNet . Desempaquételo en un lugar conveniente, cambie el nombre de la carpeta principal de  ioLibrary_Driver-master a  ioLibrary_Driver  y arrástrelo dentro del proyecto Eclipse. Ahora necesitamos habilitar la compilación de la carpeta agregada. Haga clic con el botón derecho del ratón en la   carpeta ioLibrary_Driver y elija Configuraciones de recursos -> Excluir de las compilaciones … y deseleccione los elementos Depurar y Liberar .

A continuación, debemos agregar las carpetas de inclusión adecuadas dentro de la configuración del proyecto. Necesitamos agregar estas carpetas de Eclipse:

  • “../ioLibrary_Driver/Ethernet”
  • “../ioLibrary_Driver/Ethernet/W5100”

dentro de Configuración del proyecto-> Compilación C / C ++-> Configuración-> Compilador de ARM C cruzado -> Incluye como se muestra a continuación.

Captura de pantalla 2015-08-13 en 7.40.10

Repita el mismo paso para la sección Cross ARM C ++ Compiler-> Include . Finalmente, debemos configurar el chip WIZNet adecuado (la biblioteca io está diseñada para ser utilizada con todos los chips W5X00). Abra el archivo  ioLibrary_Driver / Ethernet / wizchip_conf.c y cambie la macro _WIZCHIP_ a 5100 (la macro se define alrededor de la línea 64).

636465…#define _WIZCHIP_            5100   // 5100, 5200, 5300, 5500…

Configurando la interfaz SP

De acuerdo. Ahora podemos comenzar a codificar cosas serias El primer paso es configurar la interfaz SPI asociada a los pines PB_12..15: SPI2. Tengo que decir que la forma más sencilla de hacerlo es utilizar la herramienta STM32CubeMX. Genera automáticamente todo lo necesario para configurar correctamente el puerto SPI. Sin embargo, el código generado por CubeMX está un poco articulado en varias rutinas y archivos de origen. Entonces, no es práctico usarlo aquí, ya que haría este tutorial demasiado complicado de seguir. He definido esta función en el archivo main.c:

123456789101112131415161718192021222324252627282930313233343536373839void MX_SPI2_Init(void){    GPIO_InitTypeDef GPIO_InitStruct;     hspi2.Instance = SPI2;    hspi2.Init.Mode = SPI_MODE_MASTER;    hspi2.Init.Direction = SPI_DIRECTION_2LINES;    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;    hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;    hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;    hspi2.Init.NSS = SPI_NSS_SOFT;    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;    hspi2.Init.TIMode = SPI_TIMODE_DISABLED;    hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;     __SPI2_CLK_ENABLE();    /**SPI2 GPIO Configuration    PB12     ——> SPI2_NSS    PB13     ——> SPI2_SCK    PB14     ——> SPI2_MISO    PB15     ——> SPI2_MOSI    */    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;    GPIO_InitStruct.Pull = GPIO_NOPULL;    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);     /*Configure GPIO pin : PA5 */    GPIO_InitStruct.Pin = GPIO_PIN_12;    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;    GPIO_InitStruct.Pull = GPIO_PULLUP;    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);  HAL_SPI_Init(&hspi2);}

Esta rutina hace dos cosas. Primero, configura correctamente la interfaz SPI para que funcione con el chip W5100. Esto se hace configurando la variable hspi2 , cuyo tipo es   SPI_HandleTypeDef . La variable se define como variable global dentro del archivo main.c , ya que la usaremos en otras rutinas. En segundo lugar, la rutina configura los pines asociados a la interfaz SPI2: PB12 a PB15. Los pines PB13 a PB15 están configurados como pines de función alternativa (AF), ya que se usarán como interfaz SPI; El pin PB12 es el pin de selección de chip (CS), y está configurado como Pin de salida en modo pull-up (esto evita que los pines estén “bajos” al flotar).

Configurando USART

En este proyecto, utilizaremos el USART asociado a la interfaz ST-Link para enviar algunos mensajes en el puerto COM virtual. Puedes encontrar más sobre esto aquí . Antes de que podamos imprimir mensajes en la serie, debemos configurar la interfaz USART2 en consecuencia. Este trabajo se realiza mediante la siguiente función, definida en el archivo main.c.

12345678910111213141516171819202122232425262728/* USART2 init function */void MX_USART2_UART_Init(void){    GPIO_InitTypeDef GPIO_InitStruct;     huart2.Instance = USART2;    huart2.Init.BaudRate = 115200;    huart2.Init.WordLength = UART_WORDLENGTH_8B;    huart2.Init.StopBits = UART_STOPBITS_1;    huart2.Init.Parity = UART_PARITY_NONE;    huart2.Init.Mode = UART_MODE_TX_RX;    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;    huart2.Init.OverSampling = UART_OVERSAMPLING_16;     __USART2_CLK_ENABLE();      /**USART2 GPIO Configuration    PA2     ——> USART2_TX    PA3     ——> USART2_RX    */    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;    GPIO_InitStruct.Pull = GPIO_NOPULL;    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);     HAL_UART_Init(&huart2);}

Como lo hemos hecho para la interfaz SPI, primero tenemos que configurar los periféricos USART2 (parámetros elegidos son: velocidad de transmisión 115200 , de 8 bits , 1 bit de parada , sin paridad , sin control de flujo de hardware ). A continuación, debemos configurar el pin asociado (PA2 y PA3) como pines de función alternativa.

Configurar ioLibrary

La biblioteca de WIZnet está diseñada para que se pueda utilizar con la mayoría de MCU (y HAL) en el mercado. Esto significa que se diseñó de manera abstracta para que sea responsabilidad del usuario proporcionar el código específico que funciona con el hardware. En nuestro caso necesitamos suministrar 4 funciones personalizadas:

  • Una función para seleccionar el chip esclavo durante la transferencia de SPI (es decir, una función que baja el pin GPIO asociado a CS – PB_12 en nuestro caso).
  • Una función para deseleccionar el chip esclavo.
  • Una función para escribir 1 byte en la interfaz SPI.
  • Una función para leer 1 byte en la interfaz SPI.

Deja un comentario

Tu dirección de correo electrónico no será publicada.