DataFlash - Problema com gravações sequenciais

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

DataFlash - Problema com gravações sequenciais

Mensagempor baltazar » 20 Nov 2012 15:08

Senhores,

Estou trabalhando pela primeira vez com uma memória flash e estou apanhando para conseguir gravar uma grande quantidade de pequenos pacotes.

A memória em questão é uma DataFlash SPI da Atmel modelo AT45DB321D.

O produto em questão é um coletor de dados que armazena pequenos registros a cada intervalo de tempo e isso estava funcionando bem até que resolvi implementar uma rotina para preencher a memória, chamando várias vezes a minha rotina original de armazenamento do registro, coisa bem simples.

Acontece que os dados gravados "automaticamente" apresentam lixo em alguns pontos, quando não "pulam" registros ou "ignoram" alguns.

O mais intrigante é que a cada vez que executo a rotina eu tenho um resultado diferente.

Já tentei colocar um delay entre os registros e o resultado foi o mesmo...

Alguém já teve alguma experiência parecida e pode me dar uma luz? Tenho certeza de que deve ser uma coisa simples, mas já estou ficando sem ideias aqui...

Abraços e obrigado!
baltazar
Bit
 
Mensagens: 42
Registrado em: 10 Nov 2006 18:47

Mensagempor cfreund » 20 Nov 2012 15:16

Veja se ajuda:

Lembre de ajustar o PAGESIZE. Se não me engano, são 528 bytes por padrão. Veja no datasheet.


Código: Selecionar todos
#ifndef DATAFLASH_H
#define DATAFLASH_H

#include <stdint.h>

#include <avr/io.h>
#include <avr/power.h>

#define PORT_SPI   PORTB
#define DDR_SPI      DDRB

#define DD_SCK      PB5
#define DD_MISO      PB4
#define DD_MOSI      PB3
#define DD_SS      PB2

#define SPI_NOP      0xFF

#define SPIFLASH_CONFIG_CS      DDRB  |= (1 << PB2)
#define SPIFLASH_ASSERT_CS      PORTB &= ~(1 << PB2)
#define SPIFLASH_RELEASE_CS      PORTB |= (1 << PB2)

#define CMD_DEVICEID_READ            0x9F
#define CMD_DEEP_POWER_DOWN            0xB9
#define CMD_RESUME_POWER_DOWN         0xAB
#define CMD_MAIN_MEMORY_PAGE_READ      0xD2
#define CMD_STATUS_REGISTER_READ      0xD7
#define CMD_BUFFER1_WRITE            0x84
#define CMD_BUF1_TO_MAIN_PAGE_PROGRAM   0x83
#define CMD_MAIN_MEM_PAGE_TO_BUF1      0x53

#define DATAFLASH_PAGESIZE            528

void dflash_Init(void);

uint16_t dflash_GetDeviceID(void);

uint8_t dflash_GetStatus(void);

void dflash_PowerDown(uint8_t down);

void dflash_Read(uint32_t addr, uint16_t nbytes, uint8_t *data);

void dflash_Write(uint32_t addr, uint16_t nbytes, uint8_t *data);

#endif


Código: Selecionar todos
#include "spi.h"
#include "dataflash.h"

void dflash_Init(void){
   SPIFLASH_RELEASE_CS;
   SPIFLASH_CONFIG_CS;
}

uint16_t dflash_GetDeviceID(void){
   uint16_t devid;
   
   SPIFLASH_ASSERT_CS;
   spiSendByte(CMD_DEVICEID_READ);
   devid = spiRecvByte();
   devid = (devid << 8) | spiRecvByte();
   SPIFLASH_RELEASE_CS;
   
   return devid;
}

uint8_t dflash_GetStatus(void){
   uint8_t status;
   
   SPIFLASH_ASSERT_CS;
   spiSendByte(CMD_STATUS_REGISTER_READ);
   status = spiRecvByte();
   SPIFLASH_RELEASE_CS;
   
   return status;
}

void dflash_PowerDown(uint8_t down){
   SPIFLASH_ASSERT_CS;
   if(down) spiSendByte(CMD_DEEP_POWER_DOWN); else spiSendByte(CMD_RESUME_POWER_DOWN);
   SPIFLASH_RELEASE_CS;
}

void dflash_Read(uint32_t addr, uint16_t nbytes, uint8_t *data){
   while(!(dflash_GetStatus() & (1 << 7)));
   
   if(addr) addr = ((addr / DATAFLASH_PAGESIZE) << 10) | (addr % DATAFLASH_PAGESIZE); else addr %= DATAFLASH_PAGESIZE;
   
   SPIFLASH_ASSERT_CS;
   spiSendByte(CMD_MAIN_MEMORY_PAGE_READ);
   spiSendByte(addr >> 16);
   spiSendByte(addr >>  8);
   spiSendByte(addr);
   spiSendByte(SPI_NOP);
   spiSendByte(SPI_NOP);
   spiSendByte(SPI_NOP);
   spiSendByte(SPI_NOP);
   while(nbytes--) *data++ = spiRecvByte();
   SPIFLASH_RELEASE_CS;
}

void dflash_Write(uint32_t addr, uint16_t nbytes, uint8_t *data){
   uint16_t page;
   
   if(addr) page = addr / DATAFLASH_PAGESIZE; else page = 0;
   
   while(!(dflash_GetStatus() & (1 << 7)));

   SPIFLASH_ASSERT_CS;
   spiSendByte(CMD_MAIN_MEM_PAGE_TO_BUF1);
   spiSendByte(page >> 6);
   spiSendByte(page << 2);
   spiSendByte(0);
   SPIFLASH_RELEASE_CS;
   
   while(!(dflash_GetStatus() & (1 << 7)));

   SPIFLASH_ASSERT_CS;
   spiSendByte(CMD_BUFFER1_WRITE);
   spiSendByte((addr % DATAFLASH_PAGESIZE) >> 16);
   spiSendByte((addr % DATAFLASH_PAGESIZE) >> 8);
   spiSendByte((addr % DATAFLASH_PAGESIZE));
   while(nbytes--) spiSendByte(*data++);
   SPIFLASH_RELEASE_CS;
   
   spiSendByte(SPI_NOP);

   SPIFLASH_ASSERT_CS;
   spiSendByte(CMD_BUF1_TO_MAIN_PAGE_PROGRAM);
   spiSendByte(page >> 6);
   spiSendByte(page << 2);
   spiSendByte(0);
   SPIFLASH_RELEASE_CS;
}

Avatar do usuário
cfreund
Word
 
Mensagens: 672
Registrado em: 14 Out 2006 14:02
Localização: São Paulo

Mensagempor Red Neck Guy » 20 Nov 2012 18:16

Olha eu nunca utilizei essa dataflash em questão, mas itens que tu deves observar:
1) Monitorar o flag que indica que a operação foi finalizada
2) Sempre que for escrever em uma página, transferir o conteúdo dela para o buffer ram interno ou copiar para um buffer no microcontrolador caso o a DF não possua, como nos modeloes SST25xx.
3) Nessa tua dataflash em questão existem comandos do tipo, copiar página para o buffer, aí tu alterar o buffer, manda apagar a página e programar o buffer lá. O que acontece é que a próxima escrita só pode ser feita depois de "um tempo" ou depois que o flag de busy estiver liberado.
4) Tu tem certeza que está comunicando com a memória? Tentou ler a assinatura dela?
5) Uma prática que eu adoto é ler o que escrevi na DF para ter garantia que os dados estão lá.
6) Sem conhecer o teu hardware e o teu código é só o que dá pra te ajudar.
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Mensagempor RobL » 21 Nov 2012 15:17

É isso que colocaram aí.
Só para lembrar : Estas memos gravam somente páginas, ou seja, se formos gravar um byte, em certa posição, de uma página, toda a página será gravada. Por exemplo, um byte no meio da página, que começa no endereço zero, será gravado 0xFF em toda a página e será diferente somente no seu byte.
Portanto, sua rotina, após preencher a primeira página, tem que começar exatamente, no endereço da segunda página.
O ideal é sempre estar com a ram, cheia com uma página e transferir para a flash, pois gravar um byte ou uma página leva o mesmo tempo (ordem de grandeza unidades de milisegundos).
Se sua rotina não preenche uma página, e vai enchendo-a aos poucos, uma página, deve tomar cuidado, pois neste caso, os dados já gravados, terão que estar na mesma posição na ram(serão regravados) e os novos na sequência (pois estas memos só gravam uma página sempre).
Se ainda não preencher a página e sua rotina gravar uma página, acima do último dado válido na ram, estará um lixo, de sua ram, até completar uma página.
Se sua rotina errar o endereço inicial e final de qualquer página, dados já gravados serão alterados.

Nota: mesmo quando se grava um byte, gravação randômica, neste caso, também será gravado uma página, mas em todos os dados desta página, será feita uma operação lógica, com efeito similar a uma leitura dos dados desta página e regravando, desta forma, mantendo os demais dados já gravados, nesta página, sem alteração a não ser o seu dado endereçado que será alterado.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Mensagempor tcpipchip » 21 Nov 2012 16:36

Por falar nesta memoria...voces conhecem um PROGRAMADOR barato para esta memoria ?
Tentei equinox e xeltec e é uma forturna...quero por o U-BOOT nelas....minha placa linux teste nao tem JTAG :(
Avatar do usuário
tcpipchip
Dword
 
Mensagens: 6560
Registrado em: 11 Out 2006 22:32
Localização: TCPIPCHIPizinho!

Mensagempor baltazar » 04 Dez 2012 15:21

Resolvido!

O problema, pra variar, estava nas constantes do CCS.

Quem por acaso tiver o mesmo problema, basta incluir os seguintes defines:

#define SPI_MODE_0_0 0x4000
#define SPI_MODE_0_1 0x0000
#define SPI_MODE_1_0 0x0010
#define SPI_MODE_1_1 0x4010

Os originais do CCS não configuram direito o barramento SPI.
baltazar
Bit
 
Mensagens: 42
Registrado em: 10 Nov 2006 18:47

Mensagempor andre_luis » 04 Dez 2012 16:28

tcpipchip escreveu:Por falar nesta memoria...voces conhecem um PROGRAMADOR barato para esta memoria ?
Tentei equinox e xeltec e é uma forturna...quero por o U-BOOT nelas....minha placa linux teste nao tem JTAG :(


A muito tempo atrás, fiz um gravador pela porta paralela, para uma memória EEPROM de 3,3v via SPI. Foi relativamente tranquilo. O hardware do gravador, prativamente era o conector, onde a placa ficava soldada.


+++
"Por maior que seja o buraco em que você se encontra, relaxe, porque ainda não há terra em cima."
Avatar do usuário
andre_luis
Dword
 
Mensagens: 5447
Registrado em: 11 Out 2006 18:27
Localização: Brasil - RJ


Voltar para PIC

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

cron

x