文章目录
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
}
}