对于STM32开发板例子,采用SPI访问Flash的方式,觉得比较困惑,特做深入分析。基本源码如下,分析内容以黑色字体标注。
开始非常疑惑为什么连接Flash设备的引脚采用GPIO引脚,实际是:GOPI重映射的具体信息在《【中文】STM32F系列ARM内核32位高性能微控制器参考手册V10_1》的8.3.10 SPI 1复用功能重映射。
SPI1重映像
复用功能 |
SPI1_REMAP = 0 |
SPI1_REMAP = 1 |
SPI1_NSS | PA4 | PA15 |
SPI1_SCK | PA5 | PB3 |
SPI1_MISO | PA6 | PB4 |
SPI1_MOSI | PA7 | PB5 |
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 由于开发板中SPI CF卡和Flash采用线路复用,因此,先要将CF的片选引脚进行禁用
/* Disable SD CS */
GPIO_InitStructure.GPIO_Pin = SD_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(SD_CS_GPIO_PORT, &GPIO_InitStructure);
GPIO_SetBits(SD_CS_GPIO_PORT, SD_CS_PIN);
/* Enable SPI1 and GPIO clocks */
//很奇怪,为什么没有主设备和从设备,而是采用GPIO管脚的方式与SPI引脚进行进行连接。(采用GPIO重映射功能,将管脚映射到SPI上)
/*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,
SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIO
and SPI_FLASH_SPI_SCK_GPIO Periph clock enable */
RCC_APB2PeriphClockCmd(SPI_FLASH_CS_GPIO_CLK | SPI_FLASH_SPI_MOSI_GPIO_CLK |
SPI_FLASH_SPI_MISO_GPIO_CLK | SPI_FLASH_SPI_SCK_GPIO_CLK |
RCC_APB2Periph_GPIOD, ENABLE);
/*!< SPI_FLASH_SPI Periph clock enable */
RCC_APB2PeriphClockCmd(SPI_FLASH_SPI_CLK, ENABLE);
/*!< AFIO Periph clock enable */
//因为复用重映射所以要启用AFIO时钟?
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*!< Remap SPI3 Pins */
//GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE);
//将引脚配置为时钟输出
/*!< Configure SPI_FLASH_SPI pins: SCK */
GPIO_InitStructure.GPIO_Pin = SPI_FLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(SPI_FLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure SPI_FLASH_SPI pins: MISO */
GPIO_InitStructure.GPIO_Pin = SPI_FLASH_SPI_MISO_PIN;
GPIO_Init(SPI_FLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure SPI_FLASH_SPI pins: MOSI */
GPIO_InitStructure.GPIO_Pin = SPI_FLASH_SPI_MOSI_PIN;
GPIO_Init(SPI_FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure SPI_FLASH_SPI_CS_PIN pin: SPI_FLASH Card CS pin */
GPIO_InitStructure.GPIO_Pin = SPI_FLASH_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(SPI_FLASH_CS_GPIO_PORT, &GPIO_InitStructure);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH();
/* SPI1 configuration */
// W25X16: data input on the DIO pin is sampled on the rising edge of the CLK.
// Data on the DO and DIO pins are clocked out on the falling edge of CLK.
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;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI1, ENABLE);
}