From 8421ecfa277eeb813e7c217955328c6329208f38 Mon Sep 17 00:00:00 2001 From: aozima Date: Thu, 21 Feb 2013 20:10:54 +0800 Subject: [PATCH] update SD card driver: use RT-Thread SPI driver. --- bsp/stm32f107/drivers/SConscript | 9 + bsp/stm32f107/drivers/board.c | 13 +- bsp/stm32f107/drivers/board.h | 3 + bsp/stm32f107/drivers/msd.c | 2546 ++++++++++++++-------- bsp/stm32f107/drivers/msd.h | 265 +-- bsp/stm32f107/drivers/platform.c | 90 +- bsp/stm32f107/drivers/rt_stm32f10x_spi.c | 372 ++++ bsp/stm32f107/drivers/rt_stm32f10x_spi.h | 38 + bsp/stm32f107/drivers/stm32f10x_it.c | 14 +- bsp/stm32f107/drivers/usart.c | 1 + bsp/stm32f107/project.uvproj | 321 +-- bsp/stm32f107/readme.txt | 2 +- bsp/stm32f107/rtconfig.h | 2 +- 13 files changed, 2353 insertions(+), 1323 deletions(-) create mode 100644 bsp/stm32f107/drivers/rt_stm32f10x_spi.c create mode 100644 bsp/stm32f107/drivers/rt_stm32f10x_spi.h diff --git a/bsp/stm32f107/drivers/SConscript b/bsp/stm32f107/drivers/SConscript index 5bbef4878..1c4176abd 100644 --- a/bsp/stm32f107/drivers/SConscript +++ b/bsp/stm32f107/drivers/SConscript @@ -4,6 +4,15 @@ from building import * cwd = os.path.join(str(Dir('#')), 'drivers') src = Glob('*.c') + +# remove no need file. +if GetDepend('RT_USING_LWIP') == False: + SrcRemove(src, 'stm32_eth.c') + +if GetDepend('RT_USING_SPI') == False: + SrcRemove(src, 'rt_stm32f10x_spi.c') + SrcRemove(src, 'msd.c') + CPPPATH = [cwd] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) diff --git a/bsp/stm32f107/drivers/board.c b/bsp/stm32f107/drivers/board.c index 6845e3cc4..20b89c964 100644 --- a/bsp/stm32f107/drivers/board.c +++ b/bsp/stm32f107/drivers/board.c @@ -14,7 +14,6 @@ #include #include - #include "board.h" /** @@ -45,15 +44,15 @@ void NVIC_Configuration(void) * This is the timer interrupt service routine. * */ -void rt_hw_timer_handler(void) +void SysTick_Handler(void) { - /* enter interrupt */ - rt_interrupt_enter(); + /* enter interrupt */ + rt_interrupt_enter(); - rt_tick_increase(); + rt_tick_increase(); - /* leave interrupt */ - rt_interrupt_leave(); + /* leave interrupt */ + rt_interrupt_leave(); } /** diff --git a/bsp/stm32f107/drivers/board.h b/bsp/stm32f107/drivers/board.h index 6baae403b..7d067fcc5 100644 --- a/bsp/stm32f107/drivers/board.h +++ b/bsp/stm32f107/drivers/board.h @@ -40,6 +40,9 @@ #define STM32_SRAM_SIZE 64 #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024) +#define RT_USING_UART1 +#define RT_USING_SPI1 + void rt_hw_board_init(void); void rt_hw_usart_init(void); diff --git a/bsp/stm32f107/drivers/msd.c b/bsp/stm32f107/drivers/msd.c index 123f475ca..3b4e721f1 100644 --- a/bsp/stm32f107/drivers/msd.c +++ b/bsp/stm32f107/drivers/msd.c @@ -1,951 +1,1691 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : msd.c -* Author : MCD Application Team -* Version : V2.1 -* Date : 05/30/2008 -* Description : MSD card driver source file. -* Pin assignment: -* ---------------------------------------------- -* | STM32F10x | MSD Pin | -* ---------------------------------------------- -* | P0.4 | ChipSelect 1 | -* | P0.1 / MOSI | DataIn 2 | -* | | GND 3 (0 V) | -* | | VDD 4 (3.3 V) | -* | P0.2 / SCLK | Clock 5 | -* | | GND 6 (0 V) | -* | P0.0 / MISO | DataOut 7 | -* ----------------------------------------------- -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -* FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED -* IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE. -*******************************************************************************/ - -/* Includes ------------------------------------------------------------------*/ -#include "msd.h" -#include -#include - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ -/* Select MSD Card: ChipSelect pin low */ -#define MSD_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4) -/* Deselect MSD Card: ChipSelect pin high */ -#define MSD_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4) -#define MSD_SPI SPI1 -#define MSD_RCC_SPI RCC_APB2Periph_SPI1 - -/* Private function prototypes -----------------------------------------------*/ -static void SPI_Config(void); -/* Private functions ---------------------------------------------------------*/ - -/******************************************************************************* -* Function Name : MSD_Init -* Description : Initializes the MSD/SD communication. -* Input : None -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_Init(void) -{ - u32 i = 0; - - /* Initialize SPI */ - SPI_Config(); - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte 0xFF, 10 times with CS high*/ - /* rise CS and MOSI for 80 clocks cycles */ - for (i = 0; i < 10; i++) - { - /* Send dummy byte 0xFF */ - MSD_WriteByte(DUMMY); - } - /*------------Put MSD in SPI mode--------------*/ - /* MSD initialized and set to SPI mode properly */ - return (MSD_GoIdleState()); -} - -/******************************************************************************* -* Function Name : MSD_WriteBlock -* Description : Writes a block on the MSD -* Input : - pBuffer : pointer to the buffer containing the data to be -* written on the MSD. -* - WriteAddr : address to write on. -* - NumByteToWrite: number of data to write -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) -{ - u32 i = 0; - u8 rvalue = MSD_RESPONSE_FAILURE; - - /* MSD chip select low */ - MSD_CS_LOW(); - /* Send CMD24 (MSD_WRITE_BLOCK) to write multiple block */ - MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr, 0xFF); - - /* Check if the MSD acknowledged the write block command: R1 response (0x00: no errors) */ - if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) - { - /* Send a dummy byte */ - MSD_WriteByte(DUMMY); - /* Send the data token to signify the start of the data */ - MSD_WriteByte(0xFE); - /* Write the block data to MSD : write count data by block */ - for (i = 0; i < NumByteToWrite; i++) - { - /* Send the pointed byte */ - MSD_WriteByte(*pBuffer); - /* Point to the next location where the byte read will be saved */ - pBuffer++; - } - /* Put CRC bytes (not really needed by us, but required by MSD) */ - MSD_ReadByte(); - MSD_ReadByte(); - /* Read data response */ - if (MSD_GetDataResponse() == MSD_DATA_OK) - { - rvalue = MSD_RESPONSE_NO_ERROR; - } - } - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte: 8 Clock pulses of delay */ - MSD_WriteByte(DUMMY); - /* Returns the reponse */ - return rvalue; -} - -/******************************************************************************* -* Function Name : MSD_ReadBlock -* Description : Reads a block of data from the MSD. -* Input : - pBuffer : pointer to the buffer that receives the data read -* from the MSD. -* - ReadAddr : MSD's internal address to read from. -* - NumByteToRead : number of bytes to read from the MSD. -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead) -{ - u32 i = 0; - u8 rvalue = MSD_RESPONSE_FAILURE; - - /* MSD chip select low */ - MSD_CS_LOW(); - /* Send CMD17 (MSD_READ_SINGLE_BLOCK) to read one block */ - MSD_SendCmd(MSD_READ_SINGLE_BLOCK, ReadAddr, 0xFF); - - /* Check if the MSD acknowledged the read block command: R1 response (0x00: no errors) */ - if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) - { - /* Now look for the data token to signify the start of the data */ - if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) - { - /* Read the MSD block data : read NumByteToRead data */ - for (i = 0; i < NumByteToRead; i++) - { - /* Save the received data */ - *pBuffer = MSD_ReadByte(); - /* Point to the next location where the byte read will be saved */ - pBuffer++; - } - /* Get CRC bytes (not really needed by us, but required by MSD) */ - MSD_ReadByte(); - MSD_ReadByte(); - /* Set response value to success */ - rvalue = MSD_RESPONSE_NO_ERROR; - } - } - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte: 8 Clock pulses of delay */ - MSD_WriteByte(DUMMY); - /* Returns the reponse */ - return rvalue; -} - -/******************************************************************************* -* Function Name : MSD_WriteBuffer -* Description : Writes many blocks on the MSD -* Input : - pBuffer : pointer to the buffer containing the data to be -* written on the MSD. -* - WriteAddr : address to write on. -* - NumByteToWrite: number of data to write -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite) -{ - u32 i = 0, NbrOfBlock = 0, Offset = 0; - u8 rvalue = MSD_RESPONSE_FAILURE; - - /* Calculate number of blocks to write */ - NbrOfBlock = NumByteToWrite / BLOCK_SIZE; - /* MSD chip select low */ - MSD_CS_LOW(); - - /* Data transfer */ - while (NbrOfBlock --) - { - /* Send CMD24 (MSD_WRITE_BLOCK) to write blocks */ - MSD_SendCmd(MSD_WRITE_BLOCK, WriteAddr + Offset, 0xFF); - - /* Check if the MSD acknowledged the write block command: R1 response (0x00: no errors) */ - if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) - { - return MSD_RESPONSE_FAILURE; - } - /* Send dummy byte */ - MSD_WriteByte(DUMMY); - /* Send the data token to signify the start of the data */ - MSD_WriteByte(MSD_START_DATA_SINGLE_BLOCK_WRITE); - /* Write the block data to MSD : write count data by block */ - for (i = 0; i < BLOCK_SIZE; i++) - { - /* Send the pointed byte */ - MSD_WriteByte(*pBuffer); - /* Point to the next location where the byte read will be saved */ - pBuffer++; - } - /* Set next write address */ - Offset += 512; - /* Put CRC bytes (not really needed by us, but required by MSD) */ - MSD_ReadByte(); - MSD_ReadByte(); - /* Read data response */ - if (MSD_GetDataResponse() == MSD_DATA_OK) - { - /* Set response value to success */ - rvalue = MSD_RESPONSE_NO_ERROR; - } - else - { - /* Set response value to failure */ - rvalue = MSD_RESPONSE_FAILURE; - } - } - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte: 8 Clock pulses of delay */ - MSD_WriteByte(DUMMY); - /* Returns the reponse */ - return rvalue; -} - -/******************************************************************************* -* Function Name : MSD_ReadBuffer -* Description : Reads multiple block of data from the MSD. -* Input : - pBuffer : pointer to the buffer that receives the data read -* from the MSD. -* - ReadAddr : MSD's internal address to read from. -* - NumByteToRead : number of bytes to read from the MSD. -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead) -{ - u32 i = 0, NbrOfBlock = 0, Offset = 0; - u8 rvalue = MSD_RESPONSE_FAILURE; - - /* Calculate number of blocks to read */ - NbrOfBlock = NumByteToRead / BLOCK_SIZE; - /* MSD chip select low */ - MSD_CS_LOW(); - - /* Data transfer */ - while (NbrOfBlock --) - { - /* Send CMD17 (MSD_READ_SINGLE_BLOCK) to read one block */ - MSD_SendCmd (MSD_READ_SINGLE_BLOCK, ReadAddr + Offset, 0xFF); - /* Check if the MSD acknowledged the read block command: R1 response (0x00: no errors) */ - if (MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) - { - return MSD_RESPONSE_FAILURE; - } - /* Now look for the data token to signify the start of the data */ - if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) - { - /* Read the MSD block data : read NumByteToRead data */ - for (i = 0; i < BLOCK_SIZE; i++) - { - /* Read the pointed data */ - *pBuffer = MSD_ReadByte(); - /* Point to the next location where the byte read will be saved */ - pBuffer++; - } - /* Set next read address*/ - Offset += 512; - /* get CRC bytes (not really needed by us, but required by MSD) */ - MSD_ReadByte(); - MSD_ReadByte(); - /* Set response value to success */ - rvalue = MSD_RESPONSE_NO_ERROR; - } - else - { - /* Set response value to failure */ - rvalue = MSD_RESPONSE_FAILURE; - } - } - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte: 8 Clock pulses of delay */ - MSD_WriteByte(DUMMY); - /* Returns the reponse */ - return rvalue; -} - -/******************************************************************************* -* Function Name : MSD_GetCSDRegister -* Description : Read the CSD card register. -* Reading the contents of the CSD register in SPI mode -* is a simple read-block transaction. -* Input : - MSD_csd: pointer on an SCD register structure -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_GetCSDRegister(sMSD_CSD* MSD_csd) -{ - u32 i = 0; - u8 rvalue = MSD_RESPONSE_FAILURE; - u8 CSD_Tab[16]; - - /* MSD chip select low */ - MSD_CS_LOW(); - /* Send CMD9 (CSD register) or CMD10(CSD register) */ - MSD_SendCmd(MSD_SEND_CSD, 0, 0xFF); - - /* Wait for response in the R1 format (0x00 is no errors) */ - if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) - { - if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) - { - for (i = 0; i < 16; i++) - { - /* Store CSD register value on CSD_Tab */ - CSD_Tab[i] = MSD_ReadByte(); - } - } - /* Get CRC bytes (not really needed by us, but required by MSD) */ - MSD_WriteByte(DUMMY); - MSD_WriteByte(DUMMY); - /* Set response value to success */ - rvalue = MSD_RESPONSE_NO_ERROR; - } - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte: 8 Clock pulses of delay */ - MSD_WriteByte(DUMMY); - - /* Byte 0 */ - MSD_csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; - MSD_csd->SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2; - MSD_csd->Reserved1 = CSD_Tab[0] & 0x03; - /* Byte 1 */ - MSD_csd->TAAC = CSD_Tab[1] ; - /* Byte 2 */ - MSD_csd->NSAC = CSD_Tab[2]; - /* Byte 3 */ - MSD_csd->MaxBusClkFrec = CSD_Tab[3]; - /* Byte 4 */ - MSD_csd->CardComdClasses = CSD_Tab[4] << 4; - /* Byte 5 */ - MSD_csd->CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4; - MSD_csd->RdBlockLen = CSD_Tab[5] & 0x0F; - /* Byte 6 */ - MSD_csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; - MSD_csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; - MSD_csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; - MSD_csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4; - MSD_csd->Reserved2 = 0; /* Reserved */ - MSD_csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10; - /* Byte 7 */ - MSD_csd->DeviceSize |= (CSD_Tab[7]) << 2; - /* Byte 8 */ - MSD_csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6; - MSD_csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; - MSD_csd->MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); - /* Byte 9 */ - MSD_csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; - MSD_csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; - MSD_csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1; - /* Byte 10 */ - MSD_csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7; - MSD_csd->EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2; - MSD_csd->EraseGrMul = (CSD_Tab[10] & 0x03) << 3; - /* Byte 11 */ - MSD_csd->EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5; - MSD_csd->WrProtectGrSize = (CSD_Tab[11] & 0x1F); - /* Byte 12 */ - MSD_csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; - MSD_csd->ManDeflECC = (CSD_Tab[12] & 0x60) >> 5; - MSD_csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; - MSD_csd->MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2; - /* Byte 13 */ - MSD_csd->MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6; - MSD_csd->WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5; - MSD_csd->Reserved3 = 0; - MSD_csd->ContentProtectAppli = (CSD_Tab[13] & 0x01); - /* Byte 14 */ - MSD_csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; - MSD_csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6; - MSD_csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; - MSD_csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; - MSD_csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2; - MSD_csd->ECC = (CSD_Tab[14] & 0x03); - /* Byte 15 */ - MSD_csd->msd_CRC = (CSD_Tab[15] & 0xFE) >> 1; - MSD_csd->Reserved4 = 1; - - /* Return the reponse */ - return rvalue; -} - -/******************************************************************************* -* Function Name : MSD_GetCIDRegister -* Description : Read the CID card register. -* Reading the contents of the CID register in SPI mode -* is a simple read-block transaction. -* Input : - MSD_cid: pointer on an CID register structure -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_GetCIDRegister(sMSD_CID* MSD_cid) -{ - u32 i = 0; - u8 rvalue = MSD_RESPONSE_FAILURE; - u8 CID_Tab[16]; - - /* MSD chip select low */ - MSD_CS_LOW(); - /* Send CMD10 (CID register) */ - MSD_SendCmd(MSD_SEND_CID, 0, 0xFF); - - /* Wait for response in the R1 format (0x00 is no errors) */ - if (!MSD_GetResponse(MSD_RESPONSE_NO_ERROR)) - { - if (!MSD_GetResponse(MSD_START_DATA_SINGLE_BLOCK_READ)) - { - /* Store CID register value on CID_Tab */ - for (i = 0; i < 16; i++) - { - CID_Tab[i] = MSD_ReadByte(); - } - } - /* Get CRC bytes (not really needed by us, but required by MSD) */ - MSD_WriteByte(DUMMY); - MSD_WriteByte(DUMMY); - /* Set response value to success */ - rvalue = MSD_RESPONSE_NO_ERROR; - } - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte: 8 Clock pulses of delay */ - MSD_WriteByte(DUMMY); - - /* Byte 0 */ - MSD_cid->ManufacturerID = CID_Tab[0]; - /* Byte 1 */ - MSD_cid->OEM_AppliID = CID_Tab[1] << 8; - /* Byte 2 */ - MSD_cid->OEM_AppliID |= CID_Tab[2]; - /* Byte 3 */ - MSD_cid->ProdName1 = CID_Tab[3] << 24; - /* Byte 4 */ - MSD_cid->ProdName1 |= CID_Tab[4] << 16; - /* Byte 5 */ - MSD_cid->ProdName1 |= CID_Tab[5] << 8; - /* Byte 6 */ - MSD_cid->ProdName1 |= CID_Tab[6]; - /* Byte 7 */ - MSD_cid->ProdName2 = CID_Tab[7]; - /* Byte 8 */ - MSD_cid->ProdRev = CID_Tab[8]; - /* Byte 9 */ - MSD_cid->ProdSN = CID_Tab[9] << 24; - /* Byte 10 */ - MSD_cid->ProdSN |= CID_Tab[10] << 16; - /* Byte 11 */ - MSD_cid->ProdSN |= CID_Tab[11] << 8; - /* Byte 12 */ - MSD_cid->ProdSN |= CID_Tab[12]; - /* Byte 13 */ - MSD_cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; - /* Byte 14 */ - MSD_cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8; - /* Byte 15 */ - MSD_cid->ManufactDate |= CID_Tab[14]; - /* Byte 16 */ - MSD_cid->msd_CRC = (CID_Tab[15] & 0xFE) >> 1; - MSD_cid->Reserved2 = 1; - - /* Return the reponse */ - return rvalue; -} - -/******************************************************************************* -* Function Name : MSD_SendCmd -* Description : Send 5 bytes command to the MSD card. -* Input : - Cmd: the user expected command to send to MSD card -* - Arg: the command argument -* - Crc: the CRC -* Output : None -* Return : None -*******************************************************************************/ -void MSD_SendCmd(u8 Cmd, u32 Arg, u8 Crc) -{ - u32 i = 0x00; - u8 Frame[6]; - - /* Construct byte1 */ - Frame[0] = (Cmd | 0x40); - /* Construct byte2 */ - Frame[1] = (u8)(Arg >> 24); - /* Construct byte3 */ - Frame[2] = (u8)(Arg >> 16); - /* Construct byte4 */ - Frame[3] = (u8)(Arg >> 8); - /* Construct byte5 */ - Frame[4] = (u8)(Arg); - /* Construct CRC: byte6 */ - Frame[5] = (Crc); - - /* Send the Cmd bytes */ - for (i = 0; i < 6; i++) - { - MSD_WriteByte(Frame[i]); - } -} - -/******************************************************************************* -* Function Name : MSD_GetDataResponse -* Description : Get MSD card data response. -* Input : None -* Output : None -* Return : The MSD status: Read data response xxx01 -* - status 010: Data accecpted -* - status 101: Data rejected due to a crc error -* - status 110: Data rejected due to a Write error. -* - status 111: Data rejected due to other error. -*******************************************************************************/ -u8 MSD_GetDataResponse(void) -{ - u32 i = 0; - u8 response, rvalue; - - while (i <= 64) - { - /* Read resonse */ - response = MSD_ReadByte(); - /* Mask unused bits */ - response &= 0x1F; - - switch (response) - { - case MSD_DATA_OK: - { - rvalue = MSD_DATA_OK; - break; - } - - case MSD_DATA_CRC_ERROR: - return MSD_DATA_CRC_ERROR; - - case MSD_DATA_WRITE_ERROR: - return MSD_DATA_WRITE_ERROR; - - default: - { - rvalue = MSD_DATA_OTHER_ERROR; - break; - } - } - /* Exit loop in case of data ok */ - if (rvalue == MSD_DATA_OK) - break; - /* Increment loop counter */ - i++; - } - /* Wait null data */ - while (MSD_ReadByte() == 0); - /* Return response */ - return response; -} - -/******************************************************************************* -* Function Name : MSD_GetResponse -* Description : Returns the MSD response. -* Input : None -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_GetResponse(u8 Response) -{ - u32 Count = 0xFFF; - - /* Check if response is got or a timeout is happen */ - while ((MSD_ReadByte() != Response) && Count) - { - Count--; - } - - if (Count == 0) - { - /* After time out */ - return MSD_RESPONSE_FAILURE; - } - else - { - /* Right response got */ - return MSD_RESPONSE_NO_ERROR; - } -} - -/******************************************************************************* -* Function Name : MSD_GetStatus -* Description : Returns the MSD status. -* Input : None -* Output : None -* Return : The MSD status. -*******************************************************************************/ -u16 MSD_GetStatus(void) -{ - u16 Status = 0; - - /* MSD chip select low */ - MSD_CS_LOW(); - /* Send CMD13 (MSD_SEND_STATUS) to get MSD status */ - MSD_SendCmd(MSD_SEND_STATUS, 0, 0xFF); - - Status = MSD_ReadByte(); - Status |= (u16)(MSD_ReadByte() << 8); - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte 0xFF */ - MSD_WriteByte(DUMMY); - - return Status; -} - -/******************************************************************************* -* Function Name : MSD_GoIdleState -* Description : Put MSD in Idle state. -* Input : None -* Output : None -* Return : The MSD Response: - MSD_RESPONSE_FAILURE: Sequence failed -* - MSD_RESPONSE_NO_ERROR: Sequence succeed -*******************************************************************************/ -u8 MSD_GoIdleState(void) -{ - int i; - /* MSD chip select low */ - MSD_CS_LOW(); - /* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI mode */ - MSD_SendCmd(MSD_GO_IDLE_STATE, 0, 0x95); - - /* Wait for In Idle State Response (R1 Format) equal to 0x01 */ - if (MSD_GetResponse(MSD_IN_IDLE_STATE)) - { - /* No Idle State Response: return response failue */ - return MSD_RESPONSE_FAILURE; - } - /*----------Activates the card initialization process-----------*/ - do - { - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send Dummy byte 0xFF */ - MSD_WriteByte(DUMMY); - for (i = 0; i < 0xfff; i++); - - /* MSD chip select low */ - MSD_CS_LOW(); - for (i = 0; i < 0xfff; i++); - - /* Send CMD1 (Activates the card process) until response equal to 0x0 */ - MSD_SendCmd(MSD_SEND_OP_COND, 0, 0xFF); - /* Wait for no error Response (R1 Format) equal to 0x00 */ - } - while (MSD_GetResponse(MSD_RESPONSE_NO_ERROR)); - - /* MSD chip select high */ - MSD_CS_HIGH(); - /* Send dummy byte 0xFF */ - MSD_WriteByte(DUMMY); - - return MSD_RESPONSE_NO_ERROR; -} - -/******************************************************************************* -* Function Name : MSD_WriteByte -* Description : Write a byte on the MSD. -* Input : Data: byte to send. -* Output : None -* Return : None. -*******************************************************************************/ -u8 MSD_WriteByte(u8 Data) -{ - /* Wait until the transmit buffer is empty */ - while (SPI_I2S_GetFlagStatus(MSD_SPI, SPI_I2S_FLAG_TXE) == RESET); - /* Send the byte */ - SPI_I2S_SendData(MSD_SPI, Data); - - /* Get the received data */ - Data = SPI_I2S_ReceiveData(MSD_SPI); - - return Data; -} - -/******************************************************************************* -* Function Name : MSD_ReadByte -* Description : Read a byte from the MSD. -* Input : None. -* Output : None -* Return : The received byte. -*******************************************************************************/ -u8 MSD_ReadByte(void) -{ - u8 Data = 0; - - /* Wait until the transmit buffer is empty */ - while (SPI_I2S_GetFlagStatus(MSD_SPI, SPI_I2S_FLAG_TXE) == RESET); - /* Send the byte */ - SPI_I2S_SendData(MSD_SPI, DUMMY); - - /* Wait until a data is received */ - while (SPI_I2S_GetFlagStatus(MSD_SPI, SPI_I2S_FLAG_RXNE) == RESET); - /* Get the received data */ - Data = SPI_I2S_ReceiveData(MSD_SPI); - - /* Return the shifted data */ - return Data; -} - -/******************************************************************************* -* Function Name : SPI_Config -* Description : Initializes the SPI and CS pins. -* Input : None -* Output : None -* Return : None -*******************************************************************************/ -void SPI_Config(void) -{ - uint32_t delay; - GPIO_InitTypeDef GPIO_InitStructure; - SPI_InitTypeDef SPI_InitStructure; - - /* GPIOA and GPIOC Periph clock enable */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); - /* SPI Periph clock enable */ - RCC_APB2PeriphClockCmd(MSD_RCC_SPI, ENABLE); - - /* Configure SPI pins: SCK, MISO and MOSI */ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_Init(GPIOA, &GPIO_InitStructure); - - /* Configure PA4 pin: CS pin, PC4 : SD Power */ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_Init(GPIOA, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_Init(GPIOC, &GPIO_InitStructure); - - /* SPI 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(MSD_SPI, &SPI_InitStructure); - - /* SPI enable */ - SPI_Cmd(MSD_SPI, ENABLE); - - /* active SD card */ - GPIO_ResetBits(GPIOC, GPIO_Pin_4); - for (delay = 0; delay < 0xfffff; delay ++); -} - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ - /* - * RT-Thread SD Card Driver - * 2009-04-17 Bernard first version - * 2010-07-15 Modify read/write according new block driver interface + * File : msd.c + * SPI mode SD Card Driver + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-04-17 Bernard first version. + * 2010-07-15 aozima Modify read/write according new block driver interface. + * 2012-02-01 aozima use new RT-Thread SPI drivers. + * 2012-04-11 aozima get max. data transfer rate from CSD[TRAN_SPEED]. + * 2012-05-21 aozima update MMC card support. */ -#include -#include -static struct rt_device sdcard_device; -static struct dfs_partition part; +#include +#include "msd.h" -#define SECTOR_SIZE 512 +//#define MSD_TRACE + +#ifdef MSD_TRACE +#define MSD_DEBUG(...) rt_kprintf("[MSD] %d ", rt_tick_get()); rt_kprintf(__VA_ARGS__); +#else +#define MSD_DEBUG(...) +#endif /* #ifdef MSD_TRACE */ + +#define DUMMY 0xFF + +#define CARD_NCR_MAX 8 + +#define CARD_NRC 1 +#define CARD_NCR 1 + +static struct msd_device _msd_device; + +/* function define */ +static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long); + +static rt_err_t MSD_take_owner(struct rt_spi_device* spi_device); +static void MSD_take_cs(struct rt_spi_device* device); +static void MSD_release_cs(struct rt_spi_device* device); + +static rt_err_t _wait_token(struct rt_spi_device* device, uint8_t token); +static rt_err_t _wait_ready(struct rt_spi_device* device); +static rt_size_t rt_msd_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size); +static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size); +static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size); +static rt_size_t rt_msd_sdhc_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size); + +static rt_err_t MSD_take_owner(struct rt_spi_device* spi_device) +{ + rt_err_t result; + + result = rt_mutex_take(&(spi_device->bus->lock), RT_WAITING_FOREVER); + if(result == RT_EOK) + { + if (spi_device->bus->owner != spi_device) + { + /* not the same owner as current, re-configure SPI bus */ + result = spi_device->bus->ops->configure(spi_device, &spi_device->config); + if (result == RT_EOK) + { + /* set SPI bus owner */ + spi_device->bus->owner = spi_device; + } + } + } + + return result; +} + +static void MSD_take_cs(struct rt_spi_device* device) +{ + struct rt_spi_message message; + + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = RT_NULL; + message.length = 0; + message.cs_take = 1; + message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); +} + +static void MSD_release_cs(struct rt_spi_device* device) +{ + struct rt_spi_message message; + + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = RT_NULL; + message.length = 0; + message.cs_take = 0; + message.cs_release = 1; + + /* transfer message */ + device->bus->ops->xfer(device, &message); +} + +static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long) +{ + rt_tick_t tick_end = tick_start + tick_long; + rt_tick_t tick_now = rt_tick_get(); + rt_bool_t result = RT_FALSE; + + if(tick_end >= tick_start) + { + if (tick_now >= tick_end) + { + result = RT_TRUE; + } + else + { + result = RT_FALSE; + } + } + else + { + if ((tick_now < tick_start ) && (tick_now >= tick_end) ) + { + result = RT_TRUE; + } + else + { + result = RT_FALSE; + } + } + + return result; +} + +static uint8_t crc7(const uint8_t *buf, int len) +{ + unsigned char i, j, crc, ch, ch2, ch3; + + crc = 0; + + for (i = 0; i < len; i ++) + { + ch = buf[i]; + + for (j = 0; j < 8; j ++, ch <<= 1) + { + ch2 = (crc & 0x40) ? 1 : 0; + ch3 = (ch & 0x80) ? 1 : 0; + + if (ch2 ^ ch3) + { + crc ^= 0x04; + crc <<= 1; + crc |= 0x01; + } + else + { + crc <<= 1; + } + } + } + + return crc; +} + +static rt_err_t _send_cmd( + struct rt_spi_device* device, + uint8_t cmd, + uint32_t arg, + uint8_t crc, + response_type type, + uint8_t * response +) +{ + struct rt_spi_message message; + uint8_t cmd_buffer[8]; + uint8_t recv_buffer[sizeof(cmd_buffer)]; + uint32_t i; + + cmd_buffer[0] = DUMMY; + cmd_buffer[1] = (cmd | 0x40); + cmd_buffer[2] = (uint8_t)(arg >> 24); + cmd_buffer[3] = (uint8_t)(arg >> 16); + cmd_buffer[4] = (uint8_t)(arg >> 8); + cmd_buffer[5] = (uint8_t)(arg); + + if(crc == 0x00) + { + crc = crc7(&cmd_buffer[1], 5); + crc = (crc<<1) | 0x01; + } + cmd_buffer[6] = (crc); + + cmd_buffer[7] = DUMMY; + + /* initial message */ + message.send_buf = cmd_buffer; + message.recv_buf = recv_buffer; + message.length = sizeof(cmd_buffer); + message.cs_take = message.cs_release = 0; + + _wait_ready(device); + + /* transfer message */ + device->bus->ops->xfer(device, &message); + + for(i=CARD_NCR; i<(CARD_NCR_MAX+1); i++) + { + uint8_t send = DUMMY; + + /* initial message */ + message.send_buf = &send; + message.recv_buf = response; + message.length = 1; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + + if(0 == (response[0] & 0x80)) + { + break; + } + } /* wait response */ + + if((CARD_NCR_MAX+1) == i) + { + return RT_ERROR;//fail + } + + //recieve other byte + if(type == response_r1) + { + return RT_EOK; + } + else if(type == response_r1b) + { + rt_tick_t tick_start = rt_tick_get(); + uint8_t recv; + + while(1) + { + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = &recv; + message.length = 1; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + + if(recv == DUMMY) + { + return RT_EOK; + } + + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(2000))) + { + return RT_ETIMEOUT; + } + } + } + else if(type == response_r2) + { + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = response+1; + message.length = 1; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + } + else if((type == response_r3) || (type == response_r7)) + { + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = response+1; + message.length = 4; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + } + else + { + return RT_ERROR; // unknow type? + } + + return RT_EOK; +} + +static rt_err_t _wait_token(struct rt_spi_device* device, uint8_t token) +{ + struct rt_spi_message message; + rt_tick_t tick_start; + uint8_t send, recv; + + tick_start = rt_tick_get(); + + /* wati token */ + /* initial message */ + send = DUMMY; + message.send_buf = &send; + message.recv_buf = &recv; + message.length = 1; + message.cs_take = message.cs_release = 0; + + while(1) + { + /* transfer message */ + device->bus->ops->xfer(device, &message); + + if(recv == token) + { + return RT_EOK; + } + + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_WAIT_TOKEN_TIMES))) + { + MSD_DEBUG("[err] wait data start token timeout!\r\n"); + return RT_ETIMEOUT; + } + } /* wati token */ +} + +static rt_err_t _wait_ready(struct rt_spi_device* device) +{ + struct rt_spi_message message; + rt_tick_t tick_start; + uint8_t send, recv; + + tick_start = rt_tick_get(); + + send = DUMMY; + /* initial message */ + message.send_buf = &send; + message.recv_buf = &recv; + message.length = 1; + message.cs_take = message.cs_release = 0; + + while(1) + { + /* transfer message */ + device->bus->ops->xfer(device, &message); + + if(recv == DUMMY) + { + return RT_EOK; + } + + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(1000))) + { + MSD_DEBUG("[err] wait ready timeout!\r\n"); + return RT_ETIMEOUT; + } + } +} + +static rt_err_t _read_block(struct rt_spi_device* device, void * buffer, uint32_t block_size) +{ + struct rt_spi_message message; + rt_err_t result; + + /* wati token */ + result = _wait_token(device, MSD_TOKEN_READ_START); + if(result != RT_EOK) + { + return result; + } + + /* read data */ + { + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = buffer; + message.length = block_size; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + } /* read data */ + + /* get crc */ + { + uint8_t recv_buffer[2]; + + /* initial message */ + message.send_buf = RT_NULL; + message.recv_buf = recv_buffer; + message.length = 2; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + } /* get crc */ + + return RT_EOK; +} + +static rt_err_t _write_block(struct rt_spi_device* device, const void * buffer, uint32_t block_size, uint8_t token) +{ + struct rt_spi_message message; + uint8_t send_buffer[16]; + + rt_memset(send_buffer, DUMMY, sizeof(send_buffer)); + send_buffer[sizeof(send_buffer) - 1] = token; + + /* send start block token */ + { + /* initial message */ + message.send_buf = send_buffer; + message.recv_buf = RT_NULL; + message.length = sizeof(send_buffer); + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + } + + /* send data */ + { + /* initial message */ + message.send_buf = buffer; + message.recv_buf = RT_NULL; + message.length = block_size; + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + } + + /* put crc and get data response */ + { + uint8_t recv_buffer[3]; + uint8_t response; + + /* initial message */ + message.send_buf = send_buffer; + message.recv_buf = recv_buffer; + message.length = sizeof(recv_buffer); + message.cs_take = message.cs_release = 0; + + /* transfer message */ + device->bus->ops->xfer(device, &message); + +// response = 0x0E & recv_buffer[2]; + response = MSD_GET_DATA_RESPONSE(recv_buffer[2]); + if(response != MSD_DATA_OK) + { + MSD_DEBUG("[err] write block fail! data response : 0x%02X\r\n", response); + return RT_ERROR; + } + } + + /* wati ready */ + return _wait_ready(device); +} /* RT-Thread Device Driver Interface */ static rt_err_t rt_msd_init(rt_device_t dev) { - sMSD_CSD MSD_csd; - MSD_GetCSDRegister(&MSD_csd); + struct msd_device * msd = (struct msd_device *)dev; + uint8_t response[MSD_RESPONSE_MAX_LEN]; + rt_err_t result = RT_EOK; + rt_tick_t tick_start; + uint32_t OCR; - return RT_EOK; + if(msd->spi_device == RT_NULL) + { + MSD_DEBUG("[err] the SPI SD device has no SPI!\r\n"); + return RT_EIO; + } + + /* config spi */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = 1000*400; /* 400kbit/s */ + rt_spi_configure(msd->spi_device, &cfg); + } /* config spi */ + + /* init SD card */ + { + struct rt_spi_message message; + + result = MSD_take_owner(msd->spi_device); + + if (result != RT_EOK) + { + goto _exit; + } + + MSD_release_cs(msd->spi_device); + + /* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and + start to supply at least 74 SD clocks to the SD card with keeping CMD line to high. + In case of SPI mode, CS shall be held to high during 74 clock cycles. */ + { + uint8_t send_buffer[100]; /* 100byte > 74 clock */ + + /* initial message */ + memset(send_buffer, DUMMY, sizeof(send_buffer)); + message.send_buf = send_buffer; + message.recv_buf = RT_NULL; + message.length = sizeof(send_buffer); + message.cs_take = message.cs_release = 0; + + /* transfer message */ + msd->spi_device->bus->ops->xfer(msd->spi_device, &message); + } /* send 74 clock */ + + /* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI mode */ + { + tick_start = rt_tick_get(); + + while(1) + { + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response); + MSD_release_cs(msd->spi_device); + + if((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE)) + { + break; + } + + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES))) + { + MSD_DEBUG("[err] SD card goto IDLE mode timeout!\r\n"); + result = RT_ETIMEOUT; + goto _exit; + } + } + + MSD_DEBUG("[info] SD card goto IDLE mode OK!\r\n"); + } /* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI mode */ + + /* CMD8 */ + { + tick_start = rt_tick_get(); + + do + { + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, SEND_IF_COND, 0x01AA, 0x87, response_r7, response); + MSD_release_cs(msd->spi_device); + + if(result == RT_EOK) + { + MSD_DEBUG("[info] CMD8 response : 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n", + response[0], response[1], response[2], response[3], response[4]); + + if(response[0] & (1<<2)) + { + /* illegal command, SD V1.x or MMC card */ + MSD_DEBUG("[info] CMD8 is illegal command.\r\n"); + MSD_DEBUG("[info] maybe Ver1.X SD Memory Card or MMC card!\r\n"); + msd->card_type = MSD_CARD_TYPE_SD_V1_X; + break; + } + else + { + /* SD V2.0 or later or SDHC or SDXC memory card! */ + MSD_DEBUG("[info] Ver2.00 or later or SDHC or SDXC memory card!\r\n"); + msd->card_type = MSD_CARD_TYPE_SD_V2_X; + } + + if((0xAA == response[4]) && (0x00 == response[3])) + { + /* SD2.0 not support current voltage */ + MSD_DEBUG("[err] VCA = 0, SD2.0 not surpport current operation voltage range\r\n"); + result = RT_ERROR; + goto _exit; + } + } + else + { + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(200))) + { + MSD_DEBUG("[err] CMD8 SEND_IF_COND timeout!\r\n"); + result = RT_ETIMEOUT; + goto _exit; + } + } + } + while(0xAA != response[4]); + } /* CMD8 */ + + /* Ver1.X SD Memory Card or MMC card */ + if(msd->card_type == MSD_CARD_TYPE_SD_V1_X) + { + rt_bool_t is_sd_v1_x = RT_FALSE; + rt_tick_t tick_start; + + /* try SD Ver1.x */ + while(1) + { + MSD_take_cs(msd->spi_device); + + result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response); + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[info] It maybe SD1.x or MMC But it is Not response to CMD58!\r\n"); + goto _exit; + } + + if(0 != (response[0]&0xFE)) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[info] It look CMD58 as illegal command so it is not SD card!\r\n"); + break; + } + MSD_release_cs(msd->spi_device); + + OCR = response[1]; + OCR = (OCR<<8) + response[2]; + OCR = (OCR<<8) + response[3]; + OCR = (OCR<<8) + response[4]; + MSD_DEBUG("[info] OCR is 0x%08X\r\n", OCR); + + if( 0 == (OCR & (0x1 << 15))) + { + MSD_DEBUG(("[err] SD 1.x But not surpport current voltage\r\n")); + result = RT_ERROR; + goto _exit; + } + + /* --Send ACMD41 to make card ready */ + tick_start = rt_tick_get(); + + /* try CMD55 + ACMD41 */ + while(1) + { + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41))) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[info] try CMD55 + ACMD41 timeout! mabey MMC card!\r\n"); + break; + } + + MSD_take_cs(msd->spi_device); + + /* CMD55 APP_CMD */ + result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response); + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + continue; + } + + if(0 != (response[0]&0xFE)) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[info] Not SD card2 , may be MMC\r\n"); + break; + } + + /* ACMD41 SD_SEND_OP_COND */ + result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x00, 0x00, response_r1, response); + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + continue; + } + + if(0 != (response[0]&0xFE)) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[info] Not SD card4 , may be MMC\r\n"); + break; + } + + if(0 == (response[0]&0xFF)) + { + MSD_release_cs(msd->spi_device); + is_sd_v1_x = RT_TRUE; + MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n"); + break; + } + } /* try CMD55 + ACMD41 */ + + break; + } /* try SD Ver1.x */ + + /* try MMC */ + if(is_sd_v1_x != RT_TRUE) + { + uint32_t i; + + MSD_DEBUG("[info] try MMC card!\r\n"); + MSD_release_cs(msd->spi_device); + + /* send dummy clock */ + { + uint8_t send_buffer[100]; + + /* initial message */ + memset(send_buffer, DUMMY, sizeof(send_buffer)); + message.send_buf = send_buffer; + message.recv_buf = RT_NULL; + message.length = sizeof(send_buffer); + message.cs_take = message.cs_release = 0; + + for(i=0; i<10; i++) + { + /* transfer message */ + msd->spi_device->bus->ops->xfer(msd->spi_device, &message); + } + } /* send dummy clock */ + + /* send CMD0 goto IDLE state */ + tick_start = rt_tick_get(); + while(1) + { + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response); + MSD_release_cs(msd->spi_device); + + if((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE)) + { + break; + } + + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES))) + { + MSD_DEBUG("[err] SD card goto IDLE mode timeout!\r\n"); + result = RT_ETIMEOUT; + goto _exit; + } + } /* send CMD0 goto IDLE stat */ + + /* send CMD1 */ + tick_start = rt_tick_get(); + while(1) + { + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, SEND_OP_COND, 0x00, 0x00, response_r1, response); + MSD_release_cs(msd->spi_device); + + if((result == RT_EOK) && (response[0] == MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[info] It is MMC card!!!\r\n"); + msd->card_type = MSD_CARD_TYPE_MMC; + break; + } + + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES))) + { + MSD_DEBUG("[err] SD card goto IDLE mode timeout!\r\n"); + result = RT_ETIMEOUT; + goto _exit; + } + } /* send CMD1 */ + } /* try MMC */ + } + else if(msd->card_type == MSD_CARD_TYPE_SD_V2_X) + { + MSD_take_cs(msd->spi_device); + + result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response); + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to CMD58!\r\n"); + goto _exit; + } + + if((response[0] & 0xFE) != 0) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] It look CMD58 as illegal command so it is not SD card!\r\n"); + result = RT_ERROR; + goto _exit; + } + + MSD_release_cs(msd->spi_device); + + OCR = response[1]; + OCR = (OCR<<8) + response[2]; + OCR = (OCR<<8) + response[3]; + OCR = (OCR<<8) + response[4]; + MSD_DEBUG("[info] OCR is 0x%08X\r\n", OCR); + + if( 0 == (OCR & (0x1 << 15))) + { + MSD_DEBUG(("[err] SD 1.x But not surpport current voltage\r\n")); + result = RT_ERROR; + goto _exit; + } + + /* --Send ACMD41 to make card ready */ + tick_start = rt_tick_get(); + + /* try CMD55 + ACMD41 */ + do + { + MSD_take_cs(msd->spi_device); + if(rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41))) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] SD Ver2.x or later try CMD55 + ACMD41 timeout!\r\n"); + result = RT_ERROR; + goto _exit; + } + + /* CMD55 APP_CMD */ + result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x65, response_r1, response); +// if((result != RT_EOK) || (response[0] == 0x01)) + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + continue; + } + + if((response[0] & 0xFE) != 0) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] Not SD ready!\r\n"); + result = RT_ERROR; + goto _exit; + } + + /* ACMD41 SD_SEND_OP_COND */ + result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x40000000, 0x77, response_r1, response); + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] ACMD41 fail!\r\n"); + result = RT_ERROR; + goto _exit; + } + + if((response[0] & 0xFE) != 0) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[info] Not SD card4 , response : 0x%02X\r\n", response[0]); +// break; + } + } + while(response[0] != MSD_RESPONSE_NO_ERROR); + MSD_release_cs(msd->spi_device); + /* try CMD55 + ACMD41 */ + + /* --Read OCR again */ + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response); + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to 2nd CMD58!\r\n"); + goto _exit; + } + + if((response[0] & 0xFE) != 0) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] It look 2nd CMD58 as illegal command so it is not SD card!\r\n"); + result = RT_ERROR; + goto _exit; + } + MSD_release_cs(msd->spi_device); + + OCR = response[1]; + OCR = (OCR<<8) + response[2]; + OCR = (OCR<<8) + response[3]; + OCR = (OCR<<8) + response[4]; + MSD_DEBUG("[info] OCR 2nd read is 0x%08X\r\n", OCR); + + if((OCR & 0x40000000) != 0) + { + MSD_DEBUG("[info] It is SD2.0 SDHC Card!!!\r\n"); + msd->card_type = MSD_CARD_TYPE_SD_SDHC; + } + else + { + MSD_DEBUG("[info] It is SD2.0 standard capacity Card!!!\r\n"); + } + } /* MSD_CARD_TYPE_SD_V2_X */ + else + { + MSD_DEBUG("[err] SD card type unkonw!\r\n"); + result = RT_ERROR; + goto _exit; + } + } /* init SD card */ + + if(msd->card_type == MSD_CARD_TYPE_SD_SDHC) + { + dev->read = rt_msd_sdhc_read; + dev->write = rt_msd_sdhc_write; + } + else + { + dev->read = rt_msd_read; + dev->write = rt_msd_write; + } + + /* set CRC */ + { + MSD_release_cs(msd->spi_device); + MSD_take_cs(msd->spi_device); +#ifdef MSD_USE_CRC + result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response); +#else + result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response); +#endif + MSD_release_cs(msd->spi_device); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD59 CRC_ON_OFF fail! response : 0x%02X\r\n", response[0]); + result = RT_ERROR; + goto _exit; + } + } /* set CRC */ + + /* CMD16 SET_BLOCKLEN */ + { + MSD_release_cs(msd->spi_device); + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, SET_BLOCKLEN, SECTOR_SIZE, 0x00, response_r1, response); + MSD_release_cs(msd->spi_device); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD16 SET_BLOCKLEN fail! response : 0x%02X\r\n", response[0]); + result = RT_ERROR; + goto _exit; + } + msd->geometry.block_size = SECTOR_SIZE; + msd->geometry.bytes_per_sector = SECTOR_SIZE; + } + + /* read CSD */ + { + uint8_t CSD_buffer[MSD_CSD_LEN]; + + MSD_take_cs(msd->spi_device); +// result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0xAF, response_r1, response); + result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response); + + if(result != RT_EOK) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] CMD9 SEND_CSD timeout!\r\n"); + goto _exit; + } + + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_release_cs(msd->spi_device); + MSD_DEBUG("[err] CMD9 SEND_CSD fail! response : 0x%02X\r\n", response[0]); + result = RT_ERROR; + goto _exit; + } + + result = _read_block(msd->spi_device, CSD_buffer, MSD_CSD_LEN); + MSD_release_cs(msd->spi_device); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read CSD fail!\r\n"); + goto _exit; + } + + /* Analyze CSD */ + { + uint8_t CSD_STRUCTURE; + uint32_t C_SIZE; + uint32_t card_capacity; + + uint8_t tmp8; + uint16_t tmp16; + uint32_t tmp32; + + /* get CSD_STRUCTURE */ + tmp8 = CSD_buffer[0] & 0xC0; /* 0b11000000 */ + CSD_STRUCTURE = tmp8 >> 6; + + /* MMC CSD Analyze. */ + if(msd->card_type == MSD_CARD_TYPE_MMC) + { + uint8_t C_SIZE_MULT; + uint8_t READ_BL_LEN; + + if(CSD_STRUCTURE > 2) + { + MSD_DEBUG("[err] bad CSD Version : %d\r\n", CSD_STRUCTURE); + result = RT_ERROR; + goto _exit; + } + + if(CSD_STRUCTURE == 0) + { + MSD_DEBUG("[info] CSD version No. 1.0\r\n"); + } + else if(CSD_STRUCTURE == 1) + { + MSD_DEBUG("[info] CSD version No. 1.1\r\n"); + } + else if(CSD_STRUCTURE == 2) + { + MSD_DEBUG("[info] CSD version No. 1.2\r\n"); + } + + /* get TRAN_SPEED 8bit [103:96] */ + tmp8 = CSD_buffer[3]; + tmp8 &= 0x03; /* [2:0] transfer rate unit.*/ + if(tmp8 == 0) + { + msd->max_clock = 100 * 1000; /* 0=100kbit/s. */ + } + else if(tmp8 == 1) + { + msd->max_clock = 1 * 1000 * 1000; /* 1=1Mbit/s. */ + } + else if(tmp8 == 2) + { + msd->max_clock = 10 * 1000 * 1000; /* 2=10Mbit/s. */ + } + else if(tmp8 == 3) + { + msd->max_clock = 100 * 1000 * 1000; /* 3=100Mbit/s. */ + } + if(tmp8 == 0) + { + MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dkbit/s.\r\n", tmp8, msd->max_clock/1000); + } + else + { + MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dMbit/s.\r\n", tmp8, msd->max_clock/1000/1000); + } + + /* get READ_BL_LEN 4bit [83:80] */ + tmp8 = CSD_buffer[5] & 0x0F; /* 0b00001111; */ + READ_BL_LEN = tmp8; /* 4 bit */ + MSD_DEBUG("[info] CSD : READ_BL_LEN : %d %dbyte\r\n", READ_BL_LEN, (1 << READ_BL_LEN)); + + /* get C_SIZE 12bit [73:62] */ + tmp16 = CSD_buffer[6] & 0x03; /* get [73:72] 0b00000011 */ + tmp16 = tmp16<<8; + tmp16 += CSD_buffer[7]; /* get [71:64] */ + tmp16 = tmp16<<2; + tmp8 = CSD_buffer[8] & 0xC0; /* get [63:62] 0b11000000 */ + tmp8 = tmp8>>6; + tmp16 = tmp16 + tmp8; + C_SIZE = tmp16; //12 bit + MSD_DEBUG("[info] CSD : C_SIZE : %d\r\n", C_SIZE); + + /* get C_SIZE_MULT 3bit [49:47] */ + tmp8 = CSD_buffer[9] & 0x03;//0b00000011; + tmp8 = tmp8<<1; + tmp8 = tmp8 + ((CSD_buffer[10] & 0x80/*0b10000000*/)>>7); + C_SIZE_MULT = tmp8; // 3 bit + MSD_DEBUG("[info] CSD : C_SIZE_MULT : %d\r\n", C_SIZE_MULT); + + /* memory capacity = BLOCKNR * BLOCK_LEN */ + /* BLOCKNR = (C_SIZE+1) * MULT */ + /* MULT = 2^(C_SIZE_MULT+2) */ + /* BLOCK_LEN = 2^READ_BL_LEN */ + card_capacity = (1 << READ_BL_LEN) * ((C_SIZE + 1) * (1 << (C_SIZE_MULT+2))); + msd->geometry.sector_count = card_capacity / msd->geometry.bytes_per_sector; + MSD_DEBUG("[info] card capacity : %d Mbyte\r\n", card_capacity/(1024*1024)); + } + else /* SD CSD Analyze. */ + { + if(CSD_STRUCTURE == 0) + { + uint8_t C_SIZE_MULT; + uint8_t READ_BL_LEN; + + MSD_DEBUG("[info] CSD Version 1.0\r\n"); + + /* get TRAN_SPEED 8bit [103:96] */ + tmp8 = CSD_buffer[3]; + if(tmp8 == 0x32) + { + msd->max_clock = 1000 * 1000 * 10; /* 10Mbit/s. */ + } + else if(tmp8 == 0x5A) + { + msd->max_clock = 1000 * 1000 * 50; /* 50Mbit/s. */ + } + else + { + msd->max_clock = 1000 * 1000 * 1; /* 1Mbit/s default. */ + } + MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dMbit/s.\r\n", tmp8, msd->max_clock/1000/1000); + + /* get READ_BL_LEN 4bit [83:80] */ + tmp8 = CSD_buffer[5] & 0x0F; /* 0b00001111; */ + READ_BL_LEN = tmp8; /* 4 bit */ + MSD_DEBUG("[info] CSD : READ_BL_LEN : %d %dbyte\r\n", READ_BL_LEN, (1 << READ_BL_LEN)); + + /* get C_SIZE 12bit [73:62] */ + tmp16 = CSD_buffer[6] & 0x03; /* get [73:72] 0b00000011 */ + tmp16 = tmp16<<8; + tmp16 += CSD_buffer[7]; /* get [71:64] */ + tmp16 = tmp16<<2; + tmp8 = CSD_buffer[8] & 0xC0; /* get [63:62] 0b11000000 */ + tmp8 = tmp8>>6; + tmp16 = tmp16 + tmp8; + C_SIZE = tmp16; //12 bit + MSD_DEBUG("[info] CSD : C_SIZE : %d\r\n", C_SIZE); + + /* get C_SIZE_MULT 3bit [49:47] */ + tmp8 = CSD_buffer[9] & 0x03;//0b00000011; + tmp8 = tmp8<<1; + tmp8 = tmp8 + ((CSD_buffer[10] & 0x80/*0b10000000*/)>>7); + C_SIZE_MULT = tmp8; // 3 bit + MSD_DEBUG("[info] CSD : C_SIZE_MULT : %d\r\n", C_SIZE_MULT); + + /* memory capacity = BLOCKNR * BLOCK_LEN */ + /* BLOCKNR = (C_SIZE+1) * MULT */ + /* MULT = 2^(C_SIZE_MULT+2) */ + /* BLOCK_LEN = 2^READ_BL_LEN */ + card_capacity = (1 << READ_BL_LEN) * ((C_SIZE + 1) * (1 << (C_SIZE_MULT+2))); + msd->geometry.sector_count = card_capacity / msd->geometry.bytes_per_sector; + MSD_DEBUG("[info] card capacity : %d Mbyte\r\n", card_capacity/(1024*1024)); + } + else if(CSD_STRUCTURE == 1) + { + MSD_DEBUG("[info] CSD Version 2.0\r\n"); + + /* get TRAN_SPEED 8bit [103:96] */ + tmp8 = CSD_buffer[3]; + if(tmp8 == 0x32) + { + msd->max_clock = 1000 * 1000 * 10; /* 10Mbit/s. */ + } + else if(tmp8 == 0x5A) + { + msd->max_clock = 1000 * 1000 * 50; /* 50Mbit/s. */ + } + else if(tmp8 == 0x0B) + { + msd->max_clock = 1000 * 1000 * 100; /* 100Mbit/s. */ + /* UHS50 Card sets TRAN_SPEED to 0Bh (100Mbit/sec), */ + /* for both SDR50 and DDR50 modes. */ + } + else if(tmp8 == 0x2B) + { + msd->max_clock = 1000 * 1000 * 200; /* 200Mbit/s. */ + /* UHS104 Card sets TRAN_SPEED to 2Bh (200Mbit/sec). */ + } + else + { + msd->max_clock = 1000 * 1000 * 1; /* 1Mbit/s default. */ + } + MSD_DEBUG("[info] TRAN_SPEED: 0x%02X, %dMbit/s.\r\n", tmp8, msd->max_clock/1000/1000); + + /* get C_SIZE 22bit [69:48] */ + tmp32 = CSD_buffer[7] & 0x3F; /* 0b00111111 */ + tmp32 = tmp32<<8; + tmp32 += CSD_buffer[8]; + tmp32 = tmp32<<8; + tmp32 += CSD_buffer[9]; + C_SIZE = tmp32; + MSD_DEBUG("[info] CSD : C_SIZE : %d\r\n", C_SIZE); + + /* memory capacity = (C_SIZE+1) * 512K byte */ + card_capacity = (C_SIZE + 1) / 2; /* unit : Mbyte */ + msd->geometry.sector_count = card_capacity * 1024; /* 1 Mbyte = 512 byte X 2048 */ + MSD_DEBUG("[info] card capacity : %d.%d Gbyte\r\n", card_capacity/1024, (card_capacity%1024)*100/1024); + } + else + { + MSD_DEBUG("[err] bad CSD Version : %d\r\n", CSD_STRUCTURE); + result = RT_ERROR; + goto _exit; + } + } /* SD CSD Analyze. */ + } /* Analyze CSD */ + + } /* read CSD */ + + /* config spi to high speed */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = msd->max_clock; + + rt_spi_configure(msd->spi_device, &cfg); + } /* config spi */ + +_exit: + MSD_release_cs(msd->spi_device); + rt_mutex_release(&(msd->spi_device->bus->lock)); + return result; } static rt_err_t rt_msd_open(rt_device_t dev, rt_uint16_t oflag) { - return RT_EOK; +// struct msd_device * msd = (struct msd_device *)dev; + return RT_EOK; } static rt_err_t rt_msd_close(rt_device_t dev) { - return RT_EOK; +// struct msd_device * msd = (struct msd_device *)dev; + return RT_EOK; } static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) { - rt_uint8_t status; - rt_uint32_t i; + struct msd_device * msd = (struct msd_device *)dev; + uint8_t response[MSD_RESPONSE_MAX_LEN]; + rt_err_t result = RT_EOK; - status = MSD_RESPONSE_NO_ERROR; - // rt_kprintf("read: 0x%x, size %d\n", pos, size); + result = MSD_take_owner(msd->spi_device); - /* read all sectors */ - for (i = 0; i < size; i ++) - { - status = MSD_ReadBlock((rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE), - (part.offset + pos + i)* SECTOR_SIZE, SECTOR_SIZE); - if (status != MSD_RESPONSE_NO_ERROR) - { - rt_kprintf("sd card read failed\n"); - return 0; - } - } + if (result != RT_EOK) + { + goto _exit; + } - if (status == MSD_RESPONSE_NO_ERROR) return size; + /* config spi to high speed */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = msd->max_clock; - rt_kprintf("read failed: %d\n", status); - return 0; + rt_spi_configure(msd->spi_device, &cfg); + } /* config spi */ + + /* SINGLE_BLOCK? */ + if(size == 1) + { + MSD_take_cs(msd->spi_device); + + result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos); + size = 0; + goto _exit; + } + + result = _read_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos); + size = 0; + } + } + else if(size > 1) + { + uint32_t i; + + MSD_take_cs(msd->spi_device); + + result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos); + size = 0; + goto _exit; + } + + for(i=0; ispi_device, + (uint8_t *)buffer + msd->geometry.bytes_per_sector * i, + msd->geometry.bytes_per_sector); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos); + size = i; + break; + } + } + + /* send CMD12 stop transfer */ + result = _send_cmd(msd->spi_device, STOP_TRANSMISSION, 0x00, 0x00, response_r1b, response); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK, send stop token fail!\r\n"); + } + } /* READ_MULTIPLE_BLOCK */ + +_exit: + /* release and exit */ + MSD_release_cs(msd->spi_device); + rt_mutex_release(&(msd->spi_device->bus->lock)); + + return size; +} + +static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + struct msd_device * msd = (struct msd_device *)dev; + uint8_t response[MSD_RESPONSE_MAX_LEN]; + rt_err_t result = RT_EOK; + + result = MSD_take_owner(msd->spi_device); + + if (result != RT_EOK) + { + goto _exit; + } + + /* config spi to high speed */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = msd->max_clock; + + rt_spi_configure(msd->spi_device, &cfg); + } /* config spi */ + + /* SINGLE_BLOCK? */ + if(size == 1) + { + MSD_take_cs(msd->spi_device); + + result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos); + size = 0; + goto _exit; + } + + result = _read_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read SINGLE_BLOCK #%d fail!\r\n", pos); + size = 0; + } + } + else if(size > 1) + { + uint32_t i; + + MSD_take_cs(msd->spi_device); + + result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos); + size = 0; + goto _exit; + } + + for(i=0; ispi_device, + (uint8_t *)buffer + msd->geometry.bytes_per_sector * i, + msd->geometry.bytes_per_sector); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK #%d fail!\r\n", pos); + size = i; + break; + } + } + + /* send CMD12 stop transfer */ + result = _send_cmd(msd->spi_device, STOP_TRANSMISSION, 0x00, 0x00, response_r1b, response); + if(result != RT_EOK) + { + MSD_DEBUG("[err] read READ_MULTIPLE_BLOCK, send stop token fail!\r\n"); + } + } /* READ_MULTIPLE_BLOCK */ + +_exit: + /* release and exit */ + MSD_release_cs(msd->spi_device); + rt_mutex_release(&(msd->spi_device->bus->lock)); + + return size; } static rt_size_t rt_msd_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) { - rt_uint8_t status; - rt_uint32_t i; + struct msd_device * msd = (struct msd_device *)dev; + uint8_t response[MSD_RESPONSE_MAX_LEN]; + rt_err_t result; - status = MSD_RESPONSE_NO_ERROR; - // rt_kprintf("write: 0x%x, size %d\n", pos, size); + result = MSD_take_owner(msd->spi_device); - /* write all sectors */ - for (i = 0; i < size; i ++) - { - status = MSD_WriteBuffer((rt_uint8_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE), - (part.offset + pos + i)* SECTOR_SIZE, SECTOR_SIZE); - if (status != MSD_RESPONSE_NO_ERROR) - { - rt_kprintf("sd card write failed\n"); - return 0; - } - } + if (result != RT_EOK) + { + MSD_DEBUG("[err] get SPI owner fail!\r\n"); + goto _exit; + } - if (status == MSD_RESPONSE_NO_ERROR) return size; + /* config spi to high speed */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = msd->max_clock; - rt_kprintf("write failed: %d\n", status); - return 0; + rt_spi_configure(msd->spi_device, &cfg); + } /* config spi */ + + /* SINGLE_BLOCK? */ + if(size == 1) + { + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD WRITE_BLOCK fail!\r\n"); + size = 0; + goto _exit; + } + + result = _write_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector, MSD_TOKEN_WRITE_SINGLE_START); + if(result != RT_EOK) + { + MSD_DEBUG("[err] write SINGLE_BLOCK #%d fail!\r\n", pos); + size = 0; + } + } + else if(size > 1) + { + struct rt_spi_message message; + uint32_t i; + + MSD_take_cs(msd->spi_device); + +#ifdef MSD_USE_PRE_ERASED + if(msd->card_type != MSD_CARD_TYPE_MMC) + { + /* CMD55 APP_CMD */ + result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD55 APP_CMD fail!\r\n"); + size = 0; + goto _exit; + } + + /* ACMD23 Pre-erased */ + result = _send_cmd(msd->spi_device, SET_WR_BLK_ERASE_COUNT, size, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] ACMD23 SET_BLOCK_COUNT fail!\r\n"); + size = 0; + goto _exit; + } + } +#endif + + result = _send_cmd(msd->spi_device, WRITE_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD WRITE_MULTIPLE_BLOCK fail!\r\n"); + size = 0; + goto _exit; + } + + /* write all block */ + for(i=0; ispi_device, + (const uint8_t *)buffer + msd->geometry.bytes_per_sector * i, + msd->geometry.bytes_per_sector, + MSD_TOKEN_WRITE_MULTIPLE_START); + if(result != RT_EOK) + { + MSD_DEBUG("[err] write SINGLE_BLOCK #%d fail!\r\n", pos); + size = i; + break; + } + } /* write all block */ + + /* send stop token */ + { + uint8_t send_buffer[18]; + + rt_memset(send_buffer, DUMMY, sizeof(send_buffer)); + send_buffer[sizeof(send_buffer) - 1] = MSD_TOKEN_WRITE_MULTIPLE_STOP; + + /* initial message */ + message.send_buf = send_buffer; + message.recv_buf = RT_NULL; + message.length = sizeof(send_buffer); + message.cs_take = message.cs_release = 0; + + /* transfer message */ + msd->spi_device->bus->ops->xfer(msd->spi_device, &message); + } + + /* wait ready */ + result = _wait_ready(msd->spi_device); + if(result != RT_EOK) + { + MSD_DEBUG("[warning] wait WRITE_MULTIPLE_BLOCK stop token ready timeout!\r\n"); + } + } /* size > 1 */ + +_exit: + /* release and exit */ + MSD_release_cs(msd->spi_device); + rt_mutex_release(&(msd->spi_device->bus->lock)); + + return size; +} + +static rt_size_t rt_msd_sdhc_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + struct msd_device * msd = (struct msd_device *)dev; + uint8_t response[MSD_RESPONSE_MAX_LEN]; + rt_err_t result; + + result = MSD_take_owner(msd->spi_device); + + if (result != RT_EOK) + { + goto _exit; + } + + /* config spi to high speed */ + { + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ + cfg.max_hz = msd->max_clock; + + rt_spi_configure(msd->spi_device, &cfg); + } /* config spi */ + + /* SINGLE_BLOCK? */ + if(size == 1) + { + MSD_take_cs(msd->spi_device); + result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD WRITE_BLOCK fail!\r\n"); + size = 0; + goto _exit; + } + + result = _write_block(msd->spi_device, buffer, msd->geometry.bytes_per_sector, MSD_TOKEN_WRITE_SINGLE_START); + if(result != RT_EOK) + { + MSD_DEBUG("[err] write SINGLE_BLOCK #%d fail!\r\n", pos); + size = 0; + } + } + else if(size > 1) + { + struct rt_spi_message message; + uint32_t i; + + MSD_take_cs(msd->spi_device); + +#ifdef MSD_USE_PRE_ERASED + /* CMD55 APP_CMD */ + result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD55 APP_CMD fail!\r\n"); + size = 0; + goto _exit; + } + + /* ACMD23 Pre-erased */ + result = _send_cmd(msd->spi_device, SET_WR_BLK_ERASE_COUNT, size, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] ACMD23 SET_BLOCK_COUNT fail!\r\n"); + size = 0; + goto _exit; + } +#endif + + result = _send_cmd(msd->spi_device, WRITE_MULTIPLE_BLOCK, pos, 0x00, response_r1, response); + if((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) + { + MSD_DEBUG("[err] CMD WRITE_MULTIPLE_BLOCK fail!\r\n"); + size = 0; + goto _exit; + } + + /* write all block */ + for(i=0; ispi_device, + (const uint8_t *)buffer + msd->geometry.bytes_per_sector * i, + msd->geometry.bytes_per_sector, + MSD_TOKEN_WRITE_MULTIPLE_START); + if(result != RT_EOK) + { + MSD_DEBUG("[err] write MULTIPLE_BLOCK #%d fail!\r\n", pos); + size = i; + break; + } + } /* write all block */ + + /* send stop token */ + { + uint8_t send_buffer[18]; + + rt_memset(send_buffer, DUMMY, sizeof(send_buffer)); + send_buffer[sizeof(send_buffer) - 1] = MSD_TOKEN_WRITE_MULTIPLE_STOP; + + /* initial message */ + message.send_buf = send_buffer; + message.recv_buf = RT_NULL; + message.length = sizeof(send_buffer); + message.cs_take = message.cs_release = 0; + + /* transfer message */ + msd->spi_device->bus->ops->xfer(msd->spi_device, &message); + } + + result = _wait_ready(msd->spi_device); + if(result != RT_EOK) + { + MSD_DEBUG("[warning] wait WRITE_MULTIPLE_BLOCK stop token ready timeout!\r\n"); + } + } /* size > 1 */ + +_exit: + /* release and exit */ + MSD_release_cs(msd->spi_device); + rt_mutex_release(&(msd->spi_device->bus->lock)); + + return size; } static rt_err_t rt_msd_control(rt_device_t dev, rt_uint8_t cmd, void *args) { + struct msd_device * msd = (struct msd_device *)dev; + RT_ASSERT(dev != RT_NULL); - return RT_EOK; + if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) + { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) return -RT_ERROR; + + geometry->bytes_per_sector = msd->geometry.bytes_per_sector; + geometry->block_size = msd->geometry.block_size; + geometry->sector_count = msd->geometry.sector_count; + } + + return RT_EOK; } -void rt_hw_msd_init() +rt_err_t msd_init(const char * sd_device_name, const char * spi_device_name) { - if (MSD_Init() == MSD_RESPONSE_NO_ERROR) - { - rt_uint8_t status; - rt_uint8_t *sector; + rt_err_t result = RT_EOK; + struct rt_spi_device * spi_device; - /* register sdcard device */ - sdcard_device.init = rt_msd_init; - sdcard_device.open = rt_msd_open; - sdcard_device.close = rt_msd_close; - sdcard_device.read = rt_msd_read; - sdcard_device.write = rt_msd_write; - sdcard_device.control = rt_msd_control; + spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name); + if(spi_device == RT_NULL) + { + MSD_DEBUG("spi device %s not found!\r\n", spi_device_name); + return -RT_ENOSYS; + } + rt_memset(&_msd_device, 0, sizeof(_msd_device)); + _msd_device.spi_device = spi_device; - /* no private */ - sdcard_device.user_data = RT_NULL; - /* get the first sector to read partition table */ - sector = (rt_uint8_t*) rt_malloc (512); - if (sector == RT_NULL) - { - rt_kprintf("allocate partition sector buffer failed\n"); - return; - } + /* register sdcard device */ + _msd_device.parent.type = RT_Device_Class_Block; - status = MSD_ReadBlock(sector, 0, 512); - if (status == MSD_RESPONSE_NO_ERROR) - { - /* get the first partition */ - status = dfs_filesystem_get_partition(&part, sector, 0); - if (status != RT_EOK) - { - /* there is no partition table */ - part.offset = 0; - part.size = 0; - } - } - else - { - /* there is no partition table */ - part.offset = 0; - part.size = 0; - } + _msd_device.geometry.bytes_per_sector = 0; + _msd_device.geometry.sector_count = 0; + _msd_device.geometry.block_size = 0; - /* release sector buffer */ - rt_free(sector); + _msd_device.parent.init = rt_msd_init; + _msd_device.parent.open = rt_msd_open; + _msd_device.parent.close = rt_msd_close; + _msd_device.parent.read = RT_NULL; + _msd_device.parent.write = RT_NULL; + _msd_device.parent.control = rt_msd_control; - rt_device_register(&sdcard_device, "sd0", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); - } - else - { - rt_kprintf("sdcard init failed\n"); - } + /* no private, no callback */ + _msd_device.parent.user_data = RT_NULL; + _msd_device.parent.rx_indicate = RT_NULL; + _msd_device.parent.tx_complete = RT_NULL; + + result = rt_device_register(&_msd_device.parent, sd_device_name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); + + return result; } diff --git a/bsp/stm32f107/drivers/msd.h b/bsp/stm32f107/drivers/msd.h index 2ed985bb3..e00494433 100644 --- a/bsp/stm32f107/drivers/msd.h +++ b/bsp/stm32f107/drivers/msd.h @@ -1,173 +1,132 @@ -/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** -* File Name : msd.h -* Author : MCD Application Team -* Version : V2.1 -* Date : 05/30/2008 -* Description : Header for msd.c file. -******************************************************************************** -* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. -* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, -* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE -* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING -* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. -* FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED -* IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE. -*******************************************************************************/ +/* + * File : msd.h + * SPI mode SD Card Driver + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-04-17 Bernard first version. + */ -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __MSD_H -#define __MSD_H +#ifndef MSD_H_INCLUDED +#define MSD_H_INCLUDED -/* Includes ------------------------------------------------------------------*/ -#include +#include +#include -/* Private define ------------------------------------------------------------*/ -/* Block Size */ -#define BLOCK_SIZE 512 +/* SD command (SPI mode) */ +#define GO_IDLE_STATE 0 /* CMD0 R1 */ +#define SEND_OP_COND 1 /* CMD1 R1 */ +#define SWITCH_FUNC 6 /* CMD6 R1 */ +#define SEND_IF_COND 8 /* CMD8 R7 */ +#define SEND_CSD 9 /* CMD9 R1 */ +#define SEND_CID 10 /* CMD10 R1 */ +#define STOP_TRANSMISSION 12 /* CMD12 R1B */ +#define SEND_STATUS 13 /* CMD13 R2 */ +#define SET_BLOCKLEN 16 /* CMD16 R1 */ +#define READ_SINGLE_BLOCK 17 /* CMD17 R1 */ +#define READ_MULTIPLE_BLOCK 18 /* CMD18 R1 */ +#define WRITE_BLOCK 24 /* CMD24 R1 */ +#define WRITE_MULTIPLE_BLOCK 25 /* CMD25 R1 */ +#define PROGRAM_CSD 27 /* CMD27 R1 */ +#define SET_WRITE_PROT 28 /* CMD28 R1B */ +#define CLR_WRITE_PROT 29 /* CMD29 R1B */ +#define SEND_WRITE_PROT 30 /* CMD30 R1 */ +#define ERASE_WR_BLK_START_ADDR 32 /* CMD32 R1 */ +#define ERASE_WR_BLK_END_ADDR 33 /* CMD33 R1 */ +#define ERASE 38 /* CMD38 R1B */ +#define LOCK_UNLOCK 42 /* CMD42 R1 */ +#define APP_CMD 55 /* CMD55 R1 */ +#define GEN_CMD 56 /* CMD56 R1 */ +#define READ_OCR 58 /* CMD58 R3 */ +#define CRC_ON_OFF 59 /* CMD59 R1 */ -/* Dummy byte */ -#define DUMMY 0xFF +/* Application-Specific Command */ +#define SD_STATUS 13 /* ACMD13 R2 */ +#define SEND_NUM_WR_BLOCKS 22 /* ACMD22 R1 */ +#define SET_WR_BLK_ERASE_COUNT 23 /* ACMD23 R1 */ +#define SD_SEND_OP_COND 41 /* ACMD41 R1 */ +#define SET_CLR_CARD_DETECT 42 /* ACMD42 R1 */ +#define SEND_SCR 51 /* ACMD51 R1 */ /* Start Data tokens */ /* Tokens (necessary because at nop/idle (and CS active) only 0xff is on the data/command line) */ -#define MSD_START_DATA_SINGLE_BLOCK_READ 0xFE /* Data token start byte, Start Single Block Read */ -#define MSD_START_DATA_MULTIPLE_BLOCK_READ 0xFE /* Data token start byte, Start Multiple Block Read */ -#define MSD_START_DATA_SINGLE_BLOCK_WRITE 0xFE /* Data token start byte, Start Single Block Write */ -#define MSD_START_DATA_MULTIPLE_BLOCK_WRITE 0xFD /* Data token start byte, Start Multiple Block Write */ -#define MSD_STOP_DATA_MULTIPLE_BLOCK_WRITE 0xFD /* Data toke stop byte, Stop Multiple Block Write */ +#define MSD_TOKEN_READ_START 0xFE /* Data token start byte, Start Single Block Read */ +#define MSD_TOKEN_WRITE_SINGLE_START 0xFE /* Data token start byte, Start Single Block Write */ -/* MSD functions return */ -#define MSD_SUCCESS 0x00 -#define MSD_FAIL 0xFF +#define MSD_TOKEN_WRITE_MULTIPLE_START 0xFC /* Data token start byte, Start Multiple Block Write */ +#define MSD_TOKEN_WRITE_MULTIPLE_STOP 0xFD /* Data toke stop byte, Stop Multiple Block Write */ /* MSD reponses and error flags */ -#define MSD_RESPONSE_NO_ERROR 0x00 -#define MSD_IN_IDLE_STATE 0x01 -#define MSD_ERASE_RESET 0x02 -#define MSD_ILLEGAL_COMMAND 0x04 -#define MSD_COM_CRC_ERROR 0x08 -#define MSD_ERASE_SEQUENCE_ERROR 0x10 -#define MSD_ADDRESS_ERROR 0x20 -#define MSD_PARAMETER_ERROR 0x40 -#define MSD_RESPONSE_FAILURE 0xFF +#define MSD_RESPONSE_NO_ERROR 0x00 +#define MSD_IN_IDLE_STATE 0x01 +#define MSD_ERASE_RESET 0x02 +#define MSD_ILLEGAL_COMMAND 0x04 +#define MSD_COM_CRC_ERROR 0x08 +#define MSD_ERASE_SEQUENCE_ERROR 0x10 +#define MSD_ADDRESS_ERROR 0x20 +#define MSD_PARAMETER_ERROR 0x40 +#define MSD_RESPONSE_FAILURE 0xFF /* Data response error */ -#define MSD_DATA_OK 0x05 -#define MSD_DATA_CRC_ERROR 0x0B -#define MSD_DATA_WRITE_ERROR 0x0D -#define MSD_DATA_OTHER_ERROR 0xFF +#define MSD_DATA_OK 0x05 +#define MSD_DATA_CRC_ERROR 0x0B +#define MSD_DATA_WRITE_ERROR 0x0D +#define MSD_DATA_OTHER_ERROR 0xFF +#define MSD_DATA_RESPONSE_MASK 0x1F +#define MSD_GET_DATA_RESPONSE(res) (res & MSD_DATA_RESPONSE_MASK) -/* Commands: CMDxx = CMD-number | 0x40 */ -#define MSD_GO_IDLE_STATE 0 /* CMD0=0x40 */ -#define MSD_SEND_OP_COND 1 /* CMD1=0x41 */ -#define MSD_SEND_CSD 9 /* CMD9=0x49 */ -#define MSD_SEND_CID 10 /* CMD10=0x4A */ -#define MSD_STOP_TRANSMISSION 12 /* CMD12=0x4C */ -#define MSD_SEND_STATUS 13 /* CMD13=0x4D */ -#define MSD_SET_BLOCKLEN 16 /* CMD16=0x50 */ -#define MSD_READ_SINGLE_BLOCK 17 /* CMD17=0x51 */ -#define MSD_READ_MULTIPLE_BLOCK 18 /* CMD18=0x52 */ -#define MSD_SET_BLOCK_COUNT 23 /* CMD23=0x57 */ -#define MSD_WRITE_BLOCK 24 /* CMD24=0x58 */ -#define MSD_WRITE_MULTIPLE_BLOCK 25 /* CMD25=0x59 */ -#define MSD_PROGRAM_CSD 27 /* CMD27=0x5B */ -#define MSD_SET_WRITE_PROT 28 /* CMD28=0x5C */ -#define MSD_CLR_WRITE_PROT 29 /* CMD29=0x5D */ -#define MSD_SEND_WRITE_PROT 30 /* CMD30=0x5E */ -#define MSD_TAG_SECTOR_START 32 /* CMD32=0x60 */ -#define MSD_TAG_SECTOR_END 33 /* CMD33=0x61 */ -#define MSD_UNTAG_SECTOR 34 /* CMD34=0x62 */ -#define MSD_TAG_ERASE_GROUP_START 35 /* CMD35=0x63 */ -#define MSD_TAG_ERASE_GROUP_END 36 /* CMD36=0x64 */ -#define MSD_UNTAG_ERASE_GROUP 37 /* CMD37=0x65 */ -#define MSD_ERASE 38 /* CMD38=0x66 */ -#define MSD_READ_OCR 39 /* CMD39=0x67 */ -#define MSD_CRC_ON_OFF 40 /* CMD40=0x68 */ +#define MSD_CMD_LEN 6 /**< command, arg and crc. */ +#define MSD_RESPONSE_MAX_LEN 5 /**< response max len */ +#define MSD_CSD_LEN 16 /**< SD crad CSD register len */ +#define SECTOR_SIZE 512 /**< sector size, default 512byte */ -/* Exported types ------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -typedef struct _MSD_CSD /*Card Specific Data*/ +/* card try timeout, unit: ms */ +#define CARD_TRY_TIMES 3000 +#define CARD_TRY_TIMES_ACMD41 800 +#define CARD_WAIT_TOKEN_TIMES 800 + +#define MSD_USE_PRE_ERASED /**< id define MSD_USE_PRE_ERASED, before CMD25, send ACMD23 */ + +/** + * SD/MMC card type + */ +typedef enum { - vu8 CSDStruct; /* CSD structure */ - vu8 SysSpecVersion; /* System specification version */ - vu8 Reserved1; /* Reserved */ - vu8 TAAC; /* Data read access-time 1 */ - vu8 NSAC; /* Data read access-time 2 in CLK cycles */ - vu8 MaxBusClkFrec; /* Max. bus clock frequency */ - vu16 CardComdClasses; /* Card command classes */ - vu8 RdBlockLen; /* Max. read data block length */ - vu8 PartBlockRead; /* Partial blocks for read allowed */ - vu8 WrBlockMisalign; /* Write block misalignment */ - vu8 RdBlockMisalign; /* Read block misalignment */ - vu8 DSRImpl; /* DSR implemented */ - vu8 Reserved2; /* Reserved */ - vu16 DeviceSize; /* Device Size */ - vu8 MaxRdCurrentVDDMin; /* Max. read current @ VDD min */ - vu8 MaxRdCurrentVDDMax; /* Max. read current @ VDD max */ - vu8 MaxWrCurrentVDDMin; /* Max. write current @ VDD min */ - vu8 MaxWrCurrentVDDMax; /* Max. write current @ VDD max */ - vu8 DeviceSizeMul; /* Device size multiplier */ - vu8 EraseGrSize; /* Erase group size */ - vu8 EraseGrMul; /* Erase group size multiplier */ - vu8 WrProtectGrSize; /* Write protect group size */ - vu8 WrProtectGrEnable; /* Write protect group enable */ - vu8 ManDeflECC; /* Manufacturer default ECC */ - vu8 WrSpeedFact; /* Write speed factor */ - vu8 MaxWrBlockLen; /* Max. write data block length */ - vu8 WriteBlockPaPartial; /* Partial blocks for write allowed */ - vu8 Reserved3; /* Reserded */ - vu8 ContentProtectAppli; /* Content protection application */ - vu8 FileFormatGrouop; /* File format group */ - vu8 CopyFlag; /* Copy flag (OTP) */ - vu8 PermWrProtect; /* Permanent write protection */ - vu8 TempWrProtect; /* Temporary write protection */ - vu8 FileFormat; /* File Format */ - vu8 ECC; /* ECC code */ - vu8 msd_CRC; /* CRC */ - vu8 Reserved4; /* always 1*/ -} -sMSD_CSD; + MSD_CARD_TYPE_UNKNOWN = 0, /**< unknown */ + MSD_CARD_TYPE_MMC, /**< MultiMedia Card */ + MSD_CARD_TYPE_SD_V1_X, /**< Ver 1.X Standard Capacity SD Memory Card */ + MSD_CARD_TYPE_SD_V2_X, /**< Ver 2.00 or later Standard Capacity SD Memory Card */ + MSD_CARD_TYPE_SD_SDHC, /**< High Capacity SD Memory Card */ + MSD_CARD_TYPE_SD_SDXC, /**< later Extended Capacity SD Memory Card */ +}msd_card_type; -typedef struct _MSD_CID /*Card Identification Data*/ +typedef enum { - vu8 ManufacturerID; /* ManufacturerID */ - vu16 OEM_AppliID; /* OEM/Application ID */ - vu32 ProdName1; /* Product Name part1 */ - vu8 ProdName2; /* Product Name part2*/ - vu8 ProdRev; /* Product Revision */ - vu32 ProdSN; /* Product Serial Number */ - vu8 Reserved1; /* Reserved1 */ - vu16 ManufactDate; /* Manufacturing Date */ - vu8 msd_CRC; /* CRC */ - vu8 Reserved2; /* always 1*/ -} -sMSD_CID; + response_type_unknown = 0, + response_r1, + response_r1b, + response_r2, + response_r3, + response_r4, + response_r5, + response_r7, +}response_type; -/* Exported constants --------------------------------------------------------*/ -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions ------------------------------------------------------- */ +struct msd_device +{ + struct rt_device parent; /**< RT-Thread device struct */ + struct rt_device_blk_geometry geometry; /**< sector size, sector count */ + struct rt_spi_device * spi_device; /**< SPI interface */ + msd_card_type card_type; /**< card type: MMC SD1.x SD2.0 SDHC SDXC */ + uint32_t max_clock; /**< MAX SPI clock */ +}; -/*----- High layer function -----*/ -u8 MSD_Init(void); -u8 MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite); -u8 MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead); -u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite); -u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead); -u8 MSD_GetCSDRegister(sMSD_CSD* MSD_csd); -u8 MSD_GetCIDRegister(sMSD_CID* MSD_cid); +extern rt_err_t msd_init(const char * sd_device_name, const char * spi_device_name); -/*----- Medium layer function -----*/ -void MSD_SendCmd(u8 Cmd, u32 Arg, u8 Crc); -u8 MSD_GetResponse(u8 Response); -u8 MSD_GetDataResponse(void); -u8 MSD_GoIdleState(void); -u16 MSD_GetStatus(void); - -/*----- Low layer function -----*/ -u8 MSD_WriteByte(u8 byte); -u8 MSD_ReadByte(void); - -#endif /* __MSD_H */ - -/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ +#endif // MSD_H_INCLUDED diff --git a/bsp/stm32f107/drivers/platform.c b/bsp/stm32f107/drivers/platform.c index 694b4843b..a429e232a 100644 --- a/bsp/stm32f107/drivers/platform.c +++ b/bsp/stm32f107/drivers/platform.c @@ -5,18 +5,98 @@ #include "stm32_eth.h" #endif /* RT_USING_LWIP */ +#ifdef RT_USING_SPI +#include "rt_stm32f10x_spi.h" + +#if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT) +#include "msd.h" +#endif /* RT_USING_DFS */ + +/* + * SPI1_MOSI: PA7 + * SPI1_MISO: PA6 + * SPI1_SCK : PA5 + * + * CS0: PA4 SD card. +*/ +static void rt_hw_spi_init(void) +{ +#ifdef RT_USING_SPI1 + /* register spi bus */ + { + static struct stm32_spi_bus stm32_spi; + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable GPIO clock */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, + ENABLE); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + stm32_spi_register(SPI1, &stm32_spi, "spi1"); + } + + /* attach cs */ + { + static struct rt_spi_device spi_device; + static struct stm32_spi_cs spi_cs; + + GPIO_InitTypeDef GPIO_InitStructure; + + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + + /* spi21: PG10 */ + spi_cs.GPIOx = GPIOA; + spi_cs.GPIO_Pin = GPIO_Pin_4; + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); + + GPIO_InitStructure.GPIO_Pin = spi_cs.GPIO_Pin; + GPIO_SetBits(spi_cs.GPIOx, spi_cs.GPIO_Pin); + GPIO_Init(spi_cs.GPIOx, &GPIO_InitStructure); + + rt_spi_bus_attach_device(&spi_device, "spi10", "spi1", (void*)&spi_cs); + } +#endif /* RT_USING_SPI1 */ +} +#endif /* RT_USING_SPI */ + + void rt_platform_init(void) { -#ifdef RT_USING_LWIP - /* initialize eth interface */ - rt_hw_stm32_eth_init(); -#endif /* RT_USING_LWIP */ +#ifdef RT_USING_SPI + rt_hw_spi_init(); #if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT) /* init sdcard driver */ { extern void rt_hw_msd_init(void); - rt_hw_msd_init(); + GPIO_InitTypeDef GPIO_InitStructure; + + /* PC4 : SD Power */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + /* SD card power on. */ + GPIO_ResetBits(GPIOC, GPIO_Pin_4); + rt_thread_delay(2); + + msd_init("sd0", "spi10"); } #endif /* RT_USING_DFS && RT_USING_DFS_ELMFAT */ + +#endif // RT_USING_SPI + +#ifdef RT_USING_LWIP + /* initialize eth interface */ + rt_hw_stm32_eth_init(); +#endif /* RT_USING_LWIP */ + } diff --git a/bsp/stm32f107/drivers/rt_stm32f10x_spi.c b/bsp/stm32f107/drivers/rt_stm32f10x_spi.c new file mode 100644 index 000000000..26d623535 --- /dev/null +++ b/bsp/stm32f107/drivers/rt_stm32f10x_spi.c @@ -0,0 +1,372 @@ +#include "rt_stm32f10x_spi.h" + +static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration); +static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message); + +static struct rt_spi_ops stm32_spi_ops = +{ + configure, + xfer +}; + +#ifdef USING_SPI1 +static struct stm32_spi_bus stm32_spi_bus_1; +#endif /* #ifdef USING_SPI1 */ + +#ifdef USING_SPI2 +static struct stm32_spi_bus stm32_spi_bus_2; +#endif /* #ifdef USING_SPI2 */ + +#ifdef USING_SPI3 +static struct stm32_spi_bus stm32_spi_bus_3; +#endif /* #ifdef USING_SPI3 */ + +//------------------ DMA ------------------ +#ifdef SPI_USE_DMA +static uint8_t dummy = 0xFF; +#endif + +#ifdef SPI_USE_DMA +static void DMA_Configuration(struct stm32_spi_bus * stm32_spi_bus, const void * send_addr, void * recv_addr, rt_size_t size) +{ + DMA_InitTypeDef DMA_InitStructure; + + DMA_ClearFlag(stm32_spi_bus->DMA_Channel_RX_FLAG_TC + | stm32_spi_bus->DMA_Channel_RX_FLAG_TE + | stm32_spi_bus->DMA_Channel_TX_FLAG_TC + | stm32_spi_bus->DMA_Channel_TX_FLAG_TE); + + /* RX channel configuration */ + DMA_Cmd(stm32_spi_bus->DMA_Channel_RX, DISABLE); + DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(stm32_spi_bus->SPI->DR)); + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; + + DMA_InitStructure.DMA_BufferSize = size; + + if(recv_addr != RT_NULL) + { + DMA_InitStructure.DMA_MemoryBaseAddr = (u32) recv_addr; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + } + else + { + DMA_InitStructure.DMA_MemoryBaseAddr = (u32) (&dummy); + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; + } + + DMA_Init(stm32_spi_bus->DMA_Channel_RX, &DMA_InitStructure); + + DMA_Cmd(stm32_spi_bus->DMA_Channel_RX, ENABLE); + + /* TX channel configuration */ + DMA_Cmd(stm32_spi_bus->DMA_Channel_TX, DISABLE); + DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(stm32_spi_bus->SPI->DR)); + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; + + DMA_InitStructure.DMA_BufferSize = size; + + if(send_addr != RT_NULL) + { + DMA_InitStructure.DMA_MemoryBaseAddr = (u32)send_addr; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + } + else + { + DMA_InitStructure.DMA_MemoryBaseAddr = (u32)(&dummy);; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; + } + + DMA_Init(stm32_spi_bus->DMA_Channel_TX, &DMA_InitStructure); + + DMA_Cmd(stm32_spi_bus->DMA_Channel_TX, ENABLE); +} +#endif + +rt_inline uint16_t get_spi_BaudRatePrescaler(rt_uint32_t max_hz) +{ + uint16_t SPI_BaudRatePrescaler; + + /* STM32F10x SPI MAX 18Mhz */ + if(max_hz >= SystemCoreClock/2 && SystemCoreClock/2 <= 18000000) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; + } + else if(max_hz >= SystemCoreClock/4) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; + } + else if(max_hz >= SystemCoreClock/8) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; + } + else if(max_hz >= SystemCoreClock/16) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; + } + else if(max_hz >= SystemCoreClock/32) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; + } + else if(max_hz >= SystemCoreClock/64) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; + } + else if(max_hz >= SystemCoreClock/128) + { + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; + } + else + { + /* min prescaler 256 */ + SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; + } + + return SPI_BaudRatePrescaler; +} + +static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration) +{ + struct stm32_spi_bus * stm32_spi_bus = (struct stm32_spi_bus *)device->bus; + SPI_InitTypeDef SPI_InitStructure; + + SPI_StructInit(&SPI_InitStructure); + + /* data_width */ + if(configuration->data_width <= 8) + { + SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; + } + else if(configuration->data_width <= 16) + { + SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; + } + else + { + return RT_EIO; + } + /* baudrate */ + SPI_InitStructure.SPI_BaudRatePrescaler = get_spi_BaudRatePrescaler(configuration->max_hz); + /* CPOL */ + if(configuration->mode & RT_SPI_CPOL) + { + SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; + } + else + { + SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; + } + /* CPHA */ + if(configuration->mode & RT_SPI_CPHA) + { + SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; + } + else + { + SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; + } + /* MSB or LSB */ + if(configuration->mode & RT_SPI_MSB) + { + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + } + else + { + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; + } + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + SPI_InitStructure.SPI_Mode = SPI_Mode_Master; + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; + + /* init SPI */ + SPI_I2S_DeInit(stm32_spi_bus->SPI); + SPI_Init(stm32_spi_bus->SPI, &SPI_InitStructure); + /* Enable SPI_MASTER */ + SPI_Cmd(stm32_spi_bus->SPI, ENABLE); + SPI_CalculateCRC(stm32_spi_bus->SPI, DISABLE); + + return RT_EOK; +}; + +static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message) +{ + struct stm32_spi_bus * stm32_spi_bus = (struct stm32_spi_bus *)device->bus; + struct rt_spi_configuration * config = &device->config; + SPI_TypeDef * SPI = stm32_spi_bus->SPI; + struct stm32_spi_cs * stm32_spi_cs = device->parent.user_data; + rt_uint32_t size = message->length; + + /* take CS */ + if(message->cs_take) + { + GPIO_ResetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin); + } + +#ifdef SPI_USE_DMA + if(message->length > 32) + { + if(config->data_width <= 8) + { + DMA_Configuration(stm32_spi_bus, message->send_buf, message->recv_buf, message->length); + SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); + while (DMA_GetFlagStatus(stm32_spi_bus->DMA_Channel_RX_FLAG_TC) == RESET + || DMA_GetFlagStatus(stm32_spi_bus->DMA_Channel_TX_FLAG_TC) == RESET); + SPI_I2S_DMACmd(SPI, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, DISABLE); + } +// rt_memcpy(buffer,_spi_flash_buffer,DMA_BUFFER_SIZE); +// buffer += DMA_BUFFER_SIZE; + } + else +#endif + { + if(config->data_width <= 8) + { + const rt_uint8_t * send_ptr = message->send_buf; + rt_uint8_t * recv_ptr = message->recv_buf; + + while(size--) + { + rt_uint8_t data = 0xFF; + + if(send_ptr != RT_NULL) + { + data = *send_ptr++; + } + + //Wait until the transmit buffer is empty + while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET); + // Send the byte + SPI_I2S_SendData(SPI, data); + + //Wait until a data is received + while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET); + // Get the received data + data = SPI_I2S_ReceiveData(SPI); + + if(recv_ptr != RT_NULL) + { + *recv_ptr++ = data; + } + } + } + else if(config->data_width <= 16) + { + const rt_uint16_t * send_ptr = message->send_buf; + rt_uint16_t * recv_ptr = message->recv_buf; + + while(size--) + { + rt_uint16_t data = 0xFF; + + if(send_ptr != RT_NULL) + { + data = *send_ptr++; + } + + //Wait until the transmit buffer is empty + while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET); + // Send the byte + SPI_I2S_SendData(SPI, data); + + //Wait until a data is received + while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET); + // Get the received data + data = SPI_I2S_ReceiveData(SPI); + + if(recv_ptr != RT_NULL) + { + *recv_ptr++ = data; + } + } + } + } + + /* release CS */ + if(message->cs_release) + { + GPIO_SetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin); + } + + return message->length; +}; + +/** \brief init and register stm32 spi bus. + * + * \param SPI: STM32 SPI, e.g: SPI1,SPI2,SPI3. + * \param stm32_spi: stm32 spi bus struct. + * \param spi_bus_name: spi bus name, e.g: "spi1" + * \return + * + */ +rt_err_t stm32_spi_register(SPI_TypeDef * SPI, + struct stm32_spi_bus * stm32_spi, + const char * spi_bus_name) +{ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); + + if(SPI == SPI1) + { + stm32_spi->SPI = SPI1; +#ifdef SPI_USE_DMA + /* Enable the DMA1 Clock */ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); + + stm32_spi->DMA_Channel_RX = DMA1_Channel2; + stm32_spi->DMA_Channel_TX = DMA1_Channel3; + stm32_spi->DMA_Channel_RX_FLAG_TC = DMA1_FLAG_TC2; + stm32_spi->DMA_Channel_RX_FLAG_TE = DMA1_FLAG_TE2; + stm32_spi->DMA_Channel_TX_FLAG_TC = DMA1_FLAG_TC3; + stm32_spi->DMA_Channel_TX_FLAG_TE = DMA1_FLAG_TE3; +#endif + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + } + else if(SPI == SPI2) + { + stm32_spi->SPI = SPI2; +#ifdef SPI_USE_DMA + /* Enable the DMA1 Clock */ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); + + stm32_spi->DMA_Channel_RX = DMA1_Channel4; + stm32_spi->DMA_Channel_TX = DMA1_Channel5; + stm32_spi->DMA_Channel_RX_FLAG_TC = DMA1_FLAG_TC4; + stm32_spi->DMA_Channel_RX_FLAG_TE = DMA1_FLAG_TE4; + stm32_spi->DMA_Channel_TX_FLAG_TC = DMA1_FLAG_TC5; + stm32_spi->DMA_Channel_TX_FLAG_TE = DMA1_FLAG_TE5; +#endif + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); + } + else if(SPI == SPI3) + { + stm32_spi->SPI = SPI3; +#ifdef SPI_USE_DMA + /* Enable the DMA2 Clock */ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); + + stm32_spi->DMA_Channel_RX = DMA2_Channel1; + stm32_spi->DMA_Channel_TX = DMA2_Channel2; + stm32_spi->DMA_Channel_RX_FLAG_TC = DMA2_FLAG_TC1; + stm32_spi->DMA_Channel_RX_FLAG_TE = DMA2_FLAG_TE1; + stm32_spi->DMA_Channel_TX_FLAG_TC = DMA2_FLAG_TC2; + stm32_spi->DMA_Channel_TX_FLAG_TE = DMA2_FLAG_TE2; +#endif + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); + } + else + { + return RT_ENOSYS; + } + + return rt_spi_bus_register(&stm32_spi->parent, spi_bus_name, &stm32_spi_ops); +} diff --git a/bsp/stm32f107/drivers/rt_stm32f10x_spi.h b/bsp/stm32f107/drivers/rt_stm32f10x_spi.h new file mode 100644 index 000000000..55834a1da --- /dev/null +++ b/bsp/stm32f107/drivers/rt_stm32f10x_spi.h @@ -0,0 +1,38 @@ +#ifndef STM32_SPI_H_INCLUDED +#define STM32_SPI_H_INCLUDED + +#include + +#include "stm32f10x.h" +#include "stm32f10x_spi.h" + +#include "board.h" + +//#define SPI_USE_DMA + +struct stm32_spi_bus +{ + struct rt_spi_bus parent; + SPI_TypeDef * SPI; +#ifdef SPI_USE_DMA + DMA_Channel_TypeDef * DMA_Channel_TX; + DMA_Channel_TypeDef * DMA_Channel_RX; + uint32_t DMA_Channel_TX_FLAG_TC; + uint32_t DMA_Channel_TX_FLAG_TE; + uint32_t DMA_Channel_RX_FLAG_TC; + uint32_t DMA_Channel_RX_FLAG_TE; +#endif /* SPI_USE_DMA */ +}; + +struct stm32_spi_cs +{ + GPIO_TypeDef * GPIOx; + uint16_t GPIO_Pin; +}; + +/* public function list */ +rt_err_t stm32_spi_register(SPI_TypeDef * SPI, + struct stm32_spi_bus * stm32_spi, + const char * spi_bus_name); + +#endif // STM32_SPI_H_INCLUDED diff --git a/bsp/stm32f107/drivers/stm32f10x_it.c b/bsp/stm32f107/drivers/stm32f10x_it.c index 7d49d04e9..d1bf10227 100644 --- a/bsp/stm32f107/drivers/stm32f10x_it.c +++ b/bsp/stm32f107/drivers/stm32f10x_it.c @@ -5,7 +5,7 @@ * @version V3.5.0 * @date 08-April-2011 * @brief Main Interrupt Service Routines. - * This file provides template for all exceptions handler and + * This file provides template for all exceptions handler and * peripherals interrupt service routine. ****************************************************************************** * @attention @@ -19,7 +19,7 @@ * *

© COPYRIGHT 2011 STMicroelectronics

****************************************************************************** - */ + */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_it.h" @@ -107,12 +107,6 @@ void DebugMon_Handler(void) { } -void SysTick_Handler(void) -{ - extern void rt_hw_timer_handler(void); - rt_hw_timer_handler(); -} - /******************************************************************************/ /* STM32F10x Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ @@ -132,7 +126,7 @@ void USART1_IRQHandler(void) #ifdef RT_USING_UART1 extern struct rt_device uart1_device; extern void rt_hw_serial_isr(struct rt_device *device); - + /* enter interrupt */ rt_interrupt_enter(); @@ -191,7 +185,7 @@ void USART3_IRQHandler(void) /** * @} - */ + */ /******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ diff --git a/bsp/stm32f107/drivers/usart.c b/bsp/stm32f107/drivers/usart.c index 19b476f2f..a8e896019 100644 --- a/bsp/stm32f107/drivers/usart.c +++ b/bsp/stm32f107/drivers/usart.c @@ -13,6 +13,7 @@ * 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode */ +#include #include "usart.h" #include #include diff --git a/bsp/stm32f107/project.uvproj b/bsp/stm32f107/project.uvproj index 2a86c5ed7..b24ef8e9c 100644 --- a/bsp/stm32f107/project.uvproj +++ b/bsp/stm32f107/project.uvproj @@ -1,7 +1,10 @@ + 1.1 +
### uVision Project, (C) Keil Software
+ RT-Thread STM32 @@ -12,25 +15,25 @@ STM32F107VC STMicroelectronics IRAM(0x20000000-0x2000FFFF) IROM(0x8000000-0x803FFFF) CLOCK(25000000) CPUTYPE("Cortex-M3") - + "STARTUP\ST\STM32F10x.s" ("STM32 Startup Code") UL2CM3(-O14 -S0 -C0 -N00("ARM Cortex-M3") -D00(1BA00477) -L00(4) -FO7 -FD20000000 -FC800 -FN1 -FF0STM32F10x_CL -FS08000000 -FL040000) 4889 stm32f10x_lib.h - - - - - - - - - + + + + + + + + + SFD\ST\STM32F107x\STM32F107.sfr 0 - - - + + + ST\STM32F10x\ ST\STM32F10x\ @@ -54,16 +57,18 @@ 0 0 - - + + 0 0 + 0 + 0 0 0 - - + + 0 0 @@ -71,12 +76,12 @@ 1 0 fromelf --bin !L --output rtthread.bin - + 0 0 0 - + 0 @@ -90,16 +95,16 @@ 0 0 3 - - + + SARMCM3.DLL - + DARMSTM.DLL -pSTM32F107VC SARMCM3.DLL - + TARMSTM.DLL -pSTM32F107VC @@ -131,22 +136,23 @@ 1 0 1 + 0 0 7 - - - - - + + + + + - - - - - + + + + + Segger\JL2CM3.dll @@ -160,8 +166,8 @@ 4099 Segger\JL2CM3.dll - - + "" () + @@ -193,7 +199,7 @@ 0 0 "Cortex-M3" - + 0 0 0 @@ -324,7 +330,7 @@ 0x0 - + 1 @@ -339,11 +345,12 @@ 0 0 0 + 0 - + STM32F10X_CL, USE_STDPERIPH_DRIVER - - .;..\..\components\CMSIS\Include;..\..\components\dfs;..\..\components\dfs\include;..\..\components\finsh;..\..\components\init;..\..\components\net\lwip\src;..\..\components\net\lwip\src\arch\include;..\..\components\net\lwip\src\include;..\..\components\net\lwip\src\include\ipv4;..\..\components\net\lwip\src\include\netif;..\..\include;..\..\libcpu\arm\common;..\..\libcpu\arm\cortex-m3;Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x;Libraries\STM32F10x_StdPeriph_Driver\inc;applications;drivers + + .;..\..\components\CMSIS\Include;..\..\components\dfs;..\..\components\dfs\include;..\..\components\drivers\include;..\..\components\finsh;..\..\components\init;..\..\components\net\lwip\src;..\..\components\net\lwip\src\arch\include;..\..\components\net\lwip\src\include;..\..\components\net\lwip\src\include\ipv4;..\..\components\net\lwip\src\include\netif;..\..\include;..\..\libcpu\arm\common;..\..\libcpu\arm\cortex-m3;Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x;Libraries\STM32F10x_StdPeriph_Driver\inc;applications;drivers @@ -354,11 +361,12 @@ 0 0 0 + 0 - - - - + + + + @@ -370,12 +378,12 @@ 0 0x08000000 0x20000000 - - - + + + --keep __fsym_* --keep __vsym_* - - + + @@ -388,8 +396,6 @@ 1 applications\application.c - - startup.c 1 @@ -405,43 +411,36 @@ 1 drivers\board.c - - msd.c 1 drivers\msd.c - - platform.c 1 drivers\platform.c - - + + rt_stm32f10x_spi.c + 1 + drivers\rt_stm32f10x_spi.c + serial.c 1 drivers\serial.c - - stm32_eth.c 1 drivers\stm32_eth.c - - stm32f10x_it.c 1 drivers\stm32f10x_it.c - - usart.c 1 @@ -457,169 +456,121 @@ 1 Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c - - stm32f10x_crc.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_crc.c - - stm32f10x_rcc.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rcc.c - - stm32f10x_wwdg.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c - - stm32f10x_pwr.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_pwr.c - - stm32f10x_exti.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_exti.c - - stm32f10x_bkp.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_bkp.c - - stm32f10x_i2c.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c - - stm32f10x_adc.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_adc.c - - stm32f10x_dac.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dac.c - - stm32f10x_rtc.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rtc.c - - stm32f10x_fsmc.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_fsmc.c - - stm32f10x_tim.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c - - stm32f10x_iwdg.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_iwdg.c - - stm32f10x_spi.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_spi.c - - stm32f10x_flash.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_flash.c - - stm32f10x_sdio.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_sdio.c - - stm32f10x_gpio.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c - - stm32f10x_usart.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c - - stm32f10x_dbgmcu.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dbgmcu.c - - stm32f10x_dma.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dma.c - - stm32f10x_can.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_can.c - - stm32f10x_cec.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_cec.c - - misc.c 1 Libraries\STM32F10x_StdPeriph_Driver\src\misc.c - - startup_stm32f10x_cl.s 2 @@ -635,78 +586,56 @@ 1 ..\..\src\clock.c - - device.c 1 ..\..\src\device.c - - idle.c 1 ..\..\src\idle.c - - ipc.c 1 ..\..\src\ipc.c - - irq.c 1 ..\..\src\irq.c - - kservice.c 1 ..\..\src\kservice.c - - mem.c 1 ..\..\src\mem.c - - mempool.c 1 ..\..\src\mempool.c - - object.c 1 ..\..\src\object.c - - scheduler.c 1 ..\..\src\scheduler.c - - thread.c 1 ..\..\src\thread.c - - timer.c 1 @@ -722,29 +651,21 @@ 1 ..\..\libcpu\arm\cortex-m3\cpuport.c - - context_rvds.S 2 ..\..\libcpu\arm\cortex-m3\context_rvds.S - - backtrace.c 1 ..\..\libcpu\arm\common\backtrace.c - - div0.c 1 ..\..\libcpu\arm\common\div0.c - - showmem.c 1 @@ -760,36 +681,26 @@ 1 ..\..\components\dfs\src\dfs.c - - dfs_fs.c 1 ..\..\components\dfs\src\dfs_fs.c - - dfs_file.c 1 ..\..\components\dfs\src\dfs_file.c - - dfs_posix.c 1 ..\..\components\dfs\src\dfs_posix.c - - dfs_elm.c 1 ..\..\components\dfs\filesystems\elmfat\dfs_elm.c - - ff.c 1 @@ -797,6 +708,21 @@ + + DeviceDrivers + + + spi_core.c + 1 + ..\..\components\drivers\spi\spi_core.c + + + spi_dev.c + 1 + ..\..\components\drivers\spi\spi_dev.c + + + finsh @@ -805,85 +731,61 @@ 1 ..\..\components\finsh\cmd.c - - finsh_compiler.c 1 ..\..\components\finsh\finsh_compiler.c - - finsh_error.c 1 ..\..\components\finsh\finsh_error.c - - finsh_heap.c 1 ..\..\components\finsh\finsh_heap.c - - finsh_init.c 1 ..\..\components\finsh\finsh_init.c - - finsh_node.c 1 ..\..\components\finsh\finsh_node.c - - finsh_ops.c 1 ..\..\components\finsh\finsh_ops.c - - finsh_parser.c 1 ..\..\components\finsh\finsh_parser.c - - finsh_token.c 1 ..\..\components\finsh\finsh_token.c - - finsh_var.c 1 ..\..\components\finsh\finsh_var.c - - finsh_vm.c 1 ..\..\components\finsh\finsh_vm.c - - shell.c 1 ..\..\components\finsh\shell.c - - symbol.c 1 @@ -909,239 +811,171 @@ 1 ..\..\components\net\lwip\src\api\api_lib.c - - api_msg.c 1 ..\..\components\net\lwip\src\api\api_msg.c - - err.c 1 ..\..\components\net\lwip\src\api\err.c - - netbuf.c 1 ..\..\components\net\lwip\src\api\netbuf.c - - netdb.c 1 ..\..\components\net\lwip\src\api\netdb.c - - netifapi.c 1 ..\..\components\net\lwip\src\api\netifapi.c - - sockets.c 1 ..\..\components\net\lwip\src\api\sockets.c - - tcpip.c 1 ..\..\components\net\lwip\src\api\tcpip.c - - sys_arch.c 1 ..\..\components\net\lwip\src\arch\sys_arch.c - - def.c 1 ..\..\components\net\lwip\src\core\def.c - - dhcp.c 1 ..\..\components\net\lwip\src\core\dhcp.c - - dns.c 1 ..\..\components\net\lwip\src\core\dns.c - - init.c 1 ..\..\components\net\lwip\src\core\init.c - - memp.c 1 ..\..\components\net\lwip\src\core\memp.c - - netif.c 1 ..\..\components\net\lwip\src\core\netif.c - - pbuf.c 1 ..\..\components\net\lwip\src\core\pbuf.c - - raw.c 1 ..\..\components\net\lwip\src\core\raw.c - - stats.c 1 ..\..\components\net\lwip\src\core\stats.c - - sys.c 1 ..\..\components\net\lwip\src\core\sys.c - - tcp.c 1 ..\..\components\net\lwip\src\core\tcp.c - - tcp_in.c 1 ..\..\components\net\lwip\src\core\tcp_in.c - - tcp_out.c 1 ..\..\components\net\lwip\src\core\tcp_out.c - - timers.c 1 ..\..\components\net\lwip\src\core\timers.c - - udp.c 1 ..\..\components\net\lwip\src\core\udp.c - - autoip.c 1 ..\..\components\net\lwip\src\core\ipv4\autoip.c - - icmp.c 1 ..\..\components\net\lwip\src\core\ipv4\icmp.c - - igmp.c 1 ..\..\components\net\lwip\src\core\ipv4\igmp.c - - inet.c 1 ..\..\components\net\lwip\src\core\ipv4\inet.c - - inet_chksum.c 1 ..\..\components\net\lwip\src\core\ipv4\inet_chksum.c - - ip.c 1 ..\..\components\net\lwip\src\core\ipv4\ip.c - - ip_addr.c 1 ..\..\components\net\lwip\src\core\ipv4\ip_addr.c - - ip_frag.c 1 ..\..\components\net\lwip\src\core\ipv4\ip_frag.c - - etharp.c 1 ..\..\components\net\lwip\src\netif\etharp.c - - ethernetif.c 1 ..\..\components\net\lwip\src\netif\ethernetif.c - - slipif.c 1 @@ -1152,4 +986,5 @@ +
diff --git a/bsp/stm32f107/readme.txt b/bsp/stm32f107/readme.txt index 6cd589b89..8d438f6d1 100644 --- a/bsp/stm32f107/readme.txt +++ b/bsp/stm32f107/readme.txt @@ -2,4 +2,4 @@ # GoldBull debug board - 10M/100M ethernet - SPI SD Card - - LCD + SPI: SPI1 (PA5,PA6,PA7). CS:PA4 diff --git a/bsp/stm32f107/rtconfig.h b/bsp/stm32f107/rtconfig.h index 54999d5f4..7450367db 100644 --- a/bsp/stm32f107/rtconfig.h +++ b/bsp/stm32f107/rtconfig.h @@ -58,7 +58,7 @@ /* SECTION: Device System */ /* Using Device System */ #define RT_USING_DEVICE -#define RT_USING_UART1 +#define RT_USING_SPI /* SECTION: Console options */ #define RT_USING_CONSOLE