O que posso fazer se ficar sem memória Flash ou SRAM?

28

De acordo com a documentação do Arduino, o ATmega328 possui 32 KB de memória Flash para o carregador de inicialização + esboço enviado e apenas 2 KB de SRAM para dados de tempo de execução. O ATmega2560 possui um pouco mais, totalizando 256 KB e 8 KB, respectivamente.

Em ambos os casos, esses limites parecem bastante pequenos, especialmente quando comparados a dispositivos de consumo de tamanho semelhante, como smartphones.

O que você pode fazer se acabar? Por exemplo, se seu esboço é muito grande ou você precisa processar muitos dados (como seqüências de caracteres) em tempo de execução? Existe alguma maneira de expandir o Flash ou SRAM?

Peter Bloomfield
fonte
Tente usar alguma otimização de variável. Algumas variáveis ​​diferentes são discutidas aqui
TheDoctor
11
Use escopos adequados para suas variáveis, se ainda não o fizer, o compilador otimizará o uso de RAM para você quando as variáveis ​​não forem utilizadas.
jippie
11
Você pode realmente usar um Teensy 3.2 (com Teensyduino Software), que seria comparável a um Arduino. Dado que você está ficando sem memória RAM / PROGMEM, isso também significa que você provavelmente está tentando fazer com que o Arduino seja pressionado. Um Teensy 3.2 não é muito mais caro. mas possui: 32bit, 72MHz (wtf !?) 256KB FLASH e 64KB RAM e 3x UART. Não há mais memória de programa como o ATmega2560, mas a RAM e o aumento de velocidade devem ser suficientes.
Paul

Respostas:

30

Otimização
A programação de baixo nível para sistemas embarcados é bem diferente da programação para dispositivos de uso geral, como computadores e telefones celulares. A eficiência (em termos de velocidade e espaço) é muito mais importante porque os recursos são escassos. Isso significa que a primeira coisa a fazer se você ficar sem espaço é olhar para quais partes do seu código você pode otimizar.

Em termos de redução do uso do espaço do programa (Flash), o tamanho do código pode ser bastante difícil de otimizar se você não tiver experiência ou se está mais acostumado a programar para computadores desktop que não tendem a precisar dessa habilidade. Infelizmente, não existe uma abordagem de 'bala mágica' que funcione para todas as situações, embora ajude se você considerar seriamente o que seu esboço realmente precisa ter. Se um recurso não for necessário, remova-o.

Às vezes, também é útil identificar onde várias partes do seu código são iguais (ou muito semelhantes). Você pode condensá-los em funções reutilizáveis, que podem ser chamadas de vários locais. No entanto, esteja ciente de que, às vezes, tentar tornar o código muito reutilizável acaba por torná-lo mais detalhado. É um equilíbrio difícil de atingir que tende a vir com a prática. Passar algum tempo olhando como as alterações de código afetam a saída do compilador pode ajudar.

A otimização dos dados de tempo de execução (SRAM) tende a ser um pouco mais fácil quando você está acostumado. Uma armadilha muito comum para programadores iniciantes é usar muitos dados globais. Qualquer coisa declarada no escopo global existirá durante toda a vida útil do esboço, e isso nem sempre é necessário. Se uma variável for usada apenas dentro de uma função e não precisar persistir entre as chamadas, torne-a uma variável local. Se um valor precisar ser compartilhado entre funções, considere se você pode passá-lo como um parâmetro em vez de torná-lo global. Dessa forma, você só usará SRAM para essas variáveis ​​quando realmente precisar.

Outro fator importante para o uso da SRAM é o processamento de texto (por exemplo, usando a Stringclasse). De um modo geral, você deve evitar operações de String, se possível. Eles são enormes porcos da memória. Por exemplo, se você estiver enviando muito texto para serial, use várias chamadas para, em Serial.print()vez de usar a concatenação de cadeias. Tente também reduzir o número de literais de string no seu código, se possível.

Evite recursão, se possível também. Cada vez que é feita uma chamada recursiva, a pilha aumenta ainda mais o nível. Refatorar suas funções recursivas para serem iterativas.

Usar EEPROM A
EEPROM é usada para armazenamento de longo prazo de itens que mudam apenas ocasionalmente. Se você precisar usar listas grandes ou tabelas de consulta de dados fixos, considere armazená-las na EEPROM com antecedência e retire apenas o necessário quando necessário.

Obviamente, a EEPROM é bastante limitada em tamanho e velocidade e possui um número limitado de ciclos de gravação. Não é uma ótima solução para limitações de dados, mas pode ser suficiente para aliviar a carga no Flash ou SRAM. Também é possível interagir com armazenamento externo semelhante, como um cartão SD.

Expansão
Se você esgotou todas as outras opções, a expansão pode ser uma possibilidade. Infelizmente, não é possível expandir a memória Flash para aumentar o espaço do programa. No entanto, é possível expandir a SRAM. Isso significa que você pode refatorar seu esboço para reduzir o tamanho do código às custas do aumento do tamanho dos dados.

Obter mais SRAM é realmente bastante simples. Uma opção é usar um ou mais chips 23K256 . Eles são acessados ​​via SPI e existe a biblioteca SpiRAM para ajudá-lo a usá-los. Apenas tenha cuidado que eles operam em 3.3V e não em 5V!

Se você estiver usando o Mega, poderá obter os escudos de expansão SRAM em Lagrangian Point ou Rugged Circuits .

Peter Bloomfield
fonte
11
Você também pode armazenar dados constantes na memória do programa, em vez da SRAM, se tiver problemas de espaço na SRAM e liberar memória do programa. Veja aqui ou aqui
Connor Wolf
11
Outra ótima alternativa à EEPROM é um cartão SD. Ele ocupa algumas portas de E / S, mas se você precisar de muito espaço para, digamos, dados de mapa ou similares, pode ser fácil trocar e editar com um programa personalizado em um PC.
Anonymous Penguin
11
As pessoas não devem ser incentivadas a usar SRAMs SPI ou expansões de RAM, se estiverem com pouca memória. Isso é apenas um desperdício de dinheiro. Escolher um MCU maior seria mais barato. Além disso, o desempenho pode ser muito ruim. É preciso primeiro fazer uma estimativa aproximada: se o uso estimado da RAM estiver muito próximo do limite, você estará escolhendo a placa / microcontrolador / plataforma de desenvolvimento errada. Certamente, o bom uso (armazenamento de strings no flash) e a otimização (evitando o uso de algumas bibliotecas) podem ser verdadeiras transformações. No entanto, neste momento, não vejo benefícios em usar a plataforma Arduino Software.
next-hack
24

Quando você faz o upload do seu código para o seu Arduino, digamos um Uno, por exemplo, ele informa quantos bytes ele usa dos 32K disponíveis. É a quantidade de memória flash que você tem (pense no disco rígido do computador). Enquanto seu programa está em execução, ele está usando o que é chamado SRAM, e há muito menos disponível.

Às vezes, você notará que seu programa está se comportando de maneira estranha em um ponto que você nem toca há um tempo. Pode ser que suas alterações mais recentes causem falta de memória (SRAM). Aqui estão algumas dicas sobre como liberar algumas SRAM.

Armazenando seqüências no Flash em vez de SRAM.

Uma das coisas mais comuns que eu vi é que o chip está ficando sem memória porque há muitas seqüências longas.

Use a F()função ao usar seqüências de caracteres para que sejam armazenadas no Flash em vez de SRAM, pois você tem muito mais disponível.

Serial.println(F("This string will be stored in flash memory"));

Use os tipos de dados certos

Você pode salvar um byte alternando de um int(2 bytes) para um byte(1 byte). Um byte não assinado fornecerá de 0 a 255, portanto, se você tiver números que não ultrapassem 255, salve um byte!

Como sei que estou ficando sem memória?

Normalmente, você observa seu programa se comportando de forma estranha e se pergunta o que deu errado ... Você não alterou nada no código perto do ponto em que ele estava estragando, então o que dá? Está ficando sem memória.

Existem algumas funções para lhe dizer quanta memória disponível você possui.

Memoria disponivel

sachleen
fonte
Você sabe se a F()coisa é uma função específica do Arduino ou está nas bibliotecas do AVR? Você poderia considerar mencionar PROGMEM const ...também.
jippie
Além disso, você pode usar estruturas de bits para reduzir ainda mais o espaço usado por suas variáveis ​​5eg se você lidar com muitos valores booleanos).
Jfpoilpret
17

Além do que outros disseram (com o qual concordo plenamente), aconselho a ler este artigo adafruit sobre memória; está bem escrito, explica muitas coisas sobre a memória e fornece dicas sobre como otimizá-la.

No final da leitura, acho que você obteria uma resposta completa para sua pergunta.

Para resumir, você tem 2 destinos de otimização possíveis (dependendo da localização dos problemas de memória):

  • Flash (ou seja, memória do programa); para isso, você pode:
    • remova o código morto (por exemplo, qualquer código incluído, mas não usado) e variáveis ​​não utilizadas (que também ajuda na SRAM)
    • fatorar código duplicado
    • remova o gerenciador de inicialização completamente (você pode ganhar entre 0,5K para um UNO e 2 ou 4K para outros modelos do Arduino); isso tem algumas desvantagens embora
  • SRAM (ou seja, pilha, pilha e dados estáticos); para isso você pode:
    • remover variáveis ​​não utilizadas
    • otimizar o tamanho de cada variável (por exemplo, não use -4 bytes longos, se você precisar apenas de int -2 bytes)
    • use o escopo certo para suas variáveis ​​(e prefira pilha a dados estáticos quando possível)
    • reduza o tamanho dos buffers ao mínimo estrito
    • mova dados constantes para PROGMEM (ou seja, seus dados estáticos permanecerão na memória Flash e não serão copiados para SRAM no início do programa); que também se aplica a cadeias constantes para as quais você pode usar F()macro)
    • evitar alocação dinâmica se não for absolutamente necessário; você evitará uma pilha fragmentada que pode não encolher, mesmo depois de liberar memória

Uma abordagem adicional para reduzir o uso de SRAM também é descrita (mas raramente usada, porque é um pouco pesada ao codificar e não é muito eficiente), consiste em usar a EEPROM para armazenar dados criados pelo seu programa, mas não é usada até mais tarde, quando algumas condições ocorrer, quando os dados puderem ser carregados de volta na EEPROM.

jfpoilpret
fonte
11
Remoção de código morto - o compilador é muito bom em lidar com isso para você - não fará diferença se você tiver muito código que nunca é chamado. Se você acidentalmente ligar para um código que não precisa, isso é diferente, é claro.
dethSwatch
9

Há duas coisas a fazer se você ficar sem armazenamento:

  • De alguma forma, "otimize" seu código para que ele precise de menos armazenamento; ou pelo menos usa menos do tipo específico de armazenamento que você esgotou (e usa mais do tipo de armazenamento que você ainda tem bastante). Ou,
  • Adicione mais armazenamento.

Há muitas dicas on-line sobre como fazer o primeiro (e para a grande maioria das coisas que as pessoas fazem com o Arduino, o armazenamento interno é mais do que suficiente após a "otimização"). Então, vou me concentrar no segundo:

Existem três coisas que usam flash ou SRAM; cada um precisa de uma abordagem ligeiramente diferente para adicionar armazenamento:

  • armazenamento variável: é possível expandir a SRAM, como sachleen já apontou. SRAM, FRAM e NVSRAM são todos apropriados para variáveis ​​que mudam rapidamente. (Embora, em princípio, você possa usar o flash para armazenar variáveis, precisa se preocupar com o desgaste do flash). O SPI (um protocolo serial) é o mais fácil de conectar ao Arduino. A biblioteca SpiRAM funciona com o chip SRAM serial Microchip 23K256 . O chip FRAM serial Ramtron FM25W256 (agora de propriedade da Cypress) também usa SPI. O Cypress CY14B101 NVSRAM também usa SPI. Etc.

  • dados constantes que ainda precisam estar disponíveis na próxima vez que ligar: isso é quase tão simples quanto expandir a SRAM. Existem muitos dispositivos de armazenamento externos EEPROM, FRAM, NVSRAM e FLASH disponíveis. Atualmente, o menor custo por MB são cartões flash SD (que podem ser acessados ​​via SPI). O Ramtron FM25W256 (veja acima), o Cypress CY14B101 (veja acima) etc. também podem armazenar dados constantes. Muitos escudos de expansão incluem um slot para cartão SD, e várias bibliotecas e tutoriais suportam a leitura e gravação em cartões SD (flash). (Não podemos usar a SRAM para isso, porque a SRAM esquece tudo quando a energia acaba).

  • código executável: Infelizmente, não é possível expandir a memória Flash de um Arduino para aumentar o espaço do programa. No entanto, um programador sempre pode refatorar um esboço para reduzir o tamanho do código às custas do aumento do tamanho dos dados e da execução um pouco mais lenta. (Em teoria, você pode traduzir o esboço inteiro em algum idioma interpretado, armazenar essa versão em um cartão SD e, em seguida, escrever um intérprete para o idioma que é executado no Arduino para buscar e executar instruções do Cartão SD - adiante, no Arduino , um intérprete BASIC, um intérprete Tom Napier Picaro, algum idioma específico do aplicativo etc.).

David Cary
fonte