目录
系统时钟
C28x Core是CPU,CLKIN信号送入CPU后,经过CPU的分发,作为SYSCLKOUT信号送往各个外设,因此:S Y S C L K O U T = C L K I N ,但是部分低速外设还需要经过LOSPCP寄存器变成LSPCLK后提供给相关外设。进行ADC,SCI等相关外设的设置时需要知道这个具体的频率数值来进行计算。
从上图可以看出SPI-A,SPI-B,SCI-A的时钟来自低速外设时钟LSPCLK; eCAN-A,LIN-A的时钟由SYSCLKOUT的二分频获得; 其它外设的时钟都是SYSCLKOUT。其中LSPCLK的大小由LOSPCP寄存器所设置,如下图:
TMS320x2803x系列(28035为例)的时钟源选择,如下图:
时钟源选择
2803x系列DSP有两个内部时钟源(INTOSC1和INTOSC2),可以不需要外部时钟。同时,也具有PLL时钟模块。一共有4种时钟源可供选择:
1) INTOSC1(10MHz)
内部时钟源1(INTOSC1),此时钟提供给看门狗块模块,内核和CPU定时器2 。
时钟频率默认为10MHz,可以通过INTOSCnTRIM寄存器修改频率。
2) INTOSC2(10MHz)
功能与INTOSC1是一样的。
3) 外部晶体振荡器XTAL(10MHZ)
使用外部晶体振荡器给芯片提供时钟,晶振连接于X1/X2 脚。
10M晶振代表一个晶振的振荡周期是100ns,晶振的一头对地是100ns周期的正弦波,另一头是差不多1V的高电平
4) 外部时钟源XCLKIN(我的板子上没有这个外部时钟源)
如果不使用外部晶振作为时钟源,可以选择这种模式。时钟从外部时钟源的XCLKIN引脚输入生成。
注意:XCLKIN复用于GPIO19或GPIO38脚。可以通过XCLK寄存器的XCLKINSEL位选择是GPIO19还是GPIO38作为XCLKIN输入。
CLKCTL(XCLKINOFF)为1时,不使能此时钟。如果时钟源不使用或作为GPIO引脚时,用户应该在启动引导时禁用。
上面时钟图粗看起来很复杂,如果仔细分析,其实也很简单。从图的中间画一条分隔线,左边部分为4个输入时钟源,其中INTOSC1和INTOSC2是一模一样的,XTAL和XCLKIN是另外的两个时钟源; 右边部分三个时钟模块,从上到下分别是看门狗时钟WDCLK,系统时钟OSCCLK(此时钟到PLL),以及CPU定时器2时钟CPUTMR2CLK。
看完时钟框图后,下面是软件系统时钟的设置
在main函数的最初位置初始化DSP,即调用void InitialDSP(void)函数。
void InitPeripherals(void)
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2803x_SysCtrl.c file.
InitSysCtrl();
// Step 2. Init GPIO:
// This example function is found in the DSP2803x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
InitGpio();
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2803x_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in DSP2803x_DefaultIsr.c.
// This function is found in DSP2803x_PieVect.c.
InitPieVectTable();
vCsmUnlock();
// Step 4. Initialize all the Device Peripherals:
memcpy((unsigned int *)&RamfuncsRunStart,(unsigned int *)&RamfuncsLoadStart, (unsigned long)&RamfuncsLoadSize);
InitFlash();
vClearRam();
InitCla();
InitAdc();
//InitComp();
InitCpuTimers();
ConfigCpuTimer(&CpuTimer0, 60, 1000,0);
InitEPwm();
InitSci();
InitI2C();
InitECan();
//InitECap();
// Step 5. User specific code, enable interrupts
EALLOW;
Flash_CPUScaleFactor = SCALE_FACTOR;
Flash_CallbackPtr = (void*)0;
EDIS;
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
//EALLOW; // This is needed to write to EALLOW protected registers
//PieVectTable.XINT1 = &vSinSyncIn_isr;
//PieVectTable.EPWM3_INT = &vPwm3Int_isr;
//EDIS; // This is needed to disable write to EALLOW protected registers
//PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // Enable PIE Group 1 INT4
//PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
//PieCtrlRegs.PIEACK.all = PIEACK_GROUP1|PIEACK_GROUP3;
//IER |= M_INT1|M_INT3; // Enable CPU INT1
DINT; // Enable Global Interrupts
DRTM;
}
void InitPeripherals(void)
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2803x_SysCtrl.c file.
InitSysCtrl();
// Step 2. Init GPIO:
// This example function is found in the DSP2803x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
InitGpio();
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2803x_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
Interrupt 1标志。INT1是连接到CPU中断级别INT1的中断标志。
0没有INT1中断挂起
1至少有一个INT1中断挂起。给这个位写一个0,将它清除为0,并清除中断请求
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in DSP2803x_DefaultIsr.c.
// This function is found in DSP2803x_PieVect.c.
InitPieVectTable();
vCsmUnlock();
// Step 4. Initialize all the Device Peripherals:
memcpy((unsigned int *)&RamfuncsRunStart,(unsigned int *)&RamfuncsLoadStart, (unsigned long)&RamfuncsLoadSize);
InitFlash();
vClearRam();
InitCla();
InitAdc();
//InitComp();
InitCpuTimers();
ConfigCpuTimer(&CpuTimer0, 60, 1000,0);
InitEPwm();
InitSci();
InitI2C();
InitECan();
//InitECap();
// Step 5. User specific code, enable interrupts
EALLOW;
Flash_CPUScaleFactor = SCALE_FACTOR;
Flash_CallbackPtr = (void*)0;
EDIS;
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
//EALLOW; // This is needed to write to EALLOW protected registers
//PieVectTable.XINT1 = &vSinSyncIn_isr;
//PieVectTable.EPWM3_INT = &vPwm3Int_isr;
//EDIS; // This is needed to disable write to EALLOW protected registers
//PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // Enable PIE Group 1 INT4
//PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
//PieCtrlRegs.PIEACK.all = PIEACK_GROUP1|PIEACK_GROUP3;
//IER |= M_INT1|M_INT3; // Enable CPU INT1
DINT; // Enable Global Interrupts
DRTM;
}
void InitSysCtrl(void)
{
// Disable the watchdog
DisableDog();
// *IMPORTANT*
// The Device_cal function, which copies the ADC & oscillator calibration values
// from TI reserved OTP into the appropriate trim registers, occurs automatically
// in the Boot ROM. If the boot ROM code is bypassed during the debug process, the
// following function MUST be called for the ADC and oscillators to function according
// to specification. The clocks to the ADC MUST be enabled before calling this
// function.
// See the device data manual and/or the ADC Reference
// Manual for more information.
EALLOW;
SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1; // Enable ADC peripheral clock
(*Device_cal)();
SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 0; // Return ADC clock to original state
EDIS;
// Select Internal Oscillator 1 as Clock Source (default), and turn off all unused clocks to
// conserve power.
//IntOsc1Sel();
XtalOscSel(); //
// Initialize the PLL control: PLLCR and CLKINDIV
// DSP28_PLLCR and DSP28_CLKINDIV are defined in DSP2803x_Examples.h
InitPll(DSP28_PLLCR,DSP28_DIVSEL); //External clock 20MHz, Fosc=60MHz
// Initialize the peripheral clocks
InitPeripheralClocks();
}
void XtalOscSel (void) {
EALLOW;
SysCtrlRegs.CLKCTL.bit.XTALOSCOFF = 0; // Turn on XTALOSC
SysCtrlRegs.CLKCTL.bit.XCLKINOFF = 1; // Turn off XCLKIN
SysCtrlRegs.CLKCTL.bit.OSCCLKSRC2SEL = 0; // Switch to external clock
SysCtrlRegs.CLKCTL.bit.OSCCLKSRCSEL = 1; // Switch from INTOSC1 to INTOSC2/ext clk
SysCtrlRegs.CLKCTL.bit.WDCLKSRCSEL = 1; // Switch Watchdog Clk Src to external clock
SysCtrlRegs.CLKCTL.bit.INTOSC2OFF = 1; // Turn off INTOSC2
SysCtrlRegs.CLKCTL.bit.INTOSC1OFF = 1; // Turn off INTOSC1
EDIS;
}
void XtalOscSel (void) {
EALLOW;
SysCtrlRegs.CLKCTL.bit.XTALOSCOFF = 0; // Turn on XTALOSC
SysCtrlRegs.CLKCTL.bit.XCLKINOFF = 1; // Turn off XCLKIN
SysCtrlRegs.CLKCTL.bit.OSCCLKSRC2SEL = 0; // Switch to external clock
SysCtrlRegs.CLKCTL.bit.OSCCLKSRCSEL = 1; // Switch from INTOSC1 to INTOSC2/ext clk
SysCtrlRegs.CLKCTL.bit.WDCLKSRCSEL = 1; // Switch Watchdog Clk Src to external clock
SysCtrlRegs.CLKCTL.bit.INTOSC2OFF = 1; // Turn off INTOSC2
SysCtrlRegs.CLKCTL.bit.INTOSC1OFF = 1; // Turn off INTOSC1
EDIS;
}
void InitPll(Uint16 val, Uint16 divsel)
{
volatile Uint16 iVol;
// Make sure the PLL is not running in limp mode
if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
{
EALLOW;
// OSCCLKSRC1 failure detected. PLL running in limp mode.
// Re-enable missing clock logic.
SysCtrlRegs.PLLSTS.bit.MCLKCLR = 1;
EDIS;
// Replace this line with a call to an appropriate
// SystemShutdown(); function.
asm(" ESTOP0"); // Uncomment for debugging purposes
}
// DIVSEL MUST be 0 before PLLCR can be changed from
// 0x0000. It is set to 0 by an external reset XRSn
// This puts us in 1/4
if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0)
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;
EDIS;
}
// Change the PLLCR
if (SysCtrlRegs.PLLCR.bit.DIV != val)
{
EALLOW;
// Before setting PLLCR turn off missing clock detect logic
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
SysCtrlRegs.PLLCR.bit.DIV = val;
EDIS;
// Optional: Wait for PLL to lock.
// During this time the CPU will switch to OSCCLK/2 until
// the PLL is stable. Once the PLL is stable the CPU will
// switch to the new PLL value.
//
// This time-to-lock is monitored by a PLL lock counter.
//
// Code is not required to sit and wait for the PLL to lock.
// However, if the code does anything that is timing critical,
// and requires the correct clock be locked, then it is best to
// wait until this switching has completed.
// Wait for the PLL lock bit to be set.
// The watchdog should be disabled before this loop, or fed within
// the loop via ServiceDog().
// Uncomment to disable the watchdog
DisableDog();
while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1)
{
// Uncomment to service the watchdog
// ServiceDog();
}
EALLOW;
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
EDIS;
}
// If switching to 1/2
if((divsel == 1)||(divsel == 2))
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel;
EDIS;
}
// If switching to 1/1
// * First go to 1/2 and let the power settle
// The time required will depend on the system, this is only an example
// * Then switch to 1/1
if(divsel == 3)
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = 2;
DELAY_US(50L);
SysCtrlRegs.PLLSTS.bit.DIVSEL = 3;
EDIS;
}
}
注意:当我用delay_ms()函数来延时灯的亮灭时,改变分频和倍频可以改变灯的亮灭速度。
但是调用了官方的延时函数,即便改变了倍频和分频因子,改变函数的延时时间并没有改变,比如延时1s,就真的是延时1s。
void InitPll(Uint16 val, Uint16 divsel)
{
volatile Uint16 iVol;
// Make sure the PLL is not running in limp mode
if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
{
缺少时钟状态位。在复位后检查此位的状态,以确定是否检测到缺失的振荡器条件。
在正常情况下,该位应为0。对该位的写入将被忽略。该位将通过写入MCLKCLR位或强制外部重置来清除。
0表示正常操作。未检测到丢失的时钟条件。
1检测到OSCCLK缺失。主振荡器故障检测逻辑已重置设备和CPU现在被锁相环工作在软模频率上计时。当缺失的时钟检测电路自动在OSCCLKSRC2和OSCCLKSRC1之间切换时(在检测到OSCCLKSRC2故障后),该位将自动清除,缺失的时钟检测电路将重新启用。对于所有其他情况,用户需要通过向MCLKCLR位写入1来重新启用此模式。
EALLOW;
// OSCCLKSRC1 failure detected. PLL running in limp mode.
// Re-enable missing clock logic.
SysCtrlRegs.PLLSTS.bit.MCLKCLR = 1;
缺失时钟清除位。
0 写一个0没有效果。这个位总是读为0。
1强制清除缺失的时钟检测电路并复位。
如果OSCCLK仍然缺失,检测电路将再次对系统产生复位,设置缺失的时钟状态位(MCLKSTS), CPU将由软模频率下运行的锁相环供电。
EDIS;
// Replace this line with a call to an appropriate
// SystemShutdown(); function.
asm(" ESTOP0"); // Uncomment for debugging purposes
}
// DIVSEL MUST be 0 before PLLCR can be changed from
// 0x0000. It is set to 0 by an external reset XRSn
// This puts us in 1/4
if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0)
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;
EDIS;
Divide Select:当CLKIN到CPU时,在/4、/2和/1之间进行选择。
DIVSEL位的配置如下:
00, 01“CLKIN”选择“除以4”
10在“CLKIN”中选择“除以2”
11选择“CLKIN”的“除1”。(该模式只能在关闭或绕过锁相环时使用。)
}
// Change the PLLCR
if (SysCtrlRegs.PLLCR.bit.DIV != val)
{
EALLOW;
// Before setting PLLCR turn off missing clock detect logic
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
缺失时钟检测关闭位
0启用主振荡器故障检测逻辑。(默认)
1主振荡器故障检测逻辑被禁用,锁相环将不会发出跛行模式时钟。
当代码不能受到检测电路的影响时,使用此模式。
例如,如果外部时钟被关闭。
SysCtrlRegs.PLLCR.bit.DIV = val;
EDIS;
// Optional: Wait for PLL to lock.
// During this time the CPU will switch to OSCCLK/2 until
// the PLL is stable. Once the PLL is stable the CPU will
// switch to the new PLL value.
//
// This time-to-lock is monitored by a PLL lock counter.
//
// Code is not required to sit and wait for the PLL to lock.
// However, if the code does anything that is timing critical,
// and requires the correct clock be locked, then it is best to
// wait until this switching has completed.
// Wait for the PLL lock bit to be set.
// The watchdog should be disabled before this loop, or fed within
// the loop via ServiceDog().
// Uncomment to disable the watchdog
DisableDog();
while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1)
{
// Uncomment to service the watchdog
// ServiceDog();锁相锁状态位。
0表示PLLCR寄存器已被写入,PLL当前处于锁定状态。CPU被OSCCLK/2时钟控制,直到锁相锁锁。
1锁相环锁定完成,处于稳定状态。
}
EALLOW;
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
缺少时钟检测关闭位
0启用主振荡器故障检测逻辑。(默认)
1主振荡器故障检测逻辑被禁用,锁相环将不会发出跛行模式时钟。当代码不能受到检测电路的影响时,使用此模式。例如,如果外部时钟被关闭。
EDIS;
}
// If switching to 1/2
if((divsel == 1)||(divsel == 2))
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel;
EDIS;
}
// If switching to 1/1
// * First go to 1/2 and let the power settle
// The time required will depend on the system, this is only an example
// * Then switch to 1/1
if(divsel == 3)
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = 2;
DELAY_US(50L);
SysCtrlRegs.PLLSTS.bit.DIVSEL = 3;
EDIS;
}
}
8-7:
分割选择:CLKIN到CPU的位在/4,/2和/1之间选择。
DIVSEL位的配置如下:
00,01 对于CLKIN选择“除4”
10 在“CLKIN”选项中选择“除2”
11 选择“CLKIN”对应的“除1”。(此模式只能在锁相环关闭或旁路时使用。)
- 6位:MCLKOFF,丢失时钟检测关闭位;
- 0——默认设置,主振荡器时钟丢失检测使能
- 1——主振荡器时钟丢失检测禁止
- 5位:OSCOFF,控制振荡器时钟信号,该位为1,振荡器信号允许通过,兵分两路,一路直接过去,一路进入锁相环模块;
- 4位:MCLKCLR,丢失时钟清除位,若该位写0,无效,写1强制丢失时钟信号检测电路清除和复位;
- 3位:MCLKSTS, 丢失时钟信号状态位,0为正常模式,表示时钟信号没有丢失,1表示时钟信号丢失,CPU工作在无序频率模式;
- 2位:PLLOFF,锁相器关闭位;
- 1位:保留;
- 0位:PLLOCKS:锁相器锁状态位。
上面的代码都是按照手册里提供的程序流程图来写的,下面把PLLCR更改的程序流程图贴出来。
void InitPeripheralClocks(void)
{
EALLOW;
// LOSPCP prescale register settings, normally it will be set to default values
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 0; // GPIO18 = XCLKOUT
SysCtrlRegs.LOSPCP.all = 0x0002;
// XCLKOUT to SYSCLKOUT ratio. By default XCLKOUT = 1/4 SYSCLKOUT
SysCtrlRegs.XCLK.bit.XCLKOUTDIV=3; //turn off
// Peripheral clock enables set for the selected peripherals.
// If you are not using a peripheral leave the clock off
// to save on power.
//
// Note: not all peripherals are available on all 2803x derivates.
// Refer to the datasheet for your particular device.
//
// This function is not written to be an example of efficient code.
//We will turn on the Peripheral clock later
SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 0; // ADC
SysCtrlRegs.PCLKCR3.bit.COMP1ENCLK = 0; // COMP1
SysCtrlRegs.PCLKCR3.bit.COMP2ENCLK = 0; // COMP2
SysCtrlRegs.PCLKCR3.bit.COMP3ENCLK = 0; // COMP3
SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 0; // eCAP1
SysCtrlRegs.PCLKCR0.bit.ECANAENCLK= 0; // eCAN-A
SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 0; // eQEP1
SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 0; // ePWM1
SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 0; // ePWM2
SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 0; // ePWM3
SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 0; // ePWM4
SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 0; // ePWM5
SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 0; // ePWM6
SysCtrlRegs.PCLKCR0.bit.HRPWMENCLK = 0; // HRPWM
SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 0; // I2C
SysCtrlRegs.PCLKCR0.bit.LINAENCLK = 0; // LIN-A
SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 0; // CLA1
SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 0; // SCI-A
SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 0; // SPI-A
SysCtrlRegs.PCLKCR0.bit.SPIBENCLK = 0; // SPI-B
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Disable TBCLK within the ePWM
EDIS;
}
void InitPeripheralClocks(void)
{
EALLOW;
// LOSPCP prescale register settings, normally it will be set to default values
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 0; // GPIO18 = XCLKOUT
SysCtrlRegs.LOSPCP.all = 0x0002;
// XCLKOUT to SYSCLKOUT ratio. By default XCLKOUT = 1/4 SYSCLKOUT
SysCtrlRegs.XCLK.bit.XCLKOUTDIV=3; //turn off
// Peripheral clock enables set for the selected peripherals.
// If you are not using a peripheral leave the clock off
// to save on power.
//
// Note: not all peripherals are available on all 2803x derivates.
// Refer to the datasheet for your particular device.
//
// This function is not written to be an example of efficient code.
//We will turn on the Peripheral clock later
SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 0; // 关ADC
SysCtrlRegs.PCLKCR3.bit.COMP1ENCLK = 0; // COMP1
SysCtrlRegs.PCLKCR3.bit.COMP2ENCLK = 0; // COMP2
SysCtrlRegs.PCLKCR3.bit.COMP3ENCLK = 0; // COMP3
SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 0; // eCAP1
SysCtrlRegs.PCLKCR0.bit.ECANAENCLK= 0; // eCAN-A
SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 0; // eQEP1
SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 0; // ePWM1
SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 0; // ePWM2
SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 0; // ePWM3
SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 0; // ePWM4
SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 0; // ePWM5
SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 0; // ePWM6
SysCtrlRegs.PCLKCR0.bit.HRPWMENCLK = 0; // HRPWM
SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 0; // I2C
SysCtrlRegs.PCLKCR0.bit.LINAENCLK = 0; // LIN-A
SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 0; // CLA1
SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 0; // SCI-A
SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 0; // SPI-A
SysCtrlRegs.PCLKCR0.bit.SPIBENCLK = 0; // SPI-B
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Disable TBCLK within the ePWM
EDIS;
}
锁相环PLL及时钟机制
XCLKOUT信号直接来自于系统时钟SYSCLKOUT,如图25所示。
XCLKOUT可以等于SYSCLKOUT的1 或1/2或1 / 4。默认情况下,上电时,XCLKOUT = syclkout /4或XCLKOUT = OSCCLK/16。
注意:要想使用XCLKOUT这个引脚输出时钟信号的话,在XCLKOUTDIV[1:0]不能选择11,而且得复用引脚改为XLCKOUT。
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 3;
OSCCLK信号需要经过两层“关卡”才能到达CLKIN送入CPU。第一层是锁存器PLL,锁存器的作用是对OSCCLK信号进行n倍频,也就是把其信号频率提升n倍,同时也可以不使用PLL,直接把信号送到下一层“关卡”,通过PLLSTS[PLLOFF],即PLL状态寄存器的第二位可以控制是否使用PLL。DSP在复位时该位为0,默认打开PLL。使用PLL可以倍频提高CPU的运算速度。n的大小取决于PLLCR[DIV](PLL控制寄存器)的值进行设定。
PLL对OSCCLK进行倍频的同时,下一层“关卡”会对信号进行分频,因此CLKIN的频率最终由PLLCR[DIV]和PLLSTS[DIVSEL]这两个位决定,对频率进行先乘后除后送入CPU。
上图是DSP的系统控制寄存器(System Control Register File),包括了系统时钟相关的一系列寄存器,下面就重点提一下从时钟输入到CLKIN一路过来的主要寄存器和寄存器位。
主要是CLKCTL,这三个寄存器,复位后DSP内部的振荡器都处于开启状态,但是选择哪一个作为OSCCLK取决于CLKCTL的[OSCCLKSRCSEL]位,这一位复位默认为0,因此选择internal OSC1作为时钟源。之后便是PLLCR[DIV]和PLLSTS[DIVSEL]这两个寄存器共同决定CLKIN的频率。如下图所示:
需要指出的是PLLCR[DIV]在上电时为0,处于被旁路状态(旁路但是PLL处于运行状态),OSCCLK被四分频(OSCCLK/4)送入后面的信号,这是为了防止DSP超频导致系统启动时出问题。在官方的库代码中,上电后会对这两个位进行设置,比如将PLLCR[DIV]设置为12,PLLSTS[DIVSEL]设置为2,因此最终CPU运行频率为:(OSCCLK=10MHz * 12) / 2 = 60MHz,这也是数据手册给出的最大运行频率。
顺便一提Device_Cal:
Device_cal()例程被工厂编程到TI预留内存中。引导ROM自动调用Device_cal()例程,用设备特定的校准数据校准内部振荡器和ADC。在正常操作中,这个过程会自动发生,用户不需要做任何操作。
如果在开发过程中Code Composer Studio绕过了引导ROM,那么必须由应用程序初始化校准。工作示例请参见《C280 3x C/ c++头文件和外设示例》中的系统初始化。
注意:初始化这些寄存器失败将导致振荡器和ADC功能不符合规格。以下三个步骤描述了如何从应用程序调用Device_cal例程。
步骤1:创建一个指向Device_cal函数的指针,如例2-5所示。这个#定义包含在头文件和外设示例中。
步骤2:调用Device_cal()所指向的函数,如例2-5所示。在进行此调用之前,必须启用ADC时钟。
void InitGpio(void)
void InitGpio(void)
{
EALLOW;
//Input IO
//Test Mode Pin: Enable Pull Up, Qualification using 3 samples, Input GPIO
//GpioCtrlRegs.GPAPUD.bit.GPIO9 = 0;
//GpioCtrlRegs.GPAQSEL1.bit.GPIO9 = 1;
//GpioCtrlRegs.GPAMUX1.bit.GPIO9 = 0;
//GpioCtrlRegs.GPADIR.bit.GPIO9 = 0;
//Output IO
//SHCP : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1;
GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO2 = 1;
//RLY_DRV : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO4 = 1;
GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO4 = 1;
//DE : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO20 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO20 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO20 = 1;
//STCP : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO21 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO21 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO21 = 1;
//WP : Disable Pull Up, Set High
GpioCtrlRegs.GPAPUD.bit.GPIO24 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 0;
GpioDataRegs.GPASET.bit.GPIO24 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO24 = 1;
//DS : Disable Pull Up, Set High
GpioCtrlRegs.GPBPUD.bit.GPIO35 = 1;
GpioCtrlRegs.GPBMUX1.bit.GPIO35 = 0;
GpioDataRegs.GPBCLEAR.bit.GPIO35 = 1;
GpioCtrlRegs.GPBDIR.bit.GPIO35 = 1;
EDIS;
}
void InitGpio(void)
{
EALLOW;
//Input IO
//Test Mode Pin: Enable Pull Up, Qualification using 3 samples, Input GPIO
//GpioCtrlRegs.GPAPUD.bit.GPIO9 = 0;
//GpioCtrlRegs.GPAQSEL1.bit.GPIO9 = 1;为GPIO0到GPIO15选择输入限定类型。每个GPIO输入的输入限定由两个位控制,如图57所示。
00只同步到SYSCLKOUT。适用于外设和GPIO引脚。
01使用3个样品进行鉴定。对配置为GPIO或外设功能的引脚有效。
样本之间的时间间隔在GPACTRL寄存器中指定。
10使用6个样品进行鉴定。对配置为GPIO或外设功能的引脚有效。
样本之间的时间间隔在GPACTRL寄存器中指定。
11异步。(没有同步或限定)。此选项仅适用于配置为外设的引脚。如果将引脚配置为GPIO输入,则该选项与0,0相同,或者同步到SYSCLKOUT。
//GpioCtrlRegs.GPAMUX1.bit.GPIO9 = 0;
//GpioCtrlRegs.GPADIR.bit.GPIO9 = 0;
//Output IO
//SHCP : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1;
GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;每个GPIO端口A引脚(GPIO0-GPIO31)对应于这个寄存器中的一个位,如图68所示。
0的写操作被忽略。
这个寄存器总是读回一个0。
1写一个1迫使各自的输出数据锁存到低。
如果引脚被配置为GPIO输出,那么它将被驱动到低电平。
如果引脚没有被配置为GPIO输出,那么锁存被清除,但是引脚没有被驱动。
GpioCtrlRegs.GPADIR.bit.GPIO2 = 1;
//RLY_DRV : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO4 = 1;
GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO4 = 1;
//DE : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO20 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO20 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO20 = 1;
//STCP : Disable Pull Up, Set Low
GpioCtrlRegs.GPAPUD.bit.GPIO21 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 0;
GpioDataRegs.GPACLEAR.bit.GPIO21 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO21 = 1;
//WP : Disable Pull Up, Set High
GpioCtrlRegs.GPAPUD.bit.GPIO24 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 0;
GpioDataRegs.GPASET.bit.GPIO24 = 1;
GpioCtrlRegs.GPADIR.bit.GPIO24 = 1;
//DS : Disable Pull Up, Set High
GpioCtrlRegs.GPBPUD.bit.GPIO35 = 1;
GpioCtrlRegs.GPBMUX1.bit.GPIO35 = 0;
GpioDataRegs.GPBCLEAR.bit.GPIO35 = 1;
GpioCtrlRegs.GPBDIR.bit.GPIO35 = 1;
EDIS;
}
void InitPieCtrl(void)
{
// Disable Interrupts at the CPU level:
DINT;
// Disable the PIE
PieCtrlRegs.PIECTRL.bit.ENPIE = 0;
// Clear all PIEIER registers:
PieCtrlRegs.PIEIER1.all = 0;
PieCtrlRegs.PIEIER2.all = 0;
PieCtrlRegs.PIEIER3.all = 0;
PieCtrlRegs.PIEIER4.all = 0;
PieCtrlRegs.PIEIER5.all = 0;
PieCtrlRegs.PIEIER6.all = 0;
PieCtrlRegs.PIEIER7.all = 0;
PieCtrlRegs.PIEIER8.all = 0;
PieCtrlRegs.PIEIER9.all = 0;
PieCtrlRegs.PIEIER10.all = 0;
PieCtrlRegs.PIEIER11.all = 0;
PieCtrlRegs.PIEIER12.all = 0;
// Clear all PIEIFR registers:
PieCtrlRegs.PIEIFR1.all = 0;
PieCtrlRegs.PIEIFR2.all = 0;
PieCtrlRegs.PIEIFR3.all = 0;
PieCtrlRegs.PIEIFR4.all = 0;
PieCtrlRegs.PIEIFR5.all = 0;
PieCtrlRegs.PIEIFR6.all = 0;
PieCtrlRegs.PIEIFR7.all = 0;
PieCtrlRegs.PIEIFR8.all = 0;
PieCtrlRegs.PIEIFR9.all = 0;
PieCtrlRegs.PIEIFR10.all = 0;
PieCtrlRegs.PIEIFR11.all = 0;
PieCtrlRegs.PIEIFR12.all = 0;
}
PIE
PIE向量表(见表1-119)由256 × 16的SARAM块组成,如果PIE块没有被使用,它也可以用作RAM(仅在数据空间中)。
PIE向量表内容在重置时未定义。
CPU处理INT1到INT12的中断优先级。
PIE控制每组8个中断的优先级。
例如,如果INT1.1应该与INT8.1同时发生,这两个中断将由PIE块同时提交给CPU,并且CPU服务INT1.1优先。
如果INT1.1和INT1.8同时发生,则首先将INT1.1发送给CPU,然后再将INT1.8发送给CPU。
在表1-118中96个可能的MUXed中断中,目前使用了43个中断。
其余的中断为将来的设备保留。
void InitPieCtrl(void)
{
// Disable Interrupts at the CPU level:
DINT;
// Disable the PIE
PieCtrlRegs.PIECTRL.bit.ENPIE = 0;
启用从PIE向量表中获取向量。
注意:重置向量永远不会从PIE中获取,即使它是启用的。
这个向量总是从引导ROM中获取。
0如果该位设置为0,则禁用PIE块,并从引导ROM中的CPU向量表中获取向量。即使禁用了PIE块,也可以访问所有的PIE块寄存器(PIEACK, PIEIFR, PIEIER)。
1当ENPIE设置为1时,除reset外的所有向量都从PIE向量表中获取。
重置向量总是从引导ROM中获取。
// Clear all PIEIER registers:
PieCtrlRegs.PIEIER1.all = 0;这些寄存器位单独启用一个组中的中断,行为非常类似于核心中断启用寄存器。
将位设置为1将启用对相应中断的服务。
将位设置为0将禁用中断服务。X = 1到12。INTx表示CPU INT1 ~ INT12
PieCtrlRegs.PIEIER2.all = 0;
PieCtrlRegs.PIEIER3.all = 0;
PieCtrlRegs.PIEIER4.all = 0;
PieCtrlRegs.PIEIER5.all = 0;
PieCtrlRegs.PIEIER6.all = 0;
PieCtrlRegs.PIEIER7.all = 0;
PieCtrlRegs.PIEIER8.all = 0;
PieCtrlRegs.PIEIER9.all = 0;
PieCtrlRegs.PIEIER10.all = 0;
PieCtrlRegs.PIEIER11.all = 0;
PieCtrlRegs.PIEIER12.all = 0;
// Clear all PIEIFR registers:
PieCtrlRegs.PIEIFR1.all = 0;这些寄存器位指示中断当前是否处于活动状态。
它们的行为非常像CPU中断标志寄存器。
当一个中断是活动的,相应的寄存器位被设置。
当中断被服务时,或者通过向寄存器位写入0来清除该位。
还可以读取该寄存器以确定哪些中断是活动的或挂起的。
X = 1到12。
INTx表示CPU INT1 ~ INT12。
在中断处理的中断向量提取部分,piifr寄存器位被清除。
硬件优先于CPU访问PIEIFR寄存器。
PieCtrlRegs.PIEIFR2.all = 0;
PieCtrlRegs.PIEIFR3.all = 0;
PieCtrlRegs.PIEIFR4.all = 0;
PieCtrlRegs.PIEIFR5.all = 0;
PieCtrlRegs.PIEIFR6.all = 0;
PieCtrlRegs.PIEIFR7.all = 0;
PieCtrlRegs.PIEIFR8.all = 0;
PieCtrlRegs.PIEIFR9.all = 0;
PieCtrlRegs.PIEIFR10.all = 0;
PieCtrlRegs.PIEIFR11.all = 0;
PieCtrlRegs.PIEIFR12.all = 0;
}
void InitPieVectTable(void)
{
int16 i;
Uint32 *Source = (void *) &PieVectTableInit;
Uint32 *Dest = (void *) &PieVectTable;
// Do not write over first 3 32-bit locations (these locations are
// initialized by Boot ROM with boot variables)
Source = Source + 3;
Dest = Dest + 3;
EALLOW;
for(i=0; i < 125; i++)
*Dest++ = *Source++;
EDIS;
// Enable the PIE Vector Table
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
}
在任何复位之后,CPU从地址0x3FFFC0(重置向量)开始执行,它在引导ROM中。
在运行引导ROM代码之后,CPU通常会分支到地址0x80000的闪存开始。
有关控制引导过程的更多信息,请参阅ROM代码和外围设备引导章节。
uint16 vCsmUnlock()
Uint16 vCsmUnlock()
{
volatile Uint16 temp;
// Load the key registers with the current password
// These are defined in Example_Flash2803x_CsmKeys.asm
EALLOW;
CsmRegs.KEY0 = PRG_key0;
CsmRegs.KEY1 = PRG_key1;
CsmRegs.KEY2 = PRG_key2;
CsmRegs.KEY3 = PRG_key3;
CsmRegs.KEY4 = PRG_key4;
CsmRegs.KEY5 = PRG_key5;
CsmRegs.KEY6 = PRG_key6;
CsmRegs.KEY7 = PRG_key7;
EDIS;
// Perform a dummy read of the password locations
// if they match the key values, the CSM will unlock
temp = CsmPwl.PSWD0;
temp = CsmPwl.PSWD1;
temp = CsmPwl.PSWD2;
temp = CsmPwl.PSWD3;
temp = CsmPwl.PSWD4;
temp = CsmPwl.PSWD5;
temp = CsmPwl.PSWD6;
temp = CsmPwl.PSWD7;
// If the CSM unlocked, return succes, otherwise return
// failure.
if ( (CsmRegs.CSMSCR.all & 0x0001) == 0) return 1;
else return STATUS_FAIL_CSM_LOCKED;
}
1.2.3在用户应用程序中引入代码安全
在项目的开发阶段通常不需要代码安全性;
然而,一旦开发出健壮的代码,安全性是必需的。
在闪存中编写这样的代码之前,应该选择一个密码来保护设备。
一旦设置了密码,设备就得到了保护(也就是说,在适当的位置编程一个密码,执行设备重置或设置FORCESEC位(CSMSCR.15)是保护设备的操作)。
从那时起,通过任何方式(通过JTAG、外部/片上内存运行的代码等)访问调试安全内存的内容都需要提供有效的密码。
在安全内存中运行代码不需要密码(例如在典型的最终客户使用中);
但是,为了调试目的访问安全内存内容需要密码。
memcpy函数
memcpy((unsigned int *)&RamfuncsRunStart,(unsigned int *)&RamfuncsLoadStart, (unsigned long)&RamfuncsLoadSize);
LOAD_START(_RamfuncsLoadStart) 指ramfuncs这段代码的加载开始地址
LOAD_END(_RamfuncsLoadEnd),指ramfuncs这段代码的加载结束地址
这里的RamfuncsLoad一般是FLASH
RUN_START(_RamfuncsRunStart),指ramfuncs这段代码的运行开始地址
意思是把ramfuncs拷到RAM中执行
InitFlash函数
void InitFlash(void)
{
EALLOW;
//Enable Flash Pipeline mode to improve performance
//of code executed from Flash.
FlashRegs.FOPT.bit.ENPIPE = 1;
// CAUTION
//Minimum waitstates required for the flash operating
//at a given CPU rate must be characterized by TI.
//Refer to the datasheet for the latest information.
//Set the Paged Waitstate for the Flash
FlashRegs.FBANKWAIT.bit.PAGEWAIT = 2;
//Set the Random Waitstate for the Flash
FlashRegs.FBANKWAIT.bit.RANDWAIT = 2;
//Set the Waitstate for the OTP
FlashRegs.FOTPWAIT.bit.OTPWAIT = 2;
// CAUTION
//ONLY THE DEFAULT VALUE FOR THESE 2 REGISTERS SHOULD BE USED
FlashRegs.FSTDBYWAIT.bit.STDBYWAIT = 0x01FF;
FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT = 0x01FF;
EDIS;
//Force a pipeline flush to ensure that the write to
//the last register configured occurs before returning.
asm(" RPT #7 || NOP");
}
void InitFlash(void)
{
EALLOW;
//Enable Flash Pipeline mode to improve performance
//of code executed from Flash.
FlashRegs.FOPT.bit.ENPIPE = 1;
使能Flash Pipeline Mode Bit。设置此位时,Flash流水线模式激活。流水线模式通过预取指令来提高指令获取的性能。有关更多信息,请参见第1.3.2节。
当管道模式被启用时,flash等待状态(分页和随机)必须大于零。
在flash设备上,ENPIPE影响从flash和OTP的读取。
0 Flash流水线模式未激活。(默认)
1 Flash“Pipeline”模式激活。
打开Flash Pipeline模式,以提高Flash执行代码的性能。
// CAUTION
//Minimum waitstates required for the flash operating
//at a given CPU rate must be characterized by TI.
//Refer to the datasheet for the latest information.
//Set the Paged Waitstate for the Flash
FlashRegs.FBANKWAIT.bit.PAGEWAIT = 2;
Flash page读等待状态。这些寄存器位指定了在CPU时钟周期(0..15SYSCLKOUT周期)到闪存银行。请参阅第1.3.1节了解更多信息。
关于page flash访问所需的最小时间,请参阅特定于设备的数据手册。
您必须将RANDWAIT设置为大于或等于PAGEWAIT设置的值。没有提供硬件来检测大于RANDWAIT的PAGEWAIT值。
0000 每次分页flash访问零等待状态或每次访问一个syclkout周期
0001 每次分页flash访问一个等待状态,或者每次访问总共有两个syclkout周期
0010每次分页flash访问有两个等待状态,或者每次访问总共有三个syclkout周期
0011每次分页flash访问有三个等待状态,或者每次访问总共有四个syclkout周期
. . . . . .
1111每次分页flash访问有15个等待状态,或者每次访问总共有16个SYSCLKOUT周期。(默认)
//Set the Random Waitstate for the Flash
FlashRegs.FBANKWAIT.bit.RANDWAIT = 2;
Flash随机读等待状态。这些寄存器位指定了CPU时钟周期(1..15)中随机读操作的等待状态的数量syclkout周期)到闪存银行。请参阅第1.3.1节了解更多信息。
关于随机闪存访问所需的最小时间,请参阅设备特定的数据手册。
RANDWAIT必须设置大于0。也就是说,必须使用至少一个随机等待状态。另外,必须将RANDWAIT设置为大于或等于PAGEWAIT设置的值。设备将不会检测并纠正大于RANDWAIT的PAGEWAIT值。
0000非法值。RANDWAIT必须设置大于0。
0001每次随机flash访问一个等待状态,或者每次访问总共有两个SYSCLKOUT周期。
0010每次随机flash访问有两个等待状态,或者每次访问总共有三个SYSCLKOUT周期。
0011每次随机flash访问有3个等待状态,或者每次访问总共有4个syclkout周期。
. . . . . .
1111每次随机flash访问有15个等待状态,或者每次访问总共有16个SYSCLKOUT周期。(默认)
//Set the Waitstate for the OTP
FlashRegs.FOTPWAIT.bit.OTPWAIT = 2;
OTP读等待状态。这些寄存器位指定了CPU时钟周期(1..31SYSCLKOUT循环)到OTP。详细信息请参见CPU Read Or Fetch Access From flash/OTP章节。OTP中没有PAGE模式。
OTPWAIT必须设置大于0。也就是说,必须使用至少1个等待状态。关于OTP访问所需的最短时间,请参阅设备专用数据手册。
00000非法值。OTPWAIT必须设置为1或更大。
00001每次OTP访问将使用一个等待状态,每次访问总共有两个syclkout周期。
00010每次OTP访问将使用两个等待状态,每次访问总共有三个syclkout周期。
00011每次OTP访问将使用三个等待状态,每次访问总共有四个syclkout周期。
. . . . . .
11111 31个等待状态将用于一次OTP访问,每次访问总共有32个syclkout周期。
// CAUTION
//ONLY THE DEFAULT VALUE FOR THESE 2 REGISTERS SHOULD BE USED
FlashRegs.FSTDBYWAIT.bit.STDBYWAIT = 0x01FF;
FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT = 0x01FF;
EDIS;
//Force a pipeline flush to ensure that the write to
//the last register configured occurs before returning.
asm(" RPT #7 || NOP");
}
vClearRam函数
void vClearRam(void)
{
Uint16 *ram_ptr;
for (ram_ptr=(Uint16 *)0x8000; ram_ptr<(Uint16 *)0x8C00; ram_ptr++) // if release
{
*ram_ptr = 0x0000;
}
for (ram_ptr=(Uint16 *)0x0600; ram_ptr<(Uint16 *)0x0800; ram_ptr++) // if release
{
*ram_ptr = 0x0000;
}
}
InitCla函数
void InitCla(void)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 1; // CLA1 CLK Enable
DSP28x_usDelay(1); //Delay after CLK Enable Not necessary
memcpy(&Cla1funcsRunStart, &Cla1funcsLoadStart, (Uint32)&Cla1funcsLoadSize);
memcpy(&Cla1mathTablesRunStart, &Cla1mathTablesLoadStart, (Uint32)&Cla1mathTablesLoadSize);
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.PROGE = 1; // Configure the RAM as CLA program memory
Cla1Regs.MMEMCFG.bit.RAM0E = 0; // configure RAM L1, F28035 as Main Cpu Data memory 0
Cla1Regs.MMEMCFG.bit.RAM1E = 1; // Configure RAM L2, F28035 as CLA data memory 1
// Symbols used in calculation are defined in CLA_Shared.h file
Cla1Regs.MVECT1 = (Uint16)((Uint32)&Cla1Task1 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT2 = (Uint16)((Uint32)&Cla1Task2 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT3 = (Uint16)((Uint32)&Cla1Task3 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT4 = (Uint16)((Uint32)&Cla1Task4 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT5 = (Uint16)((Uint32)&Cla1Task5 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT6 = (Uint16)((Uint32)&Cla1Task6 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT7 = (Uint16)((Uint32)&Cla1Task7 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT8 = (Uint16)((Uint32)&Cla1Task8 - (Uint32)&Cla1Prog_Start);
// Map Peripheral interrupt to CLA Task
// Below Task 1 is configured to be triggered by ADC INT1
Cla1Regs.MPISRCSEL1.bit.PERINT1SEL = CLA_INT1_ADCINT1;
//Cla1Regs.MPISRCSEL1.bit.PERINT2SEL = CLA_INT2_EPWM2INT;
// Enable the IACK instruction to start a task
// Enable the CLA interrupt 8 and software force it. For Initialize the variable used in cla
asm(" RPT #3 || NOP");
Cla1Regs.MCTL.bit.IACKE = 1;
Cla1Regs.MIER.all = M_INT1|M_INT8;
Cla1ForceTask8andWait();
EDIS;
}
void InitCla(void)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 1; // CLA1 CLK Enable
DSP28x_usDelay(1); //Delay after CLK Enable Not necessary
memcpy(&Cla1funcsRunStart, &Cla1funcsLoadStart, (Uint32)&Cla1funcsLoadSize);
memcpy(&Cla1mathTablesRunStart, &Cla1mathTablesLoadStart, (Uint32)&Cla1mathTablesLoadSize);
asm(" RPT #3 || NOP");
Cla1Regs.MMEMCFG.bit.PROGE = 1; // Configure the RAM as CLA program memory MMEMCFG寄存器用于将CLA程序和数据ram映射到CPU或CLA内存空间。通常,CLA程序和数据ram的映射只发生在初始化过程中。如果一段时间后,你想重新映射这些内存到CPU空间,那么禁用中断(MIER),并通过检查MIRUN寄存器来确保所有的任务已经完成。允许在更改这些内存的映射配置和访问它们之间有两个syclkout周期。
Cla1Regs.MMEMCFG.bit.RAM0E = 0; // configure RAM L1, F28035 as Main Cpu Data memory 0
Cla1Regs.MMEMCFG.bit.RAM1E = 1; // Configure RAM L2, F28035 as CLA data memory 1
// Symbols used in calculation are defined in CLA_Shared.h file
Cla1Regs.MVECT1 = (Uint16)((Uint32)&Cla1Task1 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT2 = (Uint16)((Uint32)&Cla1Task2 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT3 = (Uint16)((Uint32)&Cla1Task3 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT4 = (Uint16)((Uint32)&Cla1Task4 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT5 = (Uint16)((Uint32)&Cla1Task5 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT6 = (Uint16)((Uint32)&Cla1Task6 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT7 = (Uint16)((Uint32)&Cla1Task7 - (Uint32)&Cla1Prog_Start);
Cla1Regs.MVECT8 = (Uint16)((Uint32)&Cla1Task8 - (Uint32)&Cla1Prog_Start);
// Map Peripheral interrupt to CLA Task
// Below Task 1 is configured to be triggered by ADC INT1
Cla1Regs.MPISRCSEL1.bit.PERINT1SEL = CLA_INT1_ADCINT1;
//Cla1Regs.MPISRCSEL1.bit.PERINT2SEL = CLA_INT2_EPWM2INT;
// Enable the IACK instruction to start a task
// Enable the CLA interrupt 8 and software force it. For Initialize the variable used in cla
asm(" RPT #3 || NOP");
Cla1Regs.MCTL.bit.IACKE = 1;
Cla1Regs.MIER.all = M_INT1|M_INT8;
Cla1ForceTask8andWait();
EDIS;
}