stm32cubeMX learning 18. SD card virtual U disk experiment

Keywords: Mobile REST Programming

This program is based on the operation environment of STM32F103ZET6.

I had some losses before running this experiment. Let me come together!

1. After the software was written, it was found that there was no enumeration of USB after the USB cable was inserted and connected to the computer

resolvent:


Wildfire's development board has a USB power on enabling IO, that is to say, when the PD3 is low power, the USB can work normally. If the pin is not enabled, the USB will not work naturally.

2. The problem of reading and writing SD card API version in HAL Library

resolvent:

I used the HAL Library of 1.8.0. There are significant changes in API between this library and the old version of HAL library. The parameters of the interface are not the same, and the meaning is different.

Interface of reading and writing SD card in old HAL Library

Let's look at the read-write API of the old version of HAL Library:

/**
  * @brief  Reads block(s) from a specified address in a card. The Data transfer 
  *         is managed by polling mode.  
  * @param  hsd: SD handle
  * @param  pReadBuffer: pointer to the buffer that will contain the received data
  * @param  ReadAddr: Address from where data is to be read  
  * @param  BlockSize: SD card Data block size (in bytes)
  *          This parameter should be 512
  * @param  NumberOfBlocks: Number of SD blocks to read   
  * @retval SD Card error state
  */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)

We can see that the BlockSize here is read in bytes, and the minimum should be 512. Because the size of a block of SD card is 512, NumberOfBlocks means the number of blocks. If you read a block, it means BlockSize512. If you read N blocks, it means BlockSize512*N.

Let's look at the SD card interface of the old HAL library

/**
  * @brief  Allows to write block(s) to a specified address in a card. The Data
  *         transfer is managed by polling mode.  
  * @param  hsd: SD handle
  * @param  pWriteBuffer: pointer to the buffer that will contain the data to transmit
  * @param  WriteAddr: Address from where data is to be written 
  * @param  BlockSize: SD card Data block size (in bytes)
  *          This parameter should be 512.
  * @param  NumberOfBlocks: Number of SD blocks to write 
  * @retval SD Card error state
  */
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)

The same is true for writing. The BlockSize here is read in bytes, and the minimum should be 512. Because the size of a block of SD card is 512, NumberOfBlocks means the number of blocks. For writing a block, it is BlockSize512. For writing N blocks, it is BlockSize512*N.

Interface of reading and writing SD card in HAL Library of new version

However, in the latest HAL library, it is unnecessary to multiply 512. Let's take a look at the description of these two functions in HAL library version 1.8.0:

/**
  * @brief  Reads block(s) from a specified address in a card. The Data transfer
  *         is managed by polling mode.
  * @note   This API should be followed by a check on the card state through
  *         HAL_SD_GetCardState().
  * @param  hsd: Pointer to SD handle
  * @param  pData: pointer to the buffer that will contain the received data
  * @param  BlockAdd: Block Address from where data is to be read
  * @param  NumberOfBlocks: Number of SD blocks to read
  * @param  Timeout: Specify timeout value
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)

Let's take a look at the interface for reading SD card. The incoming BlockAdd here is the starting address of the block. NumberOfBlocks represents the number of blocks, so it is originally read in blocks, so it is unnecessary to multiply 512.

/**
  * @brief  Allows to write block(s) to a specified address in a card. The Data
  *         transfer is managed by polling mode.
  * @note   This API should be followed by a check on the card state through
  *         HAL_SD_GetCardState().
  * @param  hsd: Pointer to SD handle
  * @param  pData: pointer to the buffer that will contain the data to transmit
  * @param  BlockAdd: Block Address where data will be written
  * @param  NumberOfBlocks: Number of SD blocks to write
  * @param  Timeout: Specify timeout value
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)

The interface for writing SD card is also the same. Here, the incoming BlockAdd is the starting address of the block. NumberOfBlocks represents the number of blocks, so it is originally written in blocks, so there is no need to multiply 512.

Therefore, when implementing the USB mass storage device interface, I should do the following:

/**
  * @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(HAL_OK != HAL_SD_ReadBlocks(&hsd,(uint8_t *)buf, blk_addr , blk_len, 1000))
         return USBD_FAIL ;
    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 */
    if(HAL_OK != HAL_SD_WriteBlocks(&hsd, (uint8_t *)buf, blk_addr , blk_len, 1000))
        return USBD_FAIL ;
    return (USBD_OK);
  /* USER CODE END 7 */
}

OK, these two problems have been solved. Let's see what we do.

1, USB enable pin configuration



PD3 pin, the default output level is low, that is to say, D + pin is enabled, and USB is powered on.
PB1 is the lamp I used for debugging.

2, RCC clock



Remember a bit here, because we use USB here. The USB clock should be configured as 48MHz. See the manual for details.
SDIO is the clock is the second frequency of HCLK.

3, Debug interface


Select serial debugging here.

4, SDIO configuration


Here, we configure the mode as the SD card mode of 4-bit wide bus. As we have known before in step 2, the clock frequency of SDIO is the dichotomy of HCLK, so we set the option of SDIOCLK clock divide factor to 2.

Turn on SDIO global interrupt.

5, USB configuration



Here, the USB device is configured as mass storage, and the rest can be defaulted.

6, Generate and add code logic


Here we'll make the stack a little larger so that we can test it later in the code.
The following interfaces are implemented in usbd storage if. C:

Storage? Getcapacity? Fs to obtain the capacity information of the U SB flash disk
 Storage? Isready? Fs to get the status of the U SB flash disk
 Storage read FS
 Storage write FS

Get how many blocks there are and the size of the blocks through the interface.

/**
  * @brief  .
  * @param  lun: .
  * @param  block_num: .
  * @param  block_size: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */
    *block_num  = hsd.SdCard.BlockNbr ;
    *block_size = hsd.SdCard.BlockSize ;
    return (USBD_OK);
  /* USER CODE END 3 */
}

Judge whether the status of SD card is ready. The description of the status is as follows:

typedef enum
{
  HAL_SD_STATE_RESET                  = ((uint32_t)0x00000000U),  /*!< SD not yet initialized or disabled  */
  HAL_SD_STATE_READY                  = ((uint32_t)0x00000001U),  /*!< SD initialized and ready for use    */
  HAL_SD_STATE_TIMEOUT                = ((uint32_t)0x00000002U),  /*!< SD Timeout state                    */
  HAL_SD_STATE_BUSY                   = ((uint32_t)0x00000003U),  /*!< SD process ongoing                  */
  HAL_SD_STATE_PROGRAMMING            = ((uint32_t)0x00000004U),  /*!< SD Programming State                */
  HAL_SD_STATE_RECEIVING              = ((uint32_t)0x00000005U),  /*!< SD Receiving State                  */
  HAL_SD_STATE_TRANSFER               = ((uint32_t)0x00000006U),  /*!< SD Transfert State                  */
  HAL_SD_STATE_ERROR                  = ((uint32_t)0x0000000FU)   /*!< SD is in error state                */
}HAL_SD_StateTypeDef;
/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
  /* USER CODE BEGIN 4 */
    uint8_t state = 0;
    state = HAL_SD_GetState(&hsd) ;
    if(HAL_SD_STATE_READY != state)
        return USBD_FAIL ;
    return (USBD_OK);
  /* USER CODE END 4 */
}

USB read and write SD card

/**
  * @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(HAL_OK != HAL_SD_ReadBlocks(&hsd,(uint8_t *)buf, blk_addr , blk_len, 1000))
         return USBD_FAIL ;
    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 */
    if(HAL_OK != HAL_SD_WriteBlocks(&hsd, (uint8_t *)buf, blk_addr , blk_len, 1000))
        return USBD_FAIL ;
    return (USBD_OK);
  /* USER CODE END 7 */
}

Add a debug blinker to the while loop of the main function.

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SDIO_SD_Init();
  MX_USART2_UART_Init();
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
 
 

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        //LED debugging light turns over at a frequency of 500ms
        HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);	
         HAL_Delay(1000);
    }

  /* USER CODE END 3 */
}

7, Operation results

Insert the USB cable into the interface of USB DEVICE and connect it to the USB port of PC, and eject the removable disk at PC, the experiment is successful.


I use a 4GB memory card and the PC displays 3.68GB. Why? Du Niang:
Kingston 4G SD card only has 3.68G?
Your computer's algorithm is 1024MB=1GB
The algorithm of U disk manufacturer is 1000MB=1GB
In addition, the product error allowed by law will be added. Generally, the manufacturer will take the minimum value and will not give you more space.
Why is 4G mobile memory card only 3.68G in the mobile phone?
Hardware manufacturers use decimal system for calculation convenience, that is, 1K for full 1000 bytes, 1M for full 1000K, and so on.
In the software design, because the computer is binary, it is 1K when it is full of 1024 bytes, i.e. 2 to the 10th power, and 1M when it is 1024K.
So the bigger your card is, the bigger the gap will be, which will be more obvious on the hard disk.

596 original articles published, 1057 praised, 1.82 million visitors+
His message board follow

Posted by kokomo310 on Tue, 18 Feb 2020 05:20:57 -0800