[原创].怎样在Nios II上跑μC/OS-II.[Quartus II][SOPC Builder][Nios II][μC/OS-II]
0赞硬件:艾米电子EP2C8 FPGA-Nios开发板 板载8MB SDRAM和EPCS4
软件:QII+NII SBTE 9.1 SP1
一 硬件部分:构建SOPC平台
1 新建QII工程及其他
(1)新建QII工程
图1-1 新建QII工程
(2)选择器件
图1-2 选择器件
(3)其他设置
图1-3 将不用管脚设置为三态输入
图1-4 将AS配置芯片设置为EPCS4
2 构建Nios II软核
(1)打开SOPC Builder,新建软核系统。
图2-1 新建软核系统
由于我想将SDRAM跑到125MHz,那么先修改一下软核输入时钟的频率为125Mhz。
图2-2 修改软核输入时钟频率
(2)添加处理器及存储器
配置SDRAM控制器。此处使用SDRAM的是三星的K4S641632K-UC60:64Mbit;16bit位宽;最大运行频率为166MHz ,CL=3。
图2-3 配置SDRAM为16bit模式
图2-3 配置SDRAM的CL=3
图2-4 配置处理器的复位向量和异常向量
(3)添加Interval Timer核
由于sys_clk_timer为μC/OS-II所必需,因此必须添加此核。
图2-5 配置Interval Timer核
(4)添加其他调试所需的核
图2-6 添加其他调试所需的核
注:大家有没有注意到所有的组件后面都自动带一个编号,“_0”,挺难看的。其实不然,由于每一个组件都会被例化成一个HDL文件,而一个SOPC系统中可以构建多个Nios II软核或其他软核,如果不带编号的话,就会相互覆盖,以致于编译错误。当然,单核的时候,去掉也无妨。
(5)自动分配基地址和中断号
图2-7 自动分配基地址和中断号
(6)编译软核系统
略
3 编译QII工程
(1)配置锁相环
输入50Mhz时钟;输出两个125Mhz时钟,其中一个相位滞后-3.5ns,作为SDRAM的时钟。由于要使用Verilog语言描述顶层模块。故在生成PLL的映射文件时候,需做如下选择。
图3-1 选择输出例化模板文件和Verilog黑盒文件
(2)编辑顶层模块
新建一个Verilog文件,并命名为与工程名相同的名称。将*_inst.v(sdram_pll_inst.v、nios_core_0_inst.v)中的代码复制进去。
代码1 ucos_ii_test.v雏形
01 |
sdram_pll sdram_pll_inst ( |
02 |
.inclk0 ( inclk0_sig ), |
03 |
.c0 ( c0_sig ), |
04 |
.c1 ( c1_sig ) |
05 |
); |
06 |
|
07 |
|
08 |
//Example instantiation for system 'nios_core_0' |
09 |
nios_core_0 nios_core_0_inst |
10 |
( |
11 |
.clk_0 (clk_0), |
12 |
.reset_n (reset_n), |
13 |
.zs_addr_from_the_sdram_0 (zs_addr_from_the_sdram_0), |
14 |
.zs_ba_from_the_sdram_0 (zs_ba_from_the_sdram_0), |
15 |
.zs_cas_n_from_the_sdram_0 (zs_cas_n_from_the_sdram_0), |
16 |
.zs_cke_from_the_sdram_0 (zs_cke_from_the_sdram_0), |
17 |
.zs_cs_n_from_the_sdram_0 (zs_cs_n_from_the_sdram_0), |
18 |
.zs_dq_to_and_from_the_sdram_0 (zs_dq_to_and_from_the_sdram_0), |
19 |
.zs_dqm_from_the_sdram_0 (zs_dqm_from_the_sdram_0), |
20 |
.zs_ras_n_from_the_sdram_0 (zs_ras_n_from_the_sdram_0), |
21 |
.zs_we_n_from_the_sdram_0 (zs_we_n_from_the_sdram_0) |
22 |
); |
有了这些模块的例化模板后,我们只要加上输入输出声明,以及略微改动即可。
代码2 ucos_ii_test.v
01 |
module ucos_ii_test( |
02 |
// CLOCK_ |
03 |
input CLOCK_50, |
04 |
// SDRAM |
05 |
output [11:0] SDRAM_ADDR, |
06 |
output [1:0] SDRAM_BA, |
07 |
output SDRAM_CAS_N, |
08 |
output SDRAM_CLK, |
09 |
output SDRAM_CKE, |
10 |
output SDRAM_CS_N, |
11 |
inout [15:0] SDRAM_DQ, |
12 |
output [1:0] SDRAM_DQM, |
13 |
output SDRAM_RAS_N, |
14 |
output SDRAM_WE_N |
15 |
); |
16 |
|
17 |
wire nios_core_clk; |
18 |
sdram_pll sdram_pll_inst( |
19 |
.inclk0 (CLOCK_50), |
20 |
.c0 (nios_core_clk), |
21 |
.c1 (SDRAM_CLK) |
22 |
); |
23 |
|
24 |
nios_core_0 nios_core_0_inst( |
25 |
// |
26 |
.clk_0 (nios_core_clk), |
27 |
// |
28 |
.reset_n (1'b1), |
29 |
|
30 |
.zs_addr_from_the_sdram_0 (SDRAM_ADDR), |
31 |
.zs_ba_from_the_sdram_0 (SDRAM_BA), |
32 |
.zs_cas_n_from_the_sdram_0 (SDRAM_CAS_N), |
33 |
.zs_cke_from_the_sdram_0 (SDRAM_CKE), |
34 |
.zs_cs_n_from_the_sdram_0 (SDRAM_CS_N), |
35 |
.zs_dq_to_and_from_the_sdram_0 (SDRAM_DQ), |
36 |
.zs_dqm_from_the_sdram_0 (SDRAM_DQM), |
37 |
.zs_ras_n_from_the_sdram_0 (SDRAM_RAS_N), |
38 |
.zs_we_n_from_the_sdram_0 (SDRAM_WE_N) |
39 |
); |
40 |
|
41 |
endmodule |
编译之,生成的RTL视图。
图3-2 该工程的RTL视图
(3)分配管脚
请参考:[原创].在Quartus II中分配管脚的两种常用方法.[Quartus II]
二 软件部分
1 使用模板创建软件工程
图1-1 使用模板创建软件工程
图1-2 选择Hello MicroC/OS-II模板
2 编译软件工程
图2-1 编译软件工程
3 运行工程
图3-1 选择运行Nios II硬件
图3-2 查看JTAG是否连接正确
运行之。
4 查看运行结果
图4-1 模板的运行结果
至此,一个可以运行的μC/OS-II的平台搭建完毕。想要深入研究μC/OS-II,只需增减相应的C代码即可。
5 附录:模板代码
01 |
#include |
02 |
#include "includes.h" |
03 |
|
04 |
/* Definition of Task Stacks */ |
05 |
#define TASK_STACKSIZE 2048 |
06 |
OS_STK task1_stk[TASK_STACKSIZE]; |
07 |
OS_STK task2_stk[TASK_STACKSIZE]; |
08 |
|
09 |
/* Definition of Task Priorities */ |
10 |
|
11 |
#define TASK1_PRIORITY 1 |
12 |
#define TASK2_PRIORITY 2 |
13 |
|
14 |
/* Prints "Hello World" and sleeps for three seconds */ |
15 |
void task1( void * pdata) |
16 |
{ |
17 |
while (1) |
18 |
{ |
19 |
printf ( "Hello from task1\n" ); |
20 |
OSTimeDlyHMSM(0, 0, 3, 0); |
21 |
} |
22 |
} |
23 |
/* Prints "Hello World" and sleeps for three seconds */ |
24 |
void task2( void * pdata) |
25 |
{ |
26 |
while (1) |
27 |
{ |
28 |
printf ( "Hello from task2\n" ); |
29 |
OSTimeDlyHMSM(0, 0, 3, 0); |
30 |
} |
31 |
} |
32 |
/* The main function creates two task and starts multi-tasking */ |
33 |
int main( void ) |
34 |
{ |
35 |
|
36 |
OSTaskCreateExt(task1, |
37 |
NULL, |
38 |
( void *)&task1_stk[TASK_STACKSIZE-1], |
39 |
TASK1_PRIORITY, |
40 |
TASK1_PRIORITY, |
41 |
task1_stk, |
42 |
TASK_STACKSIZE, |
43 |
NULL, |
44 |
0); |
45 |
|
46 |
|
47 |
OSTaskCreateExt(task2, |
48 |
NULL, |
49 |
( void *)&task2_stk[TASK_STACKSIZE-1], |
50 |
TASK2_PRIORITY, |
51 |
TASK2_PRIORITY, |
52 |
task2_stk, |
53 |
TASK_STACKSIZE, |
54 |
NULL, |
55 |
0); |
56 |
OSStart(); |
57 |
return 0; |
58 |
} |
三 一些说明
注意:sys_clk_timer是运行μC/OS-II所必需的组件。PLL为什么不加延时复位模块?我猜测Cyclone II的PLL初始化已经很快了;不需要过多延时,就可输出稳定的时钟源;但也不确定是否如此,以后再研究。
此外,使用HDL来描述顶层文件,比原理图描述方便了许多;推荐大家使用HDL。
四 参考
1 Altera.Hello MicroC/OS-II
2 Altera.Using the MicroC/OS-II RTOS with the Nios II Processor Tutorial