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
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: DSP28335是一款数字信号处理器,用于实现光伏系统的功率控制和并网功能。3kW单相光伏并网是指将3千瓦的光伏发电系统与电网连接,通过DSP28335对光伏系统的电流和电压进行控制,使其稳定地并网并输出电能。 在3kW单相光伏并网系统中,DSP28335起到了重要的作用。首先,它可以通过对光伏电池的输出电流和电压进行测量和采集,实时监控光伏发电系统的运行情况。其次,DSP28335可以通过适当的算法和控制策略,调节光伏系统的功率输出,保证其与电网的匹配并达到最佳工作状态。 在光伏系统并网过程中,DSP28335还具有以下功能:通过与电网的电压和频率同步,实现电能的有效输出;对光伏系统的电流、电压进行保护,防止超过额定值或发生故障,确保运行安全可靠;与电网同步控制,实现无功功率的补偿,并提供给电网所需的无功功率。 此外,DSP28335还具备通信接口,可以与光伏系统的监控系统进行通信,实现远程监控和故障诊断功能,提高系统的可靠性和运行效率。 综上所述,DSP28335在3kW单相光伏并网系统中扮演着重要角色,通过控制和管理光伏发电系统的功率输出,保证其与电网的稳定连接,并能够实现远程监控和故障诊断。它的高效性能和可靠性,使得光伏发电系统更加安全、高效、智能化。 ### 回答2: DSP28335是一款数字信号处理器,用于控制和调节光伏并网系统中的功率流动和电能转换。光伏并网系统的容量为3kW,意味着最大输出功率为3千瓦。单相光伏并网系统是在家庭和小商业环境中常见的一种光伏系统类型。 DSP28335能够通过对电流、电压和频率等重要参数进行监测和测量,来实现对光伏电能的高效转换。它可以通过高精度的PWM控制与逆变器的交流电网相连接,确保光伏系统的输出与电网的稳定性和安全性相匹配。 DSP28335还可以通过与光伏电池模块或光伏逆变器的通讯接口相连接,实现对系统性能的监测和管理。这样,在系统出现故障或异常情况下,可以及时发现并采取相应的措施,保证光伏并网系统的稳定运行。 此外,DSP28335的编程和调试功能也为光伏并网系统的设计和优化提供了便利。通过使用DSP28335的软件开发工具,可以编写自定义的控制算法,优化系统的功率输出和电能转换效率。同时,通过DSP28335的在线调试功能,可以实时监测和分析系统的运行情况,从而进一步优化系统的性能。 综上所述,DSP28335作为一款强大的数字信号处理器,在3kW单相光伏并网系统中扮演着重要的角色。它通过监测、测量和控制,确保光伏系统的输出功率与电网的稳定性相匹配。同时,它的编程和调试功能也为光伏并网系统的设计优化提供了便捷和灵活性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

栋哥爱做饭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值