STM32的SPI1引脚重映射后读写SD卡
来源: 芯艺
本站广告
  ENC28J60+uIP 基于TCP的MODBUS IO示例
  ENC28J60+uIP DHCP动态获取IP及UDP广播服务端示例
  ENC28J60+uIP HTTP GET方式将温度数据上传到web服务器
  C720H5上实现MODBUS远程IO
  FM1702读写S50(也叫M1)卡相关资料

初次使用STM32有些不太明白,此次调试经验奉献出来与大家分享!

系统:STM32 + SD + FATFS

STM32与SD卡的连接如下定义,PB口
#define SD_SCK   GPIO_Pin_3 
#define SD_MISO  GPIO_Pin_4 
#define SD_MOSI  GPIO_Pin_5 
#define SD_CS    GPIO_Pin_7 

我想使用SPI1并重映射引脚使用时注意的事项如下:
1.使能PB0时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
2.使能AFIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
3.使能SPI1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 , ENABLE);
4.禁用JTAG时钟复用 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); 
5.SPI1引脚重映射 GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);

接着初始化GPIO和SPI1即可,如:

void SpiOpen(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef   SPI_InitStructure;

  /* Configure SPI1 pins: SCKand MOSI */
  GPIO_InitStructure.GPIO_Pin = SD_MOSI|SD_SCK|SD_MISO;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* Configure PB7 pin: CS pin */
  GPIO_InitStructure.GPIO_Pin = SD_CS;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB,SD_CS);

  /* SPI1 Config */
  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_256;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI1, &SPI_InitStructure);

  /* SPI1 enable */
  SPI_Cmd(SPI1, ENABLE);
}

可是这一切完成的时候结果却与想象的不同,无法在SD卡内创建文件,找一个晚上没有结果
不得已采用另一种方法:软件模拟SPI测试了一下,

结果另人出呼意料,一次搞定,没有任何问题,但为了效率还是希望使用硬SPI口,于是从引脚重映射上寻找原因

又费了一晚上无果 
第三个晚上:经过无数次的 改动 + 测试 终于OK了,问题出在哪里了呢? 
原来SD卡的初始时钟不一定是<400KHz就行 ST标准库初始化系统时APB2时钟为72MHz,经过256分频波特率约等于 280KHz
(SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;)

对于我测试用的SD卡这个速度仍太快,于是降APB2时钟进行测试,OK! 

RCC_PCLK2Config(RCC_HCLK_Div4); //72/4=18MHz 

仅仅是一行代码,这就是初学代价!,哈哈. 

另外要说明的是,在MISO引脚上加了一个22k上接电阻. 


代码:

//#define USE_SOFT_SPI
#ifdef USE_SOFT_SPI

BYTE g_SPISpeedFlag=0;
static void delay_bus(void)

{
  unsigned int i=100;
  if(g_SPISpeedFlag)   //高速模式  < 25MHz
    i=10;
    
  while(--i)          //低速模式 < 400KHz
    __nop();
}

void SpiOpen(void)
{

  //IO初始化用结构体  
  GPIO_InitTypeDef GPIO_InitStructure;  
  
  //输出引脚初始化  
  GPIO_InitStructure.GPIO_Pin=SD_SCK|SD_CS|SD_MOSI;
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
  
  //输入引脚配置
  GPIO_InitStructure.GPIO_Pin=SD_MISO;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_Mode_IN_FLOATING ;
  
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  //设置端口初始电平  
  
  GPIO_SetBits(GPIOB,SD_CS);
  GPIO_SetBits(GPIOB,SD_SCK);
  g_SPISpeedFlag=0;
}


void SpiClose(void)
{
  GPIO_SetBits(GPIOB,SD_CS);
  GPIO_SetBits(GPIOB,SD_SCK);
  Stat &= ~STA_NOINIT;  
}

void SPI_SetHeighSpeed(void)
{
  g_SPISpeedFlag=1;
}

BYTE SPI_ReadWriteByte(BYTE outgoing)
{
  uint32_t i;
  uint8_t ret=0;
  delay_bus();
  for(i=0;i<8;i++)
  {
    ret<<=1;

     if(outgoing &0x80)  //主设备锁存数据
      GPIO_SetBits(GPIOB,SD_MOSI);
    else
      GPIO_ResetBits(GPIOB,SD_MOSI);    
    GPIO_ResetBits(GPIOB,SD_SCK); //产生第一个时钟沿,让从设备也在此时锁存数据

    delay_bus();  
    
    if(GPIO_ReadInputDataBit(GPIOB,SD_MISO)) //主设备采样 
      ret|=1;
     GPIO_SetBits(GPIOB,SD_SCK);   //产生第二个时钟沿,让从设备也在此时采样

    delay_bus();
    outgoing<<=1;      

  }
  return ret;
}


#else  //硬件SPI  使用SPI1引脚重映射

void SpiOpen(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef   SPI_InitStructure;

  GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);

  /* Configure SPI1 pins: SCKand MOSI */
  GPIO_InitStructure.GPIO_Pin = SD_MOSI|SD_SCK|SD_MISO;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* Configure PB7 pin: CS pin */
  GPIO_InitStructure.GPIO_Pin = SD_CS;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB,SD_CS);

  /* SPI1 Config */
  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_256;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI1, &SPI_InitStructure);

  /* SPI1 enable */
  SPI_Cmd(SPI1, ENABLE);
}

void SpiClose(void)
{
  SPI_Cmd(SPI1, DISABLE);
  Stat &= ~STA_NOINIT;  
}

void SPI_SetHeighSpeed(void)
{
    SPI_InitTypeDef   SPI_InitStructure;

    /* SPI1 Config */
    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);

    SPI_Cmd(SPI1, ENABLE);
}

BYTE SPI_ReadWriteByte(BYTE outgoing)
{
  /* Loop while DR register in not emplty */
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

  /* Send byte through the SPI1 peripheral */
  SPI_I2S_SendData(SPI1, outgoing);

  /* Wait to receive a byte */
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

  /* Return the byte read from the SPI bus */
  return SPI_I2S_ReceiveData(SPI1);
}

#endif





声明:芯艺工作室(http://www.chipart.cn)保留所有权力,转载请注明出处!

芯艺工作室    蒙ICP备06005492号

Copyright© 2004-2020 ChipArt Studio All Rights Reserved