OpenEdv-开源电子网

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

SPI使用DMA1发送无法进入进入DMA中断

[复制链接]

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
发表于 2016-12-29 14:14:45 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 不死鸟 于 2016-12-30 10:23 编辑

使用STM32F103VET,在调试SPI,使用DMA1Channel3进行发送,启用了DMA结束中断和DMA错误中断,但是发现无法进入中断,但是数据发送正常而且正确的,哪位大侠可以帮忙看看么,多谢了![mw_shl_code=c,true]DMA中断配置        
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

DMA配置
        DMA_Cmd(SPI_DMA_TX_CH, DISABLE);//关闭DMA通道

        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;                      //DMA 的目的地址为SPI的DR
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                           //传输方向是向外设写   外设为目的地
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //外设的地址不自增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                   //内存地址自增
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                   //
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                        //不循环
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                //通道优先级高
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                        //非存储器至存储器模式

        DMA_Init(SPI_DMA_TX_CH, &DMA_InitStructure);                           //配置DMA1CH3

        DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_TE3,ENABLE);                //开启完成中断和传输错误中断呢
        
        SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);   //使能SPI的 DMA

DMA发送函数
int drv_SPI_DMA_Send_Data(u8 *BufferSRC, uint32_t BufferSize)
{

        //SPI_DMA_Send_TX_Cfg(BufferSRC, BufferSize);
        
        DMA_Cmd(SPI_DMA_TX_CH, DISABLE);        
        DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_TE3,ENABLE);                //开启完成中断和传输错误中断呢
        DMA1_Channel3->CNDTR=BufferSize; //设置要传输的数据长度
        DMA1_Channel3->CMAR=(uint32_t)BufferSRC; //设置RAM缓冲区地址
        DMA_Cmd(SPI_DMA_TX_CH, ENABLE);        
        
        //while(!DMA_GetFlagStatus(DMA1_FLAG_TC3)); //等待DMA通道5传输完成
        //DMA_ClearFlag(DMA1_FLAG_TC3); //清除通道5传输完成状态标记
        //DMA_Cmd(DMA1_Channel3,DISABLE); //

}

DMA中断处理函数
void DMA1_Channel3_IRQHandler(void)
{
        
        if(DMA_GetITStatus(DMA1_IT_TE3))
        {
                iiii++;
                DMA_ClearITPendingBit(DMA1_IT_TE3);
                DMA_ClearFlag(DMA1_FLAG_TE3); //清除通道5传输完成状态标记
            DMA_Cmd(DMA1_Channel3,DISABLE); //
        }

        if(DMA_GetITStatus(DMA1_IT_TC3))
        {
                jjjj++;
                DMA_ClearITPendingBit(DMA1_IT_TC3);
                DMA_ClearFlag(DMA1_FLAG_TC3); //清除通道5传输完成状态标记
            DMA_Cmd(DMA1_Channel3,DISABLE); //
        }
}
[/mw_shl_code]






最佳答案

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

提到的两个问题找到了原因了------- 1:我在DMA初始化后调用了DMA中断配置库函数 --- DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_TE3,ENABLE); //开启完成中断和传输错误中断 如果将这个函数放在初始化之前则DMA自增就可以按照1Byte自增,数据传输正常,即符合我设置的内存和外设的datasize,但此时依然无法进入中断处理函数。 2:同样问题原因也在DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_T ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-29 14:14:46 | 显示全部楼层
提到的两个问题找到了原因了-------
1:我在DMA初始化后调用了DMA中断配置库函数 ---
DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_TE3,ENABLE);                //开启完成中断和传输错误中断
如果将这个函数放在初始化之前则DMA自增就可以按照1Byte自增,数据传输正常,即符合我设置的内存和外设的datasize,但此时依然无法进入中断处理函数。
2:同样问题原因也在DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_TE3,ENABLE);   这个函数上,如果我不调用这个库函数而是自己使用寄存器写--DMA1_Channel3->CCR |= 0x0A;,那就可以正常进入中断处理函数了。

综上,不敢说库函数有问题,但是确实会有影响。不能太依赖库函数了。。。
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-29 19:16:48 | 显示全部楼层
自己的问题自己顶啊
回复

使用道具 举报

0

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
137
金钱
137
注册时间
2016-12-25
在线时间
28 小时
发表于 2016-12-30 04:22:01 | 显示全部楼层
我今天刚试过SPI的DMA传输,可以进入中断。你贴出的代码不完整,建议你把完整的代码贴出来才好分析!
回复

使用道具 举报

2

主题

10

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
424
金钱
424
注册时间
2016-4-17
在线时间
170 小时
发表于 2016-12-30 08:11:47 | 显示全部楼层
先确保不加DMA的SPI通信成功,在加DMA,是不是接受SPI的DMA没使能啊
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-30 09:53:30 | 显示全部楼层
TDX 发表于 2016-12-30 08:11
先确保不加DMA的SPI通信成功,在加DMA,是不是接受SPI的DMA没使能啊

不加DMA是可以正常通信的,其实加了DMA也可以正常通信,只是捕捉不到发送结束之后进入中断,我已经开启了发送结束中断和发送错误中断的。
你说接收SPI的DMA中断使能是DMA_Cmd(SPI_DMA_TX_CH, ENABLE); 这个吧?
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-30 09:57:41 | 显示全部楼层
qzl200 发表于 2016-12-30 04:22
我今天刚试过SPI的DMA传输,可以进入中断。你贴出的代码不完整,建议你把完整的代码贴出来才好分析!

[mw_shl_code=c,true]void  do_SPI_init()
{
        NVIC_InitTypeDef NVIC_InitStructure;
        GPIO_InitTypeDef stGPIOInit;
        DMA_InitTypeDef DMA_InitStructure;

        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        stGPIOInit.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_5 ;
        stGPIOInit.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        stGPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIO_BANK_A,&stGPIOInit);
SPI_I2S_DeInit(SPI1);
        SPI_StructInit(&stSPI_Init);
        stSPI_Init.SPI_Direction = SPI_Direction_1Line_Tx;//单线 双向 && 输出使能   ,使处于单线发送模式 只使用spi_clk 和 mosi两根线
        stSPI_Init.SPI_Mode = SPI_Mode_Master;            //设置为主机
        stSPI_Init.SPI_DataSize = SPI_DataSize_16b;//SPI_DataSize_8b;
        stSPI_Init.SPI_CPOL = SPI_CPOL_Low;              //空闲时 时钟的稳态
        stSPI_Init.SPI_CPHA = SPI_CPHA_1Edge;                          //数据采样从第1个时钟边沿开始
        stSPI_Init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;// 波特率 = 72MHz / SPI_BaudRatePrescaler
        stSPI_Init.SPI_FirstBit = SPI_FirstBit_LSB;                  //大端 小端模式 需要逻辑确认
        stSPI_Init.SPI_CRCPolynomial = 7;                 //CRC校验多项式
        stSPI_Init.SPI_NSS = SPI_NSS_Soft;                //如果使用硬件控制模式,当NSS引脚被拉低时会产生MODF错误,所以此处应该设置为软件控制模式并将SSI为置0

        SPI_Init(SPI1,&stSPI_Init);                                                  //配置SPI

        SPI_Cmd(SPI1,ENABLE);                            //使能SPI

        DMA_DeInit(DMA1_Channel3);
        DMA_StructInit(&DMA_InitStructure);//初始化 结构体

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

        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;                      //DMA 的目的地址为SPI的DR
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                           //传输方向是向外设写   外设为目的地
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //外设的地址不自增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                   //内存地址自增
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_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(SPI_DMA_TX_CH, &DMA_InitStructure);                           //配置DMA1CH3

        DMA_ITConfig(SPI_DMA_TX_CH,DMA1_IT_TC3 | DMA1_IT_TE3,ENABLE);                //开启完成中断和传输错误中断呢
       
        SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);   //使能SPI的 DMA[/mw_shl_code]

以上是SPI初始化代码,单线传输所以只用了CLK和MOSI两根线。
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-30 10:14:20 | 显示全部楼层
本帖最后由 不死鸟 于 2016-12-30 10:16 编辑

另外还发现一个问题,我的DMA数据位宽设置为   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;        //     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //,
但在代码执行时,发现地址自增是以4Bytes为单位自增的,而不是以1Byte自增的,请问问题在哪里,如何让地址按照1Byte自增呢?
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-30 11:02:50 | 显示全部楼层
@正点原子 原子哥,请指点一二,谢谢啦
回复

使用道具 举报

2

主题

10

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
424
金钱
424
注册时间
2016-4-17
在线时间
170 小时
发表于 2016-12-30 11:29:39 | 显示全部楼层
不死鸟 发表于 2016-12-30 09:53
不加DMA是可以正常通信的,其实加了DMA也可以正常通信,只是捕捉不到发送结束之后进入中断,我已经开启了 ...

DMA1_Channel3_IRQHandler()中断函数是这个吧
回复

使用道具 举报

11

主题

94

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-12-12
在线时间
55 小时
 楼主| 发表于 2016-12-30 11:34:05 | 显示全部楼层
TDX 发表于 2016-12-30 11:29
DMA1_Channel3_IRQHandler()中断函数是这个吧

我用的就是这个啊,函数名是从.s文件中拷贝出来的,就怕自己写手滑出错。。
回复

使用道具 举报

2

主题

10

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
424
金钱
424
注册时间
2016-4-17
在线时间
170 小时
发表于 2016-12-30 13:12:44 | 显示全部楼层
不死鸟 发表于 2016-12-30 10:14
另外还发现一个问题,我的DMA数据位宽设置为   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSiz ...

你看看DMA储存/外设地址寄存器就明白了
回复

使用道具 举报

0

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
137
金钱
137
注册时间
2016-12-25
在线时间
28 小时
发表于 2016-12-31 14:21:06 | 显示全部楼层
不死鸟 发表于 2016-12-30 09:57
[mw_shl_code=c,true]void  do_SPI_init()
{
        NVIC_InitTypeDef NVIC_InitStructure;

地址增量的问题是:
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;        //
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
改为:
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位

因为字节数配置问题,导致你的数据量没有发完,所以不进入完成中断。
回复

使用道具 举报

0

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
137
金钱
137
注册时间
2016-12-25
在线时间
28 小时
发表于 2016-12-31 14:25:05 | 显示全部楼层
不死鸟 发表于 2016-12-30 09:57
[mw_shl_code=c,true]void  do_SPI_init()
{
        NVIC_InitTypeDef NVIC_InitStructure;

我说的代码指的是看看你调用SPI发送数据部分,因为你发送的数据有可能没有达到DMB的发送完成量,所以不会产生发送完成中断请求。
回复

使用道具 举报

10

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2017-4-25
在线时间
28 小时
发表于 2017-8-29 12:02:56 | 显示全部楼层
DMA1_Channel3->CCR |= 0x0A;   这个是什么意思?DMA貌似没有CCR这个寄存器呀?
回复

使用道具 举报

10

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2017-4-25
在线时间
28 小时
发表于 2017-8-29 12:04:10 | 显示全部楼层
qzl200 发表于 2016-12-31 14:21
地址增量的问题是:
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;        //
DMA ...

数据量发送完 也不应该是进入DMA的中断吧??难道不是应该是由SPI管吗?
回复

使用道具 举报

10

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2017-4-25
在线时间
28 小时
发表于 2017-8-29 12:06:21 | 显示全部楼层
qzl200 发表于 2016-12-30 04:22
我今天刚试过SPI的DMA传输,可以进入中断。你贴出的代码不完整,建议你把完整的代码贴出来才好分析!

SPI的DMA通信   是把SPI的数据通过DMA进行搬运,还是通过SPI把DMA搬运的数据发送出去呢??   
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-15 10:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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