A la cuestión de división y TI

"No presumas, Maria Ivanovna, y escucha tu canción favorita," Valenki "



A pesar del titular, el orden de presentación será el opuesto: primero sobre Texas Instruments (por supuesto, no sobre la compañía en sí, sigo siendo ingeniero, no entrenador, analista de negocios, por lo tanto, sobre los productos fabricados por la compañía), y solo luego sobre la división.

La primera parte del ballet Marlezon.

El tema de discusión será la relativamente nueva familia SS13xx (SS1310 / SS1350 / SS1352), pero es solo un punto de partida para discutir la situación en el campo de la programación de sistemas integrados. Este MK está diseñado para usarse en el diseño de dispositivos con interfaces inalámbricas de varios tipos (no me gusta mucho la nueva palabra IoT, especialmente porque no agota la posibilidad de usar esta familia).

MK está construido sobre la base del núcleo M3 con parámetros completamente aceptables, aunque no récord para la frecuencia y el tamaño de la memoria de programas y datos, tiene un conjunto suficiente de interfaces, pero estos parámetros no son de ninguna manera interesantes. La característica es que el microcircuito contiene tres núcleos MK, uno central y dos periféricos, para trabajar con dispositivos externos y para interactuar a través del éter. ¿Cuál es la razón de esta decisión?

En primer lugar, el deseo de garantizar un consumo mínimo de energía. El hecho es que la forma tradicional de reducir el consumo realizando cálculos intensivos en recursos en un tiempo relativamente corto y luego cambiando al modo de espera con una disminución en la frecuencia del reloj tiene limitaciones naturales y consumiremos un núcleo relativamente rápido a una frecuencia más baja, sin proporcionar el tiempo de reacción requerido para eventos externos Para eliminar esta contradicción, se introdujo el segundo núcleo del controlador del sensor, que proporciona interacción con el mundo exterior en el modo de baja potencia, y cuando surge la necesidad de cálculos intensivos en recursos, se activa el núcleo principal.

El tercer controlador resuelve (aunque de una manera muy complicada) la misma tarea de reducir el consumo. El hecho es que mantener protocolos de intercambio de radio a menudo requiere mantener restricciones de tiempo muy estrictas y un intento de implementarlos en el núcleo central (al mismo tiempo que ejecuta el programa de destino) requerirá aumentar la frecuencia del reloj del núcleo y, en consecuencia, la energía consumida por la fuente de energía. La separación de funciones permite eliminar esta contradicción (una solución típica en el estilo TRIZ).

No estoy absolutamente seguro de que tal separación de funciones fuera absolutamente necesaria y de que los parámetros requeridos no pudieran lograrse con soluciones arquitectónicas más simples, pero si el precio se mantiene dentro de un marco razonable y se realizan las capacidades necesarias, entonces por qué no. Además, la publicación aún no se trata del componente de hardware de MK, es solo para cubrir la situación. Consideraremos el proceso de creación de software para esta clase de MK.

Para empezar, el núcleo principal, todo es estándar aquí, tanto el núcleo M3 en sí mismo es bien conocido como la cadena de herramientas es gcc, la propia empresa recomienda dos IDE: ccs y iar. Trabajé mucho con el último de ellos, así que decidí probar qué tipo de producto generaba el sombrío genio teutónico de la mente colectiva TI. Code Composer Studio es un desarrollo de la empresa y es absolutamente gratuito sin restricciones, basado en (quién hubiera pensado) Eclipse y tiene todas las ventajas y desventajas inherentes a este entorno.

Lo único que me gustaría expresar mi desconcierto a la vez es que la compañía amablemente ofrece utilidades adicionales para trabajar con este MK (para crear una imagen de firmware de arranque a través de ether y para transferirla a MK), pero están escritos, por alguna razón, no en Java, que es la base para el entorno de programación y el sistema de tiempo de ejecución para el que forma parte del paquete de instalación, y en Phyton. No es que no me haya gustado mucho este último (aunque hay uno, no acepto establecer la estructura del programa con sangría, pero al final "los colores y los colores son diferentes"), pero no está claro por qué es necesario atraer entidades obviamente redundantes. Además, las utilidades en sí mismas no son nada complicadas, no usan bibliotecas específicas y el autor las transfirió a Java por un tiempo muy limitado sin la más mínima dificultad para aumentar la duración del programa en un 20% y, lo cual es un poco extraño, sin un cambio notable en la velocidad (considerando que el principal el tiempo de ejecución está asociado con la lectura de archivos, esto no es tan sorprendente: una nota tardía de Funtik F ...).

La segunda parte del rompecabezas radica en el hecho de que Eclipse es popular debido a la capacidad de insertar complementos fácilmente. Dado este hecho, la decisión de los desarrolladores del entorno de programación de hacer que el usuario llame a la utilidad con identificadores desde la línea de comando es extremadamente críptica, ya que previamente deshabilitó el terminal en el entorno de desarrollo con los identificadores y lanzó el programa de recepción de datos en el MK con los identificadores y luego restauró el terminal nuevamente con los identificadores. Quizás para los "programadores hindúes" esta solución parece ser la única posible y completamente justificada, pero una gran empresa podría permitirse atraer personal más calificado, probablemente no sé algo.

Además, la programación del controlador del sensor (el nombre no es muy exitoso, pero es un papel de rastreo directo) se lleva a cabo utilizando el producto Sensor Composer Studio. Inmediatamente otra pregunta: por qué es necesario tener un producto separado, no es que fuera muy difícil cambiar la ventana, pero aún así ..., especialmente porque el código creado finalmente se convierte en parte del código para el MK principal (por supuesto, está ahí no ejecutado, pero incluido en el espacio de direcciones generales de la memoria del programa).

Y aquí hay otra característica: no nos dicen nada sobre este núcleo (su arquitectura), excepto que es de 16 bits, de bajo consumo y patentado. En general, está bien, funciona y funciona bien, pero "el sedimento permanece". La siguiente es una descripción de los comandos de este kernel, según los cuales podemos suponer que se trata de una modificación de 430, aunque con características como los comandos para organizar ciclos. Se proporciona la ubicación de los registros periféricos en el espacio de direcciones general y local, y luego comienza la rareza nuevamente: muchos registros, incluidos los registros periféricos, van acompañados de la frase "solo se usa en la biblioteca de TI", y para algunos de los registros todavía se dan asignaciones de campo de bits, y para algunos no lo son. No es que estas descripciones de los registros me molesten mucho, pero ¿por qué darlas si el usuario no planea usarlas? Personalmente, no entiendo demasiado.

También puede acceder a la periferia de este núcleo desde el núcleo principal utilizando bibliotecas especiales, al mismo tiempo que puede escribir código en el entorno de programación mencionado, nuevamente utilizando algunos complementos. Aquí todo está bien, la documentación es suficiente, la configuración es conveniente, hay una representación gráfica de la configuración, depuración integrada en un modo especial (en modo general, el depurador está ocupado con el núcleo principal), en general, es bastante digno.

La siguiente parte es el núcleo para trabajar con radio, construido sobre la base de M0, ejecuta un programa desde su propia ROM (lo más probable es que sea parte de una memoria no volátil, es poco probable que un MK moderno tenga una memoria enmascarada), que no puede modificarse (al menos sobre esto en documentación no una palabra) por el usuario. La información sobre la estructura interna del canal de radio es extremadamente escasa, de hecho, solo se puede extraer de la descripción de los comandos de configuración de modo, pero el desarrollador habitual "incorporado" no la necesita.

La interacción entre el núcleo principal y la parte de radio se basa en el flujo de mensajes, que se documenta con suficiente detalle. Y esta documentación es suficiente para entender la cosa simple: usted no construirá (bueno, definitivamente no) sus mecanismos de interacción entre los núcleos, y especialmente los protocolos de comunicación, pero utilizará la biblioteca implementada por la empresa, porque la interacción es bastante complicada incluso con ella. El diseño debe tener en cuenta una gran cantidad de diversos factores, de modo que los beneficios de escribir su propio paquete no compensen el costo de crearlo. Por lo tanto, nuevamente usamos la subcapa de la biblioteca para organizar la interacción del núcleo principal con el núcleo de radio y, muy probablemente, usamos soluciones preparadas para organizar un canal de comunicación de radio estandarizado usando módulos listos, usando solo la parametrización del canal.

Creo que quedó claro para el lector que escribir un programa completo para este MK no es una tarea simple, es bastante accesible para un profesional avanzado, pero qué debe hacer un desarrollador "ordinario" (como Oleg Artamonov escribió recientemente: "Ya te diste cuenta de que cometiste un gran error con la elección" profesiones? ”). La compañía se encargó de este caso y, junto con el entorno de desarrollo, proporciona un gran paquete (conjunto de ejemplos) de programas para todas las ocasiones, que se llama SimpleLink. Además, las soluciones se ofrecen en dos versiones, ambas utilizando el sistema operativo en tiempo real TI-RTOS (en mi opinión, esta es una forma más conveniente) y en un superciclo (en caso de que odie tanto el sistema operativo incorporado que no puede comer) "). Estoy tranquilo acerca de RTOS en MK, por lo que utilizo la primera opción y le aconsejo que haga lo mismo, especialmente si comprende la configuración del proceso de compilación del sistema operativo y lo adapta a su clase de tareas, se ahorra facilidad de uso y el costo de mantener esta comodidad se reduce drásticamente.

Mi actitud personal hacia este paquete es doble: por un lado, una empresa maravillosa que simplifica drásticamente el uso de MK (por lo tanto, lo uso), pero por otro lado: "basura, desperdicio y sodomía", una gran ilustración de la frase "Si el costo de una buena arquitectura parece Es alto para usted, piense en el costo de una mala arquitectura ". (Es por eso que lo regaño). No se trata solo de la distribución de funciones por módulos y las relaciones entre ellos (aunque esto no es todo sencillo), sino también de la distribución de módulos por archivo, nombre de archivo, distribución archivos por directorios y sus nombres y estructura, etc. etc. Bueno, violar los principios de KISS y DRY es casi la regla para los desarrolladores del paquete, pero si no entiendo el código fuente del paquete (no puedo deshacerme de este estúpido hábito), y úsalo "como está", entonces todo funciona bien, al menos no he encontrado ningún problema en un proyecto específico (aparte de un sentimiento estético insultado y pérdida de fe en la humanidad).

Pero ahora puedes ir sin problemas al postulado principal de esta publicación (más vale tarde que nunca). Siempre pensé que era extremadamente difícil escribir un marco que combinara una verdadera versatilidad y un alto rendimiento. Los ejemplos de desarrollo propuestos por la compañía representan tal marco con énfasis en la versatilidad, las herramientas de personalización de aplicaciones están casi ausentes, todo está al nivel de ajustar las cuajadas. Tome uno de nuestros muchos ejemplos, cambie una pequeña pieza relacionada con mediciones y análisis (y transmisión, por supuesto), y listo. Por supuesto, el código resultante será bastante inflado en el caso general, pero le ofreceremos varios ejemplos para diferentes condiciones de aplicación, y solo tiene que elegir el más adecuado para su tarea. En un caso extremo, MK incorpora una cantidad considerable de memoria de programa para que no tenga que pensar en guardar este recurso. Además, una parte importante de las bibliotecas en ejecución ya están ocultas dentro de la ROM y solo debe llamarlas con cuidado.

No es que me opusiera a tal enfoque, e insistí categóricamente en la invención de las bicicletas, la reutilización del código es un imperativo categórico y una garantía de alta productividad del programador, pero sujeto a las siguientes condiciones:
La biblioteca de rutinas utilizadas debe ser:

  1. cuidadosamente diseñado
  2. cuidadosamente programado
  3. ampliamente documentado
  4. universal
  5. eficaz

Y si los dos últimos puntos son solo deseables (altamente deseables, pero no obstante ...), entonces los primeros tres son necesarios.

¿Qué pasa con los requisitos del paquete SimpleLink ofrecido por la empresa? Las siguientes son estimaciones en una escala de cinco puntos, obtenidas en el orden de conocimiento superficial del paquete.

1a) Las conexiones entre los módulos deben ser pensadas, los límites de competencia de cada módulo deben estar claramente delineados, eliminando la duplicación de funciones, las interfaces elaboradas: un sólido cuatro, el trabajo en su conjunto se ha realizado.

1b) La distribución de módulos en archivos con una estructura de directorios bien pensada es probablemente tres ventajas, lo que solo vale la pena repetir el texto de los módulos del programa en diferentes archivos.

2. El paquete no debe tener errores difíciles de detectar que rara vez se manifiestan (es obvio el hecho de que no debería haber mostrado errores constantemente). Es difícil hacer estimaciones aquí, observo una circunstancia desagradable: la mayoría de las funciones se pueden llamar tanto desde la memoria habitual del programa como desde la memoria permanente, y si las fuentes de la primera opción son accesibles y validadas, la segunda es mucho peor: no se nos dan instrucciones. sus fuentes no son idénticas a la primera opción, por lo que no se puede verificar.

3. La documentación para los cuatro sólidos ya es el hecho de que los autores no recurrieron al "poder y expresividad" de Doxygen en términos de documentación, da un mínimo de 1 punto, hay un sistema de enlaces contextuales, hay descripciones de los principios de funcionamiento, no pongo los cinco primeros solo en términos de documentación Nunca lo configuré, ni siquiera yo.

4. No más de cuatro debido a la falta de configuración desarrollada, pero ya mencioné esto.

5. Es difícil de decir, generalmente miro la implementación de SPI: es, por un lado, lo suficientemente simple como para apreciar la falta de rastrillo estándar, por otro lado, es lo suficientemente complejo como para tener dónde meterlos. Por lo tanto, en este paquete hay procedimientos de referencia ineficientes para escribir / leer bytes, pero si se sumerge en las profundidades, puede encontrar opciones realmente utilizadas con el MPD, todavía no puedo decir nada al respecto.

Una nota sobre las profundidades: son realmente profundas (a través de 4-5 funciones anidadas) y no puedo dejar de mencionar una característica del paquete: está escrito en C. No fui yo quien olvidó agregar dos más después de la letra, realmente no está allí. Para aquellos que están en el tema, queda mucho claro, les recomiendo a todos los demás que realicen una búsqueda emocionante para determinar el conjunto de funciones realizadas a nivel de hardware al implementar un objeto no trivial. Por supuesto, cuando se usan clases, tal tarea se vuelve trivial, pero este no es el camino de los Jedi de TI. Entiendo que esta es una preocupación necesaria para aquellos usuarios que descuidan las ventajas, pero por qué detenerse allí, pero ¿qué pasa con los desafortunados usuarios de ensamblador, por los cuales se ofendieron?

Y en conclusión: quiero enfatizar, "para que pueda ser entendido correctamente en la parte superior", no regaño a la familia MK, ni al entorno de desarrollo, ni al paquete de software, pero solo quiero que sean aún mejores, más convenientes y más atractivos para el usuario . Tengo mis propias cuentas con TI y nunca las perdonaré por la adquisición de National o incluso la adquisición anterior de Luminary con el posterior asesinato de una línea MK interesante (aunque en este último caso se castigaron a sí mismos), así como lo que me devolvieron en 2014 dinero para los cristales ordenados (aunque definitivamente no toqué Crimea), pero este sentimiento profundo no me impide ser objetivo, hicieron un buen trabajo. El concepto propuesto por la compañía, que se presenta en el epígrafe, no está demasiado cerca de mí, pero probablemente tengan razón, y no hay otra forma de cristales complejos. Esta es una tendencia y no tiene sentido luchar contra ella.

Y el hecho de que esta sea una tendencia confirma la situación con los nuevos cristales de administración de energía de Vicor. El cristal en sí es bueno (lo contrario sería sorprendente para una empresa de buena reputación), los parámetros son muy buenos, y lo mencioné solo en relación con la sección sobre la elección de componentes externos, específicamente la inductancia. En la documentación, esta sección es solo un párrafo, que indica un modelo específico de inductancia de un fabricante en particular y establece explícitamente que no se consideran otras opciones, ver el epígrafe. Entendiendo completamente las razones para el desarrollador del cristal (la frecuencia de conmutación es alta, las corrientes son significativas, el diseño de inductancia para tales condiciones no es una tarea trivial), sin embargo, debo señalar que por ahora este enfoque de diseño es inusual para mí, "pero la clave aquí es" por ahora ". Tal vez debería vender estos dos componentes en un paquete, entonces no habría preguntas.

La segunda parte del ballet Marlezon.

Bueno, ahora sobre la división, cuyo uso se descubrió en una de las bibliotecas de TI, pero no se aplica directamente a esta empresa, pero es una característica del compilador gcc. Por lo tanto, formulamos el problema desde el campo de la aritmética de direcciones: necesitamos calcular la diferencia en los índices (a saber, índices, no bytes) entre dos elementos de la matriz (o simplemente datos ubicados secuencialmente del mismo tipo) especificados por punteros a ellos.Como regla general, uno de los elementos es el primer elemento de la matriz, pero esto no es importante.

La tarea en sí es simple y en C, la solución es obvia y parece

(pointer1pointer0)/sizeof(type)

.El demonio se esconde en la implementación: el equipo de la división no se ha implementado de manera estándar en las arquitecturas MK comunes, por lo que no es rápido. Si el divisor es una variable, entonces no hay una buena solución de la palabra, pero para un valor constante hay opciones basadas en la multiplicación. Gracias a la maravillosa propiedad de la multiplicación.

(a+b)(c+d)=ac+ad+bc+bd

(la adición es aditiva, gracias, capitán) la implementación de hardware de la multiplicación es mucho más común en las implementaciones y es bastante rápida (el tema de los multiplicadores de hardware es interesante en sí mismo, pero no se trata de eso ahora). Desafortunadamente, no existe una propiedad similar para la división, por lo que es un invitado raro en términos de implementación de hardware.

Entonces, en lugar de dividir (por constante, esto es importante) queremos aplicar multiplicación, cuidado con tus manos

a/c=a(1/c)=a(N/(Nc))=a(N/c)/N

donde N es alguna constante adicional. Surge una pregunta lógica: qué tipo de basura, porque ahora tenemos dos operaciones de división en lugar de una, e incluso multiplicación, por lo que ganamos. La respuesta se elige correctamente N, si es una potencia de dos, pero la división se convierte en un desplazamiento del número a la derecha, que es mucho más barato, y si el exponente es un múltiplo de 8, entonces la división se convierte en una nueva numeración de bytes del número, que no cuesta nada en absoluto. Dado que el factor N / c es constante, lo calculamos por adelantado y todo parece estar bien, si no fuera por un detalle: la precisión de la representación de este factor.

Considere el caso específico de dividir por 10, que ocurre al convertir números de binario a decimal, luego, tomando H = 256, calculamos la constante para la multiplicación 256/10 = 25.6 y se produce un error de redondeo al número entero 25 (-2.3%) o 26 (+1.6 %) Entonces, por ejemplo, 100 * 26 = 2600 = 256 * 10 + 40 y la parte más alta del resultado es 10, que corresponde al 100/10 = 10 esperado. Podemos calcular a qué valores del dividendo el resultado se desvía del correcto en más de uno, pero para esto tendremos que resolver ecuaciones de la forma

[n/10]=[nk/N]+1

(donde los corchetes significan la parte entera con redondeo hacia abajo), y este no es un procedimiento muy claro, es más fácil hacer una simulación numérica y asegurarse de que el resultado sea correcto para un cierto n. Puede ingresar un aditivo de corrección y compensar la pérdida de precisión mediante la fórmula

(26/2+1)/256

y expandimos significativamente el rango permitido de valores de dividendos (hasta 256, es decir, en un entero sin signo de 8 bits nunca cometemos errores), pero no podemos eliminar el inconveniente fundamental del método: la presencia de un error, además, solo obtenemos un cálculo particular del resto (si es es necesario, pero este no es nuestro caso) es posible hacer solo una operación por separado, lo que afecta negativamente la velocidad del trabajo. En general, el método funciona bastante, pero su alcance es bastante limitado.

Por lo tanto, me sorprendió un poco cuando en el código compilado (como siempre, gracias a Godbolt por la oportunidad), vi en la dirección multiplicación aritmética por una cierta constante (lo suficientemente grande) en lugar de dividir por una constante (muy pequeña). Otra pregunta era que la constante no era en absoluto similar a la calculada para el método anterior. Y finalmente, el resultado no es la mitad superior del trabajo, sino la parte más joven. En general, un método un poco extraño, algo de basura, pero los cálculos muestran que funciona. Una breve reflexión revela el secreto y el método resulta ser absolutamente correcto, pero ... (por supuesto, el lector esperaba "pero ...", ya que es imposible reemplazar la división por la multiplicación en el caso general) tiene limitaciones.

Considere el número mágico 143 y examine sus divertidas propiedades 77 * 143 = 11011, su parte más joven 011 = 1 = 77/7. Es fácil ver que 784 * 143 = 112112, su parte más joven es 112 = 784/7 y así sucesivamente para todos los números que no excedan de 999 * 7 = 6993. Aquí está, una limitación natural del método, pero tomando otro número mágico 7143, ampliaremos el rango de posibilidades a 9999 * 7 = 69993. No es difícil encontrar otros números mágicos que tengan propiedades mágicas similares.

Cómo obtener estos números: queremos encontrar un número, multiplicando por el cual el dividendo puede obtener un resultado que contenga el resultado de la división en su parte más joven, en este caso por 7. Suena abstruso, pero es realmente simple, para el número de entrada 7 queremos obtenga xxx001, suponga xxx = 001 y aquí es simple street magic 1001/7 = 143. Obviamente, 143 * 7 = 1001, entonces para cualquier número = n * 7, (n * 7) * 143 = n * (7 * 143) = n * 1001 es verdadero, y la parte inferior del resultado es n, etc.

Ahora vemos un inconveniente fundamental de este método: funciona solo para números que son múltiplos del divisor y proporciona un resultado de multiplicación completamente impredecible (en el sentido que no corresponde a la división) en todos los demás casos. Pero para esta aplicación en particular, cuando restamos las direcciones de los elementos de la matriz, el resultado será exactamente un múltiplo del tamaño del elemento de la matriz y tenemos todo el derecho de usar este método. Si tomamos los números equivocados, entonces el resultado de la división tampoco debería interesarnos, "una máquina es un molino, si le arrojas piedras, entonces la harina no funcionará".

Encontrando números mágicos para divisores que no sean 7, así como pruebas de su existencia, dejamos al lector curioso. También es interesante construir una gráfica de factores dependiendo del divisor y ver las caídas y picos en él, probablemente, su presencia de alguna manera se correlaciona con la teoría de números. Por ejemplo, para el compuesto 21 = 3 * 7, este número = 381 (por supuesto, el número mínimo, el resto no nos interesa) es claramente menor que el producto 667 * 143 = 95381 e incluso no es múltiple, como pensé ingenuamente, aunque 381 = 381.

Otro hecho interesante es que los números mágicos serán diferentes en diferentes sistemas de números. Por ejemplo, en el sistema decimal, no hay una constante para dividir entre 5, ya que ninguno de los números de la forma x ... 1 puede tener un cinco como divisor y nuestro método no funciona. Pero, al mismo tiempo, en el sistema binario (hexadecimal), este problema está resuelto, ya que 1024 + 1 = 1025 = 0x401 se divide maravillosamente con el resultado 205 = 0xCD y nuestro algoritmo funciona nuevamente, por ejemplo 130 * 205 = 0x82 * 0xCD = 0xFAFA => FA = 26 = 130/5. Además, se puede demostrar (bueno, creo que sí) que ahora el problema de encontrar el factor se resuelve para cualquier divisor impar, y cualquiera par se convierte en impar con un número finito de cambios (definitivamente puedo probar esto). En cuanto a que una representación binaria es conveniente y útil, tuvimos mucha suerte con ella.

PS.Mis lectores habituales (me siento halagado con la esperanza de que existan) están perplejos: la publicación ha llegado a su fin y dónde está el "grito de Yaroslavna". No se preocupen, mis queridos, ahí está.

En las placas de depuración para CC1350 y CC1352, se usa un cristal del interruptor de antena (se usa de manera diferente, pero no importa), a saber, XMSSJE3G0PA (no intente leer esto en la transcripción rusa, estoy seguro de que muRata no tenía nada en mente). Entonces, un interruptor con características modestas: una banda de frecuencia de hasta 2.7 GHz, atenuación de transmisión - 0.28 dB, atenuación de aislamiento - 33 dB, potencia de conmutación - 20 dB. Pero todo esto se compensa con dos parámetros: dimensiones 1.5 * 1.5 mm y costo: $ 0.9, a pesar de las tecnologías aplicadas "Silicon On Insulator" y "arsenide de galio".

¿CÓMO lo hacen? Estoy hablando principalmente del precio y, en segundo lugar, por qué no lo hacemos, la pregunta es retórica

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


All Articles