OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3753|回复: 7

使用SDIO作为普通的通信接口,在发送数据时出现SDIO_FLAG_DCRCFAIL

[复制链接]

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
发表于 2016-12-24 18:12:46 | 显示全部楼层 |阅读模式
2金钱
我想使用SDIO接口作为普通的通信接口与FPGA进行通信,只使用SDIO数据接口,不使用SDIO通信协议,但是在进行测试时发现使用SDIO + DMA下发数据时会发生SDIO_FLAG_DCRCFAIL,SDIO和DMA都不会产生结束传输中断,想请教一下问题出在哪里,应该如何解决?
[mw_shl_code=applescript,true]void do_SDIO_init(void)
{
        GPIO_InitTypeDef stGPIOInit;
        NVIC_InitTypeDef NVIC_InitStructure;
        SDIO_InitTypeDef SDIO_InitStruct;

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        //设置中断分组2    2bit抢占优先级  2bit从优先级
        NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

       
        NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel4_5_IRQn;        //选择中断线0  
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;          //抢占优先级为 1  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                           //响应优先级为 0  
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                          //中断使能  
        NVIC_Init(&NVIC_InitStructure);

       
       
        /*        SDIO  引脚分配
                SDIO_CK         PC12
                SDIO_CMD        PD2
                SDIO_D0         PC8
                SDIO_D1         PC9
                SDIO_D2         PC10
                SDIO_D3         PC11
                SDIO_D4                         PB8
                SDIO_D5                         PB9
                SDIO_D6         PC6
                SDIO_D7         PC7
        */
        stGPIOInit.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
        stGPIOInit.GPIO_Mode = GPIO_Mode_AF_PP;
        stGPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIO_BANK_C,&stGPIOInit);

        stGPIOInit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
        stGPIOInit.GPIO_Mode = GPIO_Mode_AF_PP;
        stGPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIO_BANK_B,&stGPIOInit);


        stGPIOInit.GPIO_Pin = GPIO_Pin_2;
        stGPIOInit.GPIO_Mode = GPIO_Mode_AF_PP;
        stGPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIO_BANK_D,&stGPIOInit);

        /*   寄存器复位  */
        SDIO_DeInit( );

        //SDIO_CK = HCLK/(2+CLK_DIV)
        SDIO_InitStruct.SDIO_ClockDiv = SDIO_CLK_DIV_400KHz;//SDIO_CLK_DIV_1MHz;                                        //时钟分频
        SDIO_InitStruct.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
        SDIO_InitStruct.SDIO_ClockBypass = SDIO_ClockBypass_Disable;                //关闭旁路        如果开启旁路则会使用系统时钟 HCLK
        SDIO_InitStruct.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;        //开启省电模式后总线空闲时关闭sdclk时钟,逻辑不允许时钟关闭
        SDIO_InitStruct.SDIO_BusWide = SDIO_BusWide_8b;                                                //使用8位数据总线模式
        SDIO_InitStruct.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Enable;        //硬件流控,开启后,在fifo不能进行发送和接收数据时,数据传输暂停
        SDIO_Init(&SDIO_InitStruct);

        SDIO_SetPowerState(SDIO_PowerState_ON);                                //SDIO控制器供电
        SDIO_ClockCmd(ENABLE);                                                                 //SDIO时钟使能
}

[/mw_shl_code]

[mw_shl_code=c,true]void SDIO_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize )
{
        DMA_InitTypeDef DMA_InitStructure;


        DMA_StructInit(&DMA_InitStructure);//初始化 结构体
       
        DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);//清除DMA CH4标志位

        DMA_Cmd(SDIO_DMA_CH, DISABLE);//关闭DMA通道

        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SDIO->FIFO;        //DMA 的外设基址为SDIO的FIFO
        DMA_InitStructure.DMA_BufferSize = BufferSize;                                            //buffer size应该设置为多少?
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferDST;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                        //传输方向是从外设读入   外设为数据源
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;         //读过程中 外设的地址不自增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                //读过程中 内存地址自增
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Word;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                        //不循环
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                //通道优先级高
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                        //非存储器至存储器模式

        DMA_Init(SDIO_DMA_CH, &DMA_InitStructure);
        DMA_Cmd(SDIO_DMA_CH, ENABLE);
}
[/mw_shl_code]

[mw_shl_code=c,true]
void drvSDIOSendData(u16 regaddr, u8* pu8writebuff,euSDIO_BLK_SIZE euBlkSize,u32 u32BlkNum)
{
        u32 timeout = 0xFFF;
        int ii = 0;
        u32 u32BlkLen = (u32)pow(2,(euBlkSize>>4)&0x0F);
       
        SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
        SDIO_DataInitStructure.SDIO_DataLength = u32BlkLen*u32BlkNum;       //u32BlkSize * u32BlkNum;
        SDIO_DataInitStructure.SDIO_DataBlockSize = euBlkSize;                               
        SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;        //SDIO主机 --> 卡
        SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
        SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;                 //启动发送
        SDIO_DataConfig(&SDIO_DataInitStructure);

        //允许中断   发送下溢           块CRC校验错误      数据发送超时    数据发送结束   起始位错误
        SDIO_ITConfig(SDIO_IT_TXUNDERR|/*SDIO_IT_DCRCFAIL|*/SDIO_IT_DTIMEOUT|SDIO_IT_DATAEND|SDIO_IT_STBITERR, ENABLE);
        SDIO_DMACmd(ENABLE); //使能DMA
        SDIO_DMA_TxConfig((uint32_t *)pu8writebuff, u32BlkLen * u32BlkNum);


       
        while(timeout)
        {
                if((SDIO_GetITStatus(SDIO_FLAG_DATAEND) == !RESET))
                {
                        printf("data end\n");
                }
                if((SDIO_GetITStatus(SDIO_FLAG_DBCKEND) == !RESET))
                {
                        printf("block end\n");
                }
                if((SDIO_GetITStatus(SDIO_FLAG_TXACT) == !RESET))
                {
                        printf("block end\n");
                }
                timeout--;
        }
       
        printf("time out\n");


        if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
        {
                SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
                printf("001\n");
               
        }
        else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
        {
                SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
                printf("00data count is %d\n",DMA_GetCurrDataCounter(SDIO_DMA_CH));
                printf("002\n");
        }
        else if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)
        {
                SDIO_ClearFlag(SDIO_FLAG_TXUNDERR);
                printf("003\n");
        }
        else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
        {
                SDIO_ClearFlag(SDIO_FLAG_STBITERR);
                printf("004\n");
        }

}
[/mw_shl_code][mw_shl_code=applescript,true]void main()
{
        u32 mm = 1;
        SystemInit();
    RCCInit();


        do_SDIO_init();

        printf("Hello wrollld\n");
        do_ADC_Init();

        for(xx = 0;xx < sizeof(aa);xx++)
        {
                aa[xx] = xx;
        }

        while (1)
    {//TT是一个u32的数组,大小为128.
                drvSDIOSendData(0,(u8*)TT,SDIO_BLK_512_Byte,1);
               
                delay_us(1000);


               
        }

}

[/mw_shl_code]

最佳答案

查看完整内容[请看2#楼]

自问自答一下吧,我现在的运行是使用单数据线SDIO进行发送测试,使用示波器查看波形来验证数据是否正确。首先DCRCFAIL目前还是存在的,没有找到消除的办法,只能能FPGA连上之后再看看怎么处理。关于无法进入DMA中断实际是由于我给DMA buffer的赋值出现了问题,也就是代码中的这一句DMA_InitStructure.DMA_BufferSize = BufferSize; 这个BufferSize我用的是要发送的字节数,但是根据库函数对DMA_BufferSize 的解释为 /*!< Specifies ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-24 18:12:47 | 显示全部楼层
本帖最后由 不死鸟 于 2017-1-4 14:18 编辑

自问自答一下吧,我现在的运行是使用单数据线SDIO进行发送测试,使用示波器查看波形来验证数据是否正确。首先DCRCFAIL目前还是存在的,没有找到消除的办法,只能能FPGA连上之后再看看怎么处理。关于无法进入DMA中断实际是由于我给DMA buffer的赋值出现了问题,也就是代码中的这一句DMA_InitStructure.DMA_BufferSize = BufferSize; 这个BufferSize我用的是要发送的字节数,但是根据库函数对DMA_BufferSize 的解释为
/*!< Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to the configuration set in DMA_PeripheralDataSizeor DMA_MemoryDataSize members depending in the transfer direction. */
DMA_BufferSize 的数据单位应该是DMA_PeripheralDataSize或者DMA_MemoryDataSize 指定的数据单位,
如果数据单位为word,那么DMA_BufferSize 的实际值应该是要发送的字节数N/4。
个人感觉DMA_BufferSize 这个变量命名不是很恰当,它对应的寄存器是DMAy_Channelx->CNDTR,所以DMA_BufferSize 得意义是要发送的数据量。
话说回来,中/英文手册上对DMA_CNDTR寄存器的说明同样是存在问题的,
Image 1.png
Image 2.png
如划线处内容,手册中暗示其数据单位为Byte,这与事实显然是不符的。


综上,当我将DMA_BufferSize 赋予了正确的数值后,程序是可以正常进入中断的,终于可以“看上去”正常运行了。。。
多谢大家的帮助。




补充内容 (2017-1-6 14:48):
再补充一下,非常惭愧的发现DCRCFAIL错误是由于我将示波器探针挂在了数据线上,导致数据最后一位有比较严重的拖尾而产生的,将探针移开就不会再出现DCRCFAIL了。
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-24 18:14:30 | 显示全部楼层
请原子哥帮忙指点一下。@正点原子
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2016-12-25 21:15:44 | 显示全部楼层
试试查询模式
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-28 10:57:12 | 显示全部楼层

试过不使用DMA,直接进行发送,时没有问题的。
您说的查询模式是这个么??
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2017-1-2 22:26:04 | 显示全部楼层
不死鸟 发表于 2016-12-28 10:57
试过不使用DMA,直接进行发送,时没有问题的。
您说的查询模式是这个么??

就是不用DMA
你用DMA的时候,在数据收发时,屏蔽掉其他中断试试吧
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2017-1-3 19:49:34 | 显示全部楼层
正点原子 发表于 2017-1-2 22:26
就是不用DMA
你用DMA的时候,在数据收发时,屏蔽掉其他中断试试吧

在关闭硬件流控制的前提下查询模式下数据可以发送,使用单线模式用示波器查看数据也是对的。但依旧会有CRC错误。
一旦开启硬件流控发送的数据就是错误的。原子哥有什么指点么?
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2017-1-4 14:20:26 | 显示全部楼层
不死鸟 发表于 2017-1-3 19:49
在关闭硬件流控制的前提下查询模式下数据可以发送,使用单线模式用示波器查看数据也是对的。但依旧会有CR ...

有点汗颜了,今天又进行了一些测试,发现流控的开启和关闭又不会对数据发送产生影响了,鬼知道我昨天干了什么,打扰原子哥了,多谢多谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-29 04:43

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表