Erros de leitura / gravação de EEPROM no dsPIC

8

Estou executando um Microchip dsPIC30F6012a. Eu tenho esse chip em vários PCBs, todos executando o mesmo software e observo o mesmo problema em todos eles. Isso implica um problema sistêmico, não um problema pontual de produção. O problema também é reproduzível, o que implica que eu devo matá-lo se souber onde procurar. Mas ainda estou tendo dificuldades surpreendentes para depurar o aplicativo.

A placa em teste aceita 24V, que é reduzida para 5V através de um V7805. O chip roda em seu oscilador interno, com um PLL 16x, proporcionando uma velocidade de operação de ~ 29,5 MIPS. O código relevante nesta placa é essencialmente muito simples: acorde, leia os dados da EEPROM e insira um loop infinito. Interrompa a cada milissegundo, observe alguns dados ambientais e escreva um valor atualizado na EEPROM. Há outras coisas acontecendo, mas o problema ainda ocorre mesmo que o código não relacionado seja comentado, para que eu possa ter certeza de que não é relevante para o problema em questão.

Em uso geral, 95% das vezes o conselho acorda com o valor correto na memória e continua seus negócios. Os outros 5% do tempo, porém, acordam com um valor incorreto. Especificamente, ele acorda com uma versão invertida dos dados que deveria ter. É um comprimento de quatro bytes sem assinatura que estou assistindo, e a palavra superior ou inferior do comprimento pode ser alterada. Por exemplo, 10 se torna 2 ^ 16-10, que mais tarde se torna 2 ^ 32-10. Posso reproduzir a falha alternando manualmente a energia várias dúzias de vezes, mas isso não é muito consistente, e meu dedo está gasto.

Para reproduzir o problema de maneira controlada, construí uma segunda placa que conduz o fornecimento de 24V à placa em teste. (Outro dsPIC dirigindo um acoplador óptico de darlington.) A placa do testador desliga os 24V por 1,5 segundos (tempo suficiente para que o trilho de 5V caia para essencialmente 0 e fique lá por um segundo), depois liga os 24V por um período de tempo configurável . Com um tempo de funcionamento de aproximadamente 520 mS, posso reproduzir essa falha da EEPROM em cinco ciclos de energia, todas as vezes.

O trilho de 5V está se comportando razoavelmente. Ele se instala em 5V a 1 mS de ativação, com talvez 0,4V de superação, supondo que eu possa confiar no meu escopo. No desligamento, decai para 0V exponencialmente, atingindo 1V dentro de 50 mS. Não tenho avisos de compilação que pareçam relevantes, apenas variáveis ​​não utilizadas e novas linhas ausentes no final dos arquivos.

Eu tentei várias coisas:

  • Ativando / Desativando o MCLR
  • Ativando / desativando o WDT
  • Ativando / desativando a proteção de código
  • Ativar / desativar / alterar a tensão de detecção de queda de energia
  • Ativando / Desativando / Alterando o Temporizador de Inicialização
  • Configurações diferentes de PLL no oscilador interno principal
  • Ligar / desligar o meu programador PICkit 3
  • Adicionando 470 uF de capacitância ao trilho de 5V
  • Adicionando / removendo .1 uF no pull-up de 4,7k no meu pino MCLR
  • Desabilitando todas as interrupções no código e deixando apenas as atualizações de EEPROM no loop principal
  • Adicionando um atraso de 1,5 segundo à minha rotina de inicialização antes de começar a ler EEPROM

Também escrevi um código de teste separado, que não faz nada, mas grava valores continuamente na EEPROM e os lê novamente, certificando-se de que o valor não seja alterado. Dezenas de milhares de iterações não deram erros. Tudo o que posso concluir é que algo dá errado com a leitura ou gravação da EEPROM, especificamente na inicialização / desligamento.

Eu uso as mesmas bibliotecas da EEPROM desde 2007. Vi falhas ocasionais, mas nada reproduzível. O código relevante pode ser encontrado aqui:
http://srange.net/code/eeprom.c
http://srange.net/code/readEEByte.s
http://srange.net/code/eraseEEWord.s
http: / /srange.net/code/writeEEWord.s

Já vi erros de EEPROM em outros aplicativos, mas sempre como falhas pontuais, nada tão reprodutível ou consistente.

Alguém tem alguma idéia do que está acontecendo? Estou ficando sem coisas para tentar.

Stephen Collings
fonte
Por favor, veja aqui para uma atualização em resolver este problema: electronics.stackexchange.com/questions/38083/...
Stephen Collings

Respostas:

3

Duas coisas me vêm à mente:

Primeiro, de acordo com a folha de dados, um ciclo de apagamento-gravação leva pelo menos 0,8 ms e até 2,6 ms. Você diz que tem uma interrupção a cada 1 ms, o que pode levar a uma operação de gravação. Eu vi no código que você desativa as interrupções para partes do apagamento e partes da função de gravação. Mas você ainda pode ter uma intercalação engraçada das chamadas de função. Talvez ajude quando você desativa as interrupções durante toda a sequência de apagar e gravar?

Segundo - você pode escrever enquanto a energia diminui, e a gravação na EEPROM acontece exatamente no momento em que a tensão de alimentação fica abaixo da tensão operacional. Você pode tentar monitorar a tensão de alimentação e recusar uma gravação quando estiver abaixo, digamos, de 4,5V. Isso pressupõe que ele permaneça longo o suficiente acima de 2,7V como a tensão operacional mínima e a detecção de desmaios está definida para disparar apenas abaixo desse ponto.

hli
fonte
Você está perto! O ciclo é apagar-> escrever, portanto, se o desligamento ocorrer entre apagar e gravar, você perderá seus dados. Minha primeira solução foi dividir a EEPROM em várias cópias redundantes, que são automaticamente verificadas quanto a inconsistências. Mas como isso consumiu 3/4 da minha EEPROM, estou substituindo-a por um buffer de gravação simples. O buffer será um bloco EEPROM especial que contém os dados a serem gravados, o endereço no qual gravar e um sinalizador indicando que a gravação ainda não está concluída. Isso deve resolver o problema e ocupar muito menos espaço.
Stephen Collings
Agora posso confirmar que minha abordagem baseada em buffer funciona e não sofre perda de dados devido ao desligamento assíncrono entre apagar e gravar.
Stephen Collings
5

Você analisou muitos possíveis problemas de hardware. Tudo bem, mas isso provavelmente é um bug de firmware.

Infelizmente, seu código-fonte está mal documentado e está formatado para ser difícil de seguir visualmente. Seu primeiro arquivo contém uma declaração de rotinas externas na parte superior:

void readEEByte (unsigned int, unsigned int, void *);
void eraseEEWord (int não assinado, int não assinado);
void writeEEWord (sem sinal int, sem sinal int, vazio *);

Não é apenas uma má idéia colocar declarações como essa privadas nos módulos do cliente, não há um único comentário à vista! Podemos apenas adivinhar o que você pretende que essas rotinas façam a partir do nome deles, e os argumentos de chamada são completamente indocumentados. Além desse arquivo, você tem várias linhas começando com "//" e uma linha inteira de sinais de igual. Isso aumenta a desordem visual, dificultando a tentativa de seguir o código.

Você pode dizer que nada disso importa para a operação do código. No entanto, práticas de programação ruins como essa são muito importantes. Eles fazem com que o código seja mal escrito e dificultam a detecção de bugs ou mesmo o que o código deve fazer. Tudo isso resulta em uma espreita difícil de encontrar problemas, como você está descobrindo. Você até disse a si mesmo que ocasionalmente viu falhas neste código desde 2007. Essa deveria ter sido uma forte pista de um bug, possivelmente até de um design geral ruim.

Corrija a bagunça, documente corretamente todas as interfaces e coloque declarações comuns em arquivos de inclusão que você escreve uma vez e depois faça referência quando necessário. Além disso, sua declaração de que não tenho avisos de construção que parecem relevantes é uma enorme bandeira vermelha. Mais uma vez, arrume a bagunça. Ao depurar, sempre procure primeiro os problemas facilmente reproduzíveis e corrigíveis. Às vezes, esses são realmente a causa dos problemas difíceis ou, às vezes, ao corrigi-los, você descobre a causa de outros problemas. O compilador está avisando sobre falta de atenção em uma bandeja de prata. O que mais você quer? Você não deve ter variáveis ​​não utilizadas, porque elas causam confusão para quem tenta entender o seu código, e não há desculpa para perder novas linhas. Mais uma vez, corrija a bagunça óbvia deles, especialmente antes de pedir a alguém para examinar seu código.

Limpeza e atenção aos detalhes são importantes . Muito.

 

Olin Lathrop
fonte
Você está certo sobre o código. Só para esclarecer, comecei a usar esse código há cinco anos, mas alguém o escreveu. Não escrevo coisas assim. Eu ainda deveria consertá-lo, e não é bom que eu não tenha. Só para que eu não pareça muito idiota. :-)
Stephen Collings
2
É fácil acessar a EEPROM interna. Para coisas tão simples, é mais fácil escrever seu próprio código do que tentar descobrir como o bugware de outra pessoa funciona e depois corrigi-lo até que pareça funcionar. Leia a folha de dados e escreva o código. Você terminaria em uma hora.
Olin Lathrop
Eu concordo com o Olin aqui, pois é provavelmente o firmware. A errata da peça menciona que nada é suspeito com a EEPROM.
Adam Lawrence
2
@Madmad - folhas de Errata não pode dizer que há algo suspeito com a parte, mas eles nunca vou dizer que não há nada duvidoso com ele :-)
stevenvh
1
@stevenvh Minhas relações com a Microchip e suas FAE têm sido positivas. As erratas para as partes que eu estou usando foram precisas e elas surgiram para nos ajudar com problemas, muitas vezes encontrando soluções alternativas para nós.
Adam Lawrence
0

Eu tive um comportamento idêntico com 4 peças de dsPIC30F6014A (cerca de 10 usadas nos últimos meses ..), a única maneira de evitar a corrupção esporádica de dados durante o desligamento é zerar o MCLR antes do desligamento.

Obviamente, isso não é viável na prática, então optei pela substituição do dsPIC "ruim", se alguém tiver outra solução ...

Angelo
fonte
3
Por que isso não seria viável? A detecção de quedas de energia é feita muito, mesmo para salvar dados na EEPROM nos últimos ms.
Stevenvh 12/09/12