¿Cómo escribo en la memoria flash SPI?

Estoy trabajando en una aplicación de audio en la que, en lugar de almacenar datos de audio en una tarjeta SD ( Waveshield en Arduino), los almaceno en un IC de memoria flash SPI y hago rodar mi propia placa con MCU, DAC y amplificador.

Estoy usando un Winbond W25Q80BVSSIG .

Estoy bastante familiarizado con la programación de AVR usando AVRISP mkII o USBTiny , ¿la escritura de datos en flash se realiza con el mismo programador? No he podido encontrar nada al buscar programadores de memoria flash SPI específicamente.

Esta pregunta es una continuación de ésta .

No sé si existe un programador que específicamente pueda hacer esto fácilmente por usted, desde una PC o algo así, pero si hay un CPLD involucrado en su circuito, puede configurarlo para escribir datos en la memoria flash.
Creo que los módulos flash spi están diseñados hoy en día para almacenar firmware/bios que usa la CPU en la mayoría de las PC. No para dispositivos de almacenamiento robustos.

Respuestas (7)

Si simplemente está buscando una manera de programar el flash Winbond SPI con datos "precargados" que su microcontrolador leería para usar cuando se está ejecutando, entonces lo que querrá buscar es un programador que pueda hacer programación en circuito. del chip SPI Flash. Esto también se conoce como programación en el sistema (ISP).

Una opción es el programador de DediProg. Este dispositivo conectado por USB puede programar en circuito si diseña su placa correctamente. Incluso venden un clip adaptador que se puede conectar al paquete SOW-16 sin tener que diseñar un encabezado de programación separado en su placa. DediProg tiene boletines de información de aplicaciones disponibles para ayudar con el diseño correcto para uso en circuito. La estrategia principal para el diseño es encontrar una manera simple de aislar los controladores de interfaz SPI en su sistema MCU para que no interfieran con los controladores en el módulo de programación SPI. La forma más sencilla de hacer esto es colocar resistencias en serie en las líneas impulsadas por MCU entre MCU y SPI Flash. El programador se conectaría en el lado flash SPI de las resistencias en serie. Los métodos alternativos podrían incluir agregar un MUX o interruptores analógicos en las líneas de interfaz impulsadas. Un esquema aún más inteligente es agregar un "

ingrese la descripción de la imagen aquí

Una segunda opción a considerar también es el programador USB de ASIX . El Presto puede hacer varios tipos de dispositivos SPI e I 2 C, incluidos los dispositivos SPI Flash. Tengo uno de estos dispositivos específicamente para programar MCU de Atmel y varios tipos de dispositivos SPI Flash. Es una solución más rentable que la unidad anterior, pero no tan flexible. Su dispositivo más caro llamado Forte puede hacer más cosas porque tiene más pines de interfaz de destino.

ingrese la descripción de la imagen aquí

A veces puede ser beneficioso poder conectar un programador a una placa de destino sin tener que agregar un encabezado de programación. Una buena solución para esto es colocar un pequeño juego de almohadillas en un espacio especial definido por una empresa llamada TagConnect . Fabrican y venden una serie de cables de programación de conexión rápida que tienen pines pogo que encajan en la huella especial en la placa. Hay versiones del cable de 6 pines, 10 pines y 14 pines disponibles para adaptarse a una variedad de aplicaciones. El costo de los cables es muy razonable.

ingrese la descripción de la imagen aquí

Esto es muy útil. Estoy planeando programar la memoria flash antes de soldarla al PCB final. Hasta ahora he hecho esto para MCU y funcionó bien. No estoy seguro de si proporcionar pines ISP en la PCB es una buena idea o no, ya que se supone que no deben reprogramarse una vez completados.
@JYelton: en mi experiencia, es una buena idea planificar un ISP por varias razones. Las Órdenes de Cambio de Ingeniería (ECO) son una realidad en el ciclo del producto. Alguien o algo exigirá un cambio en el contenido Flash una vez que entre en producción. Los chips flash a veces son susceptibles a perturbaciones de ruido inesperadas en el circuito y terminan teniendo su contenido comprometido. Otra razón para proporcionar ISP.
¿Existe un encabezado "estándar" que sea compatible con la mayoría de estos programadores al menos a través de cables adaptadores incluidos? He visto encabezados de pines de 2x4 y 2x5 con un montón de pinouts diferentes. También vea flashrom.org/Supported_hardware
Cada uno tiene su propia idea de lo razonable. Los cables Tag-connect cuestan entre $35 y $40.
@markrages: pero para un laboratorio de desarrollo determinado o una estación de programación de fábrica, solo necesita comprar un cable. No necesita uno para cada producto. Además, estos cables son mucho más baratos que tratar de enrollar su propio accesorio pogo-pin para permitir ISP sin un conector.

Apuesto a que podrías hacerlo con un Bus Pirate sin pasar por tu MCU... que te permite realizar interacciones en serie un tanto arbitrarias directamente a un chip usando comunicación SPI, I2C o UART. Puede tomar un poco de trabajo "escribirlo", pero probablemente le permitirá hacer el trabajo.

También he visto herramientas especializadas para cargar EEPROM a través de I2C directamente, pero no flash y no SPI específicamente.

Estoy empezando a preguntarme si mi selección de flash SPI es buena, dado lo (aparentemente) oscuros que son los métodos para escribir en las malditas cosas.
Eso requeriría una secuencia de comandos seria, pero de todos modos es una buena idea. Un poco complicado para mi gusto. ¿Tal vez deberías considerar una tarjeta SD? Entonces solo necesita preocuparse por la lectura, escribir en ella con una computadora
El prototipo actual utiliza un Arduino y Waveshield (que tiene un lector de tarjetas SD). Quiero alejarme de la tarjeta SD porque creo que el costo será menor (sin lector ni tarjeta) y también más a prueba de manipulaciones.

Nunca he oído hablar de ninguna otra herramienta que hable SPI directamente con un chip de este tipo, y creo que es imposible ya que "todos" los chips requieren diferentes llamadas para diferentes operaciones.

El chip necesita llamadas SPI para escritura, lectura, cambio de sector, tamaño de datos, etc. En el capítulo Instrucciones 7.2 de la hoja de datos, puede ver todos los comandos SPI que puede enviarle. Por lo tanto, dado que todas las memorias flash externas no tienen el mismo conjunto de instrucciones, debe escribir una aplicación personalizada para esta.

EDITAR: Siendo un seguimiento, realmente recomendaría una de las memorias flash SPI propias de Atmels, ya que la mayoría de ellas ya ha escrito código abierto disponible para ellas. Mirar esta publicación de AVRFreaks le proporcionará un código para algunos de los chips flash seriales Atmels AT45xxxx.

Si lo entiendo correctamente, ¿debería escribir un programa para mi MCU que luego escriba los datos en la memoria flash? El problema es que la MCU tiene menos memoria que el flash externo, por lo que estoy algo perdido.
Sí. Puede enviar datos desde la línea serial de su computadora con UART que escribe en el flash. Además, podría escribir varios programas para la MCU, programando el flash algunos bloques a la vez. Puede llevar un poco de tiempo, pero funciona ya que el flash externo no se borrará siempre que realice un seguimiento de los sectores cambiantes correctamente.
Esta es la respuesta correcta. Por lo tanto, necesitará un programa en su PC para descargar fragmentos a la MCU, que luego los escribe en flash. Ayuda si hay una verificación de errores y no tiene que escribir un nuevo programa en la PC; así que te sugiero que encuentres algún código para XMODEM o similar.
@ pjc50 ... no tan rápido al declarar la 'respuesta correcta' :)
En realidad, muchos programadores pueden programar memorias flash; y uno de los esquemas de programación comunes utilizados con los micros atmel está bastante cerca de SPI para empezar.
¿Podría proporcionar algunos ejemplos al respecto?
¿Qué pasa con algo como esto? totalphase.com/products/cheetah_spi

Un poco tarde para la discusión, pero para cualquiera que lo lea después de una búsqueda...

Una cosa que no vi mencionada, que es absolutamente crítica cuando se programan chips SPI Flash, es el control del pin Chip Select (CS_). El pin Chip Select se usa para puntuar los comandos al SPI Flash. En particular, una transición de CS_ alto a CS_ bajo debe preceder inmediatamente a la emisión de cualquier código de operación de operación de escritura (WREN, BE, SE, PP). Si hay actividad entre la transición de CS_ (es decir, después de que CS_ haya bajado) y antes de que se transmita el código de operación de escritura, generalmente se ignorará el código de operación de escritura.

Además, lo que no se explica comúnmente en las hojas de datos de SPI Flash, porque es una parte inherente del protocolo SPI, que también es fundamental, es que por cada byte que se transmite en el bus SPI, se recibe un byte a cambio. Además, uno no puede recibir ningún byte, a menos que uno transmita un byte.

Por lo general, el maestro SPI que el usuario está comandando tiene un búfer de transmisión, que envía bytes en la línea MOSI del bus SPI y un búfer de recepción, que recibe bytes desde la línea MISO del bus SPI.

Para que los datos aparezcan en el búfer de recepción, algunos datos deben haber sido enviados al búfer de transmisión. De manera similar, cada vez que se envían datos fuera del búfer de transmisión, los datos aparecerán en el búfer de recepción.

Si uno no tiene cuidado al equilibrar las escrituras de transmisión y las lecturas de recepción, no sabrá qué esperar en el búfer de recepción. Si el búfer de recepción se desborda, los datos generalmente se derraman y se pierden.

Entonces, cuando uno envía un comando de lectura, que es un código de operación de un byte y tres bytes de dirección, primero recibirá cuatro bytes de "basura" en el búfer de recepción maestro SPI. Estos cuatro bytes de basura corresponden al código de operación y tres bytes de dirección. Mientras se transmiten, Flash aún no sabe qué leer, por lo que solo devuelve cuatro palabras basura.

Después de que se devuelvan esas cuatro palabras basura, para obtener cualquier otra cosa en el búfer de recepción, debe transmitir una cantidad de datos igual a la cantidad que desea leer. Después del código de operación y la dirección, no importa lo que transmita, es solo un relleno para enviar los DAtos de lectura desde SPI Flash al búfer de recepción.

Si no realizó un seguimiento cuidadoso de esas primeras cuatro palabras basura devueltas, podría pensar que una o más de ellas son parte de sus datos de lectura devueltos.

Por lo tanto, para saber qué está obteniendo realmente del búfer de recepción, es importante saber el tamaño de su búfer, saber cómo saber si está vacío o lleno (generalmente hay un bit de estado de registro para informar esto) y hacer un seguimiento de cómo cuánto has transmitido y cuánto has recibido.

Antes de iniciar cualquier operación SPI Flash, es una buena idea "drenar" el FIFO de recepción. Esto significa verificar el estado del búfer de recepción y vaciarlo (generalmente se hace realizando una 'lectura' del búfer de recepción) si aún no está vacío. Por lo general, vaciar (leer) un búfer de recepción ya vacío no hace daño.

La siguiente información está disponible en los diagramas de tiempo en las hojas de datos de SPI Flashes, pero a veces la gente pasa por alto los bits. Todos los comandos y datos se envían a la memoria flash SPI mediante el bus SPI. La secuencia para leer un SPI Flash es:

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.

Tenga en cuenta que los pasos 6 y 7 deben intercalarse y repetirse según el tamaño de la lectura y el tamaño de sus búferes de recepción y transmisión. Si transmite una mayor cantidad de palabras de una sola vez, de lo que puede contener su búfer de recepción, perderá algunos datos.

Para realizar un programa de página o un comando de escritura, realice estos pasos. El tamaño de la página (normalmente 256 bytes) y el tamaño del sector (normalmente 64 K) y los límites asociados son propiedades de la memoria flash SPI que está utilizando. Esta información debe estar en la hoja de datos de Flash. Omitiré los detalles del equilibrio de los búferes de transmisión y recepción.

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.

Finalmente, si su dirección de escritura no está en un límite de página (normalmente un múltiplo de 256 bytes) y escribe suficientes datos para cruzar el siguiente límite de página, los datos que deberían cruzar el límite se escribirán al principio de la página en la que la dirección de su programa cae. Entonces, si intenta escribir tres bytes en la dirección 0x0FE. Los dos primeros bytes se escribirán en 0x0fe y 0x0ff. El tercer byte se escribirá en la dirección 0x000.

Si transmite una cantidad de bytes de datos mayor que el tamaño de una página, los primeros bytes se descartarán y solo los 256 bytes finales (o el tamaño de la página) se utilizarán para programar la página.

Como siempre, no somos responsables de las consecuencias de los errores, errores tipográficos, descuidos o desajustes en lo anterior, ni en la forma en que lo utilice.

"Antes de iniciar cualquier operación SPI Flash, es una buena idea "drenar" el FIFO de recepción. Esto significa verificar el estado del búfer de recepción y vaciarlo (generalmente se realiza realizando una 'lectura' del búfer de recepción) si no está ya vacío. Por lo general, vaciar (leer) un búfer de recepción ya vacío no hace daño". ¿Qué pasos debo seguir para leer el estado del búfer de recepción y vaciar el búfer de recepción?

Compré un programador " FlashCAT " de Embedded Computers por unos 30 dólares estadounidenses. Fue sorprendentemente fácil conectarse a la PC a través de USB y escribir archivos en la memoria flash Winbond. Los métodos y programadores en otras respuestas probablemente sean igual de buenos, algunos más caros o de bricolaje, pero esta es una forma económica y simple que se ajusta a lo que estaba buscando.

Aquí hay una imagen de la configuración:

Programación con FlashCAT

El programador FlashCAT está a la izquierda, conectado a USB. Está ejecutando el firmware de programación SPI (a diferencia de JTAG) y suministra energía a la memoria flash. La alimentación suministrada es seleccionable (3,3V o 5V) con un puente.

Tengo un zócalo SOIC a DIP en la placa para facilitar la programación de varios chips. (También puede ver otro IC de memoria flash sentado en la placa).

Software FlashCAT

Todavía no he convertido mi archivo de audio al formato binario adecuado, pero escribí un archivo WAV de 211 KB en la memoria solo para probarlo, como se muestra arriba. Luego lo volví a leer y lo guardé como un archivo nuevo, le cambié el nombre a .wav y se reproduce correctamente en la PC.

El siguiente paso será codificar correctamente el archivo y escribir el software AVR para leer los datos y enviarlos a través de un DAC.

Descargo de responsabilidad: no estoy afiliado a Embedded Computers, solo soy un cliente que eligió algo económico y comparto información sobre la experiencia con el producto.

Contrariamente a algunas de las afirmaciones aquí, si bien existen algunas PROM SPI extravagantes, también hay algunas instrucciones estándar utilizadas por una gran variedad de PROM SPI, incluida la que ha elegido.

Como vicatcu ya mencionó, hay buenos cables 'bit-bash' disponibles que pueden programar SPI directamente. En cuanto a la señal, SPI se parece mucho a JTAG, por lo que cualquier tipo de cable bit-bash debería poder usarse siempre que la interfaz sea de código abierto. El protocolo interno del flash es bastante simple.

Usamos el hermano mayor de la parte que está viendo para iniciar nuestras placas FPGA (256M - 2G). El direccionamiento tiene un byte extra para manejar el volumen de almacenamiento, pero por lo demás los comandos son básicamente idénticos.

El tipo de PROM que está utilizando debe borrarse por sector y luego programarse por página. La lectura es significativamente más rápida que la escritura (en el caso de las que usamos, la programación puede llevar media hora, pero leer toda la PROM lleva menos de un segundo a 108 MHz).

Ahora, para los comandos: hay muchos más comandos disponibles en estos dispositivos de los que realmente se requieren para programarlos. En realidad solo necesitas lo siguiente:

  • RDID (leer ID): solo para verificar la PROM y la señalización antes de hacer algo más complejo.
  • WREN (habilitación de escritura): necesario antes de cada escritura.
  • PP (0x02 - programa de página) - necesario para programar una página.
  • SE (0x20 - borrado de sector) - devuelve bits en sector a '1'.
  • RDSR (0x05 - registro de estado de lectura) - necesario para monitorear el ciclo de borrado/escritura.
  • FREAD (0x0B - lectura rápida) - lee datos de PROM y verifica la escritura.

Si desea obtener más información, consulte las notas de respuesta sobre programación SPI para FPGA de Xilinx en su sitio web (http://www.xilinx.com). Implementan un subconjunto reducido de comandos para que sus FPGA puedan arrancar desde estos dispositivos.

Diseñé mi propio programador para hacer esto en base a lo que tengo disponible y escribí un script de programador en Python, pero puedes hacer lo mismo usando un cable. En su caso, consideraría seriamente hacer todo indirectamente a través de la MCU como sugiere Michael Karas. No necesita programar toda la PROM desde la MCU de una sola vez; puede hacerlo por sector.

Debería poder reutilizar el USBtiny para programar una memoria flash en lugar de una MCU de destino si se siente cómodo cambiando su programación. Sin embargo, es posible que no haya suficiente memoria para que sea lo suficientemente versátil como para programar tanto la MCU como el flash.

En algún lugar tengo una placa de un proyecto que tiene un flash ATTINY y SPI, y se usa como Arduino como un "programador" fácilmente disponible. Se usa una ligera modificación del boceto ISP para programar la MCU con avrdude, luego una utilidad personalizada envía una secuencia que pone el boceto en un modo especial y escribe bloques de datos en el flash SPI.