Como escrevo na memória flash SPI?

9

Estou trabalhando em um aplicativo de áudio em que, em vez de armazenar dados de áudio em um cartão SD ( Waveshield no Arduino), estou armazenando-os em um IC de memória flash SPI e rodando minha própria placa com MCU, DAC e amplificador.

Estou usando um Winbond W25Q80BVSSIG .

Eu estou familiarizado com a programação do AVR usando o AVRISP mkII ou o USBTiny , a gravação de dados no flash é feita com o mesmo programador? Não consegui encontrar nada ao procurar especificamente programadores de memória flash SPI.

Esta pergunta é uma continuação desta .

JYelton
fonte
Não sei se existe um programador que possa fazer isso facilmente com você, de um PC ou algo assim, mas se houver um CPLD envolvido no seu circuito, você poderá configurá-lo para gravar dados na memória flash.
deed02392
Eu acho que os módulos spi flash são projetados hoje em dia para armazenar firmware / bios que a CPU usa na maioria dos PCs. Não é para dispositivo de armazenamento robusto.
Marshal craft

Respostas:

12

Se você está simplesmente procurando uma maneira de programar o flash Winbond SPI com dados "pré-carregados" que o seu microcontrolador leria para uso quando estiver em execução, o que você desejará ver é um programador que pode fazer a programação no circuito do chip SPI Flash. Isso também é conhecido como programação no sistema (ISP).

Uma opção é o programador da DediProg. Este dispositivo conectado via USB pode programar em circuito se você projetar sua placa corretamente. Eles até vendem um clipe adaptador que pode ser anexado ao pacote SOW-16 sem precisar projetar em um cabeçalho de programação separado em sua placa. O DediProg tem boletins de informações de aplicativos disponíveis para ajudar no projeto correto para uso em circuito. A principal estratégia para o design é encontrar uma maneira simples de isolar os drivers da interface SPI no sistema MCU para que eles não interfiram com os drivers no pod de programação SPI. A maneira mais simples de fazer isso é colocar resistores em série nas linhas acionadas pelo MCU entre o MCU e o SPI Flash. O programador se conectaria no lado do flash SPI dos resistores em série. Métodos alternativos podem incluir a adição de um MUX ou comutadores analógicos nas linhas de interface acionadas. Um esquema ainda mais inteligente é adicionar um "

insira a descrição da imagem aqui

Uma segunda opção a considerar também é o programador USB do ASIX . O Presto pode executar vários tipos de dispositivos SPI e I 2 C, incluindo dispositivos SPI Flash. Eu tenho um desses dispositivos especificamente para programar MCUs Atmel e vários tipos de dispositivos SPI Flash. É uma solução mais econômica do que a unidade acima, mas não tão flexível. Seu dispositivo mais caro, chamado Forte, é capaz de fazer mais coisas porque possui mais pinos de interface de destino.

insira a descrição da imagem aqui

Às vezes, pode ser benéfico poder conectar um programador a uma placa de destino sem precisar adicionar um cabeçalho de programação. Uma boa solução para isso é colocar um pequeno conjunto de blocos em uma área especial definida por uma empresa chamada TagConnect . Eles fabricam e vendem uma série de cabos de programação de conexão rápida que possuem pinos de pogo que ocupam o espaço especial na placa. Existem versões de cabo de 6, 10 e 14 pinos disponíveis para atender a uma variedade de aplicações. O custo dos cabos é muito razoável.

insira a descrição da imagem aqui

Michael Karas
fonte
Isso é muito útil. Estou planejando programar a memória flash antes de soldá-la no PCB final. Até agora eu fiz isso para MCUs e funcionou bem. Não sei se é bom fornecer pinos do ISP no PCB ou não, pois eles não devem ser reprogramados depois de concluídos.
perfil completo de JYelton
1
@ JYelton - Na minha experiência, é uma boa idéia planejar o ISP por várias razões. Os ECO (pedidos de alteração de engenharia) são um fato da vida no ciclo do produto. Alguém ou algo exigirá uma alteração no conteúdo do Flash assim que você entrar em produção. Às vezes, os chips flash são suscetíveis a distúrbios inesperados de ruído no circuito e acabam tendo seu conteúdo comprometido. Outro motivo para fornecer ISP.
Michael Karas
1
Existe um cabeçalho "padrão" compatível com a maioria desses programadores pelo menos através de cabos adaptadores fornecidos? Eu vi 2x4 e 2x5 pin headers com um monte de diferentes pinouts Veja também flashrom.org/Supported_hardware
kert
Todo mundo tem sua própria idéia de razoável. Os cabos de conexão de etiqueta custam entre US $ 35 e US $ 40.
markrages
1
@markrages - Mas para um determinado laboratório de desenvolvimento ou estação de programação de fábrica, você só precisa comprar um cabo. Você não precisa de um para cada produto. Além disso, esses cabos são muito mais baratos do que tentar rolar sua própria fixação de pogo para permitir o ISP sem um conector.
Michael Karas
8

Aposto que você poderia fazê-lo com um Bus Pirate sem passar pelo seu MCU ... que permite executar interações seriais um tanto arbitrárias diretamente em um chip usando comunicação SPI, I2C ou UART. Pode demorar um pouco de trabalho para "guiá-lo", mas provavelmente deixaria você fazer o trabalho.

Também vi ferramentas especializadas para carregar diretamente EEPROMs por I2C, mas não flash e nem SPI especificamente.

vicatcu
fonte
Estou começando a me perguntar se minha seleção de flash SPI é boa, considerando como (aparentemente) obscuros os métodos devem ser escritos nas coisas ruins.
JYelton
1
Isso exigiria scripts sérios, mas de qualquer maneira boa ideia. Um pouco complicado para o meu gosto. Talvez você deva considerar um cartão SD? Então você só precisa se preocupar com a leitura, escrita a ele com um computador
chwi
O protótipo atual usa um Arduino e Waveshield (que possui um leitor de cartão SD). Quero me afastar do cartão SD porque acredito que o custo será menor (sem leitor e cartão) e também mais à prova de adulteração.
perfil completo de JYelton
7

Eu nunca ouvi falar de nenhuma outra ferramenta falando SPI diretamente com esse chip, e acho que é impossível, pois "todos" os chips exigem chamadas diferentes para operações diferentes.

O chip precisa de chamadas SPI para gravação, leitura, alteração de setor, tamanho de dados etc. Sob 7.2 Instruções capítulo da folha de dados, você pode ver todos os comandos SPI que podem ser enviados a ele. Portanto, como todas as memórias flash externas não possuem o mesmo conjunto de instruções, você precisa escrever um aplicativo personalizado para este.

EDIT: Sendo um acompanhamento, eu realmente recomendaria uma das memórias flash SPI próprias da Atmels, já que a maioria delas já escreveu código disponível aberto para elas. Observando esta postagem da AVRFreaks , você fornecerá o código para alguns dos chips flash serial Atmels AT45xxxx.

chwi
fonte
Se eu entendi direito, devo escrever um programa para o meu MCU que, em seguida, grava os dados na memória flash? O problema é que o MCU tem menos memória que o flash externo, por isso estou um pouco perdido.
JYelton
Sim. Você pode enviar dados da linha serial do seu computador com o UART e gravá-los no flash. Além disso, você pode escrever vários programas para o MCU, programando o flash alguns blocos de cada vez. Pode demorar um pouco, mas funciona, pois o flash externo não será apagado enquanto você acompanhar as mudanças nos setores corretamente
chwi
2
Essa é a resposta correta. Portanto, você precisará de um programa no seu PC para fazer o download de pedaços no MCU e depois gravá-los no flash. Ajuda se houver verificação de erros e você não precisar escrever um novo programa no PC; então eu sugiro que você encontre algum código para XMODEM ou similar.
pjc50
@ pjc50 ... não é tão rápido em declarar a 'resposta correta' :)
vicatcu
Na verdade, muitos programadores podem programar memórias flash; e um dos esquemas de programação comuns usados ​​com os atmel micros está bem próximo do SPI para começar.
Chris Stratton
4

Eu comprei um " FlashCAT programador" de computadores embarcados para cerca de US $ 30 US. Foi surpreendentemente fácil conectar-se ao PC via USB e gravar arquivos na memória flash Winbond. Os métodos e programadores em outras respostas provavelmente são igualmente bons, alguns mais caros ou DIY, mas essa é uma maneira barata e simples que se encaixa no que eu estava procurando.

Aqui está uma imagem da configuração:

Programando com FlashCAT

O programador FlashCAT está à esquerda, conectado ao USB. Ele está executando o firmware de programação SPI (em oposição ao JTAG) e fornecendo energia à memória flash. A energia fornecida é selecionável (3,3V ou 5V) com um jumper.

Eu tenho um soquete SOIC para DIP na placa de ensaio para facilitar a programação de vários chips. (Você também pode ver outro IC de memória flash na tábua de pão.)

FlashCAT Software

Ainda não converti meu arquivo de áudio para o formato binário adequado, mas escrevi um arquivo WAV de 211 KB na memória apenas para testar, na foto acima. Depois, li e salvei como um novo arquivo, renomeei para .wav e ele é reproduzido corretamente no PC.

O próximo passo será codificar corretamente o arquivo e gravar o software AVR para ler os dados e enviá-los através de um DAC.

Isenção de responsabilidade: não sou afiliado à Embedded Computers, sou apenas um cliente que escolheu algo barato e está compartilhando informações sobre a experiência com o produto.

JYelton
fonte
4

Meio tarde para a discussão, mas para quem lê depois de uma pesquisa ....

Uma coisa que eu não vi mencionada, que é absolutamente crítica ao programar os chips SPI Flash é o controle do pino Chip Select (CS_). O pino de seleção de chip é usado para pontuar comandos no SPI Flash. Em particular, uma transição de CS_ high para CS_ low deve preceder imediatamente a emissão de qualquer código operacional da operação de gravação (WREN, BE, SE, PP). Se houver atividade entre a transição CS_ (ou seja, após CS_ ficar baixo) e antes que o código operacional de gravação seja transmitido, o código operacional de gravação geralmente será ignorado.

Além disso, o que normalmente não é explicado nas folhas de dados do SPI Flash, porque é uma parte inerente do protocolo SPI, o que também é crítico, é que, para cada byte que um transmite no barramento SPI, recebe um byte em troca. Além disso, não se pode receber bytes, a menos que se transmita um byte.

Normalmente, o mestre SPI que o usuário está comandando possui um buffer de transmissão, que envia bytes na linha MOSI do barramento SPI e um buffer de recebimento, que recebe bytes da linha MISO do barramento SPI.

Para que quaisquer dados apareçam no buffer de recebimento, alguns dados devem ter sido enviados para o buffer de transmissão. Da mesma forma, sempre que alguém envia dados do buffer de transmissão, eles aparecem no buffer de recebimento.

Se alguém não tomar cuidado com o balanceamento de transmissões de gravação e recebimento de leituras, não saberá o que esperar no buffer de recebimento. Se o buffer de recebimento exceder, os dados geralmente são derramados e perdidos.

Portanto, quando alguém envia um comando de leitura, que é um código operacional de um byte e três bytes de endereço, primeiro recebe quatro bytes de "lixo" no buffer de recebimento mestre do SPI. Esses quatro bytes de lixo correspondem ao código operacional e aos três bytes de endereço. Enquanto esses estão sendo transmitidos, o Flash ainda não sabe o que Ler, então retorna apenas quatro palavras de lixo.

Depois que essas quatro palavras de lixo são retornadas, para obter mais alguma coisa no buffer de recebimento, você deve transmitir uma quantidade de dados igual à quantidade que deseja ler. Após o código operacional e o endereço, não importa o que você transmite, é apenas o preenchimento para enviar o Read DAta do SPI Flash para o buffer de recebimento.

Se você não acompanhou cuidadosamente as quatro primeiras palavras-lixo retornadas, pode pensar que uma ou mais delas faz parte dos Dados de Leitura retornados.

Portanto, para saber o que você está realmente recebendo do buffer de recebimento, é importante saber o tamanho do buffer, saber se ele está vazio ou cheio (geralmente há um bit de status do registro para relatar isso) e acompanhar como muita coisa que você transmitiu e quanto recebeu.

Antes de iniciar qualquer operação SPI Flash, é uma boa ideia "drenar" o FIFO de recebimento. Isso significa verificar o status do buffer de recebimento e esvaziá-lo (normalmente, executando uma 'leitura' do buffer de recebimento) se ele ainda não estiver vazio. Geralmente, esvaziar (ler) um Buffer de Recebimento já vazio não faz mal.

As informações a seguir estão disponíveis nos diagramas de tempo nas folhas de dados do SPI Flashes, mas às vezes as pessoas ignoram os bits. Todos os comandos e dados são emitidos para o flash SPI usando o barramento SPI. A sequência para ler um SPI Flash é:

1) Start with CS_ high.
2) Bring CS_ low.
3) Issue "Read" op code to SPI Flash.
4) Issue three address bytes to SPI Flash.
5) "Receive" four garbage words in Receive Buffer.
6) Transmit as many arbitrary bytes (don't cares) as you wish to receive. 
Number of transmitted bytes after address equals size of desired read.
7) Receive read data in the Receive Buffer.
8) When you've read the desired amount of data, set CS_ high to end the Read command.
If you skip this step, any additional transmissions will be interpreted as 
request for more data from (a continuation of) this Read.

Observe que as etapas 6 e 7 devem ser intercaladas e repetidas, dependendo do tamanho da leitura e do tamanho dos seus buffers de recebimento e transmissão. Se você transmitir um número maior de palavras de uma só vez, do que o seu buffer de recebimento pode conter, você espalhará alguns dados.

Para executar um comando Programa de Página ou Gravação, execute estas etapas. Tamanho da página (normalmente 256 bytes) e Tamanho do setor (normalmente 64K) e limites associados são propriedades do SPI Flash que você está usando. Esta informação deve estar na folha de dados do Flash. Omitirei os detalhes do balanceamento dos buffers de transmissão e recepção.

1) Start with CS_ high.
2) Change CS_ to low.
3) Transmit the Write Enable (WREN) op code.
4) Switch CS_ to high for at least one SPI Bus clock cycle.  This may be tens or
hundreds of host clock cycles.  All write operations do not start until CS_ goes high.  
The preceding two notes apply to all the following 'CS_ to high' steps.
5) Switch CS_ to low.
6) Gadfly loop:   Transmit the 'Read from Status Register' (RDSR) op code and 
one more byte.   Receive two bytes.  First byte is garbage.  Second byte is status.
Check status byte.  If 'Write in Progress' (WIP) bit is set, repeat loop. 
(NOTE:  May also check 'Write Enable Latch' bit is set (WEL) after WIP is clear.)
7) Switch CS_ to high.
8) Switch CS_ to low.
9) Transmit Sector Erase (SE) or Bulk Erase (BE) op code.  If sending SE, then follow
it with three byte address.
10) Switch CS_ to high.
11) Switch CS_ to low.
12) Gadfly loop:  Spin on WIP in Status Register as above in step 6.  WEL will
be unset at end.
13) Switch CS_ to high.
14) Switch CS_ to low.
15) Transmit Write Enable op code (again).
16) Switch CS_ to high.
17) Switch CS_ to low.
18) Gadfly loop:  Wait on WIP bit in Status Register to clear. (WEL will be set.)
19) Transmit Page Program (PP = Write) op code followed by three address bytes.
20) Transmit up to Page Size (typically 256 bytes) of data to write.  (You may allow
Receive data to simply spill over during this operation, unless your host hardware
has a problem with that.)
21) Switch CS_ to high.  
22) SWitch CS_ to low.
23) Gadfly loop:  Spin on WIP in the Status Register.
24) Drain Receive FIFO so that it's ready for the next user.
25)  Optional:  Repeat steps 13 to 24 as needed to write additional pages or
page segments.

Por fim, se o seu endereço de gravação não estiver no limite de uma página (normalmente um múltiplo de 256 bytes) e você gravar dados suficientes para ultrapassar o limite de página seguinte, os dados que devem cruzar o limite serão gravados no início da página em que o endereço do seu programa cai. Portanto, se você tentar escrever três bytes para endereçar 0x0FE. Os dois primeiros bytes serão gravados em 0x0fe e 0x0ff. O terceiro byte será gravado no endereço 0x000.

Se você transmitir um número de bytes de dados maior que o tamanho da página, os bytes iniciais serão descartados e apenas os bytes finais de 256 (ou tamanho da página) serão usados ​​para programar a página.

Como sempre, não nos responsabilizamos pelas consequências de quaisquer erros, erros de digitação, omissões ou perturbações acima, nem na forma como você a utiliza.

Jeff Walther
fonte
"Antes de iniciar qualquer operação SPI Flash, é uma boa idéia" drenar "o FIFO de recebimento. Isso significa verificar o status do buffer de recebimento e esvaziá-lo (geralmente feito executando uma 'leitura' do buffer de recebimento), se não estiver já está vazio. Geralmente, esvaziar (ler) um buffer de recebimento já vazio não causa danos ". quais etapas eu preciso executar para ler o status do buffer de recebimento e esvaziar o buffer de recebimento?
3

Ao contrário de algumas das declarações aqui, embora existam algumas PROMs SPI peculiares por aí, também existem algumas instruções padrão usadas por uma grande variedade de PROMs SPI, incluindo a que você escolheu.

Como o vicatcu já mencionou, existem bons cabos 'bit-bash' disponíveis que podem programar diretamente o SPI. Em termos de sinal, o SPI se parece muito com o JTAG; portanto, qualquer cabo de tipo bit-bash deve poder ser usado, desde que a interface seja de código aberto. O protocolo interno do flash é bastante simples.

Usamos o irmão mais velho da parte que você está procurando para inicializar nossas placas FPGA (256M - 2G). O endereçamento possui um byte extra para lidar com o volume de armazenamento, mas, caso contrário, os comandos são basicamente idênticos.

O tipo de PROM que você está usando deve ser apagado por setor e depois programado por página. A leitura é significativamente mais rápida que a escrita (no caso das que usamos, a programação pode levar meia hora, mas a leitura de toda a PROM leva menos de um segundo a 108 MHz).

Agora, os comandos: há muito mais comandos disponíveis nesses dispositivos do que o necessário para programá-los. Na verdade, você só precisa do seguinte:

  • RDID (ID de leitura) - apenas para verificar a PROM e a sinalização antes de fazer algo mais complexo.
  • WREN (gravação habilitada) - necessária antes de cada gravação.
  • PP (0x02 - programa de página) - necessário para programar uma página.
  • SE (0x20 - apagar setor) - retorna os bits do setor para '1'.
  • RDSR (0x05 - registro de status de leitura) - necessário para monitorar o ciclo de apagamento / gravação.
  • FREAD (0x0B - leitura rápida) - leia os dados da PROM e verifique a gravação.

Se você quiser obter mais informações, consulte as notas de resposta sobre a programação SPI para FPGAs Xilinx em seu site (http://www.xilinx.com). Eles implementam um subconjunto reduzido de comandos para que seus FPGAs possam inicializar a partir desses dispositivos.

Eu projetei meu próprio programador para fazer isso com base no que tenho disponível e escrevi um script de programador em Python, mas você pode fazer o mesmo usando um cabo. No seu caso, eu consideraria seriamente fazer tudo indiretamente através do MCU, como sugere Michael Karas. Você não precisa programar a PROM inteira do MCU de uma só vez - pode fazê-lo por setor.

Jxj
fonte
2

Você poderá reutilizar o USBtiny para programar uma memória flash em vez de um MCU de destino, se quiser mudar sua programação. No entanto, pode não haver memória suficiente para torná-lo versátil o suficiente para programar o MCU e o flash.

Em algum lugar, tenho um quadro de um projeto que possui um flash ATTINY e um SPI, e usa como Arduino como um "programador" prontamente disponível. Uma pequena modificação do esboço do ISP é usada para programar o MCU com avrdude; em seguida, um utilitário personalizado envia uma sequência que coloca o esboço em um modo especial e grava blocos de dados no flash do SPI.

Chris Stratton
fonte