pre_start属于加载函数,我们可以在loader/si/loader.c中找到它,我们还是把它复制到这里
void pre_start(void)
{
#ifdef debug
loader();
#endif
int_init();
critical();
#ifndef debug
loader();
#endif
start_sys(); //开始启动系统
}
这里有个宏debug,debug已经在eclipse中定义具体是在工程properties > c/c++Build > Settings >preprocessor中,所以一开始就要调用loader(),loader与pre_loader()功能差不多,这里是把剩余的需要复制到ram里的代码段数据段复制到ram中。然后就是执行int_init()函数,这个函数是完成中断的初始化,我们一会在看。继续就是执行critical()钩子函数,就是在启动系统之前需要做的紧急任务在此完成。最后启动系统start_sys().
这里我们详细看一下int_init()这个函数:
关于中断djyos定义了两个结构:
1、中断线数据结构,每中断一个
//移植敏感
struct int_line
{
u32 (*ISR)(ufast_t line);
struct event_ECB *sync_event; //正在等待本中断发生的事件
ucpu_t en_counter; //禁止次数计数,等于0时表示允许中断
ucpu_t int_type; //1=实时中断,0=异步信号
bool_t enable_nest; //true=本中断响应期间允许嵌套,对硬件能力有依赖
//性,也与软件设置有关。例如cortex-m3版本,异步
//信号被设置为最低优先级,从而所有异步信号都不
//允许嵌套。
//特别注意,实时中断能够无条件嵌套异步信号。
//中断响应后,由中断引擎根据enable_nest的值使能
//或禁止中断来控制是否允许嵌套,如果在响应中断
//后,硬件没有立即禁止中断,将有一个小小的"窗口"
//,在该窗口内,是允许嵌套的。例如cm3的实时中断
uint16_t my_evtt_id;
u32 prio; //优先级,含义由使用者解析
};
2.中断总控数据结构.
struct int_master_ctrl
{
//中断线属性位图,0=异步信号,1=实时中断,数组的位数刚好可以容纳中断数量,与
//中断线数据结构的int_type成员含义相同。
ucpu_t property_bitmap[cn_int_bits_words];
ucpu_t nest_asyn_signal; //中断嵌套深度,主程序=0,第一次进入中断=1,依次递加
ucpu_t nest_real; //中断嵌套深度,主程序=0,第一次进入中断=1,依次递加
//中断线使能位图,1=使能,0=禁止,反映相应的中断线的控制状态,
//与总开关/异步信号开关的状态无关.
ucpu_t enable_bitmap[cn_int_bits_words];
// bool_t en_trunk; //1=总中断使能, 0=总中断禁止
// bool_t en_asyn_signal; //1=异步信号使能,0=异步信号禁止
ucpu_t en_trunk_counter; //全局中断禁止计数,=0表示允许全局中断
ucpu_t en_asyn_signal_counter; //异步信号禁止计数,=0表示允许异步信号
};
熟悉了以上两个结构我们看一下中断初始化函数,过程已经详细注释,函数主要初始化了向量表,初始化了中断线数据结构,初始化中断总控数据结构
//----初始化中断---------------------------------------------------------------
//功能:初始化中断硬件,初始化中断线数据结构
// 2.异步信号保持禁止,它会在线程启动引擎中打开.
// 3.总中断允许,
// 用户初始化过程应该遵守如下规则:
// 1.系统开始时就已经禁止所有异步信号,用户初始化时无须担心异步信号发生.
// 2.初始化过程中如果需要操作总中断/实时中断/异步信号,应该成对使用.禁止使
// 异步信号实际处于允许状态(即异步和总中断开关同时允许).
// 3.可以操作中断线,比如连接、允许、禁止等,但应该成对使用.
// 4.建议使用save/restore函数对,不要使用enable/disable函数对.
//参数:无
//返回:无
//-----------------------------------------------------------------------------
void int_init(void)
{
ufast_t ufl_line;
int_cut_trunk(); //关总中断
int_echo_all_line();//此行动作for(ufl=0; ufl < cn_int_bits_words; ufl++) //pg_int_reg->clrpend[ufl] = 0xffffffff;
//清除全部中断线的挂起
pg_scb_reg->CCR |= 1<<bo_scb_ccr_usersetmpend;//USERSETMPEND 如果写成1,那么用户代码可
//以写软件触发中断寄存器以触发(挂起)一个主异
//常,该异常是和主堆栈指针相联系的。
for(ufl_line=0;ufl_line <= cn_int_line_last;ufl_line++)
{
tg_int_lookup_table[ufl_line] = (ufast_t)cn_limit_ufast;
u32g_vect_table[ufl_line] = (u32)__start_asyn_signal; //全部初始化为异步信号 此数组为中断 //向量表,预加载时已经加载到RAM,现在是将数组全部初始化为异步信号处理的入口地址
}
for(ufl_line=0;ufl_line < ufg_int_used_num;ufl_line++)
{
tg_int_lookup_table[tg_int_used[ufl_line]] = ufl_line;
tg_int_table[ufl_line].en_counter = 1; //禁止中断,计数为1
tg_int_table[ufl_line].int_type = cn_asyn_signal; //设为异步信号
//所有中断函数指针指向空函数
tg_int_table[ufl_line].ISR = (u32 (*)(ufast_t))NULL_func;
tg_int_table[ufl_line].sync_event = NULL; //同步事件空
tg_int_table[ufl_line].my_evtt_id = cn_invalid_evtt_id; //不弹出事件
pg_int_reg->pri[ufl_line] = 0xff; //异步信号优先级最低
}
for(ufl_line=0; ufl_line < cn_int_bits_words; ufl_line++)
{
pg_int_reg->clrena[ufl_line]=0xffffffff; //全部禁止
pg_int_reg->clrpend[ufl_line]=0xffffffff; //全部清除挂起状态
//属性位图清零,全部置为异步信号方式
tg_int_global.property_bitmap[ufl_line] = 0;
//中断使能位图清0,全部处于禁止状态
tg_int_global.enable_bitmap[ufl_line] = 0;
}
tg_int_global.nest_asyn_signal =0;
tg_int_global.nest_real=0;
// tg_int_global.en_asyn_signal = false;
tg_int_global.en_asyn_signal_counter = 1; //异步信号计数
int_cut_asyn_signal();
// tg_int_global.en_trunk = true;
tg_int_global.en_trunk_counter = 0; //总中断计数
int_contact_trunk(); //接通总中断开关
cm3_cpsie_f(); //接通所有异常开关
}
这里介绍一个eclipse的快捷键,Ctrl+h 可以调出查询对话框,可以在工作区查找字符串 函数等,很方便.
中断初始化已经完成,接下来就是开始启动系统了,下一篇我们再看.有些底层函数我们可能到系统启动完成都没有涉及到,是因为必须有中断或者调用才会涉及到,以后的时间我们看一下,现在主要是看一下系统是怎样启动的。