Como habrían visto en mi blog, codifique una lib para utilizar el puerto Serie (UART) con la BluePill con libOpenCM3. Pero debo hacer un mea culpa, ya que debido a un pequeño error la comunicación se congelaba después de transmitir/recibir 65536 datos. Por ello, deben sí o sí utilizar la versión v0.4.3 (la actual) en adelante.
Para entender el error, debemos analizar la implementación del buffer circular y la arquitectura de 32bits. Mi lib, para manejar los buffers, utiliza indices declarados como enteros sin signo de 16bits. Como analizamos en un post de AVR, los buffers circulares tienen 2 índices, uno de entrada [tail](por donde se insertan los datos), y otro de salida [head]. La condición para que empiece la transmisión es que la resta entre el de entrada y salida sea 1, lo cual codifiqué de la siguiente manera:
if((index_in - index_out) == 1) { strart_tx(); }
Lo cual no supone problemas, ya que cuando estamos en el desborde (0 – 65535), el resultado es 1… claro, siempre y cuando el 0 y el 65535 sean enteros sin signo de 16bits. ¿Por qué? Muy fácil, para entenderlo tenemos que recordar como restan las computadoras (en CA2), es decir que la resta es la suma del Complemento a 2:
3 - 4 => 3 + (-4) = -1 0011 - 0100 => 0011 + 1100 = 1111
Entonces, ¿qué pasa cuando estamos en el mayor número entero natural? Veamos:
0 - 15 => 0 + 1 = 1 0000 - 1111 => 0000 + 0001 = 0001
Esto ocurre porque el 15 en binario natural equivale al -1 en CA2, así que mi código como estaba más arriba no debería de fallar pero, pero, pero… El problema es que el STM32F103 es un ARM Cortex-M de 32 bits, por lo tanto las operaciones son en 32bits y la comparación con [resultado] == 1
este es de 32bits y el resultado también, o sea, que la operación de dos variables de 16bits estaban siendo promocionadas a 32bits, por lo tanto, el resultado estaba lejos de ser 1
.
La solución es muy sencilla, se podría declarar una variable auxiliar, como:
uint16_t res = index_in - index_out;
if(res == 1) { strart_tx(); }
Pero, gastar una variable de más no sería una solución apropiada. Por ello, lo mejor, es «exigirle» al compilador de que el resultado sea un entero sin signo de 16bits. Con un simple casteo, santo remedio:
if ((uint16_t)(index_in - index_out) == 1) { start_tx(); }
Este pequeño (e imperceptible) error, nos recuerda que debemos ser cuidadosos con las operaciones que hacemos y testear bien las funcionalidades en los límites. En C tenemos el control absoluto de lo que ocurre, y con este casteo es aún más portable a otras arquitecturas (8, 16, 64, etc.)
Pueden ver el repo en gitlab o la lib en PlatformIO.
En un futuro próximo voy a extender la lib para poder utilizarla con cualquier STM32F1xx y luego a los otros STM32Fxxx.
Nivel: Básico ¿Qué tengo que saber para este post? Diseño básico de páginas con HTML…
Nivel: Avanzado. La modificación de fuentes ATX para su utilización en laboratorio o comunicaciones es…
El pasado 23 de abril se celebró la 18° edición del FLISoL en la que…
Circuito del regulador, con los elementos de simulación. Típicamente, las motocicletas de baja cilindrada utilizan…
¿Qué puedo decir? Siempre quise tener un analizador lógico, había visto estos pequeños y baratos…
Nivel: Intermedio ¿Qué tengo que saber para este post? Entender el uso de un ADC.Programación…
Esta web usa cookies.