sistemas los ingenieria industria historia fabricantes embebidos ejemplos diversidad consumo clasificacion bajo c embedded serial-port interrupt spi

los - ¿Cómo se manejan grandes transferencias de datos en sistemas incrustados de memoria muy limitada?



sistemas embebidos de bajo consumo (4)

Tengo un microcontrolador que debe descargar un archivo grande del puerto serie de una PC (115200 baudios) y escribirlo en la memoria flash serial sobre SPI (~ 2 MHz). Las escrituras flash deben estar en bloques de 256 bytes precedidos por un comando de escritura y una dirección de página. La RAM total disponible en el sistema es de 1 kB con un tamaño de pila de 80 bytes.

Esto actualmente funciona llenando un buffer de 256 bytes del UART y luego haciendo ping-ponging a otro buffer de 256 bytes que se llena con una interrupción en la señal de RX buffer ready mientras el flash se escribe con escritura ocupada. El intercambio de buffer se repite hasta que la operación se complete.

Preferiría configurar controladores de interrupción TX / RX para los puertos SPI y UART que operan en búferes circulares separados. Por lo tanto, en lugar de buscar nuevos bytes y esperar a que se completen las operaciones, simplemente puedo completar los buffers de TX y habilitar la interrupción o verificar los buffers para los datos entrantes. Esto daría muchos más ciclos de reloj para el trabajo real en lugar de esperar a los periféricos.

Después de implementar el IRQ con buffers circulares de 128 bytes, sondeé el buffer UART RX para datos e inmediatamente los coloqué en el búfer SPI TX para hacer la transferencia de archivos. El problema que tengo con este enfoque es que no tengo suficiente RAM para los búferes y el búfer de recepción de PC se está llenando más rápido de lo que obtengo los datos en el búfer de transmisión de flash. Obviamente, la velocidad de transmisión no es el problema (115.2 kHz in y 2 MHz out), pero hay una espera de ciclo de escritura después de que se transmite cada página de 256 bytes.

Parece que las frecuentes interrupciones de SPI estaban bloqueando algunas de las interrupciones de UART y causando la pérdida de bytes. La solución que elegí fue usar un buffer de anillo para la interrupción de recepción UART y alimentar los datos en un buffer de página de 256 bytes que se envía al flash serial por sondeo para transferencias de bytes y finalización de escritura. Un buffer de 128 anillos es lo suficientemente grande como para evitar desbordamientos durante la escritura de SPI.


¿El lado UART y PC de la aplicación admite el protocolo de enlace RS-232 (control de flujo)? Si es así, cuando su búfer de recepción esté cerca de estar lleno, haga que el ISR suelte la línea CTS; si el lado de la PC está configurado para respetar el control de flujo del hardware, debe dejar de enviar cuando vea esta condición. Una vez que haya drenado (o casi drenado) el búfer de recepción, vuelva a afirmar CTS y la PC debería comenzar a enviar de nuevo.

Tenga en cuenta que esto hace que el software en el dispositivo incorporado sea considerablemente más complejo: si usted y su gerente y equipo desean realizar una transacción, esto tendría que ser un análisis.


Esto es exactamente para lo que se creó el control de flujo, sé que es un gran problema para configurarlo, pero si habilita el control de flujo en la línea serie, sus problemas serían historia.

Supongo que está transfiriendo un archivo binario, por lo que XON-XOFF no es la mejor solución, lo que deja el control del flujo de hardware.

Otra opción es usar un protocolo con control de flujo incorporado como XModem. Tengo un proyecto integrado similar donde el flash está escrito en páginas de 128 bytes. Qué coincidencia es que XModem envíe datos en bloques de 128 bytes y luego espera un ACK antes de enviar el siguiente.


Haría algo así como un scatter gather en una PC. Crea una lista vinculada de una estructura como esta:

typedef struct data_buffer { char flags; char[128] data; }

Tener uno de los bits en la bandera significa "ReadyToFlash" y uno para "Flashing". Debería poder sintonizar la cantidad de búferes en su lista vinculada para evitar que el flash capture el UART mientras se escribe o viceversa.

Si el flash llega a un bloque de almacenamiento intermedio que no es "ReadyToFlash", se detendría y necesitarías que tu UART IRQ lo inicie de nuevo. Si el UART llega a un bloque que está "ReadyToFlash" o "Flashing" se está llenando demasiado rápido y es probable que necesite otro buffer, si tiene memoria dinámica puede hacer esta sintonización en tiempo de ejecución y agregar un buffer a la lista sobre la marcha De lo contrario, solo tendrá que hacer algunas pruebas empíricas.


No estoy seguro de lo que me falta aquí, pero si el hecho es que la tasa promedio de datos que provienen de la PC es más alta que la tasa promedio, puedes escribirla en el flash, entonces vas a necesitar mucha RAM , o vas a necesitar control de flujo.

¿Pero está diciendo que funcionó cuando tenía búferes de bloque, pero ahora que tiene búferes de bytes no?

¿Puedes quedarte con los almacenamientos intermedios de bloques que se llenan con la interrupción UART RX, y cuando cada memoria intermedia está llena, pasarla al código SPI / Flash para vaciar ese buffer usando la interrupción SPI? Eso le ahorrará copiar cada byte, y en lugar de tener que hacer la lógica del buffer circular dos veces para cada byte, solo tendrá que hacerlo para cada bloque.