/********************************************************************************
 * @file    SPI_Communication_DMA.c
 * @author  SOC AE Team
 * @version V1.1
 * @date    2025-06-27
 * @brief		SPI0作为主机，SPI1作为从机，SPI0通过DMA0连续发送200个数据，SPI1通过DMA1连续接收200个数据。
 *          （主从机模式请在宏定义进行选择，SPI_Mode_=0为主机代码，SPI_Mode_=1为从机代码）
 *
 *******************************************************************************/
#include "sc32_conf.h"
#include "Function_Init.h"

/* 请选择主从机代码 */
#define SPI_Mode_ 1

#if (SPI_Mode_ == 0)
static volatile FlagStatus SPI0_Flag = RESET;
#elif (SPI_Mode_ == 1)
static volatile FlagStatus SPI1_Flag = RESET;
#endif

void SPI_Communication_DMA_Function(void)
{
	uint8_t i; 
	SPI_InitTypeDef SPI_InitStruct; //定义SPI初始化结构体变量
  DMA_InitTypeDef DMA_InitStruct; //定义DMA初始化结构体变量
	
	/* 结构体成员初始化 */
  SPI_StructInit(&SPI_InitStruct);
  DMA_StructInit(&DMA_InitStruct);
	
	/* 使能DMA的时钟 */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE);
	
#if (SPI_Mode_ == 0)	
	volatile uint8_t Communication_DMA_SPI0_SendData[200];

	for(i=0;i<200;i++)
	{
	 Communication_DMA_SPI0_SendData[i] = i;//被搬运数组写入数据
	}
  /* 使能SPI0的时钟 */
  RCC_APB0Cmd(ENABLE);  //SPI0和1外设挂载在APB0时钟上
#if defined(SC32f10xx)||defined(SC32f12xx)
  RCC_APB0PeriphClockCmd(RCC_APB0Periph_SPI0, ENABLE);
#endif
  /* 配置SPI0为主机 */
  SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;	//SPI第一沿采集数据
  SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;	//SPI空闲电平为高电平
  SPI_InitStruct.SPI_DataSize = SPI_DataSize_8B;	//数据长度为8位
  SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;	//数值传输为高位在前
  SPI_InitStruct.SPI_Mode = SPI_Mode_Master;	//SPI工作在主机模式
  SPI_InitStruct.SPI_Prescaler = SPI_Prescaler_1024;	//SPI传输频率为APB0时钟1024分频
  SPI_Init(SPI0, &SPI_InitStruct);
  /* 使能SPI0发送的DMA功能 */
  SPI_DMACmd(SPI0, SPI_DMAReq_TX, ENABLE);
	/*CLK引脚初始化*/
	GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO初始化结构体变量
#if defined(SC32f12xx)
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT_PP;
  GPIO_Init(GPIOC, &GPIO_InitStruct);
	PC_BIT(2) = 1;
#elif defined(SC32f10xx)
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT_PP;
  GPIO_Init(GPIOB, &GPIO_InitStruct);
	PB_BIT(1) = 1;
#endif

  /* 使能SPI0 */
  SPI_Cmd(SPI0, ENABLE);

  /* DMA0外设配置 */
  DMA_InitStruct.DMA_BufferSize = 200;	//DMA搬运数量为200个
  DMA_InitStruct.DMA_CircularMode = DMA_CircularMode_Disable;	//关闭循环模式
  DMA_InitStruct.DMA_DataSize = DMA_DataSize_Byte;	//传输宽度为字节
  DMA_InitStruct.DMA_SourceMode = DMA_SourceMode_INC_CIRC;	//源地址循环递增
  DMA_InitStruct.DMA_TargetMode = DMA_TargetMode_FIXED;	//目标地址固定
  DMA_InitStruct.DMA_SrcAddress = (uint32_t)Communication_DMA_SPI0_SendData;
  DMA_InitStruct.DMA_DstAddress = (uint32_t)&SPI0->SPI_DATA;
#if defined(SC32f10xx)||defined(SC32f12xx)
  DMA_InitStruct.DMA_Request = DMA_Request_SPI0_TX;	//SPI0 发送触发DMA0
#endif
  DMA_InitStruct.DMA_Priority = DMA_Priority_HIGH;	//设置优先级为高
  DMA_Init(DMA0, &DMA_InitStruct);
  /* 开启DMA0传输完成中断 */
  DMA_ITConfig(DMA0, DMA_IT_INTEN | DMA_IT_TCIE, ENABLE);
  NVIC_EnableIRQ(DMA0_IRQn);
  DMA_Cmd(DMA0, ENABLE);	//使能DMA0

#elif (SPI_Mode_ == 1)
 volatile uint8_t Communication_DMA_SPI1_ReceiveData[200];
	
  /* 使能SPI1的时钟 */
   RCC_APB1Cmd(ENABLE);//SPI1外设挂载在APB1时钟上 
#if defined(SC32f12xx)
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI1, ENABLE);
#elif defined(SC32f10xx)
   RCC_APB1Cmd(ENABLE);//SPI1外设挂载在APB1时钟上
#endif

	GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO初始化结构体变量
#if defined(SC32f10xx) ||defined(SC32f12xx)
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT_PP;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
	PA_BIT(2) = 1;	
#endif
	/* 配置SPI1为从机 */
  SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;	//SPI第一沿采集数据
  SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;	//SPI空闲电平为高电平
  SPI_InitStruct.SPI_DataSize = SPI_DataSize_8B;	//数据长度为8位
  SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;	//数值传输为高位在前
  SPI_InitStruct.SPI_Mode = SPI_Mode_Slave;	//SPI工作在从机模式
  SPI_Init(SPI1, &SPI_InitStruct);
  /* 使能SPI1接收的DMA功能 */
  SPI_DMACmd(SPI1, SPI_DMAReq_RX, ENABLE);
  /* 使能SPI1 */
  SPI_Cmd(SPI1, ENABLE);

  /* DMA1外设配置 */
  DMA_InitStruct.DMA_BufferSize = 200;	//DMA搬运数量为200个
  DMA_InitStruct.DMA_CircularMode = DMA_CircularMode_Enable;	//开启循环模式
  DMA_InitStruct.DMA_DataSize = DMA_DataSize_Byte;	//传输宽度为字节
  DMA_InitStruct.DMA_SourceMode = DMA_SourceMode_FIXED;	//源地址固定
  DMA_InitStruct.DMA_TargetMode = DMA_TargetMode_INC_CIRC;	//源地址循环递增
  DMA_InitStruct.DMA_SrcAddress = (uint32_t)&SPI1->SPI_DATA;
  DMA_InitStruct.DMA_DstAddress = (uint32_t)Communication_DMA_SPI1_ReceiveData;
#if defined(SC32f10xx)||defined(SC32f12xx)
  DMA_InitStruct.DMA_Request = DMA_Request_SPI1_RX;	//SPI1 接收触发DMA1

#endif
  DMA_InitStruct.DMA_Priority = DMA_Priority_VERY_HIGH;	//设置优先级为非常高
  DMA_Init(DMA1, &DMA_InitStruct);
  /* 开启DMA1传输完成中断 */
  DMA_ITConfig(DMA1, DMA_IT_INTEN | DMA_IT_TCIE, ENABLE);
  NVIC_EnableIRQ(DMA1_IRQn);
  DMA_Cmd(DMA1, ENABLE);//使能DMA1

#endif

  while(1)
  {
#if (SPI_Mode_ == 0)
    printf("SPI0主机发送数据为：\r\n");
		for(i=0;i<200;i++)
	    {
				printf("%d、", Communication_DMA_SPI0_SendData[i]);
			}
			printf("\r\n");
		
    DMA_SoftwareTrigger(DMA0);	//软件触发第一次搬运

    while(SPI0_Flag == RESET);	//等待DMA0搬运完成
    SPI0_Flag = RESET; //清标志
			
    /* 重新写入DMA通道传输值 */
    DMA_SetCurrDataCounter(DMA0, 200);	
			
    /* 重新使能SPI0的DMA功能，才能开启新一轮通信 */
    SPI_DMACmd(SPI0, SPI_DMAReq_TX, DISABLE);
    SPI_DMACmd(SPI0, SPI_DMAReq_TX, ENABLE);
			
#elif (SPI_Mode_ == 1)
	
    while(SPI1_Flag == RESET);	//等待DMA1搬运完成
    SPI1_Flag = RESET;	

    printf("SPI1从机接收到的数据为：\r\n");
			
    for(i=0;i<200;i++)
	  {
			printf("%d、", Communication_DMA_SPI1_ReceiveData[i]);
	  }
		printf("\r\n");
			


#endif
  }
}

void SPI_Communication_DMA_DAM0Handler(void)
{
#if (SPI_Mode_ == 0)
  if(DMA_GetFlagStatus(DMA0, DMA_FLAG_TCIF))
  {
    DMA_ClearFlag(DMA0, DMA_FLAG_TCIF);
    SPI0_Flag = SET;
  }
#endif
}

void SPI_Communication_DMA_DMA1Handler(void)
{
#if (SPI_Mode_ == 1)
  if(DMA_GetFlagStatus(DMA1, DMA_FLAG_TCIF))
  {    SPI1_Flag = SET;
    DMA_ClearFlag(DMA1, DMA_FLAG_TCIF);

  }
#endif
}

