初级会员

- 积分
- 72
- 金钱
- 72
- 注册时间
- 2014-1-8
- 在线时间
- 2 小时
|
5金钱
早上发的帖子,我把程序又看了一遍下载进单片机里发现发送的数据内容是正确的,但是总是会多发送2个字节的数据,比如我只发送0~4这5个数据,但是SPI2却接收到7个数据分别是:0,1,2,3,4,0,1这个情况是怎么造成的呢?每次发送前都会清楚DMA_ClearFlag(DMA1_FLAG_TC3);,但是问题依旧存在.
实验目的:单片机SPI1和SPI2通过DMA发送和接收(非DMA方式的SPI1和SPI2收发已经成功)
注意:这次试验因为BOSS要求不让使用外部晶振,所以我是用内部8M晶振,主频64M
实验思路:因为是循环方式的DMA收发,所以两个SPI 的DMA接收通道在配置的时候就直接使能,但是两个SPI的发送用的DMA通道配置好的时候是失能的,仅在需要发送的时候,通过更改DMA1_Channel3->CNDTR =length;中length的值来修改需要发送的数据长度,然后再使能发送的DMA通道,while(DMA_GetFlagStatus(DMA1_FLAG_TC3)==RESET);等待发送完成后,使能发送的DMA通道并清零标志位.
SPI的DMA查询是DMACurrDataCounter_SPI2Recv=DMA_GetCurrDataCounter(DMA1_Channel4);通过查询已经接收到的数据的个数来判断是否接收完毕.详细程序如下:
#define BufferSize 200
u8 SPI1_SendBuff[BufferSize]; //SPI1发送缓存数组
u8 SPI1_RecvBuff[BufferSize]; //SPI1接收缓存数组
u8 SPI2_SendBuff[BufferSize]; //SPI2发送缓存数组
u8 SPI2_RecvBuff[BufferSize]; //SPI2接收缓存数组
u16 DMACurrDataCounter_SPI2Recv=0; //SPI2的DMA接收数目缓存
//main函数一进来就是时钟配置函数
void RCC_Configuration(void)
{
// ErrorStatus HSEStartUpStatus; //定义枚举类型变量HSEStartUpStatus
RCC_DeInit(); //复位系统时钟
RCC_HSEConfig(RCC_HSE_OFF); //关闭外部时钟
RCC_HSICmd(ENABLE); //打开内部时钟
// HSEStartUpStatus=RCC_WaitForHSEStartUp(); //等待HSE稳定起振
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET); //等待内部晶振输出稳定
RCC_HCLKConfig(RCC_SYSCLK_Div1); //选择HCLK(AHB)时钟源为SYSCLK 1分频
RCC_PCLK2Config(RCC_HCLK_Div1); //选择PCLK2时钟源为HCLK(AHB) 1分频
RCC_PCLK1Config(RCC_HCLK_Div2); //选择PLCK1时钟源为HCLK(AHB) 2分频
FLASH_SetLatency(FLASH_Latency_2); //设置FLASH延时周期数为2
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预取缓存
RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_16); //选择PLL时钟源为HSI 2分频,倍频数为16,则PLL=4MHz*16=64MHz
RCC_PLLCmd(ENABLE); //使能PLL
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET); //等待PLL输出稳定
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //以PLL作为系统时钟
while(RCC_GetSYSCLKSource()!=0x08); //等待PLL成为有效系统时钟源
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //各外设时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOD|
RCC_APB2Periph_AFIO |RCC_APB2Periph_TIM1 |RCC_APB2Periph_USART1|RCC_APB2Periph_SPI1|
RCC_APB2Periph_ADC1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 |RCC_APB1Periph_SPI2 |RCC_APB1Periph_USART2, ENABLE);
}
//始终配置完毕就是SPI配置函数,串口配置函数这里直接跳过
void SPI_Configuration(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO初始化结构体GPIO_InitStructure
DMA_InitTypeDef DMA_InitStructure; //定义DMA初始化结构体DMA_InitStructure
DMA_DeInit(DMA1_Channel4); //重置DMA 1通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SPI2->DR); //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SPI2_RecvBuff; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据目的地
DMA_InitStructure.DMA_BufferSize = BufferSize; //DMA缓存大小:BufferSize
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //内存数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //设置DMA通道优先级为高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道设置为内存至内存传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure); //初始化
DMA_Cmd(DMA1_Channel4, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,DISABLE); //配置DMA接收完成后不产生中断
DMA_DeInit(DMA1_Channel5); //重置DMA 1通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SPI2->DR); //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SPI2_SendBuff; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //外设作为数据目的地
DMA_InitStructure.DMA_BufferSize = BufferSize; //DMA缓存大小:BufferSize
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //内存数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //设置DMA通道优先级为高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道设置为内存至内存传输
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //初始化
DMA_Cmd(DMA1_Channel5, DISABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,DISABLE); //配置DMA发送完成后不产生中断
DMA_DeInit(DMA1_Channel2); //重置DMA 1通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SPI1->DR); //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SPI1_RecvBuff; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为数据目的地
DMA_InitStructure.DMA_BufferSize = BufferSize; //DMA缓存大小:BufferSize
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //内存数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //设置DMA通道优先级为高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道设置为内存至内存传输
DMA_Init(DMA1_Channel2, &DMA_InitStructure); //初始化
DMA_Cmd(DMA1_Channel2, ENABLE);
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,DISABLE); //配置DMA发送完成后产生中断
DMA_DeInit(DMA1_Channel3); //重置DMA 1通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SPI1->DR); //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SPI1_SendBuff; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //外设作为数据目的地
DMA_InitStructure.DMA_BufferSize = BufferSize; //DMA缓存大小:BufferSize
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //内存数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //设置DMA通道优先级为高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道设置为内存至内存传输
DMA_Init(DMA1_Channel3, &DMA_InitStructure); //初始化
DMA_Cmd(DMA1_Channel3, DISABLE);
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
DMA_ITConfig(DMA1_Channel3,DMA_IT_TC,DISABLE); //配置DMA发送完成后产生中断
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; //设置 SPI1 引脚: SCK, MISO 和 MOSI
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //设置 SPI2 引脚: SCK, MISO 和 MOSI
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //设置 SPI1 引脚: CS
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_12; //设置 SPI2 引脚: CS
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI 设置为双线双向全双工
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI 发送接收 8 位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟悬空低
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据捕获于第二个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //内部 NSS 信号由 SSI 位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //SPI1波特率预分频值为 4
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; //数据传输从 LSB 位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //用于 CRC 值计算的多项式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置 SPI1 为主机
SPI_Init(SPI1 , &SPI_InitStructure);
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //SPI1波特率预分频值为 2
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //设置 SPI2 为从机
SPI_Init(SPI2 , &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE); //使能 SPI1
SPI_Cmd(SPI2, ENABLE); //使能 SPI2
SPI1_CS=0;
SPI2_CS=0;
}
//配置完毕后就是各个缓存数组的赋值与清零,一遍我们看到发送和接收到的数据是否正确
for(i=0;i<200;i++)
{
SPI1_SendBuff=i;
SPI2_SendBuff=i;
SPI1_RecvBuff=0xff;
SPI2_RecvBuff=0xff;
}
//然后SPI1通过DMA发送5个字节的数据,数据内容上边已经配置过为0~4;
SPI_DMA_Send(1,5);
while(1)
{
DMACurrDataCounter_SPI2Recv=0;
DMACurrDataCounter_SPI2Recv=DMA_GetCurrDataCounter(DMA1_Channel4); //查询SPI2的DMA接收通道已经接受的数据个数
printf("\r\n DMACurrDataCounter_SPI2Recv:%d \r\n",DMACurrDataCounter_SPI2Recv); //将上边查询到的个数通过串口发出去
if(DMACurrDataCounter_SPI2Recv==5) //如果刚好接收到的是5个数,说明首发成功,然后将接受到的数据发出来,验证内容是否正确,到这里实验结束
{
for(i=0;i<5;i++)
{
printf("\r\n SPI2_RecvBuff:%d \r\n",SPI2_RecvBuff);
}
while(1);
}
}
//其中SPI的DMA发送函数如下
void SPI_DMA_Send(u8 SPIx,u8 length)
{
if(SPIx==1)
{
DMA_ClearFlag(DMA1_FLAG_TC3);
DMA1_Channel3->CNDTR =length;
DMA_Cmd(DMA1_Channel3, ENABLE);
while(DMA_GetFlagStatus(DMA1_FLAG_TC3)==RESET);
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_ClearFlag(DMA1_FLAG_TC3);
}
}
现在的问题是,SPI1的DMA发送可以跑完进入下面的while(1),但是在SPI2的DMA接收个数查询那里一直查询到的是7,并不是我所发送的5个字节的数目,请原子哥和各位大神解答一下万谢.
另外之前原子哥说SPI在使用DMA的时候不能配置为全双工工作模式,我在文档里看到了这样一句话:当SPI工作在全双工模式并使用CRC检验以及启用DMA模式时,通信结束时,CRC字节的发送
和接收是自动完成的。是不是SPI在使用DMA传输的时候是可以使用全双工的呢?请赐教,在此谢过各位!
|
最佳答案
查看完整内容[请看2#楼]
[mw_shl_code=c,true]SPI_DMA_Send(1,5);
while(1)
{
DMACurrDataCounter_SPI2Recv=0;
DMACurrDataCounter_SPI2Recv=DMA_GetCurrDataCounter(DMA1_Channel4); //查询SPI2的DMA接收通道已经接受的数据个数
printf("\r\n DMACurrDataCounter_SPI2Recv:%d \r\n",DMACurrDataCounter_SPI2Recv); //将上边查询到的个数通过串口发出去
if(DMACurrDataCounter_SPI2Recv==5) //如果刚好接收到的是5个数,说 ...
|