简体   繁体   English

STM32L072 USB Flash驱动

[英]STM32L072 USB Flash Drive

I am working on an embedded C project in Keil µVision.我正在 Keil µVision 中从事嵌入式 C 项目。 Part of the project is to make the uC detect and operate as a USB flash drive.该项目的一部分是使 uC 检测并作为 USB flash 驱动器运行。 I am using a STM32L072 that is connected to external SPI Flash via SPI2 (P/N: SST26VF016B ).我正在使用通过 SPI2(P/N: SST26VF016B )连接到外部 SPI Flash 的 STM32L072。 I can read/write/erase/ the SST26V flash chip with no issues and I can communicate over USB with no problems.我可以毫无问题地读/写/擦除/SST26V flash 芯片,我可以毫无问题地通过 USB 进行通信。 If I plug the device into a Windows based computer via USB it detects as a flash drive with the appropriate capacity (in this case 64KB[ see NOTE 1 below ]).如果我通过 USB 将设备插入基于 Windows 的计算机,它会检测到具有适当容量的 flash 驱动器(在本例中为 64KB [参见下面的注释 1 ])。 Windows then will prompt me to format the drive. Windows 然后会提示我格式化驱动器。 When I try to format the drive with the following parameters:当我尝试使用以下参数格式化驱动器时:

(Capacity: 64KB, File System: FAT (Default), Allocation unit size: 512 bytes, Quick Format: checked)

Windows will issue a bunch of reads and writes and eventually fail with an error messages that reads " Windows was unable to complete the format ". Windows 将发出一堆读写操作,最终失败并显示错误消息“ Windows 无法完成格式”。

I seem to be having a problem bridging the gap between USB and SPI.我似乎在弥合 USB 和 SPI 之间的差距时遇到了问题。 I modified the usbd_storage_if.c following tutorials like this one .我按照像这样的教程修改了 usbd_storage_if.c。 I only modified a few lines of code shown below:我只修改了如下所示的几行代码:

#define STORAGE_LUN_NBR                  1  // Logical Unit Number
//#define STORAGE_BLK_NBR                  3840 // Use all memory in the SST26V
#define STORAGE_BLK_NBR                  80 // Use ONLY the first 64kB of flash for testing. 
#define STORAGE_BLK_SIZ                  0x200

#define SST26V_MEMORY_OFFSET                        0x10000 // This is the starting address of the SST26V's memory

.... ....

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
    printf("\r\nR%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
    _SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, buf);
  return (USBD_OK);
  /* USER CODE END 6 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
    int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
      /* USER CODE BEGIN 7 */
// incoming USB data packets are 512Bytes

    printf("\r\nW%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
        _SPI_FLASH_WritePage(256, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), buf); // As per SST26V datasheet, can only write 256B at a time
        _SPI_FLASH_WritePage(256, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET + 256), buf+256);
      return (USBD_OK);
      /* USER CODE END 7 */
    }

If I attempt to format the drive and then dump the 64KB flash contents over UART I get the following:如果我尝试格式化驱动器,然后通过 UART 转储 64KB flash 内容,我会得到以下信息:

:00010000|2000000000000000200020000000000000000000000000000000000000000000
:00010020|0000000000002000000020000000000000002000200000000000200020002000
:00010040|0800100010001000000000001000000010000000000000000000000010000000
:00010060|0400040004000000040004000400800000000400000010000000000000001000
:00010080|0000010000000000010000008100000000000000010000000000010001000100
:000100A0|0100010001000000000001000000000000000100000010000000000000001000
:000100C0|0000020000008200000082008200000002000000020000000000000000000000
:000100E0|0200000000000200000002000000000000000200000000001000100010000000
:00010100|0000000000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00010C00|F8FFFF0000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00010E00|F8FFFF0000000000000000000000000000000000000000000000000000000000
... (all zeros in between these regions)
:00015000|FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
... (all FF's in between these regions)
:0001FE00|0000000000000000000000000000000000000000000000000000000000000000
:0001FE20|0000000000000000000000000000000000000000000000000000000000000000
:0001FE40|0000000000000000000000000000000000000000000000000000000000000000
:0001FE60|0000000000000000000000000000000000000000000000000000000000000000
:0001FE80|0000000000000000000000000000000000000000000000000000000000000000
:0001FEA0|0000000000000000000000000000000000000000000000000000000000000000
:0001FEC0|0000000000000000000000000000000000000000000000000000000000000000
:0001FEE0|0000000000000000000000000000000000000000000000000000000000000000
:0001FF00|0000000000000000000000000000000000000000000000000000000000000000
:0001FF20|0000000000000000000000000000000000000000000000000000000000000000
:0001FF40|0000000000000000000000000000000000000000000000000000000000000000
:0001FF60|0000000000000000000000000000000000000000000000000000000000000000
:0001FF80|0000000000000000000000000000000000000000000000000000000000000000
:0001FFA0|0000000000000000000000000000000000000000000000000000000000000000
:0001FFC0|0000000000000000000000000000000000000000000000000000000000000000
:0001FFE0|0000000000000000000000000000000000000000000000000000000000000000

Any ideas what I might be missing?任何想法我可能会错过什么? I also find it slightly odd that the first 20,448 (0x4FE0) bytes is primarily zeros.我还发现前 20,448 (0x4FE0) 字节主要是零有点奇怪。 This memory chip is NAND flash and so I would except all unused space to be FF's.这个 memory 芯片是 NAND flash,所以我会把所有未使用的空间都排除在外。 Which makes me think;这让我想到; any space being written to must be erased before being written to (unless the space is already all FF's), but the smallest size I can erase on the SST26V is a sector (4 Kbyte).任何被写入的空间都必须在写入之前被擦除(除非空间已经全是 FF),但我可以在 SST26V 上擦除的最小大小是一个扇区(4 KB)。 Does this mean the my Allocation unit size should be 4096 bytes, not 512 bytes?这是否意味着我的分配单元大小应该是 4096 字节,而不是 512 字节?

NOTES笔记

1. I'm using the first 64KB of flash to make debugging easier. 1.我使用 flash 的前 64KB 来简化调试。 Takes too long to print out entire 2MB (8Mbit) of flash over UART.通过 UART 打印出整个 2MB(8Mbit)的 flash 花费的时间太长。

UPDATE # 1更新#1

I think I may have found the problem, but have yet to solve it.我想我可能已经找到了问题,但还没有解决。 When I review all of the read write addresses that are printed out over UART I find multiple instances of Windows writing 512 bytes to address 0x00010000.当我查看通过 UART 打印出的所有读写地址时,我发现 Windows 的多个实例将 512 个字节写入地址 0x00010000。 Seeing as this is NAND flash it must be erased before it can be written to again, but because the smallest amount of memory that can be erased is 4kB I suppose this means that I will have to copy the 4kB flash sector to the STM32's RAM, modify the first 512 bytes, erase the 4kB flash sector, then write what I have in RAM back to the 4kB flash sector.看到这是 NAND flash 必须先擦除它才能再次写入,但是因为可以擦除的最小 memory 是 4kB 我想这意味着我必须将 4kB flash 扇区复制到 STM32 的 RAM,修改前 512 个字节,擦除 4kB flash 扇区,然后将我在 RAM 中的内容写回 4kB flash 扇区。 Does that sound correct?这听起来正确吗? Seems inefficient.似乎效率低下。

UPDATE # 2更新#2

I confirmed that my suspicions in UPDATE 1 were correct.我确认我在 UPDATE 1 中的怀疑是正确的。 I tried using only the first 512 bytes of each sector and it works, but as a result only has 1/8 of the capacity.我尝试只使用每个扇区的前 512 个字节并且它有效,但结果只有 1/8 的容量。 More updates to follow.后续有更多更新。

I was able to solve my problem.我能够解决我的问题。 I was on the correct path in UPDATES 1 & 2.我在更新 1 和 2 中走在正确的道路上。

I was able to use the entire 2MB region of the external flash by creating some new functions that deal with flash memory from a sector perspective and a buffer in RAM that is the size of a sector (4KB).通过创建一些从扇区角度处理 flash memory 的新函数和 RAM 中一个扇区大小 (4KB) 的缓冲区,我能够使用外部 flash 的整个 2MB 区域。 See code below:请参阅下面的代码:

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
    if((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET) == 0x00010000)
    printf("\r\nR %d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET)); // print the size and address
    _SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, buf);


    
    
  return (USBD_OK);
  /* USER CODE END 6 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    uint8_t IsBlockEmptyFlag = 0; 
    uint8_t temp = 0xFF; 
    uint16_t sector_number = 0; 
    uint8_t block_number = 0; 
  /* USER CODE BEGIN 7 */

    printf("\r\nW%d:0x%08X", blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ +  bytes
    // First, check if block that we want to write to is empty (All bytes are 0xFF)
    _SPI_FLASH_GetData((blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), blk_len*STORAGE_BLK_SIZ, RAMbuffer);
    for(uint16_t i = 0; i<512; i++)
        temp &= RAMbuffer[i]; 
    if(temp == 0xFF) // then all bytes must be 0xFF and the block is ready to be writen to. 
        IsBlockEmptyFlag = 1; 
    
    if(IsBlockEmptyFlag) // if the block is empty already, have at it, write away
    {
        _SPI_FLASH_WritePage(blk_len*STORAGE_BLK_SIZ, (blk_addr * STORAGE_BLK_SIZ + SST26V_MEMORY_OFFSET), buf); 
    }
    else // if it's not empty
    {
        printf("\r\nt=%02X", temp); 
        // Find the sector number that this block is in
        sector_number = blk_addr/8; 
        
        // Save the entire flash sector to RAM
        _SPI_FLASH_ReadSector(sector_number, RAMbuffer); 
        
        // Erase the sector flash sector
        SST26V_FLASH_EraseSectorN(sector_number); 
        
        // compute the block number of the corresponding sector 
        block_number = blk_addr % 8;
        
        // create a pointer to the RAM buffer
        uint8_t *p_RAM_buffer;
        p_RAM_buffer = RAMbuffer; 
        
        // Modify the RAM buffer's appropriate block
        memcpy(p_RAM_buffer + (512*block_number), buf, blk_len*STORAGE_BLK_SIZ); 
        
        // Write the buffer back into external flash
        _SPI_FLASH_WriteSector(sector_number, RAMbuffer); 
                
    }
        
  return (USBD_OK);
  /* USER CODE END 7 */
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM