本帖最后由 nicholasldf 于 2011-4-23 22:35 编辑
三星2410的样例程序:
基于ADS1.2的S3C2410样例代码.rar
(69.34 KB)
基于2410的uCOS-II:
uCOS-II_S3C2410.zip
(179.36 KB)
1、基础阶段
话说06年第一份工作从事的是PLC开发,用protel画原理图和PCB,写AVR单片机程序,焊焊板子,还去过华强北买器件,比较杂,但是接触面比较广,为进一步学ARM打下了基础。
期间不甘心只停留在AVR单片机层次,买了邵贝贝的《uCOS-II嵌入式操作系统》,看了4-5遍,弄懂它的原理,还看了陈明计的《SmallRTOS嵌入式操作系统》,之后自己写了一个AVR的时间片调度器。
2、接触ARM
08年4月份换了工作,搞B超,接触三星的S3C2410,看2410的数据手册,开始接触到ARM的32个寄存器、中断管理、MMU、7种工作模式,还真的晕了好长一段时间,模模糊糊,弄不懂,挺痛苦的。工作中也开始实践起来,基于ADS1.2,采用uCOS-II。
先不管ARM内核的细节、产品平台底层的细节,也先不管USB、LCD、内存控制器等较复杂的部分。先搞单片机有的那些外设,发现单单写2410的驱动程序,如SPI、USART、IO控制,发现跟单片机一样,只要看2410数据手册的SPI、USART、IO口部分就行了。这时,信心有了,感觉自己多少可以把2410玩起来了。
这时买了一块2410开发板,带有ADS1.2例程,这些例程有启动汇编代码,还有底层的一些C语言初始化代码,看的很费劲,不知道是啥意思。没关系,你总会找到main函数入口吧?其他我不管,先自己在main函数里面编编代码玩玩先,试了URAT、SPI、I2C、RTC,跑起来了。这时再学学中断,按照例程的中断,自己也编写一下自己的中断例子。
发现经过例程学习ARM,效果比单看书好的多。单看书你会晕,很多不明白,越看越枯燥,越看越没信心,感觉看了很久,心里还不知道ARM是什么。学学例程的话,把ARM当单片机用,很简单,上手很快,你对ARM的恐惧感就慢慢消失了,信心也有了,再结合书本,对照例子,心中一些不明白的ARM内核原理,也逐渐开朗,哦,原来如此,原理很简单嘛。
再后来,看ARM原理、MMU、中断管理、SDRAM、LCD控制器,自然而然的都明白了。
3、提高
基础有了,慢慢的接触到USB、FAT文件系统、U-BOOT、GUI显示,一个一个的去熟悉,发现你已经入了嵌入式的大门,慢慢的积累,每搞定一个功能,也小有成就感了。
4、后记
09年五一又换了一份工作,用atmel的9260芯片,搭建软件平台,这时对以往知识的一次综合应用,以前都是现成的平台,自己在上面添加功能,修修改改,这一次,是从无到有的建立ARM+uCOS-II软件平台:
编译器选型,选了MDK,上网找**;
了解9260的启动过程,程序烧写方案;
选择调试工具,建立调试环境,使用JLINK、或者wiggler+HJTAG;
uCOS-II移植,下载了官方IAR移植版的,根据MDK做修改,终于跑起来;
编写9260各种外设驱动;
应用软件系统结构设计,多任务划分;应用编程,问题解决,这一块花的时间最多了。
学习zmodem,把官方的zmodem程序看懂,移植到产品上,做了一个不超过4K的9260引导程序,代替atmel的at91bootstrap,可以通过“超级终端+串口”烧录程序,而用SAM-BA烧写,很麻烦;
深入分析了yaffs文件系统,做了一个日志系统,计划今年将yaffs分析经验写成一个文档;
今年的计划:预测物联网趋势,网络将会大规模应用,要深入学习tcpip,学精,分析lwip代码
5、希望能给后来者参考价值。:)
任务调度器代码:
(1)头文件:任务控制块TCB定义、保存任务环境的入栽宏、恢复任务现场的出栽宏。
typedef struct
{
unsigned char* task_stk_top; //保存任务的栽顶
unsigned char task_stack[100];//任务堆栽
}OS_TASK_TCB;
//任务现场保护,保存所有寄存器的宏
#define pushall() \
__asm__ __volatile__ ("push r1" "\n\t");\
__asm__ __volatile__ ("push r0" "\n\t");\
__asm__ __volatile__ ("in r0, 0x3f" "\n\t");\保存CPU状态寄存器
__asm__ __volatile__ ("push r0" "\n\t");\
__asm__ __volatile__ ("eor r1, r1" "\n\t");\WINAVR要求R1等于0
__asm__ __volatile__ ("push r2" "\n\t");\
__asm__ __volatile__ ("push r3" "\n\t");\
__asm__ __volatile__ ("push r4" "\n\t");\
__asm__ __volatile__ ("push r5" "\n\t");\
__asm__ __volatile__ ("push r6" "\n\t");\
__asm__ __volatile__ ("push r7" "\n\t");\
__asm__ __volatile__ ("push r8" "\n\t");\
__asm__ __volatile__ ("push r9" "\n\t");\
__asm__ __volatile__ ("push r10" "\n\t");\
__asm__ __volatile__ ("push r11" "\n\t");\
__asm__ __volatile__ ("push r12" "\n\t");\
__asm__ __volatile__ ("push r13" "\n\t");\
__asm__ __volatile__ ("push r14" "\n\t");\
__asm__ __volatile__ ("push r15" "\n\t");\
__asm__ __volatile__ ("push r16" "\n\t");\
__asm__ __volatile__ ("push r17" "\n\t");\
__asm__ __volatile__ ("push r18" "\n\t");\
__asm__ __volatile__ ("push r19" "\n\t");\
__asm__ __volatile__ ("push r20" "\n\t");\
__asm__ __volatile__ ("push r21" "\n\t");\
__asm__ __volatile__ ("push r22" "\n\t");\
__asm__ __volatile__ ("push r23" "\n\t");\
__asm__ __volatile__ ("push r24" "\n\t");\
__asm__ __volatile__ ("push r25" "\n\t");\
__asm__ __volatile__ ("push r26" "\n\t");\
__asm__ __volatile__ ("push r27" "\n\t");\
__asm__ __volatile__ ("push r28" "\n\t");\
__asm__ __volatile__ ("push r29" "\n\t");\
__asm__ __volatile__ ("push r30" "\n\t");\
__asm__ __volatile__ ("push r31" "\n\t");\
//恢复任务现场,弹出所有寄存器的宏
#define popall() \
__asm__ __volatile__ ("pop r31" "\n\t");\
__asm__ __volatile__ ("pop r30" "\n\t");\
__asm__ __volatile__ ("pop r29" "\n\t");\
__asm__ __volatile__ ("pop r28" "\n\t");\
__asm__ __volatile__ ("pop r27" "\n\t");\
__asm__ __volatile__ ("pop r26" "\n\t");\
__asm__ __volatile__ ("pop r25" "\n\t");\
__asm__ __volatile__ ("pop r24" "\n\t");\
__asm__ __volatile__ ("pop r23" "\n\t");\
__asm__ __volatile__ ("pop r22" "\n\t");\
__asm__ __volatile__ ("pop r21" "\n\t");\
__asm__ __volatile__ ("pop r20" "\n\t");\
__asm__ __volatile__ ("pop r19" "\n\t");\
__asm__ __volatile__ ("pop r18" "\n\t");\
__asm__ __volatile__ ("pop r17" "\n\t");\
__asm__ __volatile__ ("pop r16" "\n\t");\
__asm__ __volatile__ ("pop r15" "\n\t");\
__asm__ __volatile__ ("pop r14" "\n\t");\
__asm__ __volatile__ ("pop r13" "\n\t");\
__asm__ __volatile__ ("pop r12" "\n\t");\
__asm__ __volatile__ ("pop r11" "\n\t");\
__asm__ __volatile__ ("pop r10" "\n\t");\
__asm__ __volatile__ ("pop r9" "\n\t");\
__asm__ __volatile__ ("pop r8" "\n\t");\
__asm__ __volatile__ ("pop r7" "\n\t");\
__asm__ __volatile__ ("pop r6" "\n\t");\
__asm__ __volatile__ ("pop r5" "\n\t");\
__asm__ __volatile__ ("pop r4" "\n\t");\
__asm__ __volatile__ ("pop r3" "\n\t");\
__asm__ __volatile__ ("pop r2" "\n\t");\
__asm__ __volatile__ ("pop r0" "\n\t");\
__asm__ __volatile__ ("out 0x3f, r0" "\n\t");\恢复CPU状态寄存器
__asm__ __volatile__ ("pop r0" "\n\t");\
__asm__ __volatile__ ("pop r1" "\n\t");\
__asm__ __volatile__ ("RETI" "\n\t");\
//******************************************************************
(2)主函数main()代码,包括8个任务,调度程序,定义8个任务,每个任务对应一个LED灯的闪烁:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "RTOS.h"
#define LED_PORT PORTA //LED端口定义
#define LED_DDR DDRA
#define LED_PIN PINA
//第1个任务定义
void task1( void )
{
unsigned char temp ;//任务1的局部变量
//在任务1启动节拍定时器
TCCR0 = 0X05;//定时器0初始化
TIMSK = 0X01;
TCNT0 = 0x00;
sei();//打开全局中断
while(1)
{
temp++;
LED_PORT ^=0X01;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第2个任务定义
void task2(void)
{
while(1)
{
LED_PORT ^=0X02;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第3个任务定义
void task3(void)
{
while(1)
{
LED_PORT ^=0X04;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第4个任务定义
void task4(void)
{
while(1)
{
LED_PORT ^=0X08;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第5个任务定义
void task5(void)
{
while(1)
{
LED_PORT ^=0X10;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第6个任务定义
void task6(void)
{
while(1)
{
LED_PORT ^=0X20;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第7个任务定义
void task7(void)
{
while(1)
{
LED_PORT ^=0X40;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//第8个任务定义
void task8(void)
{
while(1)
{
LED_PORT ^=0X80;
for( unsigned char i=0; i<250; i++)
_delay_ms(10);
}
}
//*******************************************************************
volatile unsigned char next_task = 0;//用来指出下一个运行的任务
//计数变量,在定时器0中断函数里加1,用来控制任务切换频率
volatile unsigned char count = 0;
volatile OS_TASK_TCB task_tcb[ 8 ];//定义8个任务的任务控制块TCB数组
//任务堆栽初始化函数,参数为:任务入口地址、任务序号(1-8)
unsigned char* stackinit( void (*task)( void ), unsigned char task_id )
{
unsigned char* stk;
unsigned int temp;
temp = (unsigned int)task;//任务入口地址
stk = &( task_tcb[task_id].task_stack[99] );//取得任务栽顶指针
*stk-- = (unsigned char)(temp&0xff);//将任务入口地址入栽
*stk-- = (unsigned char)(temp>>8);
//以下是CPU所有寄存器初始化,为0值,
*stk-- = (unsigned char)0x00; /* R0 = 0x00 */
*stk-- = (unsigned char)0x00; /* R1 = 0x00 */
*stk-- = (unsigned char)0x80; /* R2 = 0x00 */
*stk-- = (unsigned char)0x00; /* R3 = 0x00 */
*stk-- = (unsigned char)0x00; /* R4 = 0x00 */
*stk-- = (unsigned char)0x00; /* R5 = 0x00 */
*stk-- = (unsigned char)0x00; /* R6 = 0x00 */
*stk-- = (unsigned char)0x00; /* R7 = 0x00 */
*stk-- = (unsigned char)0x00; /* R8 = 0x00 */
*stk-- = (unsigned char)0x00; /* R9 = 0x00 */
*stk-- = (unsigned char)0x00; /* R10 = */
*stk-- = (unsigned char)0x00; /* R11 = */
*stk-- = (unsigned char)0x00; /* R12 = */
*stk-- = (unsigned char)0x00; /* R13 = */
*stk-- = (unsigned char)0x00; /* R14 = */
*stk-- = (unsigned char)0x00; /* R15 = */
*stk-- = (unsigned char)0x00; /* R16 = */
*stk-- = (unsigned char)0x00; /* R17 = */
*stk-- = (unsigned char)0x00; /* R18 = */
*stk-- = (unsigned char)0x00; /* R19 = */
*stk-- = (unsigned char)0x00; /* R20 = */
*stk-- = (unsigned char)0x00; /* R21 = */
*stk-- = (unsigned char)0x00; /* R22 = */
*stk-- = (unsigned char)0x00; /* R23 = */
*stk-- = (unsigned char)0x00; /* R24 = 0x00 */
*stk-- = (unsigned char)0x00; /* R25 = 0x00 */
*stk-- = (unsigned char)0x00; /* R26 = */
*stk-- = (unsigned char)0x00; /* R27 = */
*stk-- = (unsigned char)0x00; /* R28 = */
*stk-- = (unsigned char)0x00; /* R29 = */
*stk-- = (unsigned char)0x00; /* R30 = */
*stk-- = (unsigned char)0x00; /* R31 = */
*stk-- = (unsigned char)0x00; /* SREG = */
return ( (unsigned char*)stk );//返回当前堆栈指针
}
//任务创建函数:
void taskcreat( void (*task)( void ), unsigned char task_id )
{
unsigned char *temp;
temp = stackinit( task, task_id );//堆栽初始化,并返回栽顶指针
//初始化之后将堆栽栽顶指针保存在任务的TCB里,这个变量一直指向栽顶
task_tcb[task_id].task_stk_top = temp;
}
//调度器启动函数,用于运行第一个任务
void OS_Start( void )
{
SP = task_tcb[0].task_stk_top + 33;//堆栽指针指向第一个任务
//用中断返回指令将入口地址弹出到PC指针,运行第一个任务
asm("RETI");
}
//定时器0的中断函数:作周期中断,每次中断,表示当前任务的时间片用完,将结束当前任务,调用下一个任务
//加上下面这句,WINAVR将不保存任何寄存器
void SIG_OVERFLOW0( void ) __attribute__ ( ( signal, naked ) );
SIGNAL( SIG_OVERFLOW0 )
{
pushall( );//自己人工保存所有寄存器
count++; //每次中断加1
if(count>100)//100时任务切换,count值可以调整任务切换频率
{
count = 0;//重新清0
task_tcb[ next_task % 8 ].task_stk_top =SP;//保存当前任务的栽顶SP指针到当前任务的控制块TCB
next_task++;指向下一个任务
//堆栽指针指向下一个任务栽顶
SP = task_tcb[ next_task % 8 ].task_stk_top;
}
popall( );//人工恢复所有寄存器
}
//main()函数
int main( void )
{
//LED灯控制端口设置
LED_PORT=0Xff;
LED_DDR =0Xff;
//创建并初始化8个任务
taskcreat( task1, 0 );
taskcreat( task2, 1 );
taskcreat( task3, 2 );
taskcreat( task4, 3 );
taskcreat( task5, 4 );
taskcreat( task6, 5 );
taskcreat( task7, 6 );
taskcreat( task8, 7 );
OS_Start( );//开始运行任务
while( 1 );
}//**************************************************************** |