OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2513|回复: 5

USB虚拟U盘大于4K(一页)会出现数据错误

[复制链接]

27

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
411
金钱
411
注册时间
2014-4-18
在线时间
94 小时
发表于 2018-3-23 11:45:14 | 显示全部楼层 |阅读模式
30金钱
FLASH是W25Q64,前面1M用来放其他的东西,后面7M做文件系统。一次擦写4K,现在的问题是4K以下文件读写没问题,4K以上文件写入的时候会出现数据错乱(用单片机内置的FATFS读写没问题,只有USB虚拟U盘有这个问题)。
写入之前的文件:
QQ截图20180323113610.jpg
系统复位后再读出来后就会这样:
QQ截图20180323113552.jpg
自己写了个程序,对比也会出现不同,但是长度没有问题,都一样长。

代码基本就是原子哥教程里的


代码:
FLASH_RESERVE_SIZE = 256

FLASH_SECTOR_SIZE = 4096
Mass_Memory_Size[0] = (4096*16*128) - (256*4096);//FLASH容量 保留1M
Mass_Block_Size[0]  = 4096;//扇区大小 4K
Mass_Block_Count[0] = (128*16) - 256;//扇区个数 保留256个做升级扇区







USB读写:
[mw_shl_code=c,true]uint16_t MAL_Write(uint8_t lun, uint64_t Memory_Offset, uint32_t *Writebuff, uint16_t Transfer_Length)
{
        u8 STA;
        switch (lun)
        {
                case EX_FLASH:
                        STA=0;
                        printf("write:%lu %u\r\n", (uint32_t)Memory_Offset, Transfer_Length);
                        W25Q64_Write((u8*)Writebuff, Memory_Offset + (FLASH_RESERVE_SIZE * FLASH_SECTOR_SIZE), Transfer_Length);
                        break;
                default:
                        return MAL_FAIL;
        }
        if(STA!=0)
                return MAL_FAIL;
        return MAL_OK;
}[/mw_shl_code]

[mw_shl_code=applescript,true]uint16_t MAL_Read(uint8_t lun, uint64_t Memory_Offset, uint32_t *Readbuff, uint16_t Transfer_Length)
{
        u8 STA;
        switch (lun)
        {
                case EX_FLASH:
                        STA=0;
                        W25Q64_Read((u8*)Readbuff, Memory_Offset + (FLASH_RESERVE_SIZE * FLASH_SECTOR_SIZE), Transfer_Length);
                        break;
                default:
                        return MAL_FAIL;
        }
        if(STA!=0)
                return MAL_FAIL;
        return MAL_OK;
}[/mw_shl_code]

底层驱动代码:
[mw_shl_code=c,true]void W25Q64_Init(void)
{
        SPI_InitTypeDef  SPI_InitStructure;
        //初始化IO
        GPIO_QuickInit(GPIOD, GPIO_Pin_8,  GPIO_Mode_Out_PP); //WP
        GPIO_QuickInit(GPIOB, GPIO_Pin_12, GPIO_Mode_Out_PP); //CS
        GPIO_QuickInit(GPIOB, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_Mode_AF_PP);
        SPI_FLASH_CS = 1; //取消片选
        //初始化SPI2
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
        SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex; //双向全双工
        SPI_InitStructure.SPI_Mode              = SPI_Mode_Master; //主机
        SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b; //数据大小
        SPI_InitStructure.SPI_CPOL              = SPI_CPOL_High; //串行时钟的稳态:时钟悬空高
        SPI_InitStructure.SPI_CPHA              = SPI_CPHA_2Edge; //数据捕获(采样)于第二个时钟沿
        SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft; //NSS软件控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //波特率分频APB1外设36M/4=9M
        SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB; //MSB位在前
        SPI_InitStructure.SPI_CRCPolynomial     = 7; //CRC值计算的多项式
        SPI_Init(SPI2, &SPI_InitStructure);
        SPI_Cmd(SPI2, ENABLE);
        SPI_FLASH_WP = 1; //取消写保护
        uint16_t spi_flash_id = W25QXX_ReadID();
        if(spi_flash_id != 0XEF16)
        {
                while(1)
                {
                        printf("Flash id error.It mast be 0xEF16(W25Q64). %04X\r\n",spi_flash_id);
                        DelayMs(1000);
                }
        }
}[/mw_shl_code]

[mw_shl_code=c,true]/**
  * @brief  SPI2读写一个字节
  * @param  TxData: 要写的数据
  * @param  *RxData: 读出的数据,如果只写的话这个给NULL
  * @retval 是否成功
  */
bool SPI2_ReadWriteByte(uint8_t TxData,uint8_t *RxData)
{
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI2, TxData);
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
        if(RxData != NULL)
                *RxData = SPI_I2S_ReceiveData(SPI2);
        else
                SPI_I2S_ReceiveData(SPI2);
        return true;
}[/mw_shl_code]


[mw_shl_code=c,true]/**
  * @brief  SPI2读写一个字节
  * @param  TxData: 要写的数据
  * @param  *RxData: 读出的数据,如果只写的话这个给NULL
  * @retval 是否成功
  */
bool SPI2_ReadWriteByte(uint8_t TxData,uint8_t *RxData)
{
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI2, TxData);
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
        if(RxData != NULL)
                *RxData = SPI_I2S_ReceiveData(SPI2);
        else
                SPI_I2S_ReceiveData(SPI2);
        return true;
}[/mw_shl_code]

[mw_shl_code=c,true]
/**
  * @brief  写FLASH
  * @param  *pBuffer: 数据存储区
  * @param  WriteAddr: 写入地址(24bit)
  * @param  NumByteToWrite: 写入字节数(65535max)
  * @retval None
  */
void W25Q64_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
        uint8_t need_free = 0;
        uint32_t secpos;
        uint16_t secoff;
        uint16_t secremain;
        uint16_t i;
        uint8_t * W25QXX_BUF;
        if(W25Q64_WRITE_BUFF == NULL)
        {
                W25Q64_WRITE_BUFF = m_malloc(4096);
                need_free = 1;
                if(W25Q64_WRITE_BUFF == NULL)
                {
                        printf("Disk BUFF error\r\n");
                        return;
                }
                //printf("flash malloc ram\r\n");
        }
       
        W25QXX_BUF = W25Q64_WRITE_BUFF;
        secpos = WriteAddr / 4096;//扇区地址
        secoff = WriteAddr % 4096;//在扇区内的偏移
        secremain = 4096 - secoff;//扇区剩余空间大小
        if(NumByteToWrite <= secremain)
                secremain = NumByteToWrite;//不大于4096个字节
        while(1)
        {
                W25Q64_Read(W25QXX_BUF, secpos * 4096, 4096);//读出整个扇区的内容
                for(i = 0; i < secremain; i++)//校验数据
                {
                        if(W25QXX_BUF[secoff + i] != 0XFF)
                                break;//需要擦除            
                }
                if(i < secremain)//需要擦除
                {
                        W25Q64_EraseSector(secpos); //擦除这个扇区
                        for(i=0;i<secremain;i++) //复制
                        {
                                W25QXX_BUF[i + secoff] = pBuffer;
                        }
                        W25Q64_WriteNoCheck(W25QXX_BUF, secpos * 4096, 4096);//写入整个扇区
                }
                else
                        W25Q64_WriteNoCheck(pBuffer, WriteAddr, secremain);//写已经擦除了的,直接写入扇区剩余区间.
                if(NumByteToWrite == secremain)
                        break;//写入结束了
                else//写入未结束
                {
                        secpos ++;//扇区地址增1
                        secoff = 0;//偏移位置为0
                           pBuffer += secremain; //指针偏移
                        WriteAddr += secremain; //写地址偏移
                           NumByteToWrite -= secremain; //字节数递减
                        if(NumByteToWrite > 4096)
                                secremain = 4096;//下一个扇区还是写不完
                        else
                                secremain = NumByteToWrite; //下一个扇区可以写完了
                }
        }
        if(need_free)
        {
                m_free(W25Q64_WRITE_BUFF);
                W25Q64_WRITE_BUFF = NULL;
        }
}[/mw_shl_code]

最佳答案

查看完整内容[请看2#楼]

找到原因了,缓冲区内存不够 这里要换成Mass_Block_Size的大小 [mw_shl_code=c,true] if(Data_Buffer == NULL) Data_Buffer = m_malloc(4096); if(Bulk_Data_Buff == NULL) Bulk_Data_Buff = m_malloc(4096);[/mw_shl_code]
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

27

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
411
金钱
411
注册时间
2014-4-18
在线时间
94 小时
 楼主| 发表于 2018-3-23 11:45:15 | 显示全部楼层
找到原因了,缓冲区内存不够

这里要换成Mass_Block_Size的大小
[mw_shl_code=c,true]      if(Data_Buffer == NULL)
        Data_Buffer    = m_malloc(4096);
      if(Bulk_Data_Buff == NULL)
              Bulk_Data_Buff = m_malloc(4096);[/mw_shl_code]
回复

使用道具 举报

10

主题

196

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
390
金钱
390
注册时间
2018-3-20
在线时间
80 小时
发表于 2018-3-23 12:02:35 | 显示全部楼层
你用哪个系统格式化的?看看FATFS格式化的代码(FATFS的disk_write )
回复

使用道具 举报

10

主题

196

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
390
金钱
390
注册时间
2018-3-20
在线时间
80 小时
发表于 2018-3-23 12:04:40 | 显示全部楼层
或者用windows格式化一下,再用win写入读出。
回复

使用道具 举报

27

主题

81

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
411
金钱
411
注册时间
2014-4-18
在线时间
94 小时
 楼主| 发表于 2018-3-23 12:40:04 | 显示全部楼层
孟亮 发表于 2018-3-23 12:02
你用哪个系统格式化的?看看FATFS格式化的代码(FATFS的disk_write )

试过了,两边格式化都试过了,写进去后再读出来就不一样了。。。
回复

使用道具 举报

10

主题

196

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
390
金钱
390
注册时间
2018-3-20
在线时间
80 小时
发表于 2018-3-23 13:49:44 | 显示全部楼层
Mfweb 发表于 2018-3-23 12:40
试过了,两边格式化都试过了,写进去后再读出来就不一样了。。。

那就只能写1-4096或者1-4096*2 看看读写上哪有错误了。如果片内Fatfs读写函数和Mal里读写一样的话,考虑是不是加一些延迟看看
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-9 05:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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