2837xD之CPU2使用外设

2837xD之CPU2使用外设

  • 一、文章目的
    • 1.主要准备
  • 二、代码阅读
    • 1.CUP1代码
    • CPU2中的代码
  • 三、总结
  • 四、致谢

一、文章目的

上一篇文章主要是解决了2837xD之间的IPC交互问题,但是需要的目标是CPU2调用串口等通信功能进行信息发送到上位机的交互。因此本文主要是学习利用CPU2来驱动外设的主要流程。

1.主要准备

因为手上没有2837xD的开发板,本次实验还是以学习例程为主(有点难受)。。。

二、代码阅读

代码目的:CPU1进行时钟初始化与GPIO初始化,CPU2进行驱动外设(ADC与EPWM)
    其中,EPWM1工作在up-mode,GPIO0(EPWM1A)、GPIO1(EPWM1B)输出。
    ADC工作在连续采样模式,可以将GPIO0接入ADCINA0读取输出结果。

1.CUP1代码

void main(void)
{
   InitSysCtrl();//初始化系统时钟等
   
   InitGpio();//初始化GPIO(解锁所有GPIO等)
   
   DINT;//禁止中断
   InitPieCtrl();//恢复PIE控制器默认状态
   IER = 0x0000;
   IFR = 0x0000; //禁止中断与清除所有中断标志位
   InitPieVectTable();//初始化中断向量表
   EINT;  // 使能全局中断
   ERTM;  // 使能实时中断
   
   InitEPwm1Gpio(); //初始化EPWM1GPIO(只有CPU1能够进行GPIO中的MUX配置)
   
   EALLOW;
   DevCfgRegs.CPUSEL0.bit.EPWM1 = 1;//将外设控制权给CPU2
   DevCfgRegs.CPUSEL11.bit.ADC_A = 1;//将控制权给CPU2
   EDIS;	
   
   while(1)
   {
    	asm(" nop");
   }
}

下面先附上==InitEPwm1Gpio()==函数中的代码:

void InitEPwm1Gpio(void)
{
	EALLOW;
    GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1;    
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1;  //设置GPIO0与GPIO1为上拉模式

	GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1;   
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1;   // 设置GPIO0与GPIO1工作在EPWM模式
    EDIS;
}

通过上面的函数可以看出,需要注意的有以下几点

  • 本例中CPU1负责整个系统的初始化操作,GPIO的MUX设置只能在CPU1中完成。
  • 需要在CPU1为CPU2分配相应的外设。
  • 要提一下的是CPUSEL0-CPUSEL14寄存器决定了每个外设是属于CPU1 or CPU2

CPU1中内容不多,下面康康CPU2中的内容!

CPU2中的代码

   void main(void{
     InitSysCtrl(); //初始化系统时钟(与CPU1中的函数的内容一模一样)
     
     DINT;//关中断
     InitPieCtrl(); //初始化PIE控制器(与CPU1中的函数的内容一模一样)
     IER = 0x0000;
     IFR = 0x0000;  //禁止中断与清除中断标志
     InitPieVectTable();//初始化中断向量表
     
	 EALLOW;
	 PieVectTable.EPWM1_INT = &epwm1_isr;  //指定EPWM1的中断函数
	 EDIS;
	
	 EALLOW;
	 CpuSysRegs.PCLKCR2.bit.EPWM1=1;
	 CpuSysRegs.PCLKCR13.bit.ADC_A = 1;
	 EDIS;                                //开启相关外设对应的时钟

   

以上部分都是对工作背景以及外设的准备工作

/接着上部分代码/
	ConfigureADC(); //ADC设置函数[ADC工作在12位,单端采用模式,转换结束后产生中断,采样频率4分频]
	SetupADCContinuous(0); //设置ADC

下面附上==SetupADCContinuous(0)==函数中的代码:

void SetupADCContinuous(Uint16 channel)
{
	Uint16 acqps;

	//determine minimum acquisition window (in SYSCLKS) based on resolution
	if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION){
		acqps = 14; //75ns
	}
	else { //resolution is 16-bit
		acqps = 63; //320ns
	}

	EALLOW;
	AdcaRegs.ADCSOC0CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC1CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC2CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC3CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC4CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC5CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC6CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC7CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC8CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC9CTL.bit.CHSEL  = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC10CTL.bit.CHSEL = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC11CTL.bit.CHSEL = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC12CTL.bit.CHSEL = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC13CTL.bit.CHSEL = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC14CTL.bit.CHSEL = channel;  //SOC will convert on channel
	AdcaRegs.ADCSOC15CTL.bit.CHSEL = channel;  //SOC will convert on channel

	AdcaRegs.ADCSOC0CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC1CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC2CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC3CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC4CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC5CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC6CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC7CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC9CTL.bit.ACQPS  = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC10CTL.bit.ACQPS = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC11CTL.bit.ACQPS = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC12CTL.bit.ACQPS = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC13CTL.bit.ACQPS = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC14CTL.bit.ACQPS = acqps;    //sample window is acqps + 1 SYSCLK cycles
	AdcaRegs.ADCSOC15CTL.bit.ACQPS = acqps;    //sample window is acqps + 1 SYSCLK cycles

	AdcaRegs.ADCINTSEL1N2.bit.INT1E = 0; //disable INT1 flag
	AdcaRegs.ADCINTSEL1N2.bit.INT2E = 0; //disable INT2 flag
	AdcaRegs.ADCINTSEL3N4.bit.INT3E = 0; //disable INT3 flag
	AdcaRegs.ADCINTSEL3N4.bit.INT4E = 0; //disable INT4 flag

	AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 0;
	AdcaRegs.ADCINTSEL1N2.bit.INT2CONT = 0;
	AdcaRegs.ADCINTSEL3N4.bit.INT3CONT = 0;
	AdcaRegs.ADCINTSEL3N4.bit.INT4CONT = 0;

	AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 6;  //end of SOC6 will set INT1 flag
	AdcaRegs.ADCINTSEL1N2.bit.INT2SEL = 14; //end of SOC14 will set INT2 flag
	AdcaRegs.ADCINTSEL3N4.bit.INT3SEL = 7;  //end of SOC7 will set INT3 flag
	AdcaRegs.ADCINTSEL3N4.bit.INT4SEL = 15; //end of SOC15 will set INT4 flag

	//ADCINT2 will trigger first 8 SOCs
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC0 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC1 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC2 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC3 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC4 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC5 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC6 = 2;
   	AdcaRegs.ADCINTSOCSEL1.bit.SOC7 = 2;

	//ADCINT1 will trigger second 8 SOCs
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC8 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC9 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC10 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC11 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC12 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC13 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC14 = 1;
   	AdcaRegs.ADCINTSOCSEL2.bit.SOC15 = 1;
}

上述的设置完成了SOC0-SOC15都采集某一个通道,并且:
SOC0-SOC7由ADCINT2可以触发
SOC8-SOC15由ADCINT1可以触发

SOC6完成后触发ADCINT1中断
SOC14完成后触发ADCINT2中断
SOC7完成后触发ADCINT3中断
SOC15完成后触发ADCINT4中断

/接上述程序/
	EALLOW;
	CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =0;//停止记述
	EDIS;
	InitEPwm1Example();
	EALLOW;
	CpuSysRegs.PCLKCR0.bit.TBCLKSYNC =1;//开始记述
	EDIS;

下面附上==InitEPwm1Example()==函数中的代码:

void InitEPwm1Example()
{
   // Setup TBCLK
   EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
   EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD;       // Set timer period
   EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;    // Disable phase loading
   EPwm1Regs.TBPHS.bit.TBPHS = 0x0000;        // Phase is 0
   EPwm1Regs.TBCTR = 0x0000;                  // Clear counter
   EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2;   // Clock ratio to SYSCLKOUT
   EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2;

   // Setup shadow register load on ZERO
   EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
   EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
   EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
   EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

   // Set Compare values
   EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA;     // Set compare A value
   EPwm1Regs.CMPB.bit.CMPB = EPWM1_MIN_CMPB;     // Set Compare B value

   // Set actions
   EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET;            // Set PWM1A on Zero
   EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;          // Clear PWM1A on event A, up count

   EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET;            // Set PWM1B on Zero
   EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;          // Clear PWM1B on event B, up count

   // Interrupt where we will change the Compare Values
   EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;     // Select INT on Zero event
   EPwm1Regs.ETSEL.bit.INTEN = 1;                // Enable INT
   EPwm1Regs.ETPS.bit.INTPRD = ET_3RD;           // Generate INT on 3rd event

   // Information this example uses to keep track
   // of the direction the CMPA/CMPB values are
   // moving, the min and max allowed values and
   // a pointer to the correct ePWM registers
   epwm1_info.EPwm_CMPA_Direction = EPWM_CMP_UP; // Start by increasing CMPA & CMPB
   epwm1_info.EPwm_CMPB_Direction = EPWM_CMP_UP;
   epwm1_info.EPwmTimerIntCount = 0;             // Zero the interrupt counter
   epwm1_info.EPwmRegHandle = &EPwm1Regs;        // Set the pointer to the ePWM module
   epwm1_info.EPwmMaxCMPA = EPWM1_MAX_CMPA;      // Setup min/max CMPA/CMPB values
   epwm1_info.EPwmMinCMPA = EPWM1_MIN_CMPA;
   epwm1_info.EPwmMaxCMPB = EPWM1_MAX_CMPB;
   epwm1_info.EPwmMinCMPB = EPWM1_MIN_CMPB;

}

上述的设置完成了EPWM1的设置:

  • 1.PRD=4096 ,时钟两分频,禁止同步信号(工作在up mode
  • 2.CMPA与CMPB ,在50-4050之间循环主函数实现,这里看不到
  • 3.CTR=0时,触发中断(每三次产生一次中断
	/接上述主程序/
	
	IER |= M_INT3;
	PieCtrlRegs.PIEIER3.bit.INTx1 = 1;

 
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

	for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++)
    {
    	AdcaResults[resultsIndex] = 0;
    }
    resultsIndex = 0;         //将存储ADC转换结果的数组清空

    EALLOW;
//take conversions indefinitely in loop
    do{
    	//enable ADCINT flags
    	AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;
    	AdcaRegs.ADCINTSEL1N2.bit.INT2E = 1;
    	AdcaRegs.ADCINTSEL3N4.bit.INT3E = 1;
    	AdcaRegs.ADCINTSEL3N4.bit.INT4E = 1;
		AdcaRegs.ADCINTFLGCLR.all = 0x000F;   //开启中断,清除中断标志

    	//initialize results index
    	resultsIndex = 0;
    	//software force start SOC0 to SOC7
    	AdcaRegs.ADCSOCFRC1.all = 0x00FF;     //启动SOC0-SOC7
    	//keep taking samples until the results buffer is full
    	
    	while(resultsIndex < RESULTS_BUFFER_SIZE)
    	{
    		//wait for first set of 8 conversions to complete
    		while(0 == AdcaRegs.ADCINTFLG.bit.ADCINT3);
    		//clear both INT flags generated by first 8 conversions
    		AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
    		AdcaRegs.ADCINTFLGCLR.bit.ADCINT3 = 1;

    		//save results for first 8 conversions
    		//
    		//note that during this time, the second 8 conversions have
    		//already been triggered by EOC6->ADCIN1 and will be actively
    		//converting while first 8 results are being saved
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT1;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT2;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT3;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT4;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT5;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT6;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT7;

    		//wait for the second set of 8 conversions to complete
    		while(0 == AdcaRegs.ADCINTFLG.bit.ADCINT4);
    		//clear both INT flags generated by second 8 conversions
    		AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1;
    		AdcaRegs.ADCINTFLGCLR.bit.ADCINT4 = 1;

    		//save results for second 8 conversions
    		//
    		//note that during this time, the first 8 conversions have
    		//already been triggered by EOC14->ADCIN2 and will be actively
    		//converting while second 8 results are being saved
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT8;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT9;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT10;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT11;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT12;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT13;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT14;
    		AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT15;
    	}

    	//disable all ADCINT flags to stop sampling
    	AdcaRegs.ADCINTSEL1N2.bit.INT1E = 0;
    	AdcaRegs.ADCINTSEL1N2.bit.INT2E = 0;
    	AdcaRegs.ADCINTSEL3N4.bit.INT3E = 0;
    	AdcaRegs.ADCINTSEL3N4.bit.INT4E = 0;

    	//at this point, AdcaResults[] contains a sequence of conversions
    	//from the selected channel

    	//software breakpoint, hit run again to get updated conversions
//    	asm("   ESTOP0");
    	DELAY_US(1000);
    }while(1);
}
  • 1.进入循环,启动SOC0-SOC7。
  • 2.开启中断,清空中断标志位。
  • 3.当数组未装满时,等待INT3触发(即SOC0-SOC7完成转换),[SOC6完成后会触发INT1中断,INT1中断会触发SOC8-SOC15进行转换]。
  • 4.存储SOC0-SOC7的转换结果,再等待INT4触发(即SOC8-SOC15完成转换),[SOC14完成后会触发INT2中断,INT2中断会触发SOC0-SOC7进行转换]。
	__interrupt void epwm1_isr(void)
{
    // Update the CMPA and CMPB values
    update_compare(&epwm1_info);

    // Clear INT flag for this timer
    EPwm1Regs.ETCLR.bit.INT = 1;

    // Acknowledge this interrupt to receive more interrupts from group 3
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}

  update_compare(&epwm1_info)中改变EPWM1的相关参数(如CMPACMPB的值等)与本文的主要目的关系不大,这里不做主要介绍。

void update_compare(EPWM_INFO *epwm_info)
{
   // Every 10'th interrupt, change the CMPA/CMPB values
   if(epwm_info->EPwmTimerIntCount == 10)
   {
       epwm_info->EPwmTimerIntCount = 0;

       // If we were increasing CMPA, check to see if
       // we reached the max value.  If not, increase CMPA
       // else, change directions and decrease CMPA
	   if(epwm_info->EPwm_CMPA_Direction == EPWM_CMP_UP)
	   {
	       if(epwm_info->EPwmRegHandle->CMPA.bit.CMPA < epwm_info->EPwmMaxCMPA)
	       {
	          epwm_info->EPwmRegHandle->CMPA.bit.CMPA++;
	       }
	       else
	       {
	          epwm_info->EPwm_CMPA_Direction = EPWM_CMP_DOWN;
              epwm_info->EPwmRegHandle->CMPA.bit.CMPA--;
	       }
	   }

	   // If we were decreasing CMPA, check to see if
       // we reached the min value.  If not, decrease CMPA
       // else, change directions and increase CMPA
	   else
	   {
	       if(epwm_info->EPwmRegHandle->CMPA.bit.CMPA == epwm_info->EPwmMinCMPA)
	       {
	          epwm_info->EPwm_CMPA_Direction = EPWM_CMP_UP;
	          epwm_info->EPwmRegHandle->CMPA.bit.CMPA++;
	       }
	       else
	       {
	          epwm_info->EPwmRegHandle->CMPA.bit.CMPA--;
	       }
	   }

	   // If we were increasing CMPB, check to see if
       // we reached the max value.  If not, increase CMPB
       // else, change directions and decrease CMPB
	   if(epwm_info->EPwm_CMPB_Direction == EPWM_CMP_UP)
	   {
	       if(epwm_info->EPwmRegHandle->CMPB.bit.CMPB < epwm_info->EPwmMaxCMPB)
	       {
	          epwm_info->EPwmRegHandle->CMPB.bit.CMPB++;
	       }
	       else
	       {
	          epwm_info->EPwm_CMPB_Direction = EPWM_CMP_DOWN;
	          epwm_info->EPwmRegHandle->CMPB.bit.CMPB--;
	       }
	   }

	   // If we were decreasing CMPB, check to see if
       // we reached the min value.  If not, decrease CMPB
       // else, change directions and increase CMPB
	   else
	   {
	       if(epwm_info->EPwmRegHandle->CMPB.bit.CMPB == epwm_info->EPwmMinCMPB)
	       {
	          epwm_info->EPwm_CMPB_Direction = EPWM_CMP_UP;
	          epwm_info->EPwmRegHandle->CMPB.bit.CMPB++;
	       }
	       else
	       {
	          epwm_info->EPwmRegHandle->CMPB.bit.CMPB--;
	       }
	   }
   }
   else
   {
      epwm_info->EPwmTimerIntCount++;
   }

   return;
}

三、总结

   由以上程序可以看出,CPU2运行外设没有其他特别的步骤。主要还是需要在CPU1中对外设的归属进行声明以及初始化相关的GPIO。

    /CPU1中程序/
	InitEPwm1Gpio();//
	EALLOW;
    DevCfgRegs.CPUSEL0.bit.EPWM1 = 1;//connect to CPU2
    DevCfgRegs.CPUSEL11.bit.ADC_A = 1;//connect to CPU2
    EDIS;

四、致谢

  代码均来自与TI公司例程,本人仅做了整理和分析。我所使用的例程链接贴一下:双核例程

你可能感兴趣的:(2837x)