#include "SPI2_DMA.h"
#include "CRC16.h"
#include "string.h"
#include "main.h"
#include "ODContent_short.h"
unsigned char hex1, hex2;
int crc;
extern union structsend send; //控制指令帧-发送的数据 tx_data[12]
extern union structrec rec; //控制指令帧-接收的数据 rx_data[12]
extern union structReadr readr; //读寄存器帧-发送的数据 Read_register[6]
extern union structReadr_back readrb; //读寄存器帧-接收的数据 Read_register_back[4]
extern union structWriter writer; //写寄存器帧-发送的数据 Write_register[8]
extern union structWriter_back writerb; //写寄存器帧-接收的数据 Write_register_back[6]
unsigned char temparr[14] = {0};
unsigned char tempu;
void SPI2_DMA_Configuration(void)
{
// 1. 配置SPI2
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(GPIOB, &GPIO_InitStruct);
SPI2_SEL_DISABLE;
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High; //空闲为高电平
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge; //第二个时钟沿开始采样数据
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //60/64
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
// SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStruct);
SPI_Cmd(SPI2, ENABLE);
// 中断结构体
NVIC_InitTypeDef NVIC_InitStructure;
// DMA结构体
DMA_InitTypeDef DMA_InitStructure;
/* 使能DMA时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/* 复位初始化DMA数据流 */
DMA_DeInit(DMA1_Stream4);
/* 确保DMA数据流复位完成 */
while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE);
/* 配置 DMA Stream */
/* 通道0,数据流4 */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
/* 外设地址 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
/* 内存地址(要传输的变量的指针) ,DMA存储器0地址*/
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)send.tx_data;
/* 方向:存储器到外设 */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
/* 数据传输量 ,可设置为0, 实际发送时会重新设置*/
DMA_InitStructure.DMA_BufferSize = (uint32_t)12;
/* 外设非增量模式 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* 存储器增量模式 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 外设数据长度:8位 */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/* 内存数据长度:8位 */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/* DMA模式:正常模式 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
/* 优先级:高 */
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
/* 禁用FIFO */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
/* 外设突发单次传输 */
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/* 存储器突发单次传输 */
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* 初始化DMA Stream */
DMA_Init(DMA1_Stream4, &DMA_InitStructure);
/* 开启传输完成中断 */
DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);
// 中断初始化
/* DMA发送中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
/* 抢断优先级 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
/* 响应优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
/* 使能外部中断通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 配置NVIC */
NVIC_Init(&NVIC_InitStructure);
// 配置DMA1 Stream3通道0用于SPI2的接收
DMA_InitTypeDef dmaRxInitStruct;
dmaRxInitStruct.DMA_Channel = DMA_Channel_0;
dmaRxInitStruct.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
dmaRxInitStruct.DMA_Memory0BaseAddr = (uint32_t)rec.rx_data;
dmaRxInitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
dmaRxInitStruct.DMA_BufferSize = DATA_SIZE;
dmaRxInitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dmaRxInitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
dmaRxInitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dmaRxInitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dmaRxInitStruct.DMA_Mode = DMA_Mode_Normal;
dmaRxInitStruct.DMA_Priority = DMA_Priority_High;
dmaRxInitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
dmaRxInitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dmaRxInitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dmaRxInitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream3, &dmaRxInitStruct);
// 启用SPI2的DMA发送和接收
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
// 启用DMA1 Stream4和Stream3
// DMA_Cmd(DMA1_Stream4, ENABLE);
// DMA_Cmd(DMA1_Stream3, ENABLE);
}
void DMA1_Stream4_IRQHandler(void)
{
// DMA 发送完成
if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))
{
// 清除DMA发送完成标志
DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);
// 片选拉高,数据发送完毕
memset(send.tx_data,0,12);
DMA_Cmd(DMA1_Stream4, DISABLE);
while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET);
while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY) == 1); //保证发送接收数据完整
SPI2_SEL_DISABLE;
}
}
//开启一次DMA传输
void MYDMA_TX_Enable(DMA_Stream_TypeDef*DMA_CHx, u32 arr,int len)
{
DMA_Cmd(DMA_CHx, DISABLE ); //关闭SPI TX DMA1 所指示的通道
DMA_CHx->M0AR=(u32)arr;
DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能SPI TX DMA1 所指示的通道
}
//开启一次DMA传输
void MYDMA_RX_Enable(DMA_Stream_TypeDef*DMA_CHx,int len)
{
DMA_Cmd(DMA_CHx, DISABLE ); //关闭SPI RX DMA1 所指示的通道
DMA_CHx->M0AR=(u32)temparr;
DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA_CHx, ENABLE); //使能SPI RX DMA1 所指示的通道
}
uint8_t SPI2_ReadWriteByte(unsigned char data)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); // 等待发送区空
SPI_I2S_SendData(SPI2, data); // 通过外设SPI1发送一个byte数据
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);// 等待接收完一个byte
return SPI_I2S_ReceiveData(SPI2); // 返回通过SPIx最近接收的数据
}
/////////////////////////////////////////////
在中断中不断调用此函数,中断1ms一次
////////////////////////////////////////////
void SPI_DMA_WriteReadByte(void)
{
crc = do_crc(send.tx_data, 10);
send.sendtype.crc_H = (unsigned char)(crc>>8);
send.sendtype.crc_L = (unsigned char)(crc&0xff);
// 发送12B数据
SPI2_SEL_ENABLE;//拉低片选 (放在此处为了节省0.5us的时间)
SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx, ENABLE);//SPI 发送DMA使能
SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx, ENABLE);//SPI 接收DMA使能
MYDMA_TX_Enable(DMA1_Stream4,(u32)send.tx_data,12);//发送
MYDMA_RX_Enable(DMA1_Stream3,12);//接收
if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) == RESET)
{
DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TCIF4);
}
while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET);
while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY) == 1); //保证发送接收数据完整
//接收16B数据
#if 1
tempu = SPI2_ReadWriteByte(0x00);
tempu = SPI2_ReadWriteByte(0x00);
tempu = SPI2_ReadWriteByte(0x00);
tempu = SPI2_ReadWriteByte(0x00);
for(int i=0;i<12;i++)
rec.rx_data[i] = SPI2_ReadWriteByte(0x00);
#endif
SPI2_SEL_DISABLE;//拉高片选
}
SPI从机接收的数据如下:
.
有规律的错误,不知道是什么原因造成的