/********************************************************************************************************
*********************************************************************************************************
*
* File                : DMA.c
* Hardware Environment:	easyPIC pro v2
* Build Environment   : MPLAB V8.66 + PIC32 V2.01
* Microcontroller     : PIC32MX795F512L
* Version             : V1.0
* By                  : JEFF
* DATE				  : 20150320
*
*(c) Copyright 2010-2018, Logifind Tech CO.,LTD
*http://www.logifind.com
*All Rights Reserved
*
*********************************************************************************************************
********************************************************************************************************/
//
// 实验描述：利用串口接收16个字节数据，DMA0接收传输，再DMA1传输给PC 16个字节
//           数码管显示接收数据 LED流水   
//
// 头 文 件：C:\Program Files\Microchip\MPLAB C32 Suite\pic32-libs\include\proc
//
// 配 置 位：菜单栏 -> Help -> Topics.. -> PIC32MX Config Setting 
//
// 注意事项：波特率 9600 N 8 1  串口助手数据格式采用 HEX 
//
//-------------------------------------------------------------------------------

#include <plib.h>                    //调用通用头文件

//-------------------------------------------------------------------------------
// POSCMOD = XT, FNOSC = PRIPLL, FWDTEN = OFF
// PLLIDIV = DIV_2, PLLMUL = MUL_20
// PBDIV = 4 (default)
// Main clock = 4MHz /2 * 20    =  40MHz
// Peripheral clock = 40MHz /4  =  10MHz
// SYSCLK = 40 MHz (4MHz Crystal/FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK  = 10 MHz

#pragma config POSCMOD  = XT         //主振荡器  
#pragma config FNOSC    = PRIPLL     //倍频模式 
#pragma config FPLLIDIV = DIV_2      //输入分频 1:2
#pragma config FPLLMUL  = MUL_20     //PPL 倍频 1:20
#pragma config FPLLODIV = DIV_1      //输出分频 1:1
#pragma config FPBDIV   = DIV_4      //外设时钟
#pragma config FWDTEN   = OFF        //关闭看门狗
#pragma config ICESEL   = ICS_PGx1   //调试端口1

#define SysLED	_LATB5                          //CPU LED
#define SPEKAK  _LATD8                          //蜂呜器
#define RELAY   _LATD8                          //继电器

#define Smg_a    0xFE                           //定义段码
#define Smg_b    0xFD
#define Smg_c    0xFB
#define Smg_d    0xF7
#define Smg_e    0xEF
#define Smg_f    0xDF
#define Smg_g    0xBF
#define Smg_dp   0x7F

#define Bmp0Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_e & Smg_f 
#define Bmp1Map          Smg_b & Smg_c
#define Bmp2Map          Smg_a & Smg_b & Smg_d & Smg_e & Smg_g
#define Bmp3Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_g
#define Bmp4Map          Smg_b & Smg_c & Smg_f & Smg_g
#define Bmp5Map          Smg_a & Smg_c & Smg_d & Smg_f & Smg_g
#define Bmp6Map          Smg_a & Smg_c & Smg_d & Smg_e & Smg_f & Smg_g
#define Bmp7Map          Smg_a & Smg_b & Smg_c 
#define Bmp8Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_e & Smg_f & Smg_g
#define Bmp9Map          Smg_a & Smg_b & Smg_c & Smg_d & Smg_f & Smg_g
#define BmpAMap          Smg_a & Smg_b & Smg_c & Smg_e & Smg_f & Smg_g
#define BmpBMap          Smg_c & Smg_d & Smg_e & Smg_f & Smg_g
#define BmpCMap          Smg_a & Smg_d & Smg_e & Smg_f 
#define BmpDMap          Smg_b & Smg_c & Smg_d & Smg_e & Smg_g
#define BmpEMap          Smg_a & Smg_d & Smg_e & Smg_f & Smg_g
#define BmpFMap          Smg_a & Smg_e & Smg_f & Smg_g


const unsigned char SegCode[] =                                  //显示段码表
{
	Bmp0Map,Bmp1Map,Bmp2Map,Bmp3Map,Bmp4Map,Bmp5Map,Bmp6Map,Bmp7Map,Bmp8Map,Bmp9Map,
	BmpAMap,BmpBMap,BmpCMap,BmpDMap,BmpEMap,BmpFMap
};
unsigned char DpyNum[6] = {Smg_g,Smg_g,Smg_g,Smg_g,Smg_g,Smg_g}; //显示缓冲区        

unsigned char RX_Buffer[16] = {0};             //DMA0缓冲区
unsigned char TX_Buffer[16] = {0};             //DMA1缓冲区


//-------------------------------------------------------------------------------
//        延时函数
//-------------------------------------------------------------------------------
void Delay_xmS(unsigned int i)                 //延时程序
{
	unsigned int j;
	for(;i>0;i--)
	{
		Nop();
		for(j=0;j<255;j++)
		{
			Nop();
			ClearWDT();
		}
	}	
}

//---------------------------------------------------------------------------------
//     TMR1初始化
//---------------------------------------------------------------------------------
void Timer1_Init(void)
{
	T1CON = 0;              // Timer1 清零
	
	IFS0bits.T1IF = 0;      // Timer1 清除标志位
	IEC0bits.T1IE = 1;      // Timer1 中断允许
	IPC1bits.T1IP = 4;      // Timer1 中断优选级
	TMR1=  0x0000;  	    // Timer1 给定初值
	PR1 = 0x9C3F;           // Timer1 周期寄存器
	
	T1CONbits.TON = 1;      // Timer1 启动计数
}

//---------------------------------------------------------------------------------
//     数码管驱动
//---------------------------------------------------------------------------------
void SegDisplay(void)
{
	static unsigned char step = 0;
	LATD = (LATD&0xFF00)|DpyNum[step];  //显示缓冲
	switch(step)                        //片选
	{
		case 0: _LATB8 = 0;_LATB9 = 1;_LATB10 = 1;_LATB11 = 1;_LATB12 = 1;_LATB13 = 1;break;
		case 1: _LATB8 = 1;_LATB9 = 0;_LATB10 = 1;_LATB11 = 1;_LATB12 = 1;_LATB13 = 1;break;
		case 2: _LATB8 = 1;_LATB9 = 1;_LATB10 = 0;_LATB11 = 1;_LATB12 = 1;_LATB13 = 1;break;
		case 3: _LATB8 = 1;_LATB9 = 1;_LATB10 = 1;_LATB11 = 0;_LATB12 = 1;_LATB13 = 1;break;
		case 4: _LATB8 = 1;_LATB9 = 1;_LATB10 = 1;_LATB11 = 1;_LATB12 = 0;_LATB13 = 1;break;
		case 5: _LATB8 = 1;_LATB9 = 1;_LATB10 = 1;_LATB11 = 1;_LATB12 = 1;_LATB13 = 0;break;
		default:break;
	}
	if(step < 5) step ++;               //扫描
	else      	 step = 0;
}	

//---------------------------------------------------------------------------------
//     TMR1 中断函数
//---------------------------------------------------------------------------------
void __attribute__ ((vector(4)))__attribute__((interrupt(IPL4)))_T1Interrupt(void)
{	
	IFS0bits.T1IF = 0;
	SegDisplay();                    //数码管扫描
}

//-------------------------------------------------------------------------------
//        串口1初始化函数
//-------------------------------------------------------------------------------
void UART1_Init(void)                // 串口1初始化     
{
	U1MODEbits.SIDL  = 0;            // IDLE工作
	U1MODEbits.IREN  = 0;            // 禁止IrDA
	U1MODEbits.UEN   = 0;            // 使能RX TX引脚
	U1MODEbits.WAKE  = 0;            // 禁止唤醒
	U1MODEbits.ABAUD = 0;            // 禁止自动BUD
	U1MODEbits.RXINV = 0;            // 空闲状态为1
	U1MODEbits.BRGH  = 0;            // 16x标准波特率
	U1MODEbits.PDSEL = 0;            // 8位无奇偶校验
	U1MODEbits.STSEL = 0;            // 1个停止位
	
	U1STAbits.ADM_EN   = 0;          // 关自动地址检测
	U1STAbits.UTXISEL1 = 0;          // 发送完所有字符后中断
	U1STAbits.UTXISEL0 = 1;
	U1STAbits.UTXINV   = 0;          // 空闲状态为1
	U1STAbits.URXEN    = 1;          // 接收器使能	
	
	U1STAbits.UTXBRK   = 0;          // 禁止发送间隔位
	U1STAbits.UTXEN    = 1;          // 发送器使能
	                                               
	U1STAbits.URXISEL1 = 0;          // 接收1个字符中断
	U1STAbits.URXISEL0 = 0;
	
	U1BRG = 64;                      // PBCLK 10MHz  N 8 1 9600
	
	U1MODEbits.ON   = 1;             // 串口使能 
}

//-------------------------------------------------------------------------------
//        DMA初始化函数
//-------------------------------------------------------------------------------
void DMA_Init(void)                 //DMA 初始化
{
	DCH0ECONbits.CHSIRQ = 27;       //IRQ 编号 U1RXREG
	DCH0ECONbits.SIRQEN = 1;        //IRQ 中断
	
	DCH0SSA = KVA_TO_PA((void*)&U1RXREG);   //源 地址
	DCH0DSA = KVA_TO_PA((void*)&RX_Buffer); //目标地址
	DCH0SSIZ = 1;                   //U1RXREG 1次传输1Byte
	DCH0DSIZ = 16;                  //Buffer 传输大小
	DCH0CSIZ = 1;                   //传输 1Byte U1RXREG to Buffer

	DCH0INTbits.CHBCIE = 1;         //数据传输完成中断 
	DCH0INTbits.CHERIE = 1;         //通道地址错误中断  

	IPC9bits.DMA0IP = 4; 
	IPC9bits.DMA0IS = 2; 
	IEC1bits.DMA0IE = 1; 

	DCH0CONbits.CHAEN = 1;          //通道自动使能位 
	DCH0CONbits.CHEN = 1;           //使能DMA0通道
	
	DCH1ECONbits.CHSIRQ = 28;       //中断编号 U1TXREG
	DCH1ECONbits.SIRQEN = 1;        //IRQ 中断
	                            
	DCH1SSA = KVA_TO_PA((void*)&TX_Buffer); //源 地址
	DCH1DSA = KVA_TO_PA((void*)&U1TXREG);   //目标地址                            
	DCH1SSIZ = 16;                  //Buffer 传输长度
	DCH1DSIZ = 1;                   //U1TXREG传输1Byte
	DCH1CSIZ = 1;                   //传输 1Byte Buffer to U1TXREG
	
	DCH1INTbits.CHBCIE = 1;         //数据传输完成中断 
	DCH1INTbits.CHERIE = 1;         //通道地址错误中断  

	IPC9bits.DMA1IP = 4; 
	IPC9bits.DMA1IS = 2; 
	IEC1bits.DMA1IE = 1; 

//	DCH1CONbits.CHAEN = 1;          //通道自动使能位 
//	DCH1CONbits.CHEN = 1;           //使能DMA1通道

	DMACONbits.ON = 1;              //使能DMA 模块
}

//-------------------------------------------------------------------------------
//        DMA0 中断函数   芯片手册第7章 
//-------------------------------------------------------------------------------
void __attribute__((vector(36)))__attribute__((interrupt(IPL4)))_DMA0Interrupt(void)
{
	unsigned char i;
	if(DCH0INTbits.CHBCIF == 1)             //传输标志
	{
		for(i=0;i<16;i++)                   //复制数据
		{
			TX_Buffer[i] = RX_Buffer[i];
		}	
		DCH0INTbits.CHBCIF = 0;     
		DCH1CONbits.CHEN = 1;               //启动DMA 发送
	}
	if(DCH0INTbits.CHERIF == 1)             //地址错误
	{
		DCH0INTbits.CHERIF = 0;     
	}
	IFS1bits.DMA0IF = 0;                    // 清除中断标志
}

//-------------------------------------------------------------------------------
//        DMA1 中断函数   芯片手册第7章 
//-------------------------------------------------------------------------------
void __attribute__((vector(37)))__attribute__((interrupt(IPL4)))_DMA1Interrupt(void)
{    
	if(DCH1INTbits.CHBCIF == 1)             //传输标志
	{
		DCH1INTbits.CHBCIF = 0;     
	}
	if(DCH1INTbits.CHERIF == 1)             //地址错误
	{
		DCH1INTbits.CHERIF = 0;     
	}
	IFS1bits.DMA1IF = 0;                    // 清除中断标志
}

//-------------------------------------------------------------------------------
//        主函数
//-------------------------------------------------------------------------------
int main(void)
{
	unsigned int temp = 0;        //变量
	AD1PCFG = 0xFFFF;             //引脚为数字I/O
	TRISB  = 0xC0DF;              //RB5 RB8-RB13输出
	TRISG  = 0xFFFF;              //G端口输出
	TRISE  = 0x0000;              //E端口输出
	TRISD  = 0xFE00;              //RD0-RD7 RD8 输出
	
	Timer1_Init();                //TMR1初始化
	UART1_Init();                 //UART初始化
	DMA_Init();                   //DMAx初始化

	INTEnableSystemMultiVectoredInt(); //使能中断多向量表  
	   
	LATE = 0x00FF;                //点亮 D0 - D7
	Delay_xmS(1000);
	LATE = 0x0000;                //关闭 D0 - D7
	Delay_xmS(1000);
	LATE = 0x00FF;                //点亮 D0 - D7
	Delay_xmS(1000);
	LATE = 0x0000;                //关闭 D0 - D7
	Delay_xmS(200);

	while(1)
	{
	    //------------------------显示--------------------------
	    
	   	DpyNum[0] = SegCode[temp/10];              //数码管分段       
		DpyNum[1] = SegCode[temp%10];
		DpyNum[2] = Smg_g;
		DpyNum[3] = Smg_g;
		DpyNum[4] = SegCode[RX_Buffer[temp]>>4];   //显示接收数据高4位
		DpyNum[5] = SegCode[RX_Buffer[temp]&0x0F]; //显示接收数据低4位
		
		LATE = RX_Buffer[temp];                    //LED显示当前数据
		
		temp = (temp + 1)&0x0F;                    //循环显示
		SysLED = !SysLED;                          //CPU LED
		Delay_xmS(1000);	                       //延时
		
		//------------------------------------------------------
	}
}


//-------------------------------------------------------------------------------

