Como você lida com grandes transferências de dados em memória muito restritos, sistemas embarcados?

StackOverflow https://stackoverflow.com/questions/359745

Pergunta

Eu tenho um microcontrolador que deve baixar um arquivo grande a partir de uma porta serial do PC (115200 baud) e escrevê-lo para a memória flash de série sobre SPI (~ 2 MHz). As gravações de flash deve estar em 256 blocos de bytes precedido por um comando de escrita e endereço da página. A memória RAM total disponível no sistema é 1 kB com um tamanho da pilha 80 byte.

Este está actualmente a trabalhar por um tampão de enchimento de 256 bytes a partir do UART e, em seguida, de ping-ponging para um outro byte de tampão 256 sendo preenchido por uma interrupção no sinal de pronto RX tampão enquanto o flash é escrito para com gravações ocupados. A troca de tampão é repetido até que a operação está completa.

Eu preferiria configuração TX / RX interrupção manipuladores para os portos SPI e UART que operam em buffers circulares separadas. Então, em vez de voto para novos bytes e à espera de operações para completar eu posso simplesmente encher os buffers TX e habilitar a interrupção ou verificar os buffers para dados de entrada. Isso daria muito mais ciclos de clock para o trabalho real em vez de esperar em periféricos.

Depois de implementar o IRQ Com buffers circulares 128 bytes, eu sondar tamponar o UART RX para dados e imediatamente colocá-lo no SPI TX tampão para fazer a transferência de arquivos. O problema que estou tendo com esta abordagem é que eu não tenho RAM suficiente para os buffers e o PC buffer de recepção está enchendo mais rápido do que eu recebo os dados para o flash de transmissão tampão. Obviamente, a velocidade de transmissão não é o problema (115,2 kHz e 2 MHz), mas há uma espera ciclo de gravação depois de cada página de 256 bytes é transmitido.


Parece que as interrupções SPI freqüentes estavam bloqueando algumas das interrupções UART e causando bytes para ser desperdiçada. A solução que escolheu era usar um tampão de anel para o UART interrupção de recebimento e alimentar os dados para um tampão de byte página 256 que é enviada para o flash em série por sondagem de transferências de bytes e conclusão de gravação. Um tampão 128 do anel é suficientemente grande para evitar excessos durante a gravação SPI.

Foi útil?

Solução

Eu faria algo como uma dispersão reunir em um PC. Criar uma lista ligada de um struct como este:

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

Tem um dos bits na bandeira média "ReadyToFlash" e outra para "intermitente". Você deve ser capaz de ajustar o número de buffers na sua lista ligada para manter o flash de pegar o UART como ele escreve, ou vice-versa.

Se o flash fica a um bloco de buffer que não é "ReadyToFlash" seria parar e você precisa ter o seu UART IRQ iniciar-lo de volta. Se o UART chega a um bloco que é "ReadyToFlash" ou "intermitente" é encher muito rápido e você provavelmente precisa de outro buffer, se você tem memória dinâmica que você poderia fazer este ajuste em tempo de execução e adicionar um buffer para a lista on the fly , caso contrário, você só precisa fazer alguns testes empíricos.

Outras dicas

Será que a UART e do lado do PC do suporte de aplicações RS-232 handshaking (controle de fluxo)? Se assim for, quando seu buffer de recepção fica perto de ser completo, ter o ISR cair a linha CTS - se o lado do PC está configurado para respeitar o controle de fluxo de hardware que deve parar de enviar quando vê essa condição. Depois de ter drenado (ou quase drenado) o buffer de recepção, assert CTS novamente eo PC deve começar a enviar novamente.

Note que este faz com que o software no dispositivo incorporado consideravelmente mais complexo -. Se isso é um trade-off que você está disposto a fazer teria de ser análise feita por você e seu gerente e equipe

Este é exatamente o controle de fluxo foi criado para, eu sei que é uma enorme dor de configurar, mas se você ativar o controle de fluxo na linha serial seus problemas seria história.

Eu estou supondo que você está transferindo um arquivo binário de modo XON-XOFF não é a melhor solução, o que deixa o controle de fluxo de hardware.

Outra opção é usar um protocolo com um controle de fluxo, tais como XModem. Eu tenho um projeto incorporado semelhante onde o flash é escrito em páginas 128byte. Que coincidência que XModem envia dados em blocos 128byte então aguarda um ACK antes de enviar o seguinte.

Não sei o que eu estou sentindo falta aqui, mas se o fato é que a taxa média de dados proveniente do PC é maior do que a taxa média você pode escrevê-lo para o flash, então você está indo tanto para a necessidade de um monte de RAM, ou você está indo para controle de fluxo de necessidade.

Mas você está dizendo que ele trabalhou quando você tinha buffers de bloco, mas agora que você tem buffers de bytes não faz?

Você pode ficar com os buffers de bloco que são preenchidos pela interrupção UART RX, e quando cada buffer está cheio, mão-lo para o código SPI / Flash para esvaziar esse buffer usando a interrupção SPI? Que você vai economizar copiar cada byte e, em vez de ter que fazer a lógica buffer circular duas vezes para cada byte, você só tem que fazer isso para cada bloco.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top