> 文章列表 > dsp28335杂记3

dsp28335杂记3

dsp28335杂记3

文章目录

            • DAC实验,SPI+TLV5620
            • DAC+ADC0实验-------nice
            • DMA+ADC实验(外设到存储器)+ 中断 ==了解皮毛,嘿嘿
            • 内置XINTF接口配置 + 外扩SRAM + DMA支持 ==了解皮毛,嘿嘿
            • eCAP脉冲捕获,重点啦
            • eCAP输出PWM(APWM模式),重点啦
            • eQEP正交编码器,重点啦,=====不理解
            • eQEP实现位置速度测量,+ IQmath库 ====不理解
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-AEDIS;/*初始化GPIO;*/InitSpiaGpio();//spi的各个引脚配置//DA_LOAD  GPIO26EALLOW;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;    // ADCEDIS;// 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 modeAdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;   // A0 为采样通道AdcRegs.ADCTRL1.bit.CONT_RUN = 1;       // Setup continuous runAdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0;// Start SEQ1AdcRegs.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-AEDIS;/*初始化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 通道相关参数设置,包括指针数据长度、步长、触发源选择、触发模式等。
      dsp28335杂记3
    • (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;    // ADCEDIS;// Specific clock setting for this example:EALLOW;SysCtrlRegs.HISPCP.all = 3;	// HSPCLK = SYSCLKOUT/ADC_MODCLKEDIS;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 ModeAdcRegs.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 SEQ1AdcRegs.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 registersPieVectTable.DINTCH1= &local_DINTCH1_ISR;EDIS;   // Disable access to EALLOW protected registersIER = M_INT7 ;	                             //Enable INT7 (7.1 DMA Ch1)EnableInterrupts();
#endifEALLOW;SysCtrlRegs.PCLKCR3.bit.DMAENCLK = 1;       // DMA ClockEDIS;// Initialize DMADMAInitialize();// Configure DMA ChannelDMACH1AddrConfig(DMA_Dest,DMA_Source);DMACH1BurstConfig(15,0,1);         //Will set up to use 32-bit datasize, pointers are based on 16-bit wordsDMACH1TransferConfig(9,0,1);      //so need to increment by 2 to grab the correct locationDMACH1WrapConfig(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 timeDMACH1ModeConfig(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 interruptPieCtrlRegs.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 DMADmaRegs.DMACTRL.bit.HARDRESET = 1;// Allow DMA to run free on emulation suspendDmaRegs.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 enabledSysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1;EDIS;// Configure the GPIO for XINTF with a 16-bit data bus// This function is in DSP2833x_Xintf.cInitXintf16Gpio();// All Zones---------------------------------// Timing for all zones based on XTIMCLK = SYSCLKOUTEALLOW;XintfRegs.XINTCNF2.bit.XTIMCLK = 0;// Buffer up to 3 writesXintfRegs.XINTCNF2.bit.WRBUFF = 3;// XCLKOUT is enabledXintfRegs.XINTCNF2.bit.CLKOFF = 0;// XCLKOUT = XTIMCLKXintfRegs.XINTCNF2.bit.CLKMODE = 0;// Zone 7------------------------------------// When using ready, ACTIVE must be 1 or greater// Lead must always be 1 or greater// Zone write timingXintfRegs.XTIMING7.bit.XWRLEAD = 1;XintfRegs.XTIMING7.bit.XWRACTIVE = 2;XintfRegs.XTIMING7.bit.XWRTRAIL = 1;// Zone read timingXintfRegs.XTIMING7.bit.XRDLEAD = 1;XintfRegs.XTIMING7.bit.XRDACTIVE = 3;XintfRegs.XTIMING7.bit.XRDTRAIL = 0;// don't double all Zone read/write lead/active/trail timingXintfRegs.XTIMING7.bit.X2TIMING = 0;// Zone will not sample XREADY signalXintfRegs.XTIMING7.bit.USEREADY = 0;XintfRegs.XTIMING7.bit.READYMODE = 0;// 1,1 = x16 data bus// 0,1 = x32 data bus// other values are reservedXintfRegs.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 registersPieVectTable.DINTCH1= &local_DINTCH1_ISR;EDIS;   // Disable access to EALLOW protected registersIER = M_INT7 ;	                             //Enable INT7 (7.1 DMA Ch1)EnableInterrupts();
#endif// Initialize DMADMAInitialize(); //复位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操作模式)
    dsp28335杂记3

  • 捕获的原理

    • 捕获单元记录下定时器的时间,两个下降沿之间的时间差值就是脉冲周期即脉冲频率。
    • 同理也可以捕获脉冲的上升沿,计算上升沿与下降沿之间的时间差值即可或得占空比,
  • 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;  // ePWM5EDIS;InitEPwm5Gpio();EPwm5Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count upEPwm5Regs.TBPRD = tbprd;EPwm5Regs.TBPHS.all = 0x00000000;EPwm5Regs.AQCTLA.bit.PRD = AQ_TOGGLE;      // Toggle on PRD// TBCLK = SYSCLKOUTEPwm5Regs.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;  // eCAP1EDIS;//初始化引脚,即GPIO多路复用InitECap1Gpio();//eCAP外设相关参数设置ECap1Regs.ECCTL2.bit.CONT_ONESHT = 1;      // One-shotECap1Regs.ECCTL2.bit.STOP_WRAP = 3;        // Stop at 4 eventsECap1Regs.ECCTL1.bit.CAP1POL = 1;          // Falling edgeECap1Regs.ECCTL1.bit.CAP2POL = 0;          // Rising edgeECap1Regs.ECCTL1.bit.CAP3POL = 1;          // Falling edgeECap1Regs.ECCTL1.bit.CAP4POL = 0;          // Rising edgeECap1Regs.ECCTL1.bit.CTRRST1 = 1;          // Difference operationECap1Regs.ECCTL1.bit.CTRRST2 = 1;          // Difference operationECap1Regs.ECCTL1.bit.CTRRST3 = 1;          // Difference operationECap1Regs.ECCTL1.bit.CTRRST4 = 1;          // Difference operationECap1Regs.ECCTL2.bit.SYNCI_EN = 1;         // Enable sync inECap1Regs.ECCTL2.bit.SYNCO_SEL = 0;        // Pass throughECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable capture unitsECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;        // Start CounterECap1Regs.ECCTL2.bit.REARM = 1;            // arm one-shotECap1Regs.ECCTL1.bit.CAPLDEN = 1;          // Enable CAP1-CAP4 register loadsECap1Regs.ECEINT.bit.CEVT4 = 1;            // 4 events = interrupt//中断服务函数映射EALLOW;  // This is needed to write to EALLOW protected registersPieVectTable.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-6PieCtrlRegs.PIEIER4.bit.INTx1 = 1;// Enable global Interrupts and higher priority real-time debug events:EINT;   // Enable Global interrupt INTMERTM;   // 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 4PieCtrlRegs.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;  // eCAP1EDIS;InitECap1Gpio();// Setup APWM mode on CAP1, set period and compare registersECap1Regs.ECCTL2.bit.CAP_APWM = 1;	// Enable APWM modeECap1Regs.CAP1 = 0x01312D00;			// Set Period valueECap1Regs.CAP2 = 0x00989680;			// Set Compare valueECap1Regs.ECCLR.all = 0x0FF;			// Clear pending interruptsECap1Regs.ECEINT.bit.CTR_EQ_CMP = 1; // enable Compare Equal Int// Start countersECap1Regs.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 CMPBEPwm1Regs.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 decEPwm1Regs.AQCTLB.all=0;EPwm1Regs.AQSFRC.all=0;EPwm1Regs.AQCSFRC.all=0;EPwm1Regs.DBCTL.all=0xb;          // EPWMxB is invertedEPwm1Regs.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 = 0x0000EPwm1Regs.ETPS.all=1;	          // Interrupt on first eventEPwm1Regs.ETFLG.all=0;EPwm1Regs.ETCLR.all=0;EPwm1Regs.ETFRC.all=0;EPwm1Regs.PCCTL.all=0;EPwm1Regs.TBCTL.all=0x0010+TBCTLVAL;			// Enable TimerEPwm1Regs.TBPRD=SP;EALLOW;  // This is needed to write to EALLOW protected registersPieVectTable.EPWM1_INT= &prdTick;EDIS;IER |= M_INT3;PieCtrlRegs.PIEIER3.bit.INTx1 = 1;EINT;   // Enable Global interrupt INTMERTM;   // 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 1PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;EPwm1Regs.ETCLR.bit.INT=1;
}//==========================================
// 配置eQEP正交编码器
//==========================================
void EQEP1_Init(void)
{EALLOW;  // This is needed to write to EALLOW protected registersSysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1;  // eQEP1EDIS;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#endifEQep1Regs.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 evntEQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timer EnableEQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time outEQep1Regs.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#endifEQep1Regs.QCAPCTL.bit.CCPS=7;		// 1/128 for CAP clockEQep1Regs.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 fileif(EQep1Regs.QFLG.bit.UTO==1)                  // Unit Timeout event{/** Differentiator	**/newp=EQep1Regs.QPOSLAT;                    // Latched POSCNT valueoldp=p->oldpos;if (newp>oldp)tmp = newp - oldp;                     // x2-x1 in v=(x2-x1)/T equationelsetmp = (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);elsep->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 counterp->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 overflowtmp=(unsigned long)EQep1Regs.QCPRDLAT;else							            // Capture overflow, saturate the resulttmp=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);elsep->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 signalGpioDataRegs.GPACLEAR.bit.GPIO4 = 1;  // Normally lowEDIS;EPwm1Regs.TBSTS.all=0;EPwm1Regs.TBPHS.half.TBPHS =0;EPwm1Regs.TBCTR=0;EPwm1Regs.CMPCTL.all=0x50;     // immediate mode for CMPA and CMPBEPwm1Regs.CMPA.half.CMPA=SP/2;EPwm1Regs.CMPB=0;EPwm1Regs.AQCTLA.all=0x60;     // CTR=CMPA when inc->EPWM1A=1, when dec->EPWM1A=0EPwm1Regs.AQCTLB.all=0x09;     // CTR=PRD ->EPWM1B=1, CTR=0 ->EPWM1B=0EPwm1Regs.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 PRDEPwm1Regs.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 TimerEPwm1Regs.TBPRD=SP;EALLOW;  // This is needed to write to EALLOW protected registersPieVectTable.EPWM1_INT= &prdTick;EDIS;IER |= M_INT3;PieCtrlRegs.PIEIER3.bit.INTx1 = 1;EINT;   // Enable Global interrupt INTMERTM;   // Enable Global realtime interrupt DBGM}void EQEP1_Init(void)
{EALLOW;  // This is needed to write to EALLOW protected registersSysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1;  // eQEP1EDIS;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 measurementqep_posspeed.calc(&qep_posspeed);  //基于IQmath库来计算位置与速度// Control loop code for position control & Speed contolInterrupt_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 countEDIS;}// Acknowledge this interrupt to receive more interrupts from group 1PieCtrlRegs.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 modeEQep1Regs.QEPCTL.bit.FREE_SOFT=2;EQep1Regs.QEPCTL.bit.PCRM=00;		// PCRM=00 mode - QPOSCNT reset on index eventEQep1Regs.QEPCTL.bit.UTE=1; 		// Unit Timeout Enable EQep1Regs.QEPCTL.bit.QCLM=1; 		// Latch on unit time outEQep1Regs.QPOSMAX=0xffffffff;EQep1Regs.QEPCTL.bit.QPEN=1; 		// QEP enableEQep1Regs.QCAPCTL.bit.UPPS=5;   	// 1/32 for unit positionEQep1Regs.QCAPCTL.bit.CCPS=7;		// 1/128 for CAP clockEQep1Regs.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/forwardpos16bval=(unsigned int)EQep1Regs.QPOSCNT;     // capture position once per QA/QB periodp->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/revolutiontmp = (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 occurrenceif (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 functionif(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 negativeelseTmp1 = 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);      elsep->Speed_fr = Tmp1;// Update the electrical anglep->oldpos = newp;// Change motor speed from pu value to rpm value (Q15 -> Q0)// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Qp->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 overflowtemp1=(unsigned long)EQep1Regs.QCPRDLAT;   // temp1 = t2-t1  else							               // Capture overflow, saturate the resulttemp1=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);   elsep->Speed_pr = Tmp1;// Convert p->Speed_pr to RPMif (p->DirectionQep==0)                                 // Reverse direction = negativep->SpeedRpm_pr = -_IQmpy(p->BaseRpm,p->Speed_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Qelse                                                    // Forward direction = positivep->SpeedRpm_pr = _IQmpy(p->BaseRpm,p->Speed_pr); 	// Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_QEQep1Regs.QEPSTS.all=0x88;					// Clear Unit position event flag	// Clear overflow error flag}
}