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.