SDIO wifi Marvell8801/Marvell88w8801 介绍(二) ---- SDIO协议介绍

原创 专注于无线通信的蓬勃 2020-01-11 16:02

代码工程的GITHUB连接:
https://github.com/sj15712795029/stm32f1_marvell88w8801_marvell8801_wifi





Marvell自己实现驱动系列文章分为几篇介绍:



















每篇更新打开专栏可以看到

在介绍SDIO协议之前,我们来看下Wi-Fi市面上的种类

1. WI-FI接口介绍

市面上大致有这几种Wi-FI,其中优缺点也是我个人简介,大家一看就好,至于有不同意见,可以交流
1)UART WIFI,以ESP8266为代表,主要实现方式是芯片内集成了wifi driver tcp/ip protocol rtos memory IC等等,让你可以直接AT命令控制芯片
优点:使用便利,开发者不需要懂WIFI driver,TCP/IP protocol,RTOS的概念
缺点:功能受限,可定制化比较低,需要外挂一个MCU
另外,ESP8266也分为AT板和SDK板,SDK也可以克服以上缺点,但是我没有使用过SDK,所以不能胡说错误的引导你们
2)SDIO WIFI
3)USB WIFI
其中SDIO和USB市面上就比较多了,大部分的Wifi芯片都是以上两种接口,Marvell88w8801支持USB2.0和SDIO2.0 ,USB wifi大家看名字应该就能想象到时什么东西,就是类似于一个USB dongle,下图模样
在这里插入图片描述
SDIO WIFI我们后续会介绍,所以大家不要急
4)PCIE WIFI如图
在这里插入图片描述
5)OPENWRT WIFI
由于我没有做过这个,所以不做评论

2. SDIO协议介绍

做一个简短性的话语总结,SDIO有分为FUNC的概念,你可以把FUNC比作功能区,FUNC0是每个SDIO card必须实现的,FUNC1~7是可选存在的,一般的WIFI card会实现FUNC1,在每个FUNC中又会有寄存器的概念,FUNC0中的寄存器地址是SDIO协议规定,FUNC1~FUNC7中的寄存器地址是vendor(芯片厂商)去实现的,所以要访问一个地址的数据,首先要告知FUNC,然后再告知register address,整个大背景在这,好啦,SDIO讲解到此为止~哈哈,玩笑啦,带着这些去读下面的内容吧,会让你更容易理解

2.1 SDIO硬件接口介绍

SDIO设备的硬件操作接口有3种方式:
A、 SPI mode;
B、 SD 1-bit mode;
C、 SD 4-bit mode;
这3种方式的硬件接口及管脚定义如下面图、表:
在这里插入图片描述
图1 SDIO硬件接口(连接了2组sdio设备)
在这里插入图片描述
表1 SDIO各种模式管脚对应关系
本文不对SPI mode的相关内容介绍,有关SPI mode的内容不做过多说明。

2.2 SDIO 概念介绍

2.2.1 Common I/O Area (CIA)
The Common I/O Area (CIA) shall be implemented on all SDIO cards. The CIA is accessed by the host via I/O reads and writes to function 0. The registers within the CIA are provided to enable/disable the operation of the I/O function(s), control the generation of interrupts and optionally load software to support the I/O
functions. The registers in the CIA also provide information about the function(s) abilities and requirements. There are three distinct register structures supported within the CIA. They are:
1) Card Common Control Registers (CCCR)
2)Function Basic Registers (FBR)
3)Card Information Structure (CIS)
如图所示,就是FUNC0的CIA
在这里插入图片描述
下面我们来一一介绍CCCR,FBR,CIS
Card Common Control Registers (CCCR):CCCR说白了就是FUNC0的一些寄存器,地址和功能如下,另外,如果把所有的都列出内容实在太多,在这里只是列举一些重要的,如果想获取所有的功能,请自行参考SDIO协议:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.2.2 Function Basic Registers (FBR)
In addition to the CCCR, each supported I/O function has a 256-byte area used to allow the host to quickly determine the abilities and requirements of each function, enable power selection for each function and to enable software loading. The address of this area is from 00n00h to 00nFFh where n is the function number (1 to 7). This per-function area is structured as follows:
在这里插入图片描述
2.2.3 Card Information Structure (CIS)
The Card Information Structure provides more complete information about the card and the individual functions. The CIS is the common area to read information about all I/O functions that exist in a card. The design is based on the PC Card16 design standardized by PCMCIA. All cards that support I/O shall have a common CIS and a CIS for each function. The CIS is accessed by reads to a fixed area as shown in Table 6-5 This one area serves the card as a Common CIS and also as the storage area for each function. The common area and each function have a pointer to the start of its CIS within this memory space.
在这里插入图片描述
另外,CIS是tuple实行存在的,所以如果读出来需要自己解析,在后面小节会抽出一章节讲解tuple.
2.2.4 SDIO 命令/相应介绍
SDIO spec中有提到几点SDIO card必须要实现的以及可选要实现的命令,如下
在这里插入图片描述
必须要实现的有:CMD0,CMD3,CMD5,CMD7,CMD15,CMD52,CMD53
可选实现的有:CMD8,CMD11,CMD15
Marvell88w8801的datasheet上也有说这颗芯片支持的CMD,算是把强制需要support的都做了,选择支持的一个没做,哈哈
在这里插入图片描述
但是我们一般用到的有CMD0,CMD3,CMD5,CMD7,CMD52,CMD53,所以以这几个命令来做简短说明
1)CMD0:用于从SDIO mode切换到SPI mode
2)CMD3:询问相对可用地址,response是R6
在这里插入图片描述
代码如下:


/******************************************************************************
 *	函数名:	hw_sdio_cmd3
 * 参数:  	para(IN)		-->发送cmd3的参数
 			resp			-->cmd3的返回值
 * 返回值: 	返回执行结果
 * 描述:	发送cmd3
******************************************************************************/
static uint8_t hw_sdio_cmd3(uint32_t para,uint32_t *resp)
{
    uint8_t error_status;
    uint32_t response;
    SDIO_CmdInitTypeDef SDIO_CmdInitStructure;

    SDIO_CmdInitStructure.SDIO_Argument = para;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_CMD3;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);

    /* 等待发送完成 */
    while (SDIO_GetFlagStatus(SDIO_FLAG_CMDACT) == SET);
    error_status = hw_sdio_check_err();

    if (HW_ERR_OK != error_status)
    {
        return error_status;
    }

    /* 获取到response的结果 */
    response = SDIO_GetResponse(SDIO_RESP1);
    if (resp)
    {
        *resp = response;
    }

    return (error_status);
}

R6的格式格式为,只有红框内的数据才是软件可以获取的,其他的都是交于硬件去搞定
在这里插入图片描述
Bit 0~15是card status,如下图
在这里插入图片描述
Bit 16~31就是我们获取的相对地址,需要软件解析出来,搭配CMD7来使用
解析代码如下:


/******************************************************************************
 *	函数名:	hw_sdio_parse_r6
 * 参数:  	r6(IN)			-->R6的入参
 			rca(OUT)		-->rca的返回值
 * 返回值: 	返回执行结果
 * 描述:	解析R6的response
******************************************************************************/
static uint8_t hw_sdio_parse_r6(uint32_t r6,uint32_t *rca)
{
    HW_ENTER();
    if(rca)
    {
        *rca = RCA_IN_R6(r6);
        HW_LEAVE();
        return HW_ERR_OK;
    }
    HW_LEAVE();
    return HW_ERR_SDIO_INVALID_PARA;
}

3)CMD5, It is used to inquire about the voltage range needed by the I/O card.命令格式如下
在这里插入图片描述
Stuff Bits: Not used, shall be set to 0.
S18R: Switching to 1.8V Request
I/O OCR: Operation Conditions Register. The supported minimum and maximum values for VDD. The layout of the OCR is shown in Table 3-1. Refer to Section 4.10.1 for additional information
OCR如下图
在这里插入图片描述
CMD5的response如下图:
在这里插入图片描述
C: Set to 1 if Card is ready to operate after initialization
Number of I/O Functions: Indicates the total number ofI/O functions supported by this card. The range is 0-7. Note that the common area present on all I/O cards at Function 0 is not included in this count. The I/O functions shall be implemented sequentially beginning at function 1.
Memory Present: Set to 1 if the card also containsSD memory. Set to 0 if the card is I/O only.
S18A: Switching to 1.8V Accepted (Supported in SD mode only)
I/O OCR: Operation Conditions Register.
代码如下:


/******************************************************************************
 *	函数名:	hw_sdio_cmd5
 * 参数:  	para(IN)			-->入参
 			resp(OUT)			-->返回值
 			retry_max(IN)		-->最大尝试次数
 * 返回值: 	返回执行结果
 * 描述:	发送cmd5
******************************************************************************/
static uint8_t hw_sdio_cmd5(uint32_t para,uint32_t *resp,uint32_t retry_max)
{
    uint32_t index;
    uint32_t response;
    uint8_t error_status;
    SDIO_CmdInitTypeDef SDIO_CmdInitStructure;

    HW_ENTER();
    SDIO_CmdInitStructure.SDIO_Argument = para;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_CMD5 ;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    for (index = 0; index < retry_max; index  )
    {
        SDIO_SendCommand(&SDIO_CmdInitStructure);
        /* 等待发送完成 */
        while (SDIO_GetFlagStatus(SDIO_FLAG_CMDACT) == SET);
        error_status = hw_sdio_check_err();

        if (HW_ERR_OK != error_status)
        {
            continue;
        }
        response = SDIO_GetResponse(SDIO_RESP1);

        /* 判断是否OK */
        if(C_IN_R4(response))
        {
            if (resp)
            {
                *resp = response;
            }
            break;
        }
    }

    HW_LEAVE();
    return error_status;
}

4)CMD7
在这里插入图片描述
代码如下:



/******************************************************************************
 *	函数名:	hw_sdio_cmd7
 * 参数:  	para(IN)			-->入参
 			resp(OUT)			-->返回值
 * 返回值: 	返回执行结果
 * 描述:	发送cmd7
******************************************************************************/
static uint8_t hw_sdio_cmd7(uint32_t para,uint32_t *resp)
{
    uint8_t error_status;
    uint32_t response;
    SDIO_CmdInitTypeDef SDIO_CmdInitStructure;

    HW_ENTER();
    /* Send CMD7 SDIO_SEL_DESEL_CARD */
    SDIO_CmdInitStructure.SDIO_Argument = para;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_CMD7;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);

    /* 等待发送完成 */
    while (SDIO_GetFlagStatus(SDIO_FLAG_CMDACT) == SET);
    error_status = hw_sdio_check_err();

    if (HW_ERR_OK != error_status)
    {
        return error_status;
    }
    /* 获取返回结果 */
    response = SDIO_GetResponse(SDIO_RESP1);
    if (resp)
    {
        *resp = response;
    }

    HW_ENTER();
    return (error_status);
}

5)CMD52:CMD52是一个使用频率很高的CMD,主要是用于读写SDIO的寄存器的命令
The IO_RW_DIRECT is the simplest means to access a single register within the total 128K of register space in any I/O function, including the common I/O area (CIA). This command reads or writes 1 byte using only 1 command/response pair. A common use is to initialize registers or monitor status values for I/O functions. This command isthe fastest means to read or write single I/O registers, as it requires only a single command/response pair.
命令格式如下,红框内饰软件需要实现的东西,其他的交给硬件:
在这里插入图片描述
R/W Flag: This bit determines the direction of the I/O operation. If this bit is 0, this command
shall read data from the SDIO card at the address specified by the Function Number and the Register Address to the host. The data byte is returned in the response, R5. If this bit is set to 1, the command shall write the bytes in the Write Data field to the I/O location addressed by the Function Number and the Register Address. If the RAW flag is 0, then the data inthe register that was written shall be read and that value returned in the response.
RAW Flag: The Read after Write flag. If this bit isset to 1 and the R/W flag is set to 1, then the
command shall read the value of the register after the write. This is useful to allow writing to a control register and reading the status at the same address. If this bit is cleared, the value returned in the R5 response shall be the same as the write data in the command. If this bit is set, the data field of the R5 response shall contain the value read from the addressed register after the write operation.
Function Number: The number of the function within the I/O card you wish to read or write. Note that function 0 selects the common I/O area (CIA).
Register Address: This is the address of the byte ofdata inside of the selected function to read or write. There are 17 bits of address available so the register is located within the first 128K
(131,072) addresses of that function.
Write Data/Stuff Bits: For a direct write command (R/W=1),this is the byte that iswritten to the selected address. For a direct read (R/W=0), this field is not used and shall be set to 0
响应类型:
在这里插入图片描述
Stuff Bits Not used, shall be set to 0
Response Flags 8 Bits of flag data indicating the status of the SDIO card. Table 5-1 shows the format of these flag bits.
Read or Write Data: For an I/O write (R/W=1) with the RAW Flag set (RAW=1) this field shall contain the value read from the addressed register afterthe write of the data contained in the
command. Note that in this case, the read-back data may not be the same as the data written to the register, depending on the design of the hardware. For an I/O write with the RAW bit=0, the SDIO function shall notdo a read after write operation, and the data in this field shall be identical to the data byte in the write command. For an I/O read (R/W=0), the actual value read from that I/O location is returned in this field.
代码如下:

/******************************************************************************
 *	函数名:	hw_sdio_cmd52
 * 参数:  	write(IN)			-->执行操作,read or write
 			func_num(IN)		-->func的编号
 			address(IN)		-->address地址
 			para(IN)			-->要写的参数
 			resp(OUT)			-->读要返回的数据
 * 返回值: 	返回执行结果
 * 描述:	执行CMD52的动作
******************************************************************************/
uint8_t hw_sdio_cmd52(uint8_t write,uint8_t func_num,uint32_t address,uint8_t para,uint8_t *resp)
{
    uint8_t error_status;
    uint8_t response;
    SDIO_CmdInitTypeDef SDIO_CmdInitStructure;

    SDIO_CmdInitStructure.SDIO_Argument = write ? 0x80000000 : 0x00000000;
    SDIO_CmdInitStructure.SDIO_Argument |= func_num << 28;
    SDIO_CmdInitStructure.SDIO_Argument |= (write && resp) ? 0x08000000 : 0x00000000;
    SDIO_CmdInitStructure.SDIO_Argument |= address << 9;
    SDIO_CmdInitStructure.SDIO_Argument |= para;

    SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_CMD52;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;

    SDIO_SendCommand(&SDIO_CmdInitStructure);
    /* 等待发送完成 */
    while (SDIO_GetFlagStatus(SDIO_FLAG_CMDACT) == SET);
    error_status = hw_sdio_check_err();

    if (HW_ERR_OK != error_status)
    {
        return  HW_ERR_SDIO_CMD52_FAIL;
    }

    response = SDIO_GetResponse(SDIO_RESP1) & 0xff;
    if((!write) && resp)
    {
        *resp = response;
    }
    return  HW_ERR_OK;
}

6)CMD53:同样是一个高频使用的CMD,主要用于对某一个地址进行多数据写入或者多数据读出的CMD,此命令分为两种模式:block mode和byte mode,block mode必须是写入或者读出block size整数倍的数据,byte mode是可以写入或者读出任意大小的数据
命令格式:
在这里插入图片描述
R/W Flag: This bit determines the direction of the I/O operation. If this bit is 0, this command
reads data from the SDIO card at the address specified by the Function Number and the Register Address to the host. The read data shall be returned on the DAT[x] lines. If this bit is set to 1, the command shall write the bytes from the DAT[x] lines to the I/O location addressed by the Function Number and the Register Address.
Function Number: The number of the function within the I/O card you wish to read or write. Note that function 00h selects the common I/O area (CIA).
Block Mode (Optional) this bit, if set to 1, indicates that the read or write operation shall be performed on a block basis, rather than the normal byte basis. If this bit is set, the Byte/Block count value shall contain the number of blocks to be read/written. The block size for functions 1-7 is set by writing the block size to the I/Oblock size register in the FBR (Refer to Table 6-3 and Table 6-4). The block size for function 0 is set by writing to the FN0 Block Size register in the CCCR. Card and hostsupport of the block I/O mode is optional. The host can determine if a card supports block I/O by reading the Card supports MBIO bit (SMB) in the CCCR (Refer to Table 6-2). The block size used when Block Mode = 1 and the maximum byte count per command used when
Block Mode = 0 can be read from the CIS inthe tuple TPLFE_MAX_BLK_SIZE (Refer to Section 16.7.4) on a per-function basis.
OP code Defines the read/write operation as described in Table 5-2
在这里插入图片描述
• OP Code 0 is used to read or write multiplebytes of data to/from a single I/O register address. This command is useful when I/O data is transferred using a FIFO inside of the I/O card. In this case, multiple bytes of data are transferred to/from a single register address. For this operation, the address of the register is set into the Register Address field. Data is transferred on the DAT[0] orDAT[3:0] lines as defined for SD memory cards.
•OP Code 1 is used to read or write multiple bytes of data to/from an I/O register address that increment by 1 after each operation. This command is used when large amounts of I/O data exist within the I/O card ina RAM like data buffer. In this operation,the start address is loaded into the Register Address field. The first operation occurs at that address within the I/O card. The next operation shall occur at address 1 with the address incrementing by 1 until the operation has completed. As with OP Code 0, the number of bytes is set in the Byte Count field of the command.
Register Address: Start Address of I/O register to read or write. Range is [1FFFFh:0]
Byte/Block Count :If the command is operating on bytes (Block Mode = 0), this field contains the number of bytes to read or write. A value of 000h shall cause 512 bytes to be read or written.
在这里插入图片描述
If the command is in block mode (Block Mode=1), the Block Count field specifies the number of Data Blocks to be transferred following this command. A value of 000h indicates that the count set to infinite. In this case, the I/O blocks shall be transferred until the operation is aborted by writing to the I/O abort function select bits (ASx) in the CCCR (Refer to Table 6-1 and Table 6-2). Table 5-3 shows the relationship between the value in the command and the actual number of bytes transferred.
代码如下:

/******************************************************************************
 *	函数名:	hw_sdio_cmd52
 * 参数:  	write(IN)			-->执行操作,read or write
 			func_num(IN)		-->func的编号
 			address(IN)			-->address地址
 			incr_addr(IN)		-->地址是否累加
 			buf(IN/OUT)			-->如果操作是写,那么此参数就是要write的buffer
 									如果操作是读,那么此参数就是read返回的buffer
 			size(IN)			-->读或者写的size
 * 返回值: 	返回执行结果
 * 描述:	执行CMD53的动作
******************************************************************************/
uint8_t hw_sdio_cmd53(uint8_t write, uint8_t func_num,uint32_t address, uint8_t incr_addr, uint8_t *buf,uint32_t size)
{
    uint16_t func_cur_blk_size;

    if((phw_sdio_core->func)[func_num])
    {
        func_cur_blk_size = (phw_sdio_core->func)[func_num]->cur_blk_size;
        if(func_cur_blk_size == 0)
        {
            return HW_ERR_SDIO_BLK_SIZE_ZERO;
        }
    }
    else
    {
        return HW_ERR_SDIO_INVALID_FUNC_NUM;
    }

    if(write)
    {
        /* CMD53 write */
        hw_sdio_cmd53_write(func_num,address,incr_addr,buf,size,func_cur_blk_size);
    }
    else
    {
        /* CMD53 read */
        hw_sdio_cmd53_read(func_num,address,incr_addr,buf,size,func_cur_blk_size);
    }

    return  HW_ERR_OK;
}

2.2.5 SDIO init介绍
关于SDIO init流程,我们先以一个图示介绍,由于此图示是结合SD memroy card一起的,所以我们在图中以箭头表示流程,如图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中有一些术语如图所示:
在这里插入图片描述
大概过程如下:
1)发送CMD5没有参数,主要用于获取OCR的范围
2)FUNC的数目和OCR如果合法那么就重新发送CMD5,带着OCR的参数
3)得到RESPONSE后,查看MP的filed,正常来说SDIO MP应该为0,所以走B case
4)B case下IO为1,并且S18为0,所以直接走CMD3,然后是IO=1,MEM=0,也就是SDIO整个初始化完毕,但是SDIO还有一些其他选项需要做,比如选择SDIO设备,读取一些CCCR的信息,切换SDIO bus width,提高SDIO CLK,解析CIS,设置BLOCK size之类的,下面我贴出我在STM32写的代码,仅供参考流程,这部分也在我的GITHUB能找到


/******************************************************************************
 *	函数名:	hw_sdio_init
 * 参数:  		NULL
 * 返回值: 	返回执行结果
 * 描述:		SDIO init
 				pin脚分配
 				PC8->SDIO D0 PC9->SDIO D1 PC10->SDIO D2 PC11->SDIO D3
 				PC12->SDIO CLK
 				PD2->SDIO CMD
******************************************************************************/
uint8_t hw_sdio_init()
{
    uint32_t rca;
    uint8_t func_index;
    uint32_t cmd3_para;
    uint32_t cmd3_resp;
    uint32_t cmd5_para;
    uint32_t cmd5_resp;
    uint32_t cmd7_para;
    uint32_t cmd7_resp;

    GPIO_InitTypeDef GPIO_InitStructure;
    SDIO_InitTypeDef SDIO_InitStructure;
    //NVIC_InitTypeDef NVIC_InitStructure;

    HW_ENTER();
    hw_chip_reset();
    hw_sdio_core_init();
    /* 使能GPIO C/D的RCC时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
    /* 使能SDIO RCC时钟*/
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);
    /* 使能DMA2时钟,SDIO的DMA在DMA2 CHANNEL 4 */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

    /* 设置推挽复用 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* SDIO初始化,CLK:400KHZ,数据宽度:1 bus */
    SDIO_DeInit();
    /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178   2) = 400 KHz */
    SDIO_InitStructure.SDIO_ClockDiv = SDIO_CLK_400KHZ;
    SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising ;
    SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
    SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
    SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
    SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
    //SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Enable;
    SDIO_Init(&SDIO_InitStructure);

    /* 设置为SDIO I/O模式 */
    SDIO_SetSDIOOperation(ENABLE);
    /* Set Power State to ON */
    SDIO_SetPowerState(SDIO_PowerState_ON);
    /* Enable SDIO Clock */
    SDIO_ClockCmd(ENABLE);

    /* 设置SDIO中断,抢占优先级为3,相应优先级为4 */
#if 0
    NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = WIFI_PREE_PRIO;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = WIFI_SUB_PRIO;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    SDIO_ITConfig(SDIO_IT_CCRCFAIL |SDIO_IT_DCRCFAIL | SDIO_IT_CTIMEOUT |\
                  SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR |SDIO_IT_RXOVERR | \
                  SDIO_IT_STBITERR|SDIO_IT_SDIOIT, ENABLE);
#endif
    /* 开启SDIO的DMA,此位置尤其重要,如果在CMD53中每次开启,那么会DMA lock住 */
    SDIO_DMACmd(ENABLE);

    /* 发送cmd5 */
    cmd5_para = 0;
    if(hw_sdio_cmd5(cmd5_para,&cmd5_resp,SDIO_RETRY_MAX))
    {
        HW_LEAVE();
        return HW_ERR_SDIO_CMD5_FAIL;
    }

    /* ocr 3.2V~3.4V*/
    cmd5_para = 0x300000;
    if(hw_sdio_cmd5(cmd5_para,&cmd5_resp,SDIO_RETRY_MAX))
    {
        HW_LEAVE();
        return HW_ERR_SDIO_CMD5_FAIL;
    }

    /* 解析R4 */
    hw_sdio_parse_r4(cmd5_resp);

    /* 发送cmd3获取地址 */
    cmd3_para = 0;
    if(hw_sdio_cmd3(cmd3_para,&cmd3_resp))
    {
        HW_LEAVE();
        return HW_ERR_SDIO_CMD3_FAIL;
    }

    hw_sdio_parse_r6(cmd3_resp,&rca);

    /* 发送cmd7选地址 */
    cmd7_para = rca << 16;
    if(hw_sdio_cmd7(cmd7_para,&cmd7_resp))
    {
        HW_LEAVE();
        return HW_ERR_SDIO_CMD7_FAIL;
    }

    /* 获取CCCR版本和SDIO版本 */
    hw_sdio_get_cccr_version(&phw_sdio_core->cccr_version);
    hw_sdio_get_sdio_version(&phw_sdio_core->sdio_version);

    /* 切换到4 bus width,切换24M clk */
    hw_sdio_set_bus_width(SDIO_BUS_WIDTH_4);
    SDIO_InitStructure.SDIO_ClockDiv = SDIO_CLK_24MHZ;
    SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_4b;
    SDIO_Init(&SDIO_InitStructure);


    /* 读取每个func的CIS指针并且解析 */
    for(func_index = 0; func_index < phw_sdio_core-> func_total_num; func_index  )
    {
        uint32_t cis_ptr;
        hw_sdio_get_cis_ptr(func_index,&cis_ptr);
        hw_sdio_cis_read_parse(func_index,cis_ptr);
    }

    /* enable Func */
    for(func_index = SDIO_FUNC_1; func_index < phw_sdio_core-> func_total_num; func_index  )
    {
        hw_sdio_enable_func(func_index);
    }

    /* 使能中断 */
    hw_sdio_enable_mgr_int();
    for(func_index = SDIO_FUNC_1; func_index < phw_sdio_core-> func_total_num; func_index  )
    {
        hw_sdio_enable_func_int(func_index);
    }

    /* 设置block size */
    for(func_index = SDIO_FUNC_1; func_index < phw_sdio_core-> func_total_num; func_index  )
    {
        hw_sdio_set_blk_size(func_index,SDIO_DEFAULT_BLK_SIZE);
    }
    HW_LEAVE();

    return HW_ERR_OK;
}

2.2.6 SDIO tuple介绍

在上面小节中有说到读取的CIS是tuple chain,我们先来看下tuple的格式
在这里插入图片描述
1个byte的TPL_CODE,类似于ID
1个byte的LEN
不定长的tuple body,但是不超过255

Tuple code list如下图
在这里插入图片描述
我们还是只拿一个制造商tuple code来说明下,让你们大概知道tuple code是什么就足够了吧
在这里插入图片描述

专注于无线通信的蓬勃 朝气蓬勃——不积跬步 无以至千里, 不积小流 无以成江海
评论
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 156浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 76浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 164浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 123浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 60浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 118浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 492浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 58浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 105浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 188浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦