|
本帖最后由 silence_sky 于 2018-11-27 15:08 编辑
SPI配置:
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工
SPI_InitStruct.SPI_Mode = SPI_Mode_Master; //主
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; //8位帧
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;//空闲状态为高电平
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;//第二个跳变沿数据被采样
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; //NSS 信号由软件控制
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //预分频36/2 =18Mhz
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始
SPI_InitStruct.SPI_CRCPolynomial = 7; //CRC 值计算的多项式
SPI_Init(SPI2, &SPI_InitStruct); //根据指定的参数初始化外设 SPIx 寄存器
SPI_Cmd(SPI2,ENABLE);//使能SPI外设
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, DISABLE);
DMA配置:
DMA_DeInit(DMA1_Channel4); //将DMA的通道1寄存器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR; //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&bmpbuffA[0]; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地
DMA_InitStructure.DMA_BufferSize = 0; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
DMA_Cmd(DMA1_Channel4, DISABLE); //关闭DMA
DMA_ClearFlag(DMA1_FLAG_GL4|DMA1_FLAG_TC4|DMA1_FLAG_HT4|DMA1_FLAG_TE4);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //DMA中断使能
启动接收
//-------------------------------------------------------------------------------
//16K读dma读取
//-------------------------------------------------------------------------------
void SFLASH_DMA_ReadBlock16K(u32 addr,u8 *Buff)
{
addr*=16384;
FLASH_CS_LOW();
SPI_FLASH_SendByte(W25X_FastReadData); // W25X_ReadData W25X_FastReadData
SPI_FLASH_SendByte(addr>>16);
SPI_FLASH_SendByte(addr>>8);
SPI_FLASH_SendByte(addr);
SPI_FLASH_SendByte(0xff);
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
//while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
addr=SPI2->DR ; //读一下,清空
SPI2->CR1=0X074f; //配置为单发,注意波特率
SPI2->CR2|=0X01; //启动DMA请求
DMA1_Channel4->CNDTR = 16384;
DMA1_Channel4->CMAR =(u32)Buff;
DMA1_Channel4->CCR|=0x01; //启动DMA
}
中断
void DMA1_Channel4_IRQHandler(void)
{
OSIntEnter();
if(DMA_GetFlagStatus(DMA1_FLAG_TC4));
{
SPI2->CR2&=0Xfffe; //关闭DMA请求
FLASH_CS_HIGH();
DMA1_Channel4->CCR&=0XFFFE; //关DMA
DMA_ClearFlag(DMA1_FLAG_TC4);
SPI2->CR1 &= 0xffbf;//关闭SPI
SPI2->CR1 = 0X034f; //打开,恢复到双工,注意波特率配置
OSSemPost(Sem_SPI2_DMA_TC);
}
OSIntExit();
}
要说有什么特别的,就是SPI的DMA接收模式必须配成只接收(双线只接收),配的时候为了速度我直接寄存器赋值了。
SPI的DMA请求什么时候开,先开请求、先开DMA使能最后结果都一样。不管传多少数据量,最后SPI的CLK时钟就没停。
关键是:如果中断里不配置关闭SPI或者改变SPI的模式,时钟就一直有。
最开始发现问题就是我需要在中断里恢复SPI为双线收发模式,结果老是失败,导致下一次使用SPI时数据发送错误。一查才发现是DMA中断后SPI并没有停止工作,而SPI的CR寄存器不可以在工作期间改变。
数组里的头尾都没问题,也就是说DMA的TC中断的时候DMA已经停止往数组里送数了。单纯就是SPI没停。
数据到AF就该停了。后面B0\B1已经是下一组数据的开头了。
感觉B0、B1会传出来就是因为还没进中断程序。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|