【OK210试用体验】LED流水灯 - 在线问答 - 电子威廉希尔官方网站 论坛 - 最好最受欢迎电子论坛!

【OK210试用体验】LED流水灯

刘天 ( 楼主 ) 2015-7-15 21:27:59  只看该作者 倒序浏览
LED流水灯
象棋小子          1048272975
嵌入式教程中流水灯以及程序教程中的”Hello world”都有其特殊的意义,意味着入门。笔者此处也不例外,分别以汇编、c语言在IAR下点流水灯作为S5PV210入门程序。点流水灯之前必须对芯片有基本的认识,包括其指令集、流水线等内核架构,基本的启动流程,基本的编译器开发特性等,只有这样点亮的流水灯才算实现其意义。
1. 指令集
S5PV210是Cortex-A8内核,该内核为ARMv7-A架构,支持两个最主要的指令集:32位ARM指令集以及16/32位Thumb-2指令集。ARM指令集每条指令采用32位长度,具有最高的效率,但也需要更多的代码空间,ARM指令集是向后兼容的,即ARMv7-A的处理器几乎可以直接执行ARMv4架构的ARM指令集代码(如ARM7的应用代码)。Thumb-2是Thumb的扩展指令集,在ARMv6架构前,Thumb作为16位指令集,是作为ARM指令集的子集,它是为了减小代码量而提出的,并不完整,只支持通用功能,无法脱离ARM指令集。在ARMv7架构中,Thumb-2作为必备指令集,它支持16/32混合指令模式,几乎实现了所有的ARM指令集功能,并且效率接近ARM指令集,代码密度接近Thumb指令集。Thumb-2指令集的引入意味着程序存储器可以更小,在一些Cache应用中,相同容量的指令Cache可以缓存更多的指令,提高了指令Cache命中率,间接提升了内核性能。例如,对于Cortex-M内核,更是只支持Thumb-2指令集,因此一般无特殊情况,对于ARMv7内核,也可以直接采用Thumb-2指令集。
2. 流水线
S5PV210内核Cortex-A8配置了先进的超标量体系结构管线,能够同时执行多条指令,提供超过2.0 DMIPS/MHZ,集成了32k/32k的指令/数据一级缓存以及512k的二级缓存,从而达到最快的读取速度和最大的吞吐量,使用了先进的分支预测威廉希尔官方网站 ,并且具有专用的NEON整形和浮点型管线进行媒体和信号处理。
Cortex-A8流水线架构基于双对称、顺序发射的13级流水线,硬件上具有I/D Cache、分支预测结构,因此指令在流水线的流入流出过程变得不明确,但仍可以通过统计分析其大概的过程。
S5PV210在上电启动后,最先执行内部BL0代码,代码只初始化并开启I Cache,其它D Cache、L2 Cache、分支预测均是关闭的,设置了CPU主频为400M,最后是跳转到用户的BL1代码。我们在BL1中的流水灯代码根据以上信息,可以设计一个较精确的软件延时函数,每次访问I Cache均会命中,每次访问D Cache均从主存读取,需要相应周期的等待延时,每次跳转均会分支预测失败,清流水线需额外13个CPU时钟。在一个实用的系统中,I/D Cache、分支预测等硬件功能必须开启,不然CPU性能大大打折扣。
3. 汇编实现
汇编代码中有两点需要注意:
1) ARMv7-A架构推荐基本用Thumb-2指令集,有相当好的效率以及较好的代码密度,BL0跳转到BL1时是ARM状态,因此BL1流水灯第一条指令为ARM指令,切换到Thumb状态后开始执行Thumb-2指令。
2) 此处避开链接器功能,不使用链接文件,编写的流水灯代码应该是位置无关的,即代码加载进任意RAM位置都是可以正确执行的。

; IO port for controling LEDs
GPM0_4_BASE        EQU     0xE0200340  ; GPM04 Base Address
GPD0_BASE              EQU            0xE02000A0
GPCON_OFS          EQU       0x00        ; Control Register Offset
GPDAT_OFS          EQU     0x04        ; Data Register Offset

LED1                EQU                4                        ; GPM04_4->LED1
LED2                EQU                5                        ; GPM04_5->LED2
LED3                EQU                6                        ; GPM04_6->LED3
LED4                EQU                7                        ; GPM04_7->LED4
BEEP                EQU                0                        ; GPD0_0->BEEP

        SECtiON RESET:CODE:NOROOT(2)
        PUBLIC        __iar_program_start

        ARM
__iar_program_start
        BL        Reset
       
        THUMB
Reset
        BL        Gpio_Init

Loop
        LDR        R0, =GPM0_4_BASE
        LDR R1, [R0, #GPDAT_OFS]
        BIC        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED1 on
        LDR        R7, =1000 ; delay 1s
        BL        Delay_ms
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS]
       
        LDR R1, [R0, #GPDAT_OFS]
        BIC        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED2 on
        LDR        R7, =1000 ; delay 1s
        BL        Delay_ms
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS]       
       
        LDR R1, [R0, #GPDAT_OFS]
        BIC        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED3 on
        LDR        R7, =1000 ; delay 1s
        BL        Delay_ms
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS]       
       
        LDR R1, [R0, #GPDAT_OFS]
        BIC        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED4 on
        LDR        R7, =1000 ; delay 1s
        BL        Delay_ms
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS]
       
        LDR        R0, =GPD0_BASE
        LDR R1, [R0, #GPDAT_OFS]
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; BEEP on
        LDR        R7, =1000 ; delay 1s
        BL        Delay_ms
        BIC        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS]
       
        B        Loop
       
       
Gpio_Init
        LDR        R0, =GPM0_4_BASE
        LDR R1, [R0, #GPCON_OFS]
        BIC        R1, R1, #(0xf<<(LED1<<2))
        ORR R1, R1, #(0x1<<(LED1<<2)) ; GPM04_4 output led1
        STR        R1, [R0, #GPCON_OFS]
        LDR R1, [R0, #GPDAT_OFS]
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED1 off

        LDR R1, [R0, #GPCON_OFS]
        BIC        R1, R1, #(0xf<<(LED2<<2))
        ORR R1, R1, #(0x1<<(LED2<<2)) ; GPM04_5 output led2
        STR        R1, [R0, #GPCON_OFS]               
        LDR R1, [R0, #GPDAT_OFS]
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED2 off       
       
        LDR R1, [R0, #GPCON_OFS]
        BIC        R1, R1, #(0xf<<(LED3<<2))
        ORR R1, R1, #(0x1<<(LED3<<2)) ; GPM04_6 output led3
        STR        R1, [R0, #GPCON_OFS]       
        LDR R1, [R0, #GPDAT_OFS]
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED3 off       
       
        LDR R1, [R0, #GPCON_OFS]
        BIC        R1, R1, #(0xf<<(LED4<<2))
        ORR R1, R1, #(0x1<<(LED4<<2)) ; GPM04_7 output led4
        STR        R1, [R0, #GPCON_OFS]       
        LDR R1, [R0, #GPDAT_OFS]
        ORR        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; LED4 off       
       
        LDR        R0, =GPD0_BASE
        LDR R1, [R0, #GPCON_OFS]
        BIC        R1, R1, #(0xf<<(BEEP<<2))
        ORR R1, R1, #(0x1<<(BEEP<<2)) ; GPD0_0 output
        STR        R1, [R0, #GPCON_OFS]
        LDR R1, [R0, #GPDAT_OFS]
        BIC        R1, R1, #(1<
        STR        R1, [R0, #GPDAT_OFS] ; BEEP off       
       
        BX        LR

; ARM CLOCK 400M
Delay_ms       
        LDR  R6, =13333 ; 延时1ms
Delay2                       
        SUBS R6, R6, #1 ; 单发射 cycle 1
        ; 跳转清流水线,以下指令均只用作填充流水线
        MOV        R0, R0 ; 双发射 cycle 1
        MOV R0, R0 ; 单发射 cycle 2
        MOV R0, R0 ; 单发射 cycle 3
        MOV        R0, R0 ; 单发射 cycle 4
        MOV R0, R0 ; 单发射 cycle 5
        MOV R0, R0 ; 单发射 cycle 6
        MOV        R0, R0 ; 单发射 cycle 7
        MOV R0, R0 ; 单发射 cycle 8
        MOV R0, R0 ; 单发射 cycle 9
        MOV        R0, R0 ; 单发射 cycle 10
        MOV R0, R0 ; 单发射 cycle 11
        MOV R0, R0 ; 单发射 cycle 12
        MOV        R0, R0 ; 单发射 cycle 13
        MOV R0, R0 ; 单发射 cycle 14
        MOV R0, R0 ; 单发射 cycle 15
        MOV R0, R0 ; 单发射 cycle 16
        MOV        R6, R6 ; 单发射 cycle 17
        BNE  Delay2 ; 跳转会清流水线,13个ARM CLOCK,cycle 30

        SUBS R7, R7, #1
        BNE         Delay_ms
        BX   LR       
        END
4. C实现
C代码中需要注意两点:
1) 需要汇编指令跳转到c函数,链接器默认链接.intvec段做为代码的开头,需一条跳转汇编指令链接到代码起启位置,用来跳转到c入口。
       SECTION .intvec:CODE:NOROOT(2)
       PUBLIC   __iar_program_start
       ARM
__iar_program_start
       EXTERN  main
       BLX main
       END
2)c文件中不要尝试使用c库以及使用全局变量、静态变量等,因为此处避开链接器功能,不使用链接文件,编写的流水灯代码c运行环境都是BL0初始化的,是位置无关的,只有栈是有效的。

#include "stdint.h"


// IO port for controling LEDs
#define         GPM04_BASE        0xE0200340  // GPM04 Base Address
#define         GPD0_BASE        0xE02000A0
#define         GPCON_OFS        0x00        // Control Register Offset
#define         GPDAT_OFS        0x04        // Data Register Offset


#define         MP0_4CON_REG        (*(volatile uint32_t *)(GPM04_BASE+GPCON_OFS))
#define         MP0_4DAT_REG        (*(volatile uint32_t *)(GPM04_BASE+GPDAT_OFS))
#define         GPD0CON_REG        (*(volatile uint32_t *)(GPD0_BASE+GPCON_OFS))
#define         GPD0DAT_REG          (*(volatile uint32_t *)(GPD0_BASE+GPDAT_OFS))


#define         LED1        4        // GPM0_4->LED1
#define         LED2        5        // GPM0_5->LED2
#define         LED3        6        // GPM0_6->LED3
#define         LED4        7        // GPM0_7->LED4
#define    BEEP                0          // GPD0_0->BEEP


void Delay_ms(uint32_t Count)
{
        //延时1ms,共延时nCountms
        // Arm clock为400M,循环体每次30个Arm clock
        int32_t temp1 = 13333;
        int32_t temp2 = 0;
        asm volatile (
                "Delay_ms_0:n"
                "mov  %0, %2n"  
                "Delay_ms_1:n"
                "subs  %0, %0, #1n" // 单发射 cycle 1
                // 跳转清流水线,以下指令均只用作填充流水线
                "mov %1, %1n"        // 双发射 cycle 1
                "mov %1, %1n"        // 单发射 cycle 2
                "mov %1, %1n"        // 单发射 cycle 3
                "mov %1, %1n"        // 单发射 cycle 4        
                "mov %1, %1n"        // 单发射 cycle 5        
                "mov %1, %1n"        // 单发射 cycle 6
                "mov %1, %1n"        // 单发射 cycle 7
                "mov %1, %1n"        // 单发射 cycle 8
                "mov %1, %1n"        // 单发射 cycle 9
                "mov %1, %1n"        // 单发射 cycle 10
                "mov %1, %1n"        // 单发射 cycle 11
                "mov %1, %1n"        // 单发射 cycle 12
                "mov %1, %1n"        // 单发射 cycle 13
                "mov %1, %1n"        // 单发射 cycle 14
                "mov %1, %1n"        // 单发射 cycle 15
                "mov %1, %1n"        // 单发射 cycle 16
                "mov %0, %0n"        // 单发射 cycle 17
                "bne.w Delay_ms_1n" // 跳转会清流水线,13级流水线,cycle 30
                "subs  %1, %1, #1n"   // 调用者确保nCount不为0
                "bne.w Delay_ms_0n"
                : "+r"(temp2), "+r"(Count): "r"(temp1): "cc"
        );       
}


void Gpio_LED1(uint8_t On)
{
        if (On) {
                MP0_4DAT_REG &= ~(1<         } else {
                MP0_4DAT_REG |= (1<         }
}


void Gpio_LED2(uint8_t On)
{
        if (On) {
                MP0_4DAT_REG &= ~(1<         } else {
                MP0_4DAT_REG |= (1<         }
}


void Gpio_LED3(uint8_t On)
{
        if (On) {
                MP0_4DAT_REG &= ~(1<         } else {
                MP0_4DAT_REG |= (1<         }
}


void Gpio_LED4(uint8_t On)
{
        if (On) {
                MP0_4DAT_REG &= ~(1<         } else {       
                MP0_4DAT_REG |= (1<         }
}


void Gpio_Beep(uint8_t On)
{
        if (On) {
                GPD0DAT_REG |= (1<         } else {       
                GPD0DAT_REG &= ~(1<         }       
}


void Gpio_Init(void)
{
        // GPM04_4 output led1, off
        MP0_4CON_REG = (MP0_4CON_REG & (~(0xf<<(LED1<<2)))) | (0x1<<(LED1<<2));  
        MP0_4DAT_REG |= (1<         // GPM04_5 output led2, off
        MP0_4CON_REG = (MP0_4CON_REG & (~(0xf<<(LED2<<2)))) | (0x1<<(LED2<<2));  
        MP0_4DAT_REG |= (1<         // GPM04_6 output led3, off
        MP0_4CON_REG = (MP0_4CON_REG & (~(0xf<<(LED3<<2)))) | (0x1<<(LED3<<2));  
        MP0_4DAT_REG |= (1<         // GPM04_7 output led4, off
        MP0_4CON_REG = (MP0_4CON_REG & (~(0xf<<(LED4<<2)))) | (0x1<<(LED4<<2));  
        MP0_4DAT_REG |= (1<         // Beep output, off
        GPD0CON_REG = (GPD0CON_REG & (~(0xf<<(BEEP<<2)))) | (0x1<<(BEEP<<2));
        GPD0DAT_REG &= ~(1< }


void main(void)
{
        Gpio_Init();
        while (1) {       
                Gpio_LED1(1);
                Delay_ms(1000);       
                Gpio_LED1(0);
                Gpio_LED2(1);
                Delay_ms(1000);       
                Gpio_LED2(0);
                Gpio_LED3(1);
                Delay_ms(1000);       
                Gpio_LED3(0);
                Gpio_LED4(1);
                Gpio_Beep(1);               
                Delay_ms(1000);
                Gpio_LED4(0);
                Gpio_Beep(0);
        }
}
5. 流水灯运行
编译器直接编译生成的二进制代码是不满足相应的启动格式的,需要通过SdBoot.exe生成相应的sd/mmc烧录代码,再通过SdBoot.exe把带”_1”后缀的sd/mmc烧录文件烧录进sd/mmc卡,设置目标板从sd/mmc卡启动,即可运行sd/mmc卡里面的流水灯程序。
6. 附录
附件为基于OK210、IAR下S5PV210汇编流水灯工程例程以及C流水灯工程例程,SdBoot相关工具。
attach:// OK210_IAR_LEDS.rar (261.71 KB, 下载次数: 51)

奖励1积分

2个回复

刘盾 发表于 2015-8-22 21:40:27
请问大神写程序用的什么软件??
回复 3

举报 使用道具

刘盾 发表于 2015-8-22 21:47:56
刘盾8888 发表于 2015-8-22 21:40
请问大神写程序用的什么软件??

          是IAR吗???
回复 3

举报 使用道具

您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /6 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-9-22 16:39 , Processed in 0.382410 second(s), Total 40, Slave 30 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表