这几天都在调试DMA写入W25Q16,每次写1页256字节数据,现在遇到2个字节数据错位的问题,比如从1到256个字节依次存数值1,2,3...256,结果却成了3,4,5...256,1,2。我怀疑问题可能和DMA发送完成后的SPI善后处理有关,我的做法是DMA发送完成后进入DMA传输完成中断,中断中清除SPI的TXE中断请求后打开TXE中断,清除DMA中断请求关闭该DMA通道。 在SPI中断中判断: 1.如果是TXE中断:清除TXE中断请求,关闭TXE中断,清除RXNE中断请求后打开RXNE中断; 2.如果如果是RXNE中断:清除RXNE中断请求,关闭RXNE中断,置高片选信号退出中断处理。 代码如下: /************************************************ 函数名称 : SPI_Configuration 功 能 : SPI配置 SPI为主模式,时钟线平时为低,上升沿采集数据 8位数据格式,软件控制片选,数据高位在前 参 数 : 无 返 回 值 : 无 作 者 : ShiPeng *************************************************/ void SPI3_Configuration(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//JTAG Disable SWDP Enable GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); /* SPI: CS推挽输出 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; #ifdef SPI3_NSS_HARD GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; #else GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; #endif GPIO_Init(GPIOA, &GPIO_InitStructure); /* SPI 初始化定义 */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为双线双向全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置为主 SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收 8 位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟悬空高 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据捕获于第二个时钟沿 #ifdef SPI3_NSS_HARD SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; //硬件控制 NSS 信号 #else SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件控制 NSS 信号 #endif SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //波特率预分频值为2 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //定义了用于 CRC值计算的多项式 SPI_Init(SPI3, &SPI_InitStructure); #ifdef SPI3_NSS_HARD SPI_SSOutputCmd(SPI3, ENABLE); SPI_Cmd(SPI3, DISABLE); #else SPI_Cmd(SPI3, ENABLE); #endif DMA_Config(); } /************************************************ 函数名称 : DMA_Config 功 能 : DMA配置 参 数 : 无 返 回 值 : 无 作 者 : ShiPeng *************************************************/ void DMA_Config(void) { #define SPI3_DR_Addr ((u32)0x40003C0C) DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); /* DMA_DeInit(DMA2_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = SPI3_DR_Addr; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Rx_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 256; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA2_Channel1, &DMA_InitStructure); DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE); // Disable SPI3 DMA RX request // SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Rx, ENABLE); DMA_Cmd (DMA2_Channel1,DISABLE); */ DMA_DeInit(DMA2_Channel2); DMA_InitStructure.DMA_PeripheralBaseAddr = SPI3_DR_Addr; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Tx_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = 256; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA2_Channel2, &DMA_InitStructure); DMA_ITConfig(DMA2_Channel2, DMA_IT_TC, ENABLE); DMA_ITConfig(DMA2_Channel2, DMA_IT_TE, ENABLE); /* Disable SPI3 DMA TX request */ SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); DMA_Cmd (DMA2_Channel2,DISABLE); } /************************************************ 函数名称 : SPI_WriteByte 功 能 : SPI写一字节数据 参 数 : TxData --- 发送的字节数据 返 回 值 : 读回来的字节数据 作 者 : *************************************************/ uint8_t SPI3_WriteByte(uint8_t TxData) { while((SPI3->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET); SPI3->DR = TxData; while((SPI3->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET); return SPI3->DR; } /******************************************************************************* * Function Name : DMA2Channel2_IRQHandler * Description : This function handles DMA Stream 1 interrupt request. * Input : None * Output : None * Return : None *******************************************************************************/ void DMA2_Channel2_IRQHandler(void) { /* Test on DMA Channel1 Transfer Complete interrupt */ if(DMA_GetITStatus(DMA2_IT_TC2)) //DMA2_IT_TC1:Transfer Completed { /* Get Current Data Counter value after complete transfer */ //u16 buf16= DMA_GetCurrDataCounter(DMA2_Channel2); DMA_Cmd (DMA2_Channel2,DISABLE);//SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, DISABLE); //if (0==buf16){} SPI_I2S_ClearITPendingBit(SPI3,SPI_I2S_IT_TXE); SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, ENABLE); /* Clear DMA Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */ DMA_ClearITPendingBit(DMA2_IT_GL2); } if(DMA_GetITStatus(DMA2_IT_TE2)) { SPI3_CS_DISABLE; DMA_Config(); DMA_ClearITPendingBit(DMA2_IT_TE2); } } void SPI3_IRQHandler(void) { if (SPI_I2S_GetITStatus(SPI3,SPI_I2S_IT_TXE)) { SPI_I2S_ClearITPendingBit(SPI3,SPI_I2S_IT_TXE); SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, DISABLE); SPI_I2S_ClearITPendingBit(SPI3,SPI_I2S_IT_RXNE); SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_RXNE, ENABLE); } if (SPI_I2S_GetITStatus(SPI3,SPI_I2S_IT_RXNE)) { SPI3_CS_DISABLE; SPI_I2S_ClearITPendingBit(SPI3,SPI_I2S_IT_RXNE); SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_RXNE, DISABLE); } } void WriteFLASHPageUseDMA(uint32_t faddr) { SFLASH_WaitForNoBusy(); SFLASH_WriteEnable(); SPI3_CS_ENABLE; SPI3_WriteByte(SFLASH_WRITE_PAGE); //《页编程》指令 SPI3_WriteByte((uint8_t)(faddr>>16)); //发送24bit地址 SPI3_WriteByte((uint8_t)(faddr>>8)); SPI3_WriteByte(0); DMA_Cmd (DMA2_Channel2,ENABLE); } 如果放弃DMA采用轮询写入就不会有此问题: void SFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t nByte) { SFLASH_WriteEnable(); //写使能 SPI3_CS_ENABLE; //使能器件 SPI3_WriteByte(SFLASH_WRITE_PAGE); //《页编程》指令 SPI3_WriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址 SPI3_WriteByte((uint8_t)((WriteAddr)>>8)); SPI3_WriteByte((uint8_t)WriteAddr); while (nByte--) { SPI3_WriteByte(*pBuffer); pBuffer++; } SPI3_CS_DISABLE; SFLASH_WaitForNoBusy(); //等待空闲(等待写入结束) } |
评分
查看全部评分