打印

我的ARM学习经历 附点资料

[复制链接]
30418|134
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nicholasldf|  楼主 | 2011-3-17 15:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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 );   
}//****************************************************************

相关帖子

沙发
生化分析仪| | 2011-3-17 15:32 | 只看该作者
:victory:,加油!!写的不错

使用特权

评论回复
板凳
徐可可123| | 2011-3-18 21:18 | 只看该作者
顶,楼主在多指教

使用特权

评论回复
地板
潇湘道人| | 2011-3-19 09:33 | 只看该作者
不错!顶[img][/img]

使用特权

评论回复
5
zhanmin975| | 2011-3-19 09:36 | 只看该作者
不错 学习了

使用特权

评论回复
6
潇湘道人| | 2011-3-19 09:37 | 只看该作者
:shutup:

使用特权

评论回复
7
liulei20101008| | 2011-3-19 09:41 | 只看该作者
不错,很有收获,顶楼主

使用特权

评论回复
8
q564785326| | 2011-3-19 09:45 | 只看该作者
不错

使用特权

评论回复
9
slovef2199| | 2011-3-21 13:45 | 只看该作者
学习了

使用特权

评论回复
10
潇湘道人| | 2011-3-21 16:09 | 只看该作者
这个要顶

使用特权

评论回复
11
yezhubenyue| | 2011-3-21 22:39 | 只看该作者
学习了~~~

使用特权

评论回复
12
ttlasong| | 2011-3-22 09:59 | 只看该作者
写得很好,加油。;P

使用特权

评论回复
13
sysdriver| | 2011-3-24 13:31 | 只看该作者
感觉这样的路程也不是简单的.
第一个:
           要有毅力,不然还真学不下去,不过搞电子的人都很有毅力的.
第二个:
        前面的学习对于熟练单片机的人来说,是简单的.
但是后面的描述:
        再后来,看ARM原理、MMU、中断管理、SDRAM、LCD控制器,自然而然的都明白了。
     3、提高
     基础有了,慢慢的接触到USB、FAT文件系统、U-BOOT、GUI显示,一个一个的去熟悉,发现你已经入了嵌入式的大门,慢慢的积累,每搞定一个功能,也小有成就感了。

涉及到系统的东西,几句就能解决的话那遍地都是学ARM的了.而且,即使能进门了,想要向深处爬,不从基础上,不从原理上学习,肯定不行的.

看LZ的水平,也是还在刚进门的时候

使用特权

评论回复
14
nicholasldf|  楼主 | 2011-3-25 00:23 | 只看该作者
14# sysdriver

呵呵,我水平很一般,所以在不停的学习,,学无止境。。
个人兴趣目标是把网络研究透一点,争取能自己写一个协议栈出来。
相信随着年月积累,,会迈出菜鸟行列,,早日跨入你们大牛行列。

使用特权

评论回复
15
yang58439363| | 2011-3-25 17:31 | 只看该作者
顶,谢谢

使用特权

评论回复
16
liuzhenya| | 2011-3-26 16:38 | 只看该作者
学习了

使用特权

评论回复
17
zsh198702| | 2011-3-27 21:39 | 只看该作者
够大师级的了

使用特权

评论回复
18
susongfu| | 2011-3-28 13:43 | 只看该作者
没基础   很多看不懂,学习

使用特权

评论回复
19
JESH.J| | 2011-3-29 11:11 | 只看该作者
有过收益……写的不错……

使用特权

评论回复
20
tangbin0505| | 2011-3-29 17:12 | 只看该作者
学习过,谢了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

261

帖子

10

粉丝