硬汉嵌入式论坛

 找回密码
 立即注册
查看: 442|回复: 2
收起左侧

[有问必答] 这两段代码计算方式怎么去理解?

[复制链接]

23

主题

58

回帖

127

积分

初级会员

积分
127
发表于 2023-7-29 22:35:28 | 显示全部楼层 |阅读模式
[C] 纯文本查看 复制代码
#include "at32_spiflash.h"

#define flash_spi_cs_low()       gpio_bits_reset(FLASH_SPI_CS_GPIO, FLASH_SPI_CS_PIN)
#define flash_spi_cs_high()      gpio_bits_set(FLASH_SPI_CS_GPIO, FLASH_SPI_CS_PIN) 

#define flash_dummy_byte    0xff
#define flah_page_size      256
#define flah_sector_size      0x1000


static uint8_t flash_spi_readbyte(void);
static uint8_t flash_spi_sendbyte(uint8_t byte);
static void flash_spi_writeenable(void);
static void flash_spi_erasesector(uint32_t sectoraddr);
static void flash_spi_waitforwriteend(void);
static void flash_spi_writepage(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite);
static uint32_t flash_spi_getid(void);
uint32_t spi_flash_size = 0x1000000;
uint32_t spi_flash_sectorsize = flah_sector_size;
uint32_t device_id = 0;
uint8_t gtmpbuff[4096] = {0};

/**
  * @brief  Initializes the peripherals used by the SPI FLASH driver.
  * @param  None
  * @retval None
  */
 void flash_spi_init(void)
 {
    gpio_init_type GPIO_InitStructure;
    spi_init_type SPI_InitStruct;
     
    /*RCC Config*/
   crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);
   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);


    /*Configure SPI SCK pin*/
    GPIO_InitStructure.gpio_pins  = FLASH_SPI_SCK_PIN;
    GPIO_InitStructure.gpio_mode = GPIO_MODE_MUX;
    GPIO_InitStructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init(FLASH_SPI_SCK_GPIO, &GPIO_InitStructure);

     /*Configure SPI MISO pin*/
    GPIO_InitStructure.gpio_pins  = FLASH_SPI_MISO_PIN;
    gpio_init(FLASH_SPI_MISO_GPIO, &GPIO_InitStructure);
     
    /*Configure SPI MOSI pin*/
    GPIO_InitStructure.gpio_pins  = FLASH_SPI_MOSI_PIN;
    gpio_init(FLASH_SPI_MOSI_GPIO, &GPIO_InitStructure);
     
     /*Configure SPI CS pin*/
    GPIO_InitStructure.gpio_mode = GPIO_MODE_OUTPUT;
    GPIO_InitStructure.gpio_pins  = FLASH_SPI_CS_PIN;
    gpio_init(FLASH_SPI_CS_GPIO, &GPIO_InitStructure);
    
    /*Deselect FLASH*/
    flash_spi_cs_high();
    
    /*SPI Configuration*/  
    SPI_InitStruct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
    SPI_InitStruct.master_slave_mode = SPI_MODE_MASTER;
    SPI_InitStruct.mclk_freq_division = SPI_MCLK_DIV_4;
    SPI_InitStruct.frame_bit_num = SPI_FRAME_8BIT;
    SPI_InitStruct.first_bit_transmission = SPI_FIRST_BIT_MSB;
    SPI_InitStruct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
    SPI_InitStruct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
    SPI_InitStruct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
    spi_init(FLASH_SPI, &SPI_InitStruct);
    
    
    spi_crc_polynomial_set(FLASH_SPI, 7);
    
    /*Enable SPI*/
    spi_enable(FLASH_SPI, TRUE);
    
    device_id = flash_spi_getid();
    if ( device_id == 0xef16 )
    {
        spi_flash_size = 0x800000; /*8m byte*/
    }else if ( device_id == 0xef17 )
    {
        spi_flash_size = 0x1000000; /*16m byte*/
    }else
    {
        spi_flash_size = 0;
    }
     
}
 


/**
  * @brief  Sends a byte through the SPI interface and return the byte received
  *         from the SPI bus.
  * @param  byte: byte to send.
  * @retval The value of the received byte.
  */
static uint8_t flash_spi_sendbyte(uint8_t byte)
{
  /*!< Loop while DR register in not emplty */
  while (spi_i2s_flag_get(FLASH_SPI, SPI_I2S_TDBE_FLAG) == RESET);

  /*!< Send byte through the SPI1 peripheral */
  spi_i2s_data_transmit(FLASH_SPI, byte);

  /*!< Wait to receive a byte */
  while (spi_i2s_flag_get(FLASH_SPI, SPI_I2S_RDBF_FLAG) == RESET);

  /*!< Return the byte read from the SPI bus */
  return spi_i2s_data_receive(FLASH_SPI);
}

/**
  * @brief  Reads a byte from the SPI Flash.
  * @note   This function must be used only if the Start_Read_Sequence function
  *         has been previously called.
  * @param  None
  * @retval Byte Read from the SPI Flash.
  */
static uint8_t flash_spi_readbyte(void)
{
  return (flash_spi_sendbyte(flash_dummy_byte));
}

/**
  * @brief  Enables the write access to the FLASH.
  * @param  None
  * @retval None
  */
static void flash_spi_writeenable(void)
{
  /*!< Select the FLASH: Chip Select low */
  flash_spi_cs_low();

  /*!< Send "Write Enable" instruction */
  flash_spi_sendbyte(FLASH_CMD_WREN);

  /*!< Deselect the FLASH: Chip Select high */
  flash_spi_cs_high();
}

/**
  * @brief  Polls the status of the Write In Progress (WIP) flag in the FLASH's
  *         status register and loop until write opertaion has completed.
  * @param  None
  * @retval None
  */
static void flash_spi_waitforwriteend(void)
{
    uint8_t flashstatus = 0;

    /*!< Select the FLASH: Chip Select low */
    flash_spi_cs_low();

    /*!< Send "Read Status Register" instruction */
    flash_spi_sendbyte(FLASH_CMD_READSTS);

    /*!< Loop as long as the memory is busy with a write cycle */
    do
    {
       /*!< Send a dummy byte to generate the clock needed by the FLASH
        and put the value of the status register in FLASH_Status variable */
        flashstatus = flash_spi_sendbyte(flash_dummy_byte);

    }
    while ((flashstatus & 0x1) == SET); /* Write in progress */

    /*!< Deselect the FLASH: Chip Select high */
    flash_spi_cs_high();
}

/**
  * @brief  Erases the specified FLASH sector.
  * @param  SectorAddr: address of the sector to erase.
  * @retval None
  */
static void flash_spi_erasesector(uint32_t sectoraddr)
{
    /*!< send write enable instruction */
    flash_spi_writeenable();

    /*!< sector erase */
    /*!< select the flash: chip select low */
    flash_spi_cs_low();
    /*!< send sector erase instruction */
    flash_spi_sendbyte(FLASH_CMD_ERASE_SECTOR);
    /*!< send sectoraddr high nibble address byte */
    flash_spi_sendbyte((sectoraddr & 0xff0000) >> 16);
    /*!< send sectoraddr medium nibble address byte */
    flash_spi_sendbyte((sectoraddr & 0xff00) >> 8);
    /*!< send sectoraddr low nibble address byte */
    flash_spi_sendbyte(sectoraddr & 0xff);
    /*!< deselect the flash: chip select high */
    flash_spi_cs_high();

    /*!< wait the end of flash writing */
    flash_spi_waitforwriteend();
}


/**
  * @brief  Writes more than one byte to the FLASH with a single WRITE cycle 
  *         (Page WRITE sequence).
  * @note   The number of byte can't exceed the FLASH page size.
  * @param  pBuffer: pointer to the buffer  containing the data to be written
  *         to the FLASH.
  * @param  WriteAddr: FLASH's internal address to write to.
  * @param  NumByteToWrite: number of bytes to write to the FLASH, must be equal
  *         or less than "sFLASH_PAGESIZE" value.
  * @retval None
  */
static void flash_spi_writepage(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
  /*!< enable the write access to the flash */
  flash_spi_writeenable();

  /*!< select the flash: chip select low */
  flash_spi_cs_low();
  /*!< send "write to memory " instruction */
  flash_spi_sendbyte(FLASH_CMD_WRITEPAGE);
  /*!< send writeaddr high nibble address byte to write to */
  flash_spi_sendbyte((writeaddr & 0xff0000) >> 16);
  /*!< send writeaddr medium nibble address byte to write to */
  flash_spi_sendbyte((writeaddr & 0xff00) >> 8);
  /*!< send writeaddr low nibble address byte to write to */
  flash_spi_sendbyte(writeaddr & 0xff);

  /*!< while there is data to be written on the flash */
  while (numbytetowrite--)
  {
    /*!< send the current byte */
    flash_spi_sendbyte(*pbuffer);
    /*!< point on the next byte to be written */
    pbuffer++;
  }

  /*!< deselect the flash: chip select high */
  flash_spi_cs_high();

  /*!< wait the end of flash writing */
  flash_spi_waitforwriteend();
}

/**
  * @brief  Writes block of data to the FLASH. In this function, the number of
  *         WRITE cycles are reduced, using Page WRITE sequence.
  * @param  pBuffer: pointer to the buffer  containing the data to be written
  *         to the FLASH.
  * @param  WriteAddr: FLASH's internal address to write to.
  * @param  NumByteToWrite: number of bytes to write to the FLASH.
  * @retval None
  */
void flash_spi_writebuffer(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
  uint16_t pager;
  pager = flah_page_size - (writeaddr % flah_page_size);
  if ( numbytetowrite <= pager )
  {
    pager = numbytetowrite;
  }
  
  while ( 1 )
  {
    flash_spi_writepage(pbuffer, writeaddr, pager);
    if ( pager == numbytetowrite )
      break;
    else
    {
      pbuffer += pager;
      writeaddr += pager;
      numbytetowrite -= pager;
      if ( numbytetowrite > flah_page_size )
        pager = flah_page_size;
      else
        pager = numbytetowrite;
    }
  }
}


/**
  * @brief  Reads a block of data from the FLASH.
  * @param  pBuffer: pointer to the buffer that receives the data read from the FLASH.
  * @param  ReadAddr: FLASH's internal address to read from.
  * @param  NumByteToRead: number of bytes to read from the FLASH.
  * @retval None
  */
void flash_spi_read(uint8_t* pbuffer, uint32_t readaddr, uint16_t numbytetoread)
{
  /*!< select the flash: chip select low */
  flash_spi_cs_low();

  /*!< send "read from memory " instruction */
  flash_spi_sendbyte(FLASH_CMD_READPAGE);

  /*!< send readaddr high nibble address byte to read from */
  flash_spi_sendbyte((readaddr & 0xff0000) >> 16);
  /*!< send readaddr medium nibble address byte to read from */
  flash_spi_sendbyte((readaddr& 0xff00) >> 8);
  /*!< send readaddr low nibble address byte to read from */
  flash_spi_sendbyte(readaddr & 0xff);

  while (numbytetoread--) /*!< while there is data to be read */
  {
    /*!< read a byte from the flash */
    *pbuffer = flash_spi_sendbyte(flash_dummy_byte);
    /*!< point to the next location where the byte read will be saved */
    pbuffer++;
  }

  /*!< deselect the flash: chip select high */
  flash_spi_cs_high();
}


/**
  * @brief  Writes block of data to the FLASH. In this function, the number of
  *         WRITE cycles are reduced, using Page WRITE sequence.
  * @param  pBuffer: pointer to the buffer  containing the data to be written
  *         to the FLASH.
  * @param  WriteAddr: FLASH's internal address to write to.
  * @param  NumByteToWrite: number of bytes to write to the FLASH.
  * @retval None
  */
void flash_spi_write(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
  uint32_t cnt = 0;
  uint32_t sectornum, sectoroffset, sectorremain;
  
  sectornum = writeaddr / flah_sector_size;
  sectoroffset = writeaddr % flah_sector_size;
  sectorremain = flah_sector_size - sectoroffset;
  
  if ( numbytetowrite <= sectorremain)
  {
    sectorremain = numbytetowrite;
  }
  
  while ( 1 )
  {
    /*read all sector data*/
    flash_spi_read(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
    
    /*check data is 0xff ?*/
    for ( cnt = 0; cnt < sectorremain; cnt ++ )
    {
      if ( gtmpbuff[sectoroffset + cnt] != 0xff)
        break;
    }
    
    if ( cnt < sectorremain ) /*need sector erase*/
    {
      flash_spi_erasesector(sectornum * flah_sector_size);
      for ( cnt = 0; cnt < sectorremain; cnt ++ )
        gtmpbuff[cnt + sectoroffset] = pbuffer[cnt];
      flash_spi_writebuffer(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
    }
    else
    {
      flash_spi_writebuffer(pbuffer, writeaddr, sectorremain);
    }
    
    if ( sectorremain == numbytetowrite )
      break;
    
    else
    {
      sectornum ++;
      sectoroffset = 0;
      pbuffer += sectorremain;
      writeaddr += sectorremain;
      numbytetowrite -= sectorremain;
      if ( numbytetowrite > flah_sector_size )
      {
        sectorremain = flah_sector_size;
      }
      else
      {
        sectorremain = numbytetowrite;
      }
    }
    
  }
  
}

/**
  * @brief  Reads FLASH identification.
  * @param  None
  * @retval FLASH identification
  */
uint32_t flash_spi_getid(void)
{
    /*用户可根据不同flash采用不同的指令获取id*/
    uint16_t flash_id = 0;
    flash_spi_cs_low();
    flash_spi_sendbyte(FLASH_GETID);
    flash_spi_sendbyte(0x00);
    flash_spi_sendbyte(0x00);
    flash_spi_sendbyte(0x00);
    flash_id |= flash_spi_readbyte() << 8;
    flash_id |= flash_spi_readbyte();
    flash_spi_cs_high();
    return flash_id;
}


/**
  * @brief  Get FLASH SIZE.
  * @param  None
  * @retval FLASH identification
  */
uint32_t flash_spi_getsize(void)
{
    return spi_flash_size; 
}


/**
  * @brief  Get FLASH Sector SIZE.
  * @param  None
  * @retval FLASH identification
  */
uint32_t flash_spi_sectorsize(void)
{
    return spi_flash_sectorsize; /*4k*/
}

/**
  * @brief  Get FLASH Page SIZE.
  * @param  None
  * @retval FLASH identification
  */
uint32_t flash_spi_pagesize(void)
{
    //return flah_page_size; /*256byte*/
    return 4096; /*可根据代码配置usb buffer 一次可以接受多少数据, 最大4k*/
}




上面是总的程序,下面两个代码段是从上摘出来的
[C] 纯文本查看 复制代码
void flash_spi_writebuffer(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
  uint16_t pager;
  pager = flah_page_size - (writeaddr % flah_page_size);
  if ( numbytetowrite <= pager )
  {
    pager = numbytetowrite;
  }
  
  while ( 1 )
  {
    flash_spi_writepage(pbuffer, writeaddr, pager);
    if ( pager == numbytetowrite )
      break;
    else
    {
      pbuffer += pager;
      writeaddr += pager;
      numbytetowrite -= pager;
      if ( numbytetowrite > flah_page_size )
        pager = flah_page_size;
      else
        pager = numbytetowrite;
    }
  }
}

第一段
[C] 纯文本查看 复制代码
void flash_spi_write(uint8_t* pbuffer, uint32_t writeaddr, uint16_t numbytetowrite)
{
  uint32_t cnt = 0;
  uint32_t sectornum, sectoroffset, sectorremain;
  
  sectornum = writeaddr / flah_sector_size;
  sectoroffset = writeaddr % flah_sector_size;
  sectorremain = flah_sector_size - sectoroffset;
  
  if ( numbytetowrite <= sectorremain)
  {
    sectorremain = numbytetowrite;
  }
  
  while ( 1 )
  {
    /*read all sector data*/
    flash_spi_read(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
    
    /*check data is 0xff ?*/
    for ( cnt = 0; cnt < sectorremain; cnt ++ )
    {
      if ( gtmpbuff[sectoroffset + cnt] != 0xff)
        break;
    }
    
    if ( cnt < sectorremain ) /*need sector erase*/
    {
      flash_spi_erasesector(sectornum * flah_sector_size);
      for ( cnt = 0; cnt < sectorremain; cnt ++ )
        gtmpbuff[cnt + sectoroffset] = pbuffer[cnt];
      flash_spi_writebuffer(gtmpbuff, sectornum * flah_sector_size, flah_sector_size);
    }
    else
    {
      flash_spi_writebuffer(pbuffer, writeaddr, sectorremain);
    }
    
    if ( sectorremain == numbytetowrite )
      break;
    
    else
    {
      sectornum ++;
      sectoroffset = 0;
      pbuffer += sectorremain;
      writeaddr += sectorremain;
      numbytetowrite -= sectorremain;
      if ( numbytetowrite > flah_sector_size )
      {
        sectorremain = flah_sector_size;
      }
      else
      {
        sectorremain = numbytetowrite;
      }
    }
    
  }
  
}

第二段


spi flash 不是输入一个地址后一直写的话地址会自动增加嘛,为什么还要去区分是哪个扇区的呢?
回复

使用道具 举报

23

主题

58

回帖

127

积分

初级会员

积分
127
 楼主| 发表于 2023-7-29 22:47:36 | 显示全部楼层
[C] 纯文本查看 复制代码
uint32_t flash_addr = addr + USB_FLASH_ADDR_OFFSET;
  uint32_t i = 0, page_len = 2048, tolen = len;
  uint32_t erase_addr = flash_addr;
  switch(lun)
  {
    case 0:
      flash_unlock();
      while(tolen >= page_len)
      {
        flash_sector_erase(erase_addr);
        tolen -= page_len;
        erase_addr += page_len;
      }
      for(i = 0; i < len; i ++)
      {
        flash_byte_program(flash_addr+i, buf[i]);
      }
      flash_lock();
      break;
    case 1:
      break;
  }

这个内部的为什么都不用做一系列判断?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2023-7-30 10:01:10 | 显示全部楼层
地址自制是一个页内自增,即256字节大小,而擦除最小单位是1个扇区4KB
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-29 00:10 , Processed in 0.180498 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表