Operación de lectura SPI Flash

Hoy vi a alguien preguntando sobre cómo leer datos de SPI flash, ¿por qué se lee así?

Primero dé una función, la función de lectura de SPI:

/*!
    \brief      read a block of data from the flash
    \param[in]  pbuffer: pointer to the buffer that receives the data read from the flash
    \param[in]  read_addr: flash's internal address to read from
    \param[in]  num_byte_to_read: number of bytes to read from the flash
    \param[out] none
    \retval     none
*/
spiflash_ret spiflash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read)
{
    spiflash_ret ret = spiflash_ret_success;
    /* select the flash: chip slect low */
    SPI_FLASH_CS_LOW();

    /* send "read from memory " instruction */
    spi_flash_send_byte(READ);

    /* send read_addr high nibble address byte to read from */
    spi_flash_send_byte((read_addr & 0xFF0000) >> 16);
    /* send read_addr medium nibble address byte to read from */
    spi_flash_send_byte((read_addr& 0xFF00) >> 8);
    /* send read_addr low nibble address byte to read from */
    spi_flash_send_byte(read_addr & 0xFF);

    /* while there is data to be read */
    while(num_byte_to_read--){
        /* read a byte from the flash */
        *pbuffer = spi_flash_send_byte(DUMMY_BYTE);
        /* point to the next location where the byte read will be saved */
        pbuffer++;
    }

    /* deselect the flash: chip select high */
    SPI_FLASH_CS_HIGH();
    
    return ret;
}

Los parámetros de la función ya no se mencionarán, solo mírelos si hay comentarios. Una es la dirección de datos que se devolverá y la otra es la dirección que se leerá. Debería ser un poco más popular aquí, qué posición en la memoria flash debería leerse, y la última es el número de bytes leídos.

¡OK! Todavía hay conocimiento aquí, al menos debe haber tales preguntas:

¡Para el segundo parámetro! El segundo parámetro es la ubicación del flash, lo que significa que queremos leer los datos del flash.

Hay que pensar en lo grande que es este rango. El rango depende de la capacidad del flash

Por ejemplo, estoy usando flash 4M, 4M, 4 * 1024 * 1024 bytes.

Aquí primero expreso 4M en binario y hexadecimal, y lo uso más tarde:

Método de tabla hexadecimal 4M: 0x40 00 00 (un espacio está vacío entre cada dos bytes)

La representación binaria de 4M: 100 0000 0000 0000 0000 0000 (Lo siento, es un poco larga, tiene 23 dígitos en total, lo cuenta)

Bien en la función

En primer lugar, debes conocer la selección de películas de SPI. Si no conoces muchas búsquedas en línea, no hablaré de ellas (porque no sé ...)

Los puntos clave para ser dicho primer paso

    spi_flash_send_byte(READ);

Esta función envía datos READ, lo siento porque READ se define aquí como 0x03, que no está definido antes, lo siento.

En otras palabras, al leer, primero se debe enviar un 0x03. ¿Por qué es 0x03?

Ven, echemos un vistazo a SPEC, manual de datos Flash:

Publica la imagen a continuación:

 A continuación, se muestra una forma de leer datos flash:

El comando Leer bytes de datos (lectura) va seguido de una dirección de 3 bytes (A23-A00, y cada bit está bloqueado en el borde ascendente de SCLK.

Ok, solo mire una oración y vea lo que encontramos El comando (Leer) es seguido por una dirección de 3 bytes

El comando de lectura es 0x03, vea el comando 03H en la imagen de abajo, a la derecha, seguido de la dirección de 3 bytes es la dirección de 24 bits en la imagen

¿Por qué es una dirección de 24 bits? Piense en ello. Después de enviar 0x03 a flash, no le hemos dicho a flash dónde queremos leer el flash.

Entonces, dígale inmediatamente a flash la posición a leer, ¿cuántos bits es esta posición? 23! Es decir, el método de representación binaria de 4M que mencionamos anteriormente, pero ¿por qué aquí es de 24 bits? Se divide uniformemente entre 8 y no se usa el bit más alto.

Esta es la razón por la que enviamos tres direcciones de bytes en nuestro código. ¿Por qué quieres enviarlo tres veces? ¿Envía primero el bit alto o primero el bit bajo?

Mire la imagen, la imagen es de 23 a 0, por lo que cuando envíe, primero debe enviar el bit alto, luego el bit bajo. La razón para enviar tres veces es que nuestra función solo admite el envío de datos de 8 bits

Publica esta función:

/*!
    \brief      send a byte through the SPI interface and return the byte received from the SPI bus
    \param[in]  byte: byte to send
    \param[out] none
    \retval     the value of the received byte
*/
uint8_t spi_flash_send_byte(uint8_t byte)
{
    /* loop while data register in not emplty */
    while (RESET == spi_i2s_flag_get(SPI1,SPI_FLAG_TBE));

    /* send byte through the SPI1 peripheral */
    spi_i2s_data_transmit(SPI1,byte);

    /* wait to receive a byte */
    while(RESET == spi_i2s_flag_get(SPI1,SPI_FLAG_RBNE));

    /* return the byte read from the SPI bus */
    return(spi_i2s_data_receive(SPI1));
}

Como puede ver, el parámetro es uint8_t.

Después de enviar el comando de lectura y la posición de lectura, flash sabe dónde queremos obtener los datos, ¡así que podemos leer tanto como queramos!

La siguiente es la operación de lectura cíclica.

    /* while there is data to be read */
    while(num_byte_to_read--){
        /* read a byte from the flash */
        *pbuffer = spi_flash_send_byte(DUMMY_BYTE);
        /* point to the next location where the byte read will be saved */
        pbuffer++;
    }

¿Cómo leer en bucle?

Envíe un comando DUMMY_BYTE (0xFF) directamente a la memoria flash. Luego, esta función devuelve los datos para ser leídos. Si lee en orden, leerá los datos del pedido comenzando desde la dirección correspondiente, y luego leerá el archivo. Igual, mantenga leyendo.

Aquí hay dos pensamientos. Algunas personas dicen, ¿por qué enviar 0xFF? De hecho, puedes publicar cualquier cosa, no te preocupes por esto, -_- ||

Finalmente, mire la función spi_flash_send_byte

Solo mire la función publicada anteriormente, hay comentarios dentro,

Lo principal es este código:

    /* send byte through the SPI1 peripheral */
    spi_i2s_data_transmit(SPI1,byte);

Y el siguiente código, -_- ||, neto para decir algunas tonterías, un total de 4 oraciones, dos oraciones son importantes

    /* return the byte read from the SPI bus */
    return(spi_i2s_data_receive(SPI1));

Primero mira transmitir, la oración para enviar datos:

La realización de esta función:

/*!
    \brief      SPI transmit data
    \param[in]  spi_periph: SPIx(x=0,1,2)
    \param[in]  data: 16-bit data
    \param[out] none
    \retval     none
*/
void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data)
{
    SPI_DATA(spi_periph) = (uint32_t)data;
}

Es muy simple, simplemente escriba un dato en un registro, si lo adivinó correctamente

Mira la implementación de otra función del receptor:

/*!
    \brief      SPI receive data
    \param[in]  spi_periph: SPIx(x=0,1,2)
    \param[out] none
    \retval     16-bit data
*/
uint16_t spi_i2s_data_receive(uint32_t spi_periph)
{
    return ((uint16_t)SPI_DATA(spi_periph));
}

¿Cuál es la base para leer datos del mismo registro?

Eche un vistazo al manual de datos de la MCU que estamos usando y vea la parte de SPI, que tiene una introducción sobre SPI_DATA:

 Mire la siguiente descripción de texto: "El hardware tiene dos búferes: búfer de envío y búfer de recepción. Escribir datos en SPI_DATA (este registro) almacenará los datos en el búfer de envío, y los datos de lectura de SPI_DATA recibirán El búfer obtiene los datos. "

Esta es la base teórica para implementar estas dos funciones en el SDK. Por supuesto, este es un registro de 16 bits y puede elegir entre 8 o 16 bits.

Si no lo entiende, puede dejar un mensaje para discutir wow, ^ _ ^

Supongo que te gusta

Origin blog.csdn.net/yangkunhenry/article/details/104703339
Recomendado
Clasificación