TA的每日心情 | 奋斗 2016-12-6 18:19 |
---|
签到天数: 7 天 连续签到: 1 天 [LV.3]偶尔看看II
|
MPC5604B 是飞思卡尔半导体公司的32位单片机,其内核采用了32位PowerPC架构,内核是,e200Z0,PowerPC处理器最早是由AIM联盟设计的,是RISC结构中的一种。MPC5604B具有512KB 的代码Flash,64KB的 数据FLASH,以及48KB的动态RAM。具有最高64MHz总线频率,2个eMIOS,4个LIN,3个DSPI,6个CAN和1个I2C等。怎么说,该有的外设都有了,实际上这个芯片主要用在汽车上的,看看他具有这么多LIN和CAN就知道了,MPC56xx系列是汽车通用的控制器。
芯片基本就介绍完了,64MHz的运行频率怎么说也不算慢,但64MHz的运行频率运算速度只有50多MIPS。本人从淘宝上淘来的一个MPC5604B的核心板,蓝宇电子的,看起来还不错,给的例程太少。拿到之后就从NXP官网下载了一个CodeWarrior V2.10标准版,,一装上就能用,代码限制是128KB,也不知道怎么破解。还有,貌似CodeWarrior 10.6/10.7最新的编译器都支持MPC了,这个编译器确实不怎么习惯,觉得没有我的CodeWarrior V5.1 和CodeWarrior V6.3好用。
这个界面如图1所示,设置监视变量不好弄,有时候还不走,变量无法设置进制和刷新频率。上面的运行按钮就更是不好用了,没有CW5.1/6.3的跳出什么的。总之,很是不习惯,功能好像没有CW5.1/6.3多。不过,比之CW 5.1和CW6.3多了一个在RAM中仿真的功能还真不错。话说MC9S08DZ60的单片机除了速度慢,用起来还真不错,我对这个单片机最熟了。其次是MC9S12XS128MAL,这个用起来也方便,数据手册容易看。还用了一个芯片是MC9S12XEP100,属于前者的增强型,16位单片机,功能复杂多了,ECT功能强大,还有协处理器,但我用的较少,不是很熟。这些用的下载器都是用BDM背景调试,而MPC5604B不支持BDM,用的是标准JTAG通信,就是图2所示的OSBDM,这个下载器是一个师兄给我的。看起来是他们自己做的。
硬件什么的都有了,就可以写程序了。写这个芯片的程序可真费劲,资料少,而且用法跟S12和S08的用起来都不一样。数据手册没想到只有900多页,也够精简的。在CW2.1下头文件都是用结构和联合来写的,用起来诧异较大。另外,芯片的最低位为MSB,其中的字段又是正常顺序,这花了好一会才纠正过来。
先是搞明白了通用IO,写了一个让LED闪烁的程序。发现SIU_PCR[]寄存器竟然只能一次写一个,不能一下配置32个端口,难道是我理解错了?SIU_GPDO[]倒是能一次写32位。
接下来就是配置时钟了,参考官网还有数据手册,还是比较容易配置成FMPLL模式的,外部8MHz晶振,锁频到最高64MHz,启动时钟检测器。但是没有开频率调制,也不知道公式是啥。默认运行模式RUN0,芯片有7中运行模式,支持管理员模式和用户模式。这里采用默认模式,开启所有外设。
接下来就是开中断了。查看手册,发现有两种中断模式,软件中断和硬件中断。写这个中断花了三四天时间,参考官方给的硬件中断程序,用编译器新建的项目跟前者总是不符。参考别人的论坛,再仔细看数据手册,检查程序,才发现我写的软件中断处理,结果开了硬件中断。
如图3为硬件中断下的处理流程,硬件中断处理起来比较麻烦,每个中断都需要单独的前处理和后处理程序,但响应速度最快
,每个中断都有唯一的向量号,映射到唯一的句柄。而软件中断(图4)不需要单独的前处理和后处理程序,执行效率稍有下降,但程序简单。中断管理模块会将所有外设的中断经过处理计算得出跳转的中断地址,这些所有外设中断都只对应内核e200Z0的IVOR4中断。
本例是要采用RTC模模块中的API模式定时,让LED等闪烁。API模式理解和设置相对简单,配置为1ms中断一次。当采用硬件中断时,参考编译器自带的例程,需要修改handlers_vle.s文件,即修改硬件中断处理程序的预处理和后处理程序,照猫画虎,就把API的处理程序给出了。如下所示:
.section .ivor_handlers,text_vle
.equ INTC_EOIR_PRC0, 0xfff48018 # Dual Core: Proc 0 End Of Interrupt Reg. addr.
.equ INTC_EOIR, 0xfff48018 # Single Core: End Of Interrupt Reg. addr.
.extern API_Inter
.extern Pit1ISR
//.extern SwIrq4ISR
.globl APIHandler
.globl Pit1Handler
//.globl SwIrq4Handler
APIHandler:
# PROLOGUE
e_stwu r1, -0x50 (r1) # Create stack frame and store back chain
se_stw r3, 0x28 (r1) # Store a working register
# Note: use se_ form for r0-7, r24-41 with positive offset
mfsrr0 r3 # Store SRR0:1 (must be done before enabling EE)
se_stw r3, 0x0C (r1)
mfsrr1 r3
se_stw r3, 0x10 (r1)
wrteei 1 # Set MSR[EE]=1
e_stw r12, 0x4C (r1) # Store rest of gprs
e_stw r11, 0x48 (r1)
e_stw r10, 0x44 (r1)
e_stw r9, 0x40 (r1)
e_stw r8, 0x3C (r1)
se_stw r7, 0x38 (r1)
se_stw r6, 0x34 (r1)
se_stw r5, 0x30 (r1)
se_stw r4, 0x2C (r1)
se_stw r0, 0x24 (r1)
mfcr r3 # Store CR
se_stw r3, 0x20 (r1)
mfxer r3 # Store XER
se_stw r3, 0x1C (r1)
se_mfctr r3 # Store CTR
se_stw r3, 0x18 (r1)
se_mflr r4 # Store LR
se_stw r4, 0x14 (r1)
e_bl API_Inter # Branch to ISR, but return here
# EPILOGUE
se_lwz r3, 0x14 (r1) # Restore LR
se_mtlr r3
se_lwz r3, 0x18 (r1) # Restore CTR
se_mtctr r3
se_lwz r3, 0x1C (r1) # Restore XER
mtxer r3
se_lwz r3, 0x20 (r1) # Restore CR
mtcrf 0xff, r3
se_lwz r0, 0x24 (r1) # Restore other gprs except working registers
se_lwz r5, 0x30 (r1)
se_lwz r6, 0x34 (r1)
se_lwz r7, 0x38 (r1)
e_lwz r8, 0x3C (r1)
e_lwz r9, 0x40 (r1)
e_lwz r10, 0x44 (r1)
e_lwz r11, 0x48 (r1)
e_lwz r12, 0x4C (r1)
mbar 0 # Ensure store to clear interrupt flag bit completed
# Use 1 of the following 2 lines:
# e_lis r3, INTC_EOIR_PRC0@ha # Dual Core: Load upper half proc 0 EIOR addr. to r3
e_lis r3, INTC_EOIR@ha # Single Core: Load upper half of EIOR address to r3
se_li r4, 0
wrteei 0 # Disable interrupts for rest of handler
# Use 1 or 2 of the next appropriate lines:
# e_stw r4, INTC_EOIR_PRC0@l(r3) # Dual Core - Write 0 to proc'r 0 INTC_EIOR
e_stw r4, INTC_EOIR@l(r3) # Single Core - Write 0 to proc'r 0 INTC_EIOR
se_lwz r3, 0x0C (r1) # Restore SRR0
mtsrr0 r3
se_lwz r3, 0x10 (r1) # Restore SRR1
mtsrr1 r3
se_lwz r4, 0x2C (r1) # Restore working registers
se_lwz r3, 0x28 (r1)
e_add16i r1, r1, 0x50 # Delete stack frame
se_rfi # End of Interrupt
此外还要修改intc_hw_branch_table中对应中断的向量地址。将向量模式配置为硬件向量,在RAM中编译执行,发现寄存器中的值确实代表硬件中断,且中断正确执行,说明确实编译正确了。这个直接在自带程序基础上修改的,跟新建的项目差别太大。两者的初始化程序以及链接配置都不一样。原本想结合在一起,结果发现不行。
至于软件中断就比较好配置了,新建的项目标配了“IntcInterrupts.c”这个文件,有相应的子函数可以调用。如 EXCEP_InitExceptionHandlers(); //初始化异常处理函数 INTC_InitINTCInterrupts(); //清中断 INTC_InstallINTCInterruptHandler(RtcIn,39,5); //中断初始化程序,优先级5
注意将中断模式配置成软件向量模式,就可以了方便的设置软件中断了。设置为完成后,在RAM中运行,发现LED等正常闪烁,中断计数增加,寄存器中显示为软件中断,说明编译正确。下面分别给出软件中断和硬件中断的核心程序,供参考学习,有什么不对的敬请指正。
!!硬件中断
//***********************************************************
// 程序功能:MPC5604 硬件中断测试
// 编 写:ChenYanan
// 日 期: 2016.11.02
// 芯 片:MPC5604BML06
// 晶 振:8Mhz
//***********************************************************
#include "MPC5604B_0M27V_0102.h" //使用该库文件,与编译器生成的不同
#include "main.h"
//extern IVOR4Handler();
extern uint32_t __IVPR_VALUE;
Tvar tvar;
//==================================中断服务程序=================================
//RTC中断程序,中断程序由外部文件声明
void API_Inter(void)
{
tvar.u32RTC++;
RTC.RTCS.B.APIF=1; //清中断
}
void SwIrq4ISR(void)
{
INTC.SSCIR[4].R = 1; //清除标志
}
void Pit1ISR(void)
{
tvar.u32debug++;
PIT.CH[1].TFLG.B.TIF = 1; //清除标志
}
//-------------------------------------------------------------------
// 初始化中断向量
asm void Init_IrqVectors(void)
{
lis r3, __IVPR_VALUE@h //IVPR值由链接文件传递
ori r3, r3, __IVPR_VALUE@l
mtivpr r3
}
//----------------------------------------------------------------------
void DisaWatchdog(void) //禁用看门狗
{
SWT.SR.R = 0x0000c520; // Write keys to clear soft lock bit
SWT.SR.R = 0x0000d928;
SWT.CR.R = 0x8000010A; // Clear watchdog enable (WEN)
}
//-------------------------------------------------------------------------------
//延时函数
void Delay(uint32 deftime)
{
tvar.u32count=tvar.u32RTC;
while((uint32)(tvar.u32RTC-tvar.u32count)<deftime) ;
}
//---------------------------------------------------------------------------
//初始化运行模式
void Init_MC_ME(void)
{
ME.MER.R = 0x0000001D; //打开RUN0 DRUN SAFE RESET模式
ME.RUNPC[0].R=0x000000FE; // 外设在所有模式均打开
ME.RUN[0].B.MVRON =1; // 电压规整器开
ME.RUN[0].B.DFLAON=3; // FLASH处于正常模式
ME.RUN[0].B.CFLAON=3; // 代码寄存器处于正常模式
ME.RUN[0].B.FXOSC0ON=1; // 外部晶振打开
ME.RUN[0].B.FMPLLON=1; // RUN0模式锁相环开
ME.RUN[0].R|=0x04; // 选择PLL时钟
ME.PCTL[91].R = 0x00; //RTC在RUN0模式开启
ME.PCTL[92].R = 0x00; //PIT在RUN0模式开启
ME.MCTL.R = 0x40005AF0; // 设置RUN0模式,控制KEY p147
ME.MCTL.R = 0x4000A50F; // 设置RUN0模式反转KEY p147
while(ME.GS.B.S_MTRANS==1) ; // 等待进入响应模式
while(ME.GS.B.S_CURRENTMODE != 4) ; //RUN0处于电流模式
}
//--------------------------------------------------------------------------
//初始化时钟PLL=64Mhz fPLL=fosc*NDIV/IDF/ODF
//FVCO: 256MHz-512MHz
void Init_MCGM(void)
{
//CGM.FMPLL_CR.R = 0x02400100;
CGM.FMPLL_CR.B.EN_PLL_SW=1; //渐进式时钟切换
CGM.FMPLL_CR.B.IDF=0;
CGM.FMPLL_CR.B.NDIV=64;
CGM.FMPLL_CR.B.ODF=2; //设置PLL0 64 MHz
while(!CGM.FMPLL_CR.B.S_LOCK) ; //等待PLL锁定
// if(ME.GS.S_SYSCLK==0b0100); //如果是PLL时钟
while(!ME.GS.B.S_FMPLL) ; //等待PLL稳定
CGM.CMU_CSR.B.CME_A=1; //FMPLL 检测器开
CGM.CMU_HFREFR_A.R=258; //上限64.5MHz
CGM.CMU_LFREFR_A.R=254; //上限63.5MHz
RGM.FBRE.B.BE_FMPLL=1; // FMPLL失败复位使能
}
//------------------------------------------------------------------------------------
//时钟输出
void InitOutputClock(void)
{
CGM.OC_EN.B.EN = 1; // 时钟输出使能
CGM.OCDS_SC.B.SELDIV = 3; // 输出分频 8
CGM.OCDS_SC.B.SELCTL = 2; // 选择 FMPLL时钟
SIU.PCR[0].B.PA= 2; // PA0作为时钟输出 64MHz/8=8MHz
}
// --------------------------------------------------------------------------------------
// 初始化实时时钟,采用API模式
void Init_RTC(void)
{
CGM.SIRC_CTL.B.RCDIV=0; // RC振荡器不分频
CGM.SIRC_CTL.B.SIRCON_STDBY=1; // StandBy模式开SIRC
//ME.PCTL[91].R = 0x00;
RTC.RTCSUPV.R=0x80000000; //仅在管理员模式可访问其余寄存器
//RTC.RTCC.R = 0; //重置
RTC.RTCC.B.CLKSEL=1; //选择128KHz SIRC
RTC.RTCC.B.DIV32EN=1; //32分频使能 4kHz
RTC.RTCC.B.CNTEN=1; //计数使能
RTC.RTCC.B.APIVAL=4; //1ms中断一次,在APIEN之前定义,最小值4
RTC.RTCC.B.APIEN=1; //API使能
RTC.RTCS.B.APIF=1; //清中断
RTC.RTCC.B.APIIE=1; //API中断使能
INTC.PSR[39].R = 0x01; //设置API的中断优先级为1
}
//---------------------------------------------------------------------------
void Init_PIT(void)
{
PIT.PITMCR.R = 0x00000001; // 使能PIT 在DEBUG模式中停止
PIT.CH[1].LDVAL.R = 64000; //溢出时间1ms = 64000 clk x 1sec/64M
PIT.CH[1].TCTRL.R = 0x000000003; //使能PIT中断
}
//------------------------------------------------------------------------------
//初始化中断,采用IntcInterrupts.c文件中的函数进行初始化
void Init_INTC(void)
{
INTC.MCR.B.HVEN = 1; // 硬件中断向量模式 **注意此值
INTC.MCR.B.VTES = 0; // 4字节
}
//=============================================================================
//主函数
void main(void)
{
//uint32 u32i;
DisableIrq();
DisaWatchdog();
Init_MC_ME();
Init_MCGM();
//InitOutputClock();
Init_IrqVectors();
Init_INTC(); //初始化中断
Init_RTC(); //初始化RTC中断
//Init_PIT();
EnableIrq();
SIU.PCR[70].B.IBE=0; //端口PE6 对应70
SIU.PCR[70].B.PA=0;
SIU.PCR[70].B.OBE=1;
SIU.PCR[70].B.WPE=1;
SIU.GPDO[70].B.PDO = 1; //
//F G置为输出
//for(u32i=0;u32i<32;u32i++)
// SIU.PCR[64+u32i].R|=0x0203; //上拉使能
// SIU.GPDO[80].R|=0x01;
//SIU.PGPDO[2].R=0x0000ff80;//F0-F8
// CGM.OC_EN.
while (1)
{
Delay(1000);
SIU.GPDO[70].B.PDO ^=1 ; //亮灭
}
}
//====================================================================================
//END
!!软件中断
//***********************************************************
// 程序功能:MPC5604 测试
// 编 写:ChenYanan
// 日 期: 2016.11.02
// 芯 片:MPC5604BML06
// 晶 振:8Mhz
//***********************************************************
#include "MPC5604B_M07N.h"
#include "IntcInterrupts.h"
#include "main.h"
Tvar tvar;
//==================================中断服务程序=================================
//RTC中断程序
void RtcIn(void)
{
tvar.u32RTC++;
RTC.RTCS.B.APIF=1; //清中断
}
void SwIrq4ISR(void)
{
INTC.SSCIR[4].R = 1; //清中断标志位
}
void Pit1ISR(void)
{
tvar.u32debug++;
SIU.GPDO[70].B.PDO ^= 0b01; //亮
PIT.CH[1].TFLG.B.TIF = 1; //清中断标志位
}
//===============================================================================
//----------------------------------------------------------------------
void DisaWatchdog(void) //禁用看门狗
{
SWT.SR.R = 0x0000c520; // Write keys to clear soft lock bit
SWT.SR.R = 0x0000d928;
SWT.CR.R = 0x8000010A; // Clear watchdog enable (WEN)
}
//-------------------------------------------------------------------------------
//延时函数
void Delay(uint32 deftime)
{
tvar.u32count=tvar.u32RTC;
while((uint32)(tvar.u32RTC-tvar.u32count)<deftime) ;
}
//---------------------------------------------------------------------------
//初始化运行模式
void Init_MC_ME(void)
{
ME.MER.R = 0x0000001D; //打开RUN0 DRUN SAFE RESET模式
ME.RUNPC[0].R=0x000000FE; // 外设在所有模式均打开
ME.RUN[0].B.MVRON =1; // 电压规整器开
ME.RUN[0].B.DFLAON=3; // FLASH处于正常模式
ME.RUN[0].B.CFLAON=3; // 代码寄存器处于正常模式
ME.RUN[0].B.FXOSC0ON=1; // 外部晶振打开
ME.RUN[0].B.FMPLLON=1; // RUN0模式锁相环开
ME.RUN[0].R|=0x04; // 选择PLL时钟
ME.PCTL[91].R = 0x00; //RTC在RUN0模式开启
ME.PCTL[92].R = 0x00; //PIT在RUN0模式开启
ME.MCTL.R = 0x40005AF0; // 设置RUN0模式,控制KEY p147
ME.MCTL.R = 0x4000A50F; // 设置RUN0模式反转KEY p147
while(ME.GS.B.S_MTRANS==1) ; // 等待进入响应模式
while(ME.GS.B.S_CURRENTMODE != 4) ; //RUN0处于电流模式
}
//--------------------------------------------------------------------------
//初始化时钟PLL=64Mhz fPLL=fosc*NDIV/IDF/ODF
//FVCO: 256MHz-512MHz
void Init_MCGM(void)
{
//CGM.FMPLL_CR.R = 0x02400100;
CGM.FMPLL_CR.B.EN_PLL_SW=1; //渐进式时钟切换
CGM.FMPLL_CR.B.IDF=0;
CGM.FMPLL_CR.B.NDIV=64;
CGM.FMPLL_CR.B.ODF=2; //设置PLL0 64 MHz
while(!CGM.FMPLL_CR.B.S_LOCK) ; //等待PLL锁定
// if(ME.GS.S_SYSCLK==0b0100); //如果是PLL时钟
while(!ME.GS.B.S_FMPLL) ; //等待PLL稳定
CGM.CMU_CSR.B.CME_A=1; //FMPLL 检测器开
CGM.CMU_HFREFR_A.R=258; //上限64.5MHz
CGM.CMU_LFREFR_A.R=254; //上限63.5MHz
RGM.FBRE.B.BE_FMPLL=1; // FMPLL失败复位使能
}
//------------------------------------------------------------------------------------
//时钟输出
void InitOutputClock(void)
{
CGM.OC_EN.B.EN = 1; // 时钟输出使能
CGM.OCDS_SC.B.SELDIV = 3; // 输出分频 8
CGM.OCDS_SC.B.SELCTL = 2; // 选择 FMPLL时钟
SIU.PCR[0].B.PA= 2; // PA0作为时钟输出 64MHz/8=8MHz
}
// --------------------------------------------------------------------------------------
// 初始化实时时钟,采用API模式
void Init_RTC(void)
{
CGM.SIRC_CTL.B.RCDIV=0; // RC振荡器不分频
CGM.SIRC_CTL.B.SIRCON_STDBY=1; // StandBy模式开SIRC
//ME.PCTL[91].R = 0x00;
RTC.RTCSUPV.R=0x80000000; //仅在管理员模式可访问其余寄存器
//RTC.RTCC.R = 0; //重置
RTC.RTCC.B.CLKSEL=1; //选择128KHz SIRC
RTC.RTCC.B.DIV32EN=1; //32分频使能 4kHz
RTC.RTCC.B.CNTEN=1; //计数使能
RTC.RTCC.B.APIVAL=4; //1ms中断一次,在APIEN之前定义,最小值4
RTC.RTCC.B.APIEN=1; //API使能
RTC.RTCS.B.APIF=1; //清中断
RTC.RTCC.B.APIIE=1; //API中断使能
}
//---------------------------------------------------------------------------
void Init_PIT(void)
{
PIT.PITMCR.R = 0x00000001; // 使能PIT 在DEBUG模式中停止
PIT.CH[1].LDVAL.R = 64000; //溢出时间1ms = 64000 clk x 1sec/64M
PIT.CH[1].TCTRL.R = 0x000000003; //使能PIT中断
}
//------------------------------------------------------------------------------
//初始化中断,采用IntcInterrupts.c文件中的函数进行初始化
void Init_INTC(void)
{
INTC.MCR.B.HVEN = 0; // 软件向量模式
INTC.MCR.B.VTES = 0; // 4字节
EXCEP_InitExceptionHandlers(); //初始化异常处理函数
INTC_InitINTCInterrupts(); //清中断
INTC_InstallINTCInterruptHandler(RtcIn,39,5); //中断初始化程序,优先级5
//INTC_InstallINTCInterruptHandler(Pit1ISR,60,1); //中断初始化程序,优先级1
//INTC_InstallINTCInterruptHandler(SwIrq4ISR,4,5);
}
//=============================================================================
//主函数
void main(void)
{
//uint32 u32i;
DisableIrq();
DisaWatchdog();
Init_MC_ME();
Init_MCGM();
//InitOutputClock();
Init_INTC(); //初始化中断
Init_RTC(); //初始化RTC中断
//Init_PIT();
EnableIrq();
SIU.PCR[70].B.IBE=0; //端口PE6 对应70
SIU.PCR[70].B.PA=0;
SIU.PCR[70].B.OBE=1;
//SIU.PCR[70].B.WPE=1;
SIU.GPDO[70].B.PDO = 1; //
//F G置为输出
//for(u32i=0;u32i<32;u32i++)
// SIU.PCR[64+u32i].R|=0x0203; //上拉使能
// SIU.GPDO[80].R|=0x01;
//SIU.PGPDO[2].R=0x0000ff80;//F0-F8
// CGM.OC_EN.
while (1)
{
Delay(1000);
SIU.GPDO[70].B.PDO ^=1 ; //亮灭
}
}
//====================================================================================
//END
|
-
图1 CW界面
-
图2 单片机和下载器
-
图3 硬件中断
-
图4 软件中断
|