刚好用的spi2 发来看看 晚上回来没有板子就不测试你的了 我的测试已经ok 我用SD卡记录数据
也是从原子哥的来的
fatfs需要的再联系
[mw_shl_code=c,true]/**
******************************************************************************
* @file bsp_sd.c
* @author Nick Thinkfly.studio
* @version V1.0
* @date 2014-10-6
* @brief This file provides all the sd functions.
******************************************************************************
* @attention
*
* FILE FOR THINKFLY.STUDIO ONLY
*
* <h2><center>© COPYRIGHT ThinkFly.Studio</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <bsp_sd.h>
/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Global variables ---------------------------------------------------------*/
static u8 SD_TYPE; /* SD卡类型 */
/* Private function prototypes -----------------------------------------------*/
static u8 BSP_SD_SendCmd ( u8 cmd, u32 arg, u8 crc );
static u8 BSP_SD_ReceiveData ( u8* buf, u16 len );
static void BSP_SD_DisSelect ( void );
static u8 BSP_SD_Select ( void );
static u8 BSP_SD_SendBlock ( u8* dataBuf, u8 cmd );
/* Exported functions ---------------------------------------------------------*/
/**
* @brief 初始化SD卡
* @note 先初始化SPI
* @param void
* @retval u8 0:初始化成功 ;1:初始化失败
* @author Nick.liao
*/
u8 BSP_SD_Init()
{
u8 RX; /*存放SD卡返回值*/
u16 timeOut; /*超时计数*/
u8 buf[4];
u16 i;
/* SPI2在BSP_Init中初始化 */
BSP_SPI_Init();
/* 拉高片选SD卡IO*/
SD_CS = 1;
/* SD卡初始化用低速SPI */
BSP_SPI_SetSpeed ( SPI_BaudRatePrescaler_256 );
for ( i = 0; i < 20; i++ ) /* 发送最少74个脉冲 */
{
BSP_SPI_RW ( 0XFF );
}
timeOut = 20;
do
{
RX = BSP_SD_SendCmd ( CMD0, 0, 0x95 ); /* 进入IDLE状态 */
}
while ( ( RX != 0X01 ) && timeOut-- );
SD_TYPE = 0; /* 默认无卡 */
if ( RX == 0x01 )
{
if ( BSP_SD_SendCmd ( CMD8, 0x1AA, 0x87 ) == 0x01 ) /* SD V2.0 */
{
for ( i = 0; i < 4; i++ ) buf = BSP_SPI_RW ( 0xFF );
if ( buf[2] == 0X01 && buf[3] == 0XAA ) /* SD卡是否支持2.7v-3.6v */
{
timeOut = 0xFFFE;
do
{
BSP_SD_SendCmd ( CMD55, 0, 0x01 );
RX = BSP_SD_SendCmd ( CMD41, 0x40000000, 0X01 );
}
while ( RX && timeOut );
/* 鉴别SD卡2.0 */
if ( timeOut && BSP_SD_SendCmd ( CMD58, 0, 0X01 ) == 0 )
{
for ( i = 0; i < 4; i++ ) buf = BSP_SPI_RW ( 0XFF );
if ( buf[0] & 0x40 ) SD_TYPE = SD_TYPE_V2HC;
else SD_TYPE = SD_TYPE_V2;
}
}
}
else /* SD V1.x/ MMC */
{
BSP_SD_SendCmd ( CMD55, 0, 0X01 ); /*发送CMD55 */
RX = BSP_SD_SendCmd ( CMD41, 0, 0X01 ); /*发送CMD41 */
if ( RX <= 1 )
{
SD_TYPE = SD_TYPE_V1;
timeOut = 0XFFFE;
do /*等待退出IDLE模式*/
{
BSP_SD_SendCmd ( CMD55, 0, 0X01 ); /*发送CMD55 */
RX = BSP_SD_SendCmd ( CMD41, 0, 0X01 ); /*发送CMD41 */
}
while ( RX && timeOut-- );
}
else
{
SD_TYPE = SD_TYPE_MMC; /*MMC V3 */
timeOut = 0XFFFE;
do /*等待退出IDLE模式*/
{
RX = BSP_SD_SendCmd ( CMD1, 0, 0X01 ); /*发送CMD1 */
}
while ( RX && timeOut-- );
}
if ( timeOut == 0 || BSP_SD_SendCmd ( CMD16, 512, 0X01 ) != 0 ) SD_TYPE = SD_TYPE_ERR; /*错误的卡*/
}
}
SD_CS = 1;
BSP_SPI_SetSpeed ( SPI_BaudRatePrescaler_2 );
if ( SD_TYPE )return SOK;
else return SERR_SD_INIT;
}
/**
* @brief 发送一个SD卡命令(6个字节)
* @note None
* @param void
* @retval u8 SD卡的响应 其中0x80表示超时
* @author Nick.liao
*/
u8 BSP_SD_SendCmd ( u8 cmd, u32 arg, u8 crc )
{
u8 r1;
u8 timeOut = 0;
BSP_SD_DisSelect(); /* 取消上次片选 */
if ( BSP_SD_Select() ) return 0XFF; /* 片选失效 */
/* 发送命令 */
BSP_SPI_RW ( cmd | 0x40 );
BSP_SPI_RW ( arg >> 24 );
BSP_SPI_RW ( arg >> 16 );
BSP_SPI_RW ( arg >> 8 );
BSP_SPI_RW ( arg );
BSP_SPI_RW ( crc );
if ( cmd == CMD12 ) BSP_SPI_RW ( 0xff );
timeOut = 0X1F;
r1 = 0x80;
do
{
r1 = BSP_SPI_RW ( 0xFF );
}
while ( ( r1 & 0X80 ) && timeOut-- );
return r1;
}
/**
* @brief 使能SD卡的片选
* @note None
* @param None
* @retval u8 0:成功;1:失败,并且取消片选
* @author Nick.liao
*/
static u8 BSP_SD_Select ( void )
{
SD_CS = 0;
if ( BSP_SD_WaitReady() == 0 ) return 0; /* 等待成功 */
BSP_SD_DisSelect();
return 1; /* 等待失败 */
}
/**
* @brief 等待卡准备好
* @note None
* @param void
* @retval u8 0:准备好;1:超时没有准备好
* @author Nick.liao
*/
u8 BSP_SD_WaitReady ( void )
{
u32 timeOut = 0;
do
{
if ( BSP_SPI_RW ( 0XFF ) == 0XFF ) return 0;
}
while ( timeOut < 0xFFFFFF );
return 1;
}
/**
* @brief 读取一个数据包
* @note None
* @param BufPtr 存储数据地址 len 数据长度
* @retval u8 0:成功;1:失败
* @author Nick.liao
*/
static u8 BSP_SD_ReceiveData ( u8* BufPtr, u16 len )
{
if ( BSP_SD_GetResponse ( 0xFE ) ) return 1; //等待SD卡发回数据起始令牌0xFE
while ( len-- ) //开始接收数据
{
*BufPtr = BSP_SPI_RW ( 0xFF );
BufPtr++;
}
//下面是2个伪CRC(dummy CRC)
BSP_SPI_RW ( 0xFF );
BSP_SPI_RW ( 0xFF );
return 0;//读取成功
}
/**
* @brief 得到SD卡指定的响应
* @note None
* @param void
* @retval u8 0:得到指定响应;其他 响应失败
* @author Nick.liao
*/
u8 BSP_SD_GetResponse ( u8 Response )
{
u16 timeOut = 0xFFF;
while ( ( BSP_SPI_RW ( 0XFF ) != Response ) && timeOut ) timeOut--; /*等待得到准确的回应 */
if ( timeOut == 0 ) return MSD_RESPONSE_FAILURE; /*得到回应失败 */
else return MSD_RESPONSE_NO_ERROR; /*正确回应 */
}
/**
* @brief 获取卡标识寄存器CID或者CSD内容
* @note None
* @param InfoCmd 可选CSD_CMD/CID_CMD
BufPtr 存储CID的buf 128位 16*8
* @retval u8 0:成功;1:失败
* @author Nick.liao
*/
u8 BSP_SD_GetInfo ( u8 InfoCmd, u8* BufPtr )
{
u8 r1;
r1 = BSP_SD_SendCmd ( InfoCmd, 0, 0X01 );
if ( !r1 )
{
/* 接收16个字节的数据 */
r1 = BSP_SD_ReceiveData ( BufPtr, 16 );
}
if ( r1 ) return 1;
else return 0;
}
/**
* @brief 失能SD卡的SPI片选
* @note None
* @param None
* @retval None
* @author Nick.liao
*/
static void BSP_SD_DisSelect ( void )
{
SD_CS = 1;
BSP_SPI_RW ( 0xff ); /* 提供额外的8个时钟 */
}
/**
* @brief 获取扇区总数
* @note None
* @param None
* @retval SectorCount 0表示读取出错 其他为扇区数
* @author Nick.liao
*/
u32 BSP_SD_GetSectorCount ( void )
{
u8 CSD_Buf[16];
u32 Capacity;
u8 n;
u16 csize;
/* 取CSD信息,如果期间出错,返回0 */
if ( BSP_SD_GetInfo ( CSD_CMD, CSD_Buf ) != 0 ) return 0;
/* 如果为SDHC卡,按照下面方式计算 */
if ( ( CSD_Buf[0] & 0xC0 ) == 0x40 ) /* V2.00的卡 */
{
csize = CSD_Buf[9] + ( ( uint16_t ) CSD_Buf[8] << 8 ) + 1;
Capacity = ( uint32_t ) csize << 10; /* 得到扇区数 */
}
else /* V1.XX的卡 */
{
n = ( CSD_Buf[5] & 15 ) + ( ( CSD_Buf[10] & 128 ) >> 7 ) + ( ( CSD_Buf[9] & 3 ) << 1 ) + 2;
csize = ( CSD_Buf[8] >> 6 ) + ( ( uint16_t ) CSD_Buf[7] << 2 ) + ( ( uint16_t ) ( CSD_Buf[6] & 3 ) << 10 ) + 1;
Capacity = ( uint32_t ) csize << ( n - 9 ); /* 得到扇区数 */
}
return Capacity;
}
/**
* @brief 读取指定扇区数据
* @note None
* @param dataBuf 缓存数据指针,容量512整数倍
sector 扇区地址
cnt 读取扇区数,cnt=1和>1采用指令不一样
* @retval 0 成功
1 失败
* @author Nick.liao
*/
u8 BSP_SD_ReadSector ( u8*dataBuf, u32 sector, u8 cnt )
{
u8 R1;
if ( SD_TYPE != SD_TYPE_V2HC ) sector <<= 9; /*转换为字节地址 */
if ( cnt == 1 )
{
R1 = BSP_SD_SendCmd ( CMD17, sector, 0X01 ); /* 读命令 */
if ( R1 == 0 ) /* 指令发送成功 */
{
R1 = BSP_SD_ReceiveData ( dataBuf, 512 ); /* 接收512个字节 */
}
}
else
{
R1 = BSP_SD_SendCmd ( CMD18, sector, 0X01 ); /* 连续读命令 */
do
{
R1 = BSP_SD_ReceiveData ( dataBuf, 512 ); /* 接收512个字节 */
dataBuf += 512;
}
while ( --cnt && R1 == 0 );
BSP_SD_SendCmd ( CMD12, 0, 0X01 ); /* 发送停止命令 */
}
BSP_SD_DisSelect(); /* 取消片选 */
return R1;
}
/**
* @brief 向SD卡发送数据
* @note None
* @param dataBuf 数据缓存指针
cmd 用来发送的命令
* @retval 0 成功
1 等待中
* @author Nick.liao
*/
static u8 BSP_SD_SendBlock ( u8* dataBuf, u8 cmd )
{
u16 t;
if ( BSP_SD_WaitReady() ) return 1; /* 等待准备失效 */
BSP_SPI_RW ( cmd );
if ( cmd != 0XFD ) /* 不是结束指令 */
{
for ( t = 0; t < 512; t++ ) BSP_SPI_RW ( dataBuf[t] ); /* 提高速度,减少函数传参时间 */
BSP_SPI_RW ( 0xFF ); /* 忽略crc */
BSP_SPI_RW ( 0xFF );
t = BSP_SPI_RW ( 0xFF ); /* 接收响应 */
if ( ( t & 0x1F ) != 0x05 ) return 2; /* 响应错误 */
}
return 0; /* 写入成功 */
}
/**
* @brief 向SD卡写数据
* @note None
* @param dataBuf 数据缓存指针,大小为512*cnt
sector 写入扇区起始地址
cnt 连续写入的扇区数
* @retval 0 成功
其他 错误码
* @author Nick.liao
*/
u8 BSP_SD_WriteSector ( u8* dataBuf, u32 sector, u8 cnt )
{
u8 R1;
if ( SD_TYPE != SD_TYPE_V2HC ) sector *= 512; /* 转换为字节地址 */
if ( cnt == 1 )
{
R1 = BSP_SD_SendCmd ( CMD24, sector, 0X01 ); /* 读命令 */
if ( R1 == 0 ) /* 指令发送成功 */
{
R1 = BSP_SD_SendBlock ( dataBuf, 0xFE ); /* 写512个字节 */
}
}
else
{
if ( SD_TYPE != SD_TYPE_MMC )
{
BSP_SD_SendCmd ( CMD55, 0, 0X01 );
BSP_SD_SendCmd ( CMD23, cnt, 0X01 ); /* 发送指令 */
}
R1 = BSP_SD_SendCmd ( CMD25, sector, 0X01 ); /* 连续写命令 */
if ( R1 == 0 )
{
do
{
R1 = BSP_SD_SendBlock ( dataBuf, 0xFC ); /* 写512个字节 */
dataBuf += 512;
}
while ( --cnt && R1 == 0 );
R1 = BSP_SD_SendBlock ( 0, 0xFD ); /* 写结束指令 */
}
}
BSP_SD_DisSelect(); /* 取消片选 */
return R1;
}
[/mw_shl_code]
bsp_spi.c
[mw_shl_code=c,true]/**
******************************************************************************
* @file bsp_spi.c
* @author Nick Thinkfly.studio
* @version V1.0
* @date 2014-11-11
* @brief This file provides all the spi functions.
******************************************************************************
* @attention
*
* FILE FOR THINKFLY.STUDIO ONLY
*
* <h2><center>© COPYRIGHT ThinkFly.Studio</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <bsp_spi.h>
/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Global variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions ---------------------------------------------------------*/
/**
* @brief 初始化spi2
* @note None
* @param void
* @retval None
* @author Nick.liao
*/
void BSP_SPI_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOB, ENABLE );
RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOD, ENABLE );
RCC_APB1PeriphClockCmd ( RCC_APB1Periph_SPI2, ENABLE );
GPIO_PinAFConfig ( GPIOB, GPIO_PinSource13, GPIO_AF_SPI2 );
GPIO_PinAFConfig ( GPIOB, GPIO_PinSource14, GPIO_AF_SPI2 );
GPIO_PinAFConfig ( GPIOB, GPIO_PinSource15, GPIO_AF_SPI2 );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //PB13~15复用功能输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init ( GPIOB, &GPIO_InitStructure ); //初始化
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 ( SPI2, &SPI_InitStructure );
SPI_Cmd ( SPI2, ENABLE );
/* 启动传输 */
BSP_SPI_RW ( 0xff );
/* SD卡片选IO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init ( GPIOB, &GPIO_InitStructure );
/* RES SPI片选*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Init ( GPIOB, &GPIO_InitStructure );
/* 片选拉高,取消全部片选 */
GPIO_SetBits ( GPIOB, GPIO_Pin_11 );
GPIO_SetBits ( GPIOB, GPIO_Pin_12 );
}
/**
* @brief 设置spi2的速度--通过修改分频系数 sys@168mhz APB1@42MHz
* @note None
* @param SPI_BaudRatePrescaler_x x=2、4、、256
* @retval None
* @author Nick.liao
*/
void BSP_SPI_SetSpeed ( u8 SPI_BaudRatePrescaler )
{
assert_param ( IS_SPI_BAUDRATE_PRESCALER ( SPI_BaudRatePrescaler ) );
SPI2->CR1 &= 0XFFC7;
SPI2->CR1 |= SPI_BaudRatePrescaler;
SPI_Cmd ( SPI2, ENABLE );
}
/**
* @brief 通过SPI2发送和接受一个字节
* @note None
* @param u8 TxData 要发送的字节
* @retval u8 RxData 要接受的字节
* @author Nick.liao
*/
u8 BSP_SPI_RW ( u8 TxData )
{
/*等待发射区空*/
while ( SPI_I2S_GetFlagStatus ( SPI2, SPI_I2S_FLAG_TXE ) == RESET ) {}
/*通过SPI2发送一个字节*/
SPI_I2S_SendData ( SPI2, TxData );
/*等待接受一个字节*/
while ( SPI_I2S_GetFlagStatus ( SPI2, SPI_I2S_FLAG_RXNE ) == RESET ) {}
return SPI_I2S_ReceiveData ( SPI2 );
}
[/mw_shl_code]
|