Programar AVR EEPROM diretamente da fonte C

11

Quando você inclui o seguinte código em uma fonte do AVR C, aparentemente pode programar diretamente os fusíveis, sem a necessidade de um comando extra ou arquivo .hex:

#include <avr/io.h>

FUSES = {
        .low =          LFUSE_DEFAULT ,
        .high =         HFUSE_DEFAULT ,
        .extended =     EFUSE_DEFAULT ,
};

Existe um truque semelhante para programar valores na EEPROM?

Verifiquei /usr/lib/avr/include/avr/fuse.honde posso encontrar alguns comentários sobre uma macro, mas não consigo encontrar um comentário semelhante /usr/lib/avr/include/avr/eeprom.he interpretar o material do pré-processador está um pouco fora do meu alcance.

Seria realmente útil se eu pudesse incluir valores EEPROM padrão no código-fonte C. Alguém sabe como fazer isso?

edit1:

Esse truque do FUSES é executado apenas no tempo do ISP, não no tempo de EXECUÇÃO. Portanto, não há fusíveis sendo programados no código de montagem resultante no controlador. Em vez disso, o programador passa automaticamente por um ciclo de programação extra do FUSES.

edit2:

Eu uso as ferramentas avr-gcc e avrdude no Linux.

jippie
fonte
Isso é apenas ao programar ISP? A maioria dos gerenciadores de inicialização não permite que você programe fusíveis, certo?
angelatlarge
2
Não tenho tempo para escrever uma resposta completa no momento, mas como sugestão, tente uma pesquisa na diretiva EEMEM. Além disso, pode ser necessário alterar a configuração do vinculador para criar um arquivo .EPP separado que o programador usará.
precisa
@angelatlarge Apenas programação ISP. Não há carregador de inicialização nesta configuração.
jippie
2
Observe que as respostas para isso dependem inteiramente do que a cadeia de ferramentas está disposta a registrar em sua saída e do que o programador está disposto a analisar. A maioria das cadeias de ferramentas pode ser configurada para criar uma seção especial (ou colocar os dados em um endereço fictício); portanto, tudo depende do programador poder extraí-lo ou ser orientado por um script personalizado que o faria.
Chris Stratton

Respostas:

7

Com o avr-gcc, a EEMEMmacro pode ser usada na definição de uma variável, consulte os libcdocumentos e um exemplo aqui :

#include <avr/eeprom.h>
char myEepromString[] EEMEM = "Hello World!";

declara que a matriz de caracteres reside em uma seção chamada ".eeprom" que, após a compilação, informa ao programador que esses dados devem ser programados na EEPROM. Dependendo do software do programador, pode ser necessário fornecer explicitamente o nome do arquivo ".eep" criado durante o processo de compilação ao programador, ou ele pode ser implicitamente encontrado sozinho.

JimmyB
fonte
Eu usei um nome de arquivo um pouco diferente do que eu deveria, mas estes são os comandos que eu incluí para programar EEPROM a partir da linha de comando (e makefile):
jippie
1
Crie um arquivo que contenha dados Intel Hex usados ​​pelo programador:avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 ihex $(src).elf $(src).eeprom.hex
jippie 30/03
1
A programação real é feita por:avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U eeprom:w:$(src).eeprom.hex
jippie 30/03
7

Sim, você pode gravar manualmente os dados padrão na EEPROM no código-fonte. Primeiro, confira este guia incrível sobre a EEPROM com o AVR: Tutorial do AVR EEPROM de Dean. Além disso, devo acrescentar que é uma idéia melhor criar um arquivo .eep contendo os dados da EEPROM usando o makefile que será programado no dispositivo junto com o código-fonte. No entanto, se você não estiver familiarizado com várias operações de makefile e vinculador, isso ainda poderá ser feito no seu arquivo de código-fonte - isso acontecerá assim que o circuito for ligado, interrompendo a operação inicial do programa.

No início do programa (antes de qualquer tipo de loop principal), você poderia fazer algo assim:

#include <avr/eeprom.h>

#define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_2 52  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_3 68  // This could be anything from 0 to the highest EEPROM address

uint8_t dataByte1 = 0x7F;  // Data for address 1
uint8_t dataByte2 = 0x33;  // Data for address 2
uint8_t dataByte3 = 0xCE;  // Data for address 3

eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);

A função "update" verifica primeiro se esse valor já existe, para economizar gravações desnecessárias, preservando a vida útil da EEPROM. No entanto, fazer isso em muitos locais pode demorar um pouco. Talvez seja melhor verificar um único local. Se esse for o valor desejado, o restante das atualizações poderá ser ignorado completamente. Por exemplo:

if(eeprom_read_byte((uint8_t*)SOME_LOCATION) != DESIRED_VALUE){
  eeprom_write_byte((uint8_t*)SOME_LOCATION, DESIRED_VALUE);
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
  eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
  eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);
}

Se você deseja atualizar grandes quantidades de dados, tente usar outras funções, como eeprom_update_block(...). E definitivamente leia esse tutorial; está bem escrito.

Você pode colocar todas as instruções de atualização da EEPROM em uma única instrução condicional do pré-processador. Isso é muito simples de fazer:

#if defined _UPDATE_EEPROM_
  #define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
  uint8_t dataByte = 0x7F;  // Data for address 1
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
#endif // _UPDATE_EEPROM_

Esse bit de código nem será compilado, a menos que você faça o seguinte:

#define _UPDATE_EEPROM_

Você pode deixar isso como um comentário e, em seguida, descomentar se precisar alterar os valores padrão da EEPROM. Para obter mais informações sobre o pré-processador C, consulte este manual online . Acho que você pode estar mais interessado nas seções sobre macros e declarações condicionais.

Kurt E. Clothier
fonte
Parece que a resposta correta está no último parágrafo do PDF vinculado. Ch. 7 Setting Initial Values.
jippie
Sim você está correto. Mencionei isso no meu primeiro parágrafo, mas continuei caso você não estivesse familiarizado com os arquivos .eep e o vinculador no makefile!
Kurt E. Clothier
1
Usar endereços EEPROM estáticos é uma prática recomendada. É melhor usar o atributo EEMEM e deixar o compilador gerenciar a distribuição de endereços. Além disso, eu recomendaria implementar / executar uma verificação CRC em cada seção. Se o CRC falhar, a seção correspondente conterá dados não inicializados ou corrompidos. Dessa forma, você pode implementar um mecanismo de fallback para a configuração anterior em caso de corrupção de dados.
Rev1.0
"Usar endereços EEPROM estáticos é uma má prática." Por quê?
angelatlarge
1
Ao usar EEMEMvariáveis, o compilador cuida do gerenciamento de qual variável reside onde está na EEPROM. Dessa forma, você opera apenas em ponteiros (constantes, gerados pelo compilador) para variáveis ​​ao acessar os dados. Se, por outro lado, você definir explicitamente o endereço em que cada variável reside, terá que cuidar desses endereços, inclusive assegurando que nenhuma variável ocupe acidentalmente o mesmo endereço, substituindo-se; ou recalcular todos os endereços, caso o tamanho de armazenamento de uma variável seja alterado no futuro etc.
JimmyB 27/13/13