STM32H743基于SPI的SD卡驱动开发流程简析

电子说

1.2w人已加入

描述

STM32H743以太网驱动调试

硬件环境:
基于STM32H743IIT6自研单板
(1)外部时钟:25MHz
(2)调试串口: PC12 ———> UART5_TX
PD2 ———> UART5_RX
(3)SPI6
PG12 ———> SPI6_MISO
PG13 ———> SPI6_SCK
PG14 ———> SPI6_MOSI
PG8 ———> SPI6_NSS

软件开发环境
RT-Thread Studio
版本: 2.2.6
构建ID: 202211231640
OS: Windows 10, v.10.0, x86_64 / win32

调试串口+以太网

RT-Thread配置

SPI接口

SPI接口

SPI配置
在board.h文件中,参考SPI配置说明依次配置SPI参数

/ -------------------------- SPI CONFIG BEGIN -------------------------- /
/** if you want to use spi bus you can use the following instructions.

STEP 1, open spi driver framework support in the RT-Thread Settings file

STEP 2, define macro related to the spi bus* ```
such as #define BSP_USING_SPI1


STEP 3, copy your spi init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end of board.c file

such as     void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)

STEP 4, modify your stm32xxxx_hal_config.h file to support spi peripherals. define macro related to the peripherals

such as     #define HAL_SPI_MODULE_ENABLED

/
#define BSP_USING_SPI
/
#define BSP_USING_SPI1*/
/ #define BSP_USING_SPI2 /
/ #define BSP_USING_SPI3 /
/ #define BSP_USING_SPI4 /
/ #define BSP_USING_SPI5 /
#define BSP_USING_SPI6
/ -------------------------- SPI CONFIG END -------------------------- /
在board.c文件中添加HAL_SPI_MspInit函数

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(spiHandle->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 /
/
USER CODE END SPI1_MspInit 0 /
/
* Initializes the peripherals clock
/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI1;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/
SPI1 clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration
PG9 ------> SPI1_MISO
PG11 ------> SPI1_SCK
PB5 ------> SPI1_MOSI
/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/
SPI1 interrupt Init /
HAL_NVIC_SetPriority(SPI1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
/
USER CODE BEGIN SPI1_MspInit 1 /
/
USER CODE END SPI1_MspInit 1 */
}
else if(spiHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI2;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
/**SPI2 GPIO Configuration
PB10 ------> SPI2_SCK
PB15 ------> SPI2_MOSI
PI2 ------> SPI2_MISO
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
else if(spiHandle->Instance==SPI3)
{
/* USER CODE BEGIN SPI3_MspInit 0 */
/* USER CODE END SPI3_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI3;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SPI3 clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**SPI3 GPIO Configuration
PB2 ------> SPI3_MOSI
PC10 ------> SPI3_SCK
PC11 ------> SPI3_MISO
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* SPI3 interrupt Init */
HAL_NVIC_SetPriority(SPI3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI3_IRQn);
/* USER CODE BEGIN SPI3_MspInit 1 */
/* USER CODE END SPI3_MspInit 1 */
}
else if(spiHandle->Instance==SPI4)
{
/* USER CODE BEGIN SPI4_MspInit 0 */
/* USER CODE END SPI4_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI4;
PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_D2PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SPI4 clock enable */
__HAL_RCC_SPI4_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/**SPI4 GPIO Configuration
PE2 ------> SPI4_SCK
PE5 ------> SPI4_MISO
PE6 ------> SPI4_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;//GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* SPI4 interrupt Init */
HAL_NVIC_SetPriority(SPI4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI4_IRQn);
/* USER CODE BEGIN SPI4_MspInit 1 */
/* USER CODE END SPI4_MspInit 1 */
}
else if(spiHandle->Instance==SPI5)
{
/* USER CODE BEGIN SPI5_MspInit 0 */
/* USER CODE END SPI5_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI5;
PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_D2PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SPI5 clock enable */
__HAL_RCC_SPI5_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
/**SPI5 GPIO Configuration
PF7 ------> SPI5_SCK
PF8 ------> SPI5_MISO
PF9 ------> SPI5_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* SPI5 interrupt Init */
HAL_NVIC_SetPriority(SPI5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI5_IRQn);
/* USER CODE BEGIN SPI5_MspInit 1 */
/* USER CODE END SPI5_MspInit 1 */
}
else if(spiHandle->Instance==SPI6)
{
/* USER CODE BEGIN SPI6_MspInit 0 */
/* USER CODE END SPI6_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI6;
PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_D3PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SPI6 clock enable */
__HAL_RCC_SPI6_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/**SPI6 GPIO Configuration
PG12 ------> SPI6_MISO
PG13 ------> SPI6_SCK
PG14 ------> SPI6_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI6;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/* SPI6 interrupt Init */
HAL_NVIC_SetPriority(SPI6_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI6_IRQn);
/* USER CODE BEGIN SPI6_MspInit 1 */
/* USER CODE END SPI6_MspInit 1 */
}
}
在stm32h7xx_hal_conf.h文件中,打开宏定义:

#define HAL_SPI_MODULE_ENABLED

在drv_spi.c文件的spi_config数组中用到了SPI6_BUS_CONFIG,默认工程是没有的,需要自己添加,可以参考已有的SPI配置

SPI接口

在spi_config.h文件尾部添加SPI6_BUS_CONFIG

#ifdef BSP_USING_SPI6
#ifndef SPI6_BUS_CONFIG
#define SPI6_BUS_CONFIG
{
.Instance = SPI6,
.bus_name = "spi6",
}
#endif /* SPI6_BUS_CONFIG /
#endif /
BSP_USING_SPI6 /
//#ifdef BSP_SPI6_TX_USING_DMA
//#ifndef SPI6_TX_DMA_CONFIG
//#define SPI6_TX_DMA_CONFIG
// {
// .dma_rcc = SPI6_TX_DMA_RCC,
// .Instance = SPI6_TX_DMA_INSTANCE,
// .channel = SPI6_TX_DMA_CHANNEL,
// .dma_irq = SPI6_TX_DMA_IRQ,
// }
//#endif /
SPI6_TX_DMA_CONFIG /
//#endif /
BSP_SPI6_TX_USING_DMA /
//
//#ifdef BSP_SPI6_RX_USING_DMA
//#ifndef SPI6_RX_DMA_CONFIG
//#define SPI6_RX_DMA_CONFIG
// {
// .dma_rcc = SPI6_RX_DMA_RCC,
// .Instance = SPI6_RX_DMA_INSTANCE,
// .channel = SPI6_RX_DMA_CHANNEL,
// .dma_irq = SPI6_RX_DMA_IRQ,
// }
//#endif /
SPI6_RX_DMA_CONFIG /
//#endif /
BSP_SPI6_RX_USING_DMA */
在dfs_fs.c文件中,添加文件系统默认装载表:

const struct dfs_mount_tbl mount_table[] =
{
{"sd0", "/", "elm", 0, 0},
{0}
};

在driver目录下添加drv_spi_tfcard.c文件

测试

SPI接口

至此完成基于SPI的SD驱动框架。

遗留问题
添加SD后,MPU配置会影响以太网ping的效果,使用下面配置SD卡、以太网均正常

{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU /
HAL_MPU_Disable();
/
* Initializes and configures the Region and the memory to be protected
/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x30040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/
* Initializes and configures the Region and the memory to be protected
/
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.BaseAddress = 0x30044000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/
Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
使用下面的配置,以太网ping不通

{
MPU_Region_InitTypeDef MPU_InitStruct;
/* Disable the MPU /
HAL_MPU_Disable();
/
Configure the MPU attributes as WT for AXI SRAM /
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0X00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#ifdef BSP_USING_SDRAM
/
Configure the MPU attributes as WT for SDRAM /
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xC0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#endif
#ifdef BSP_USING_ETH
/
Configure the MPU attributes as Device not cacheable
for ETH DMA descriptors and RX Buffers*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#endif
/* Configure the MPU attributes as WT for QSPI /
// MPU_InitStruct.Enable = MPU_REGION_ENABLE;
// MPU_InitStruct.BaseAddress = 0x90000000;
// MPU_InitStruct.Size = MPU_REGION_SIZE_8MB;
// MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
// MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
// MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
// MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
// MPU_InitStruct.Number = MPU_REGION_NUMBER3;
// MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
// MPU_InitStruct.SubRegionDisable = 0X00;
// MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
//
// HAL_MPU_ConfigRegion(&MPU_InitStruct);
/
Enable the MPU /
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
/
Enable CACHE */
SCB_EnableICache();
SCB_EnableDCache();
return RT_EOK;
}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分