Uso del c贸digo mbed en su propio proyecto STM32: experimente el overclocking de la pantalla LCD china

A veces, el c贸digo de otra persona realmente ayuda a conectar el hierro perif茅rico al microcontrolador. Desafortunadamente, adaptar el c贸digo de otra persona a su proyecto puede ser m谩s dif铆cil que reescribirlo usted mismo, especialmente cuando se trata de mega frameworks como arduino o mbed. Deseando conectar un LCD chino basado en ILI9341 a la placa STM32L476G DISCOVERY, el autor se propuso usar el controlador escrito para mbed en el proyecto de demostraci贸n desde ST sin cambiar una sola l铆nea en su c贸digo. Como resultado, fue posible al mismo tiempo overclockear la pantalla a velocidades de actualizaci贸n sin precedentes de 27 fps.





Introducci贸n al problema.


ST Microelectronics produce microcontroladores que son muy interesantes, tanto en t茅rminos de capacidades como de precio, y tambi茅n liberan placas para un r谩pido desarrollo. Se discutir谩 uno de ellos: DESCUBRIMIENTO STM32L476G . Las capacidades inform谩ticas de esta placa son muy alentadoras: un ARM de 32 bits con una frecuencia de reloj m谩xima de 80 MHz puede realizar operaciones de punto flotante. Al mismo tiempo, puede reducir el consumo de energ铆a al m铆nimo y trabajar con bater铆a, esperando la oportunidad de hacer algo 煤til. Decid铆 conectar a este dispositivo una pantalla LCD en color china barata con una resoluci贸n de 320 por 240 trabajando en la interfaz SPI. Aqu铆 se describe en detalle c贸mo usarlo con mbed . Mbed- Este es un entorno de programaci贸n en l铆nea donde puede compilar firmware para usted mismo sin tener un compilador en su computadora, luego descargarlo y flashearlo simplemente copi谩ndolo en su placa compatible con mbed, que parece un disco extra铆ble cuando est谩 conectado a USB. Todo esto es genial, pero hay algunos problemas. En primer lugar, no todas las placas son compatibles con mbed. En segundo lugar, hay muchos proyectos existentes que no son compatibles con mbed de ninguna manera, incluido el software suministrado por ST. Y finalmente, no todos los desarrolladores son compatibles con mbed, algunos (por ejemplo, el autor de estas l铆neas) encuentran m谩s desventajas que ventajas en esta maravillosa herramienta. 驴Cu谩les son estas desventajas? Discutiremos a continuaci贸n, por ahora es suficiente mencionar que despu茅s de conectar el controlador de pantalla para el proyecto de demostraci贸n de ST y algunas optimizaciones simples, comenz贸 a funcionar unas 10 veces m谩s r谩pido.

Aprendiendo el c贸digo del conductor


Es hora de descargar y estudiar el c贸digo fuente del controlador de pantalla. El trabajo con puertos en mbed se organiza mediante llamadas a m茅todos de clase que representan puertos de E / S. Por ejemplo, la clase DigitalOut implementa el acceso al puerto de salida. Al asignar una instancia de este objeto cero o uno, se inicia la escritura del bit correspondiente en el puerto de salida. La clase DigitalOut se inicializa con el tipo enumerado PinName, cuyo 煤nico prop贸sito es identificar la rama del procesador. Uno de los principales inconvenientes de implementar DigitalOut y otras clases que implementan E / S es que el puerto se inicializa en el constructor de la instancia de clase. Esto es ideal para parpadear un LED si se crea una instancia de la clase DigitalOut en la pila en la funci贸n principal. Pero imagine que tenemos muchos tipos diferentes de hierro, cuya inicializaci贸n se encuentra dispersa en varios m贸dulos.Si hacemos que las instancias de nuestras clases de E / S sean est谩ticas, perdemos todo control sobre la inicializaci贸n, ya que ocurrir谩 antes de la funci贸n principal y en un orden arbitrario. Las bibliotecas ST (llamadas HAL - nivel de abstracci贸n de hardware) usan un paradigma diferente y m谩s flexible. Cada puerto de entrada / salida tiene su propio contexto y un conjunto de funciones que funcionan con 茅l, pero pueden llamarse exactamente cuando sea necesario. Los contextos de puerto generalmente se crean como variables est谩ticas, pero no se produce una inicializaci贸n autom谩tica no controlada (las bibliotecas ST se escriben en C). Tambi茅n vale la pena mencionar una utilidad extremadamente conveniente.Las bibliotecas ST (llamadas HAL - nivel de abstracci贸n de hardware) usan un paradigma diferente y m谩s flexible. Cada puerto de entrada / salida tiene su propio contexto y un conjunto de funciones que funcionan con 茅l, pero pueden llamarse exactamente cuando sea necesario. Los contextos de puerto generalmente se crean como variables est谩ticas, pero no se produce una inicializaci贸n autom谩tica no controlada (las bibliotecas ST se escriben en C). Tambi茅n vale la pena mencionar una utilidad extremadamente conveniente.Las bibliotecas ST (llamadas HAL - nivel de abstracci贸n de hardware) usan un paradigma diferente y m谩s flexible. Cada puerto de entrada / salida tiene su propio contexto y un conjunto de funciones que funcionan con 茅l, pero pueden llamarse exactamente cuando sea necesario. Los contextos de puerto generalmente se crean como variables est谩ticas, pero no se produce una inicializaci贸n autom谩tica no controlada (las bibliotecas ST se escriben en C). Tambi茅n vale la pena mencionar una utilidad extremadamente conveniente.pero no se produce una inicializaci贸n no controlada autom谩tica en este caso (las bibliotecas ST se escriben en C). Tambi茅n vale la pena mencionar una utilidad extremadamente conveniente.pero no se produce una inicializaci贸n no controlada autom谩tica en este caso (las bibliotecas ST se escriben en C). Tambi茅n vale la pena mencionar una utilidad extremadamente conveniente.CubeMX , que puede generar todo el c贸digo de inicializaci贸n necesario para el conjunto de puertos que necesita e incluso le permite realizar cambios posteriormente a este conjunto de puertos sin afectar su propio c贸digo. Su 煤nico inconveniente es la imposibilidad de usar con proyectos existentes, debe comenzar el proyecto con el uso de esta utilidad.

La biblioteca mbed usa las mismas funciones HAL de la biblioteca ST para inicializar los recursos del microcontrolador, pero esto lo hace sorprendentemente irreflexivo en algunos lugares. Para asegurarse de esto, solo mire el c贸digo de inicializaci贸n del puerto SPI (que necesitamos trabajar con la pantalla) en el archivo spi_api.c. La funci贸n spi_init primero busca un puerto SPI adecuado por los tramos que usar谩, y luego llama a la funci贸n init_spi, que en realidad inicializa el puerto. En este caso, los 3 puertos SPI posibles usan una estructura de contexto est谩tico
static SPI_HandleTypeDef SpiHandle;

Este es esencialmente un ejemplo cl谩sico de uso de variables globales en lugar de locales. Incluso teniendo en cuenta el hecho de que tenemos un n煤cleo inform谩tico, el contexto global no est谩 protegido del uso simult谩neo en diferentes lugares del c贸digo, todav铆a hay interrupciones, as铆 como desplazar la multitarea.

Conecta la biblioteca a tu proyecto


Por lo tanto, no quiero escribir todo el c贸digo en mbed. Me gustan los ejemplos de ST que vienen con CubeMX mucho m谩s . No encontr茅 el controlador terminado para mi LCD para bibliotecas ST, no quer铆a escribirlo yo mismo. Quedaba una forma alternativa de divertirse de alguna manera: conectar el controlador escrito para mbed y no requerir que se cambie nada. Todo lo que necesita hacer es implementar las bibliotecas mbed de una manera alternativa. De hecho, la tarea es m谩s simple de lo que parece, debido a todas las bibliotecas mbed, el controlador LCD usa solo el puerto de salida y SPI. Adem谩s, necesita las funciones de formaci贸n de retrasos y clases de archivos y secuencias. Con este 煤ltimo, todo es simple: no los necesitamos y son reemplazados por enchufes que no hacen nada. Las funciones de generaci贸n de retardo son f谩ciles de escribir: est谩n en el archivowait_api.h . La implementaci贸n de clases de E / S requiere un enfoque un poco m谩s creativo. Vamos a arreglar la falta de bibliotecas mbed y no hacer la inicializaci贸n del hardware en el constructor. El constructor recibir谩 un enlace al contexto del puerto ubicado en otro lugar, su c贸digo de inicializaci贸n ser谩 completamente independiente de nuestras clases de interfaz. Hay la 煤nica forma de pasar esta informaci贸n al constructor sin cambiar el c贸digo del controlador: a trav茅s de PinName, que en lugar de simplemente enumerar las piernas ahora almacenar谩 el puntero en el puerto, el n煤mero de la pierna y, opcionalmente, el puntero al recurso (como SPI) al que est谩 conectada esta pierna.
class PinName {
public:
	PinName() : m_port(0), m_pin(0), m_obj(0) {}
	PinName(GPIO_TypeDef* port, unsigned pin, void* obj = 0)
		: m_port(port), m_pin(pin), m_obj(obj)
		{
			assert_param(m_port != 0);
		}

	GPIO_TypeDef* m_port;
	unsigned      m_pin;
	void*         m_obj;

	static PinName not_connected;
};


La implementaci贸n del puerto de salida es bastante trivial. Para mejorar el rendimiento, intentaremos usar menos las funciones de HAL y, si es posible, trabajar directamente con registros de puerto, y tambi茅n escribir c贸digo en l铆nea, lo que permitir谩 al compilador evitar llamadas a funciones.
class DigitalOut {
public:
	DigitalOut(GPIO_TypeDef* port, unsigned pin)
		: m_port(port), m_pin(pin)
		{
			assert_param(m_port != 0);
		}
	DigitalOut(PinName const& N)
		: m_port(N.m_port), m_pin(N.m_pin)
		{
			assert_param(m_port != 0);
		}
	void operator =(int bit) {
		if (bit) m_port->BSRR = m_pin;
		else     m_port->BRR  = m_pin;
	}
private:
	GPIO_TypeDef* m_port;
	unsigned      m_pin;
};


El c贸digo de implementaci贸n del puerto SPI no es mucho m谩s complicado, puede verlo aqu铆 . Como separamos la inicializaci贸n del puerto del c贸digo de interfaz, ignoramos las solicitudes de cambios de configuraci贸n. La profundidad de la palabra se recuerda simplemente. Si el usuario desea transmitir una palabra de 16 bits, y el puerto est谩 configurado como 8 bits, entonces solo tenemos que reorganizar los bytes y transferirlos uno por uno; a煤n quedan 4 bytes en el b煤fer del puerto. Todos los archivos necesarios para compilar el controlador se recopilan en el directorio compat . Ahora puede conectar los archivos del controlador original al proyecto y compilarlos. Tambi茅n necesitaremos un c贸digo que inicialice los puertos, cree una instancia del controlador y dibuje algo significativo en la pantalla.

Overclocking


Si la pantalla LCD se usa para emitir algo din谩mico, existe un deseo natural de hacer que la comunicaci贸n sea m谩s r谩pida. Lo primero que viene a la mente es aumentar la frecuencia del reloj SPI, que el controlador establece a 10MHz, pero ignoramos sus deseos y podemos configurar cualquier cosa. Result贸 que la pantalla funciona bien y a una frecuencia de 40MHz: esta es la frecuencia m谩xima de la que es capaz nuestro procesador con una frecuencia de reloj de 80MHz. Para evaluar el rendimiento, se escribi贸 un c贸digo simple que muestra un mapa de bits de 100x100 p铆xeles en un bucle. El resultado fue extrapolado a toda la pantalla (un mapa de bits que ocupa toda la pantalla simplemente no cabe en la memoria). El resultado: 11 fps est谩 muy lejos del l铆mite te贸rico de 32 fps, que se obtiene si transfiere 16 bits a cada p铆xel sin detenerse. La raz贸n se vuelve clara si nos fijamos enc贸digo fuente del controlador . Si necesita transmitir una secuencia de bytes, simplemente los transfiere uno por uno, en el mejor de los casos empaquetado en palabras de 16 bits. La raz贸n de este dise帽o ineficiente radica en la API de mbed. La clase SPI tiene un m茅todo para transmitir una matriz de datos, pero solo se puede usar de forma asincr贸nica, llamando a la funci贸n de notificaci贸n al finalizar y en el contexto de un controlador de interrupciones. No es sorprendente que pocas personas usen este m茅todo. Complement茅 mi implementaci贸n de la clase SPI con una funci贸n que env铆a un b煤fer y espera el final de la transferencia. Despu茅s de agregar una llamada a esta funci贸n al c贸digo de transferencia de mapa de bits, el rendimiento aument贸 a 27 fps, que ya est谩 muy cerca del l铆mite te贸rico.

C贸digo fuente


Mentiras aqui . Para la compilaci贸n se utiliz贸 IAR Embedded Workbench para ARM 7.50.2. Basado en el firmware de demostraci贸n de c贸digo de ST. Descripci贸n de la espiga, que est谩 conectado a la pantalla LCD se puede encontrar en el archivo lcd.h .

Source: https://habr.com/ru/post/es390909/


All Articles