2008-12-11 20 views
6

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.¿Cómo se manejan las grandes transferencias de datos en sistemas incrustados de memoria muy limitada?

Esto está trabajando actualmente completando un buffer de 256 bytes de la UART y después de ping-ponging a un otro buffer de 256 bytes siendo llenado por una interrupción en la señal de preparado búfer RX mientras el flash se escribe con escrituras ocupados. 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 separadores 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 lo 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 interrupciones frecuentes SPI bloqueaban algunas de las interrupciones UART y causando bytes se puede perder. 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.

Respuesta

3

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

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

tener uno de los bits de la bandera significa "ReadyToFlash" y otra para "intermitente". 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ía que su 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 este ajuste 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.

+0

Tenga en cuenta que 1 kB (1024 bytes) de RAM no permite muchos búferes. Sin embargo, es una buena idea. –

+0

Es cierto, aunque también podría tratar de ajustar el tamaño de los búferes (quizás 64 b), pero la sobrecarga de los indicadores comienza a afectar la eficiencia de la memoria. – joshperry

+0

Usaría una sola variable de indicador con mordiscos para cada buffer. –

4

¿El lado UART y PC de la aplicación son compatibles con 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 ISR suelte la línea CTS; si el lado de la PC está configurado para respetar el control de flujo de 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 incrustado sea considerablemente más complejo: si se trata de una compensación que está dispuesto a hacer, tendría que ser un análisis hecho por usted y su equipo gestor &.

+0

Esto sucede realmente a través de una interfaz USB y esas señales no están disponibles. Sin embargo es un buen consejo. –

4

Esto es exactamente para lo que se creó el control de flujo, sé que es un gran dolor configurar 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 utilizar 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.

+0

He usado XModem en el pasado y tengo un código para eso. Sin embargo, estoy entrando en un contrato y no puedo cambiar el cliente de PC (simplemente arroja todo el archivo a la vez). –

1

No estoy seguro de lo que me falta aquí, pero si el hecho es que la tasa promedio de datos provenientes 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 dice que funcionó cuando tenía búferes de bloque, pero ahora que tiene buffers de bytes no?

¿Puede seguir con los almacenamientos intermedios de bloque que están ocupados por la interrupción UART RX, y cuando cada memoria intermedia está llena, pasarla al código SPI/Flash para vaciar ese almacenamiento intermedio utilizando 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.

+0

El ciclo de espera para escribir una página después de la transmisión es el cuello de botella. Agregué esa información a la pregunta. –

+0

Puedo hacer que funcione con un búfer circular de 128 bytes en el UART y un búfer intermedio de 256 bytes con ocupado escribir/encuesta en el SPI. Los búferes de 128 bytes sin el intermediario 256 no funcionan. –

Cuestiones relacionadas