dsp28335杂记3

DAC实验,SPI+TLV5620

TLV5620 集合4通道的DAC输出,采用SPI通信

#define SET_LOAD 	(GpioDataRegs.GPASET.bit.GPIO26=1)
#define ClEAR_LOAD 	(GpioDataRegs.GPACLEAR.bit.GPIO26=1)


void TLV5620_Init(void)
{
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1;// SPI-A
	EDIS;

	/*初始化GPIO;*/
	InitSpiaGpio();//spi的各个引脚配置

	//DA_LOAD  GPIO26
	EALLOW;
	GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 0;// 配置GPIO为GPIO口
	GpioCtrlRegs.GPADIR.bit.GPIO26 = 1;// 定义GPIO输出引脚
	GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0;// 禁止上啦 GPIO引脚
	EDIS;

	SpiaRegs.SPICCR.all =0x0a;   //进入初始状态,数据在上升沿输出,自测禁止,11位数据模式
	SpiaRegs.SPICTL.all =0x0006; // 使能主机模式,正常相位,使能主机发送,禁止接收
			                     //溢出中断,禁止SPI中断;
	SpiaRegs.SPIBRR =0x0031;	 //SPI波特率=37.5M/50	=0.75MHZ;
	SpiaRegs.SPICCR.all =0x8a;   //退出初始状态;
	SpiaRegs.SPIPRI.bit.FREE = 1;// 自由运行

	SET_LOAD;
}

//channel是4个通道的地址(00,01,10,11)
//rng是输出范围的倍数,可以是0或1。
//dat是0~256数据,因为DAC是8位的
void DAC_SetChannelData(unsigned char channel,unsigned char rng,unsigned char dat)
{
	Uint16 dacvalue=0;

	//注意这里的有效数据是11位,SPI初始化中也进行了定义
	dacvalue = ((channel<<14) | (rng<<13) | (dat<<5));

	while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG ==1);//判断SPI的发送缓冲区是否是空的,等于0可写数据
	SpiaRegs.SPITXBUF = dacvalue;//把发送的数据写入SPI发送缓冲区
	while( SpiaRegs.SPISTS.bit.BUFFULL_FLAG==1);//当发送缓冲区出现满标志位时,开始琐存数据

	ClEAR_LOAD;
	DELAY_US(2);

	SET_LOAD;
	DELAY_US(10);
}
DAC+ADC0实验-------nice

ADC0检测 DACDB通道输出电压值

// ===================================ADC单通道配置
void ADC_Init(void)
{
	// Specific clock setting for this example:
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;    // ADC
	EDIS;

	// Specific clock setting for this example:
	EALLOW;
	SysCtrlRegs.HISPCP.all = ADC_MODCLK;	// HSPCLK = SYSCLKOUT/(2*ADC_MODCLK)
	EDIS;

	InitAdc();  // For this example, init the ADC

	// Specific ADC setup for this example:
	AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;  ADC 工作 25M 下不分频
	AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS; // 1 通道模式
	AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;        // 1  Cascaded mode
	AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;   // A0 为采样通道
	AdcRegs.ADCTRL1.bit.CONT_RUN = 1;       // Setup continuous run
	AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0;

	// Start SEQ1
	AdcRegs.ADCTRL2.all = 0x2000;  //软件触发、PWM 触发等,使用软件触发

}
Uint16 Read_ADCValue(void)
{
	while (AdcRegs.ADCST.bit.INT_SEQ1== 0);//等待 ADC 转换完成,然后清除状态标志
	AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
	return AdcRegs.ADCRESULT0>>4;
}

//=====================================DAC配置
void TLV5620_Init(void)
{
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1;   // SPI-A
	EDIS;

	/*初始化GPIO;*/
	InitSpiaGpio();

	EALLOW;
	GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 0; // 配置GPIO为GPIO口
	GpioCtrlRegs.GPADIR.bit.GPIO26 = 1;      // 定义GPIO输出引脚
	GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0;      // 禁止上啦 GPIO引脚
	EDIS;

	SpiaRegs.SPICCR.all =0x0a;///进入初始状态,数据在上升沿输出,自测禁止,11位数据模式
	SpiaRegs.SPICTL.all =0x0006; // 使能主机模式,正常相位,使能主机发送,禁止接收
		                            //溢出中断,禁止SPI中断;
	SpiaRegs.SPIBRR =0x0031;	//SPI波特率=37.5M/50	=0.75MHZ;
	SpiaRegs.SPICCR.all =0x8a; //退出初始状态;
	SpiaRegs.SPIPRI.bit.FREE = 1;  // 自由运行

	SET_LOAD;
}

void DAC_SetChannelData(unsigned char channel,unsigned char rng,unsigned char dat)
{
	Uint16 dacvalue=0;

	//注意这里的有效数据是11位,SPI初始化中也进行了定义
	dacvalue = ((channel<<14) | (rng<<13) | (dat<<5));

	while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG ==1);//判断SPI的发送缓冲区是否是空的,等于0可写数据
	SpiaRegs.SPITXBUF = dacvalue;	//把发送的数据写如SPI发送缓冲区
	while( SpiaRegs.SPISTS.bit.BUFFULL_FLAG==1);		//当发送缓冲区出现满标志位时,开始琐存数据

	ClEAR_LOAD;
	DELAY_US(2);

	SET_LOAD;
	DELAY_US(10);
}
DMA+ADC实验(外设到存储器)+ 中断 ==了解皮毛,嘿嘿
  • 将ADC0 采集到的数据 通过DMA1传输至内存(存储器)
  • DMA传送步骤:
    • ①当外设输入数据准备好,外设向 DMA 发出一个选通信号,将数据送到数据端口,向 DMA 发出请求。
    • ②DMA 控制器向 CPU 发出总线请求信号(HOLD)高电平
    • ③CPU 在现行总线周期结束后响应,向 DMA 发出响应信号(HLDA)高电平
    • ④CPU 待该总线周期结束时,放弃对总线控制,DMA 控制器接管三态总线,接口将数据送上数据总线并撤销 DMA 请求。
    • ⑤内存收到数据以后,给 DMA 一个回答,于是 DMA 修改地址指针,改变传送字节数,检查传送是否结束,没有结束,则下次接口准备好数据,再进行一次新的传输。
    • ⑥当计数值计为 0,DMA 传输过程便告结束。DMA 控制器撤销总线请求(HOLD变低),在下一个时钟周期上升沿使总线响应 HLDA 变低,DMA 释放总线,CPU取得总线控制权。
  • DMA配置步骤:
    • (1)使能 DMA 外设时钟
    • (2)初始化 DMA
    • (3)DMA 通道相关参数设置,包括指针数据长度、步长、触发源选择、触发模式等。
      在这里插入图片描述
    • (4)启动 DMA
// dma + adc + interrupt
interrupt void local_DINTCH1_ISR(void);
void DMACH1_ADC_Init(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source)
{
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;    // ADC
	EDIS;

	// Specific clock setting for this example:
	EALLOW;
	SysCtrlRegs.HISPCP.all = 3;	// HSPCLK = SYSCLKOUT/ADC_MODCLK
	EDIS;

	InitAdc();  // For this example, init the ADC

	// Specific ADC setup for this example:
	AdcRegs.ADCTRL1.bit.ACQ_PS = 0x0f;
	AdcRegs.ADCTRL3.bit.ADCCLKPS = 0x01;
	AdcRegs.ADCTRL1.bit.SEQ_CASC = 0;        // 0 Non-Cascaded Mode
	AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x1;
	AdcRegs.ADCTRL2.bit.RST_SEQ1 = 0x1;
	AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;
	AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0;   // Set up ADC to perform 4 conversions for every SOC

	// Start SEQ1
	AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 0x1;

#ifdef DMA_INT_ENABLE
	// Interrupts that are used in this example are re-mapped to
	// ISR functions found within this file.
	EALLOW;	// Allow access to EALLOW protected registers
	PieVectTable.DINTCH1= &local_DINTCH1_ISR;
	EDIS;   // Disable access to EALLOW protected registers

	IER = M_INT7 ;	                             //Enable INT7 (7.1 DMA Ch1)
	EnableInterrupts();
#endif

	EALLOW;
	SysCtrlRegs.PCLKCR3.bit.DMAENCLK = 1;       // DMA Clock
	EDIS;

	// Initialize DMA
	DMAInitialize();

	// Configure DMA Channel
	DMACH1AddrConfig(DMA_Dest,DMA_Source);
	DMACH1BurstConfig(15,0,1);         //Will set up to use 32-bit datasize, pointers are based on 16-bit words
	DMACH1TransferConfig(9,0,1);      //so need to increment by 2 to grab the correct location
	DMACH1WrapConfig(40,0,40,0);
	//Use timer0 to start the x-fer.
	//Since this is a static copy use one shot mode, so only one trigger is needed
	//Also using 32-bit mode to decrease x-fer time
	DMACH1ModeConfig(DMA_SEQ1INT,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,
						SYNC_SRC,OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE);

	StartDMACH1();
}
interrupt void local_DINTCH1_ISR(void)
{
	// To receive more interrupts from this PIE group, acknowledge this interrupt
	PieCtrlRegs.PIEACK.bit.ACK7 = 1;
}

内置XINTF接口配置 + 外扩SRAM + DMA支持 ==了解皮毛,嘿嘿
  • 对外部SRAM写入1024个16位数据,然后通过DMA将上面的数据传到芯片内存中
  • XINTF配置步骤
    • (1)XINTF 的配置程序
    • (2)时钟信号
    • (3)写缓冲器
    • (4)XINTF 访问的建立、有效、跟踪等待时间
    • (5)区域的 XREADY 采样
    • (6)带宽
    • (7)XBANK 区域切换配置
  • 初始化程序步骤
    • (1)使能 XINTF 外设时钟
    • (2)初始化 GPIO 为 XINTF 功能,即选择 GPIO 复用功能
    • (3)XINTF 外设相关参数设置,包括基准时钟 XTIMCLK、缓冲寄存器、读写建立,有效,跟踪时间、数据总线宽度等。
//==============================================================
// DMA通道配置(外设到存储器)
//==============================================================
//#define DMA_INT_ENABLE
void DMAInitialize(void)
{
	EALLOW;

	// Perform a hard reset on DMA
	DmaRegs.DMACTRL.bit.HARDRESET = 1;

	// Allow DMA to run free on emulation suspend
	DmaRegs.DEBUGCTRL.bit.FREE = 1;
	
	EDIS;
}
// Configure the timing paramaters for Zone 7.
// Notes:
//    This function should not be executed from XINTF
//    Adjust the timing based on the data manual and
//    external device requirements.
void init_zone7(void)
{
	EALLOW;
    // Make sure the XINTF clock is enabled
	SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1;
	EDIS;
	// Configure the GPIO for XINTF with a 16-bit data bus
	// This function is in DSP2833x_Xintf.c
	InitXintf16Gpio();

    // All Zones---------------------------------
    // Timing for all zones based on XTIMCLK = SYSCLKOUT
	EALLOW;
    XintfRegs.XINTCNF2.bit.XTIMCLK = 0;
    // Buffer up to 3 writes
    XintfRegs.XINTCNF2.bit.WRBUFF = 3;
    // XCLKOUT is enabled
    XintfRegs.XINTCNF2.bit.CLKOFF = 0;
    // XCLKOUT = XTIMCLK
    XintfRegs.XINTCNF2.bit.CLKMODE = 0;

    // Zone 7------------------------------------
    // When using ready, ACTIVE must be 1 or greater
    // Lead must always be 1 or greater
    // Zone write timing
    XintfRegs.XTIMING7.bit.XWRLEAD = 1;
    XintfRegs.XTIMING7.bit.XWRACTIVE = 2;
    XintfRegs.XTIMING7.bit.XWRTRAIL = 1;
    // Zone read timing
    XintfRegs.XTIMING7.bit.XRDLEAD = 1;
    XintfRegs.XTIMING7.bit.XRDACTIVE = 3;
    XintfRegs.XTIMING7.bit.XRDTRAIL = 0;

    // don't double all Zone read/write lead/active/trail timing
    XintfRegs.XTIMING7.bit.X2TIMING = 0;

    // Zone will not sample XREADY signal
    XintfRegs.XTIMING7.bit.USEREADY = 0;
    XintfRegs.XTIMING7.bit.READYMODE = 0;

    // 1,1 = x16 data bus
    // 0,1 = x32 data bus
    // other values are reserved
    XintfRegs.XTIMING7.bit.XSIZE = 3;
    EDIS;
    //Force a pipeline flush to ensure that the write to
    //the last register configured occurs before returning.
    asm(" RPT #7 || NOP");
}
void DMACH1_Init(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source)
{
#ifdef DMA_INT_ENABLE
	// Interrupts that are used in this example are re-mapped to
	// ISR functions found within this file.
	EALLOW;	// Allow access to EALLOW protected registers
	PieVectTable.DINTCH1= &local_DINTCH1_ISR;
	EDIS;   // Disable access to EALLOW protected registers

	IER = M_INT7 ;	                             //Enable INT7 (7.1 DMA Ch1)
	EnableInterrupts();
#endif

	// Initialize DMA
	DMAInitialize(); //复位DMA和允许DMA在仿真暂停时运行
	init_zone7();    //

	//使用通道DMA通道1 进行ADC的数据传输,设置ADC排序为seq1、单次触发模式等
	DMACH1AddrConfig(DMA_Dest,DMA_Source);//设置DMA的源和目标地址
	DMACH1BurstConfig(31,2,2);//设置每次突发的字节数、源地址增量、目标地址增量
	DMACH1TransferConfig(31,2,2);//设置每次传送包含多少个突发、源地址增量、目标地址增量
	DMACH1WrapConfig(0xFFFF,0,0xFFFF,0);//设置传送完毕的源地址和目标地址

	//设置DMA工作模式,
	//包括 触发源、触发源是否使能、是否使能oneshot模式、是否使能连续模式
	//是否使能外围设备同步、选择同步模式、溢出中断等等
	DMACH1ModeConfig(DMA_TINT0,PERINT_ENABLE,ONESHOT_ENABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,OVRFLOW_DISABLE,THIRTYTWO_BIT,CHINT_END,CHINT_ENABLE);

	StartDMACH1();
}
eCAP脉冲捕获,重点啦
  • 需求:通过CAP捕获F28335的ePWM5A产生的PWM脉冲信号,并得到输入信号的频率

  • F28335专门设置了脉冲捕获模块eCAP来处理脉冲量

  • 本质为捕获脉冲量的上升沿和下降沿 ==》 计算除脉宽以及占空比(周期)

  • F28335内含6组eCAP模块,其处理捕获之外,还可以产生PWM脉冲信号(APWM操作模式)
    在这里插入图片描述

  • 捕获的原理

    • 捕获单元记录下定时器的时间,两个下降沿之间的时间差值就是脉冲周期即脉冲频率。
    • 同理也可以捕获脉冲的上升沿,计算上升沿与下降沿之间的时间差值即可或得占空比,
  • eCAP 配置步骤:

    • (1)使能 eCAP 外设时钟
    • (2)初始化 GPIO 为 eCAP1 功能,即选择 GPIO 复用功能
    • (3)eCAP 外设相关参数设置,包括捕捉模式、捕获边沿信号、捕获后计数器是否清零、捕获中断等。
    • (4)编写中断函数。
//=========================================
//配置ePWM5产生pwm波
//=========================================
//setting the value of tbprd   
#define PWM5_TIMER_MIN     10
#define PWM5_TIMER_MAX     8000

// To keep track of which way the timer value is moving
#define EPWM_TIMER_UP   1
#define EPWM_TIMER_DOWN 0

// Global variables used in this example
Uint32  ECap1IntCount=0;
Uint32  ECap1PassCount=0;
Uint32  EPwm5TimerDirection=EPWM_TIMER_UP;

void EPWM5_Init(Uint16 tbprd)
{
	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
	SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 1;  // ePWM5
	EDIS;

	InitEPwm5Gpio();

	EPwm5Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
	EPwm5Regs.TBPRD = tbprd;
	EPwm5Regs.TBPHS.all = 0x00000000;
	EPwm5Regs.AQCTLA.bit.PRD = AQ_TOGGLE;      // Toggle on PRD

	// TBCLK = SYSCLKOUT
	EPwm5Regs.TBCTL.bit.HSPCLKDIV = 1;
	EPwm5Regs.TBCTL.bit.CLKDIV = 0;

	EALLOW;
	SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
	EDIS;
}
//=========================================
//配置eCAP对ePWM5A进行捕获,从而得到频率
//=========================================
__interrupt void ecap1_isr(void);
void Fail();

void eCAP1_Init(void)
{
	// 使能eCAP外设时钟
	EALLOW;
	SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1;  // eCAP1
	EDIS;

	//初始化引脚,即GPIO多路复用
	InitECap1Gpio();
	
	//eCAP外设相关参数设置
	ECap1Regs.ECCTL2.bit.CONT_ONESHT = 1;      // One-shot
	ECap1Regs.ECCTL2.bit.STOP_WRAP = 3;        // Stop at 4 events
	ECap1Regs.ECCTL1.bit.CAP1POL = 1;          // Falling edge
	ECap1Regs.ECCTL1.bit.CAP2POL = 0;          // Rising edge
	ECap1Regs.ECCTL1.bit.CAP3POL = 1;          // Falling edge
	ECap1Regs.ECCTL1.bit.CAP4POL = 0;          // Rising edge
	ECap1Regs.ECCTL1.bit.CTRRST1 = 1;          // Difference operation
	ECap1Regs.ECCTL1.bit.CTRRST2 = 1;          // Difference operation
	ECap1Regs.ECCTL1.bit.CTRRST3 = 1;          // Difference operation
	ECap1Regs.ECCTL1.bit.CTRRST4 = 1;          // Difference operation
	ECap1Regs.ECCTL2.bit.SYNCI_EN = 1;         // Enable sync in
	ECap1Regs.ECCTL2.bit.SYNCO_SEL = 0;        // Pass through
	ECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture units

	ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;        // Start Counter
	ECap1Regs.ECCTL2.bit.REARM = 1;            // arm one-shot
	ECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable CAP1-CAP4 register loads
	ECap1Regs.ECEINT.bit.CEVT4 = 1;            // 4 events = interrupt

	//中断服务函数映射
	EALLOW;  // This is needed to write to EALLOW protected registers
	PieVectTable.ECAP1_INT = &ecap1_isr;
	EDIS;    // This is needed to disable write to EALLOW protected registers
	
	//PIE中断配置
	// Enable CPU INT4 which is connected to ECAP1-4 INT:
	IER |= M_INT4;
	// Enable eCAP INTn in the PIE: Group 3 interrupt 1-6
	PieCtrlRegs.PIEIER4.bit.INTx1 = 1;
	// Enable global Interrupts and higher priority real-time debug events:
	EINT;   // Enable Global interrupt INTM
	ERTM;   // Enable Global realtime interrupt DBGM
}

// 当eCAP1连续捕获到4次边沿信号就立马进入中断
__interrupt void ecap1_isr(void)
{
	if(ECap1Regs.CAP2 > EPwm5Regs.TBPRD*2+1 || ECap1Regs.CAP2 < EPwm5Regs.TBPRD*2-1)
	{
	    Fail();
	}

	if(ECap1Regs.CAP3 > EPwm5Regs.TBPRD*2+1 || ECap1Regs.CAP3 < EPwm5Regs.TBPRD*2-1)
	{
	    Fail();
	}

	if(ECap1Regs.CAP4 > EPwm5Regs.TBPRD*2+1 || ECap1Regs.CAP4 < EPwm5Regs.TBPRD*2-1)
	{
	    Fail();
	}

	ECap1IntCount++;  // 主要监控

	if(EPwm5TimerDirection == EPWM_TIMER_UP)
	{
		if(EPwm5Regs.TBPRD < PWM5_TIMER_MAX)
		{
			EPwm5Regs.TBPRD++;
		}
		else
		{
			EPwm5TimerDirection = EPWM_TIMER_DOWN;
			EPwm5Regs.TBPRD--;
		}
	 }
	 else
	 {
	    if(EPwm5Regs.TBPRD > PWM5_TIMER_MIN)
	    {
	        EPwm5Regs.TBPRD--;
	    }
	    else
	    {
	        EPwm5TimerDirection = EPWM_TIMER_UP;
	        EPwm5Regs.TBPRD++;
	    }
	  }

	  ECap1PassCount++;// 主要监控

	  ECap1Regs.ECCLR.bit.CEVT4 = 1;
	  ECap1Regs.ECCLR.bit.INT = 1;
	  ECap1Regs.ECCTL2.bit.REARM = 1;

	  // Acknowledge this interrupt to receive more interrupts from group 4
	  PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;

	 //通过 ECap1Regs.CAP2 或者 ECap1Regs.CAP3 值就可以计算出 ePWM5 输出的脉冲频率
}

void Fail()
{
    __asm("   ESTOP0");
}
eCAP输出PWM(APWM模式),重点啦
void eCAP1_APWM_Init(void)
{
	EALLOW;
	SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1;  // eCAP1
	EDIS;

	InitECap1Gpio();

	// Setup APWM mode on CAP1, set period and compare registers
	ECap1Regs.ECCTL2.bit.CAP_APWM = 1;	// Enable APWM mode
	ECap1Regs.CAP1 = 0x01312D00;			// Set Period value
	ECap1Regs.CAP2 = 0x00989680;			// Set Compare value
	ECap1Regs.ECCLR.all = 0x0FF;			// Clear pending interrupts
	ECap1Regs.ECEINT.bit.CTR_EQ_CMP = 1; // enable Compare Equal Int

	// Start counters
	ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;
}

//========================================================
//main.c里面的使用apwm的情况
//========================================================
eCAP1_APWM_Init();

while(1)
{
	// set next duty cycle to 50%
	ECap1Regs.CAP4 = ECap1Regs.CAP1 >> 1;

	// vary freq between 7.5 Hz and 15 Hz (for 150MHz SYSCLKOUT) 5 Hz and 10 Hz (for 100 MHz SYSCLKOUT)
	if(ECap1Regs.CAP1 >= 0x01312D00)
	{
		direction = 0;
	}
	else if (ECap1Regs.CAP1 <= 0x00989680)
	{
		direction = 1;
	}

	if(direction == 0)
	{
		ECap1Regs.CAP3 = ECap1Regs.CAP1 - 500000;
	}
	else
	{
		ECap1Regs.CAP3 = ECap1Regs.CAP1 + 500000;
	}
}
eQEP正交编码器,重点啦,=====不理解
  • 需求:通过eQEP1模块测量ePWM1A输出的脉冲信号频率及其周期
  • F28335的eQEP模块通过应用正交编码器不仅可以获取速度信息,还可以获取方向以及位置信息
  • F28335的有2路eQEP模块,每个模块四个引脚(QEPA/XCLK、
    QEPB/XDIR、eQEPI 和 QPES),
  • 模式
    • (1)正交时钟模式:前两个引脚被使用在正交时钟模式。正交编码器提供两路相位差为 90 度的脉冲,相位关系决定了电机旋转方向信息,脉冲的个数可以决定电机的绝对位置信息。
    • (2)直接计数模式:此时 QEPA 引脚提供时钟输入。QEPB 引脚提供方向输入。引脚 eQEPI 是索引或者起始标记脚。QEPS 是锁存输入引脚,是否达到预定位置。
  • eQEP配置步骤:
    • (1)使能 eQEP1 外设时钟
    • (2)初始化 GPIO 为 eQEP1 功能,即选择 GPIO 复用功能
    • (3)eQEP1 外设相关参数设置,包括 QEP 计数模式、自由运行、QEP 位置计数器在索引事件复位、单位事件使能、QEP 模块使能等。
//============================================
// 配置EPWM1
//============================================
interrupt void prdTick(void);
void EPwm1Setup(void)
{
    InitEPwm1Gpio();
    
	EPwm1Regs.TBSTS.all=0;
	EPwm1Regs.TBPHS.half.TBPHS=0;
	EPwm1Regs.TBCTR=0;

	EPwm1Regs.CMPCTL.all=0x50;        // Immediate mode for CMPA and CMPB
	EPwm1Regs.CMPA.half.CMPA =SP/2;
	EPwm1Regs.CMPB=0;

	EPwm1Regs.AQCTLA.all=0x60;        // EPWMxA = 1 when CTR=CMPA and counter inc
	                                  // EPWMxA = 0 when CTR=CMPA and counter dec
	EPwm1Regs.AQCTLB.all=0;
	EPwm1Regs.AQSFRC.all=0;
	EPwm1Regs.AQCSFRC.all=0;

	EPwm1Regs.DBCTL.all=0xb;          // EPWMxB is inverted
	EPwm1Regs.DBRED=0;
	EPwm1Regs.DBFED=0;

	EPwm1Regs.TZSEL.all=0;
	EPwm1Regs.TZCTL.all=0;
	EPwm1Regs.TZEINT.all=0;
	EPwm1Regs.TZFLG.all=0;
	EPwm1Regs.TZCLR.all=0;
	EPwm1Regs.TZFRC.all=0;

	EPwm1Regs.ETSEL.all=9;            // Interrupt when TBCTR = 0x0000
	EPwm1Regs.ETPS.all=1;	          // Interrupt on first event
	EPwm1Regs.ETFLG.all=0;
	EPwm1Regs.ETCLR.all=0;
	EPwm1Regs.ETFRC.all=0;

	EPwm1Regs.PCCTL.all=0;

	EPwm1Regs.TBCTL.all=0x0010+TBCTLVAL;			// Enable Timer
	EPwm1Regs.TBPRD=SP;

	EALLOW;  // This is needed to write to EALLOW protected registers
	PieVectTable.EPWM1_INT= &prdTick;
	EDIS;

	IER |= M_INT3;
	PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
	EINT;   // Enable Global interrupt INTM
	ERTM;   // Enable Global realtime interrupt DBGM
}

interrupt void prdTick(void) // Interrupts once per ePWM period
{
   freq.calc(&freq); // Checks for event and calculates frequency in FREQCAL_Calc(FREQCAL *p)
                     // function in Example_EPwmSetup.c
   // Acknowledge this interrupt to receive more interrupts from group 1
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
   EPwm1Regs.ETCLR.bit.INT=1;
}

//==========================================
// 配置eQEP正交编码器
//==========================================
void EQEP1_Init(void)
{
	EALLOW;  // This is needed to write to EALLOW protected registers
	SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1;  // eQEP1
	EDIS;

	InitEQep1Gpio();

	EPwm1Setup();

	freq.init();   // Initializes eQEP for frequency calculation in
						// FREQCAL_Init(void)function in Example_EPwmSetup.c
}

//==========================================
// 基于 IQmath library  ,来计算频率及其周期  
//==========================================
void  FREQCAL_Init(void)
{
    #if (CPU_FRQ_150MHZ)
	  EQep1Regs.QUPRD=1500000;			// Unit Timer for 100Hz at 150MHz SYSCLKOUT
	#endif
    #if (CPU_FRQ_100MHZ)
	  EQep1Regs.QUPRD=1000000;			// Unit Timer for 100Hz at 100MHz SYSCLKOUT
	#endif

	EQep1Regs.QDECCTL.bit.QSRC=2;		// Up count mode (freq. measurement)
	EQep1Regs.QDECCTL.bit.XCR=0;        // 2x resolution (cnt falling and rising edges)

	EQep1Regs.QEPCTL.bit.FREE_SOFT=2;
	EQep1Regs.QEPCTL.bit.PCRM=00;		// QPOSCNT reset on index evnt
	EQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timer Enable
	EQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time out
	EQep1Regs.QPOSMAX=0xffffffff;
	EQep1Regs.QEPCTL.bit.QPEN=1; 		// QEP enable

	#if (CPU_FRQ_150MHZ)
	  EQep1Regs.QCAPCTL.bit.UPPS=2;   	// 1/4 for unit position at 150MHz SYSCLKOUT
	#endif
	#if (CPU_FRQ_100MHZ)
	  EQep1Regs.QCAPCTL.bit.UPPS=3;   	// 1/8 for unit position at 100MHz SYSCLKOUT
	#endif

	EQep1Regs.QCAPCTL.bit.CCPS=7;		// 1/128 for CAP clock
	EQep1Regs.QCAPCTL.bit.CEN=1; 		// QEP Capture Enable
}

void FREQCAL_Calc(FREQCAL *p)
{
     unsigned long tmp;
   	 _iq newp,oldp;

//**** Freq Calcultation using QEP position counter ****//
// Check unit Time out-event for speed calculation:
// Unit Timer is configured for 100Hz in INIT function

// For a more detailed explanation of the calculation, read
// the description at the top of this file

	if(EQep1Regs.QFLG.bit.UTO==1)                  // Unit Timeout event
	{
		/** Differentiator	**/
	 	newp=EQep1Regs.QPOSLAT;                    // Latched POSCNT value
		oldp=p->oldpos;

    	if (newp>oldp)
      		tmp = newp - oldp;                     // x2-x1 in v=(x2-x1)/T equation
    	else
      		tmp = (0xFFFFFFFF-oldp)+newp;

		p->freq_fr = _IQdiv(tmp,p->freqScaler_fr); // p->freq_fr = (x2-x1)/(T*10KHz)
		tmp=p->freq_fr;

		if (tmp>=_IQ(1))          // is freq greater than max freq (10KHz for this example)?
	 		p->freq_fr = _IQ(1);
		else
	 		p->freq_fr = tmp;

		p->freqhz_fr = _IQmpy(p->BaseFreq,p->freq_fr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
		                                                // p->freqhz_fr = (p->freq_fr)*10kHz = (x2-x1)/T

		// Update position counter
    	p->oldpos = newp;
		//=======================================

		EQep1Regs.QCLR.bit.UTO=1;					// Clear interrupt flag
	}

//**** Freq Calcultation using QEP capture counter ****//
	if(EQep1Regs.QEPSTS.bit.UPEVNT==1)              // Unit Position Event
	{
		if(EQep1Regs.QEPSTS.bit.COEF==0)            // No Capture overflow
			tmp=(unsigned long)EQep1Regs.QCPRDLAT;
		else							            // Capture overflow, saturate the result
			tmp=0xFFFF;

		p->freq_pr = _IQdiv(p->freqScaler_pr,tmp);  // p->freq_pr = X/[(t2-t1)*10KHz]
		tmp=p->freq_pr;

		if (tmp>_IQ(1))
	 		p->freq_pr = _IQ(1);
		else
	 		p->freq_pr = tmp;

		p->freqhz_pr = _IQmpy(p->BaseFreq,p->freq_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
	                                                    // p->freqhz_pr =( p->freq_pr)*10kHz = X/(t2-t1)
		EQep1Regs.QEPSTS.all=0x88;					    // Clear Unit position event flag
												     	// Clear overflow error flag
	}
}
eQEP实现位置速度测量,+ IQmath库 ====不理解
  • 且使用了 IQMath 库。它仅用于简化高精度计算、
POSSPEED qep_posspeed=POSSPEED_DEFAULTS;
Uint16 Interrupt_Count = 0;

interrupt void prdTick(void);

void EPwm1Setup(void)
{
    InitEPwm1Gpio();

    EALLOW;
	GpioCtrlRegs.GPADIR.bit.GPIO4 = 1;    // GPIO4 as output simulates Index signal
	GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;  // Normally low
	EDIS;

	EPwm1Regs.TBSTS.all=0;
	EPwm1Regs.TBPHS.half.TBPHS =0;
	EPwm1Regs.TBCTR=0;

	EPwm1Regs.CMPCTL.all=0x50;     // immediate mode for CMPA and CMPB
	EPwm1Regs.CMPA.half.CMPA=SP/2;
	EPwm1Regs.CMPB=0;

	EPwm1Regs.AQCTLA.all=0x60;     // CTR=CMPA when inc->EPWM1A=1, when dec->EPWM1A=0
	EPwm1Regs.AQCTLB.all=0x09;     // CTR=PRD ->EPWM1B=1, CTR=0 ->EPWM1B=0
	EPwm1Regs.AQSFRC.all=0;
	EPwm1Regs.AQCSFRC.all=0;

	EPwm1Regs.TZSEL.all=0;
	EPwm1Regs.TZCTL.all=0;
	EPwm1Regs.TZEINT.all=0;
	EPwm1Regs.TZFLG.all=0;
	EPwm1Regs.TZCLR.all=0;
	EPwm1Regs.TZFRC.all=0;

	EPwm1Regs.ETSEL.all=0x0A;      // Interrupt on PRD
	EPwm1Regs.ETPS.all=1;
	EPwm1Regs.ETFLG.all=0;
	EPwm1Regs.ETCLR.all=0;
	EPwm1Regs.ETFRC.all=0;

	EPwm1Regs.PCCTL.all=0;

	EPwm1Regs.TBCTL.all=0x0010+TBCTLVAL; // Enable Timer
	EPwm1Regs.TBPRD=SP;

	EALLOW;  // This is needed to write to EALLOW protected registers
	PieVectTable.EPWM1_INT= &prdTick;
	EDIS;

	IER |= M_INT3;
	PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
	EINT;   // Enable Global interrupt INTM
	ERTM;   // Enable Global realtime interrupt DBGM

}

void EQEP1_Init(void)
{
	EALLOW;  // This is needed to write to EALLOW protected registers
	SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1;  // eQEP1
	EDIS;

	InitEQep1Gpio();

	EPwm1Setup();

	qep_posspeed.init(&qep_posspeed);
}

interrupt void prdTick(void)                  // EPWM1 Interrupts once every 4 QCLK counts (one period)
{
	Uint16 i;
	// Position and Speed measurement
	qep_posspeed.calc(&qep_posspeed);  //基于IQmath库来计算位置与速度

	// Control loop code for position control & Speed contol
	Interrupt_Count++;
	if (Interrupt_Count==1000)                 // Every 1000 interrupts(4000 QCLK counts or 1 rev.)
	{
		EALLOW;
		GpioDataRegs.GPASET.bit.GPIO4 = 1;     // Pulse Index signal  (1 pulse/rev.)
		for (i=0; i<700; i++){
	}
	GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
	Interrupt_Count = 0;                   // Reset count
	EDIS;
	}

	// Acknowledge this interrupt to receive more interrupts from group 1
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
	EPwm1Regs.ETCLR.bit.INT=1;

void  POSSPEED_Init(void)
{

    #if (CPU_FRQ_150MHZ)
	  EQep1Regs.QUPRD=1500000;			// Unit Timer for 100Hz at 150 MHz SYSCLKOUT
	#endif
    #if (CPU_FRQ_100MHZ)
	  EQep1Regs.QUPRD=1000000;			// Unit Timer for 100Hz at 100 MHz SYSCLKOUT
	#endif	

	EQep1Regs.QDECCTL.bit.QSRC=00;		// QEP quadrature count mode
		
	EQep1Regs.QEPCTL.bit.FREE_SOFT=2;
	EQep1Regs.QEPCTL.bit.PCRM=00;		// PCRM=00 mode - QPOSCNT reset on index event
	EQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timeout Enable 
	EQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time out
	EQep1Regs.QPOSMAX=0xffffffff;
	EQep1Regs.QEPCTL.bit.QPEN=1; 		// QEP enable
		
	EQep1Regs.QCAPCTL.bit.UPPS=5;   	// 1/32 for unit position
	EQep1Regs.QCAPCTL.bit.CCPS=7;		// 1/128 for CAP clock
	EQep1Regs.QCAPCTL.bit.CEN=1; 		// QEP Capture Enable
	

}

void POSSPEED_Calc(POSSPEED *p)
{
     long tmp;
     unsigned int pos16bval,temp1;
   	 _iq Tmp1,newp,oldp;

//**** Position calculation - mechanical and electrical motor angle  ****//     
     p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF;    // Motor direction: 0=CCW/reverse, 1=CW/forward

	 pos16bval=(unsigned int)EQep1Regs.QPOSCNT;     // capture position once per QA/QB period
     p->theta_raw = pos16bval+ p->cal_angle;        // raw theta = current pos. + ang. offset from QA
	 
	 // The following lines calculate p->theta_mech ~= QPOSCNT/mech_scaler [current cnt/(total cnt in 1 rev.)]
	 // where mech_scaler = 4000 cnts/revolution
     tmp = (long)((long)p->theta_raw*(long)p->mech_scaler);  	// Q0*Q26 = Q26 
     tmp &= 0x03FFF000;                                        
     p->theta_mech = (int)(tmp>>11);         		// Q26 -> Q15 
     p->theta_mech &= 0x7FFF;                       
	 
	 // The following lines calculate p->elec_mech    
     p->theta_elec = p->pole_pairs*p->theta_mech;  // Q0*Q15 = Q15 
     p->theta_elec &= 0x7FFF;                      

// Check an index occurrence
     if (EQep1Regs.QFLG.bit.IEL == 1)                   
     {  
    	p->index_sync_flag = 0x00F0;
    	EQep1Regs.QCLR.bit.IEL=1;					// Clear interrupt flag
     }
      
//**** High Speed Calcultation using QEP Position counter ****//
// Check unit Time out-event for speed calculation:
// Unit Timer is configured for 100Hz in INIT function

	if(EQep1Regs.QFLG.bit.UTO==1)                    // If unit timeout (one 100Hz period)
	{ 
		/** Differentiator	**/
		// The following lines calculate position = (x2-x1)/4000 (position in 1 revolution)
	 	pos16bval=(unsigned int)EQep1Regs.QPOSLAT;	              // Latched POSCNT value		
     	tmp = (long)((long)pos16bval*(long)p->mech_scaler);  	  // Q0*Q26 = Q26 
     	tmp &= 0x03FFF000;
     	tmp = (int)(tmp>>11);         			                  // Q26 -> Q15 
     	tmp &= 0x7FFF;
		newp=_IQ15toIQ(tmp);
		oldp=p->oldpos;

   		if (p->DirectionQep==0)      				// POSCNT is counting down
   		{
    		if (newp>oldp)
      			Tmp1 = - (_IQ(1) - newp + oldp);    // x2-x1 should be negative
    		else
      		Tmp1 = newp -oldp;
   		}
   		else if (p->DirectionQep==1)      			// POSCNT is counting up
   		{
    		if (newp<oldp)
      		Tmp1 = _IQ(1) + newp - oldp;
    		else 
      		Tmp1 = newp - oldp;                     // x2-x1 should be positive
   		}

	   	if (Tmp1>_IQ(1))                            
	     	p->Speed_fr = _IQ(1);
	   	else if (Tmp1<_IQ(-1))
	     	p->Speed_fr = _IQ(-1);      
	   	else
	     	p->Speed_fr = Tmp1;

		// Update the electrical angle
    	p->oldpos = newp;
     
		// Change motor speed from pu value to rpm value (Q15 -> Q0)
		// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
   		p->SpeedRpm_fr = _IQmpy(p->BaseRpm,p->Speed_fr);  
		//=======================================
		
		EQep1Regs.QCLR.bit.UTO=1;					// Clear interrupt flag
	}	

//**** Low-speed computation using QEP capture counter ****//	
	if(EQep1Regs.QEPSTS.bit.UPEVNT==1)                 // Unit position event
	{
		if(EQep1Regs.QEPSTS.bit.COEF==0)               // No Capture overflow
			temp1=(unsigned long)EQep1Regs.QCPRDLAT;   // temp1 = t2-t1  
		else							               // Capture overflow, saturate the result
			temp1=0xFFFF;
	
		p->Speed_pr = _IQdiv(p->SpeedScaler,temp1);    // p->Speed_pr = p->SpeedScaler/temp1 
		Tmp1=p->Speed_pr;
	
		if (Tmp1>_IQ(1))
	 		p->Speed_pr = _IQ(1);   
		else
	 		p->Speed_pr = Tmp1;

	    // Convert p->Speed_pr to RPM
		if (p->DirectionQep==0)                                 // Reverse direction = negative
			p->SpeedRpm_pr = -_IQmpy(p->BaseRpm,p->Speed_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
		else                                                    // Forward direction = positive
			p->SpeedRpm_pr = _IQmpy(p->BaseRpm,p->Speed_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q

	
		EQep1Regs.QEPSTS.all=0x88;					// Clear Unit position event flag	
													// Clear overflow error flag
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋哥爱做饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值