zoukankan      html  css  js  c++  java
  • 硬件重定向

    semihosting知识可知,semihosting只是将目标系统中的IO请求交给了调试环境来处理,但是在嵌入式系统实际应用中,往往嵌入式系统和主机调试环境是独立的,而嵌入式系统又想使用标准输入输出中的库函数,这时就要使用硬件重定向技术。

    应用程序中对外设的IO请求实际是对低层最基本IO硬件的封装,例如printf()函数,其实是对将数据写入到显示器相应寄存器的抽象封装,用户不用关心具体使用了什么硬件机制,也不用关心具体怎么将其打印到屏幕上。在ADS开发环境中,semihosting低层也进行了封装。在嵌入式应用系统中,常常需要重新实现一些低级的IO功能,以适应目标系统的具体情况。像这种将底层IO由其它硬件来实现的重定向机制叫做硬件重定向。如图3-15所示。

     

    Semihosting支持

    3-15底层IO重定向

     

    Semihosting将底层基本IO函数进行了封装,默认的semihosting模式下,底层基本IO都是针对显示器,键盘等硬件进行了封装,实现了对显示器,键盘输入等硬件的驱动,IO操作等。用户可以自己定义底层的基本IO函数,来实现目标开发板上IO硬件的驱动和IO操作,并且告之连接器,在连接程序时连接用户自己定义底层基本IO函数,而不是默认的调试环境下的底层基本IO函数。这样目标开发板运行应用程序中的IO操作就被重新定向到了自己的硬件上了。例如:标准输出函数printf()的底层基本IO函数是fputc(),它是向硬件里写入一个字符函数,用户自己将该函数重写,在fputc()里面实现向UART串口打印字符,而不是打印到标准输出显示器上。这样一来, printf()系列函数的输出都被重定向到UART串口上去了。

    实现硬件重定向时有以下几点需要注意:

    (1)       声明不使用semihosting SWI来请求host主机IO操作,而是使用自定义IO操作

    (2)       驱动重定向硬件设备

    (3)       重写低级IO函数

    硬件重定向实验

    该程序文件主要用于启动处理,声明不使用semihosting SWI来请求host主机IO操作,关闭看门狗,初始化内存,最后跳入到main函数中执行。由于程序本身实现了reg_init_no_pll.txt脚本文件的功能,因此本实验不需要加载初始化脚本。

            AREA  Init, CODE, READONLY

            ; 确保不使用系统C库中的底层IO函数接口,而是使用用户自己定义IO接口

            IMPORT __use_no_semihosting_swi

     

            ENTRY

            EXPORT  Reset_Handler

     

    Reset_Handler

          ; 关闭看门狗

          ldr r0, = 0x53000000

          mov r1, #0

          str r1, [r0]

            bl initmem

                   

            IMPORT  __main

            B       __main   ; 使用B指令跳入main而不使用BL指令因为不需要返回

    initmem

          ldr r0, =0x48000000

          ldr r1, =0x48000034

          adr r2, memdata

    initmemloop

          ldr r3, [r2], #4

          str r3, [r0], #4

           teq r0, r1

          bne initmemloop

          mov pc,lr

    memdata

          DCD 0x22111110                ;BWSCON

          DCD 0x00000700                 ;BANKCON0    

          DCD 0x00000700                 ;BANKCON1    

          DCD 0x00000700                 ;BANKCON2    

          DCD 0x00000700               ;BANKCON3             

          DCD 0x00000700                 ;BANKCON4    

          DCD 0x00000700                 ;BANKCON5    

          DCD 0x00018005                 ;BANKCON6    

          DCD 0x00018005                 ;BANKCON7    

          DCD 0x008e07a3                  ;REFRESH        

          DCD 0x000000b1                 ;BANKSIZE      

           DCD 0x00000030                 ;MRSRB6 

          DCD 0x00000030                 ;MRSRB7

           END

    serial.c

    该程序文件主要实现了对UART串口的驱动和基本IO操作。由于IO请求硬件重定向最终要实现数据的输出和输入,通过读取UART串口寄存器读取串口数据取得用户输入信息,通过写入UART串口寄存器实现数据输出操作。

    #include "s3c2410.h"

     

    #define        TXD0READY    (1<<2)

    #define        RXD0READY   (1)

     

    void init_serial_A( )

    {

    //初始化UART

             GPHCON |= 0xa0;                //GPH2,GPH3 used as TXD0,RXD0

             GPHUP     = 0x0c;              //GPH2,GPH3内部上拉

     

             ULCON0   = 0x03;             //8N1         

             UCON0     = 0x05;             //查询方式

             UFCON0 = 0x00;                 //不使用FIFO

             UMCON0 = 0x00;                //不使用流控

             UBRDIV0 = 12;                   //波特率为57600

    }

     

    /* 通过串口字符发送函数 */

    void sendchar2(char c)

    {

             while( ! (UTRSTAT0 & TXD0READY) );

             UTXH0 = c;

    }

     

    /* 通过串口字符接收函数 */

    char recvchar( )

    {

             while( ! (UTRSTAT0 & RXD0READY) );

             return URXH0;

    }

    retarget.c:

    本程序文件主要重新实现了底层IO的基本函数:

    1int fgetc(FILE *f): 从文件描述符f中取得单个字符输入,scanf的底层实现函数,在C语言中所有的设备都被抽象成一个可以读写的文件,f参数就是具体IO设备,如stdout标准输出指显示器,stdin标准输入指键盘,由于本实验用串口重定向了标准输入,因此fgetc的功能主要返回从串口取得一个字符。

    2 int fputc(int ch, FILE *f):向文件描述符f里写入一个字符ch,它是printf的底层实现函数,本实验是用串口重定向标准输出,因此fputc的功能主要是向串口里写入字符ch

    3int ferror(FILE *f):标准错误的底层实现函数,本实验直接返回EOF,没有实现具体功能。

    4void _ttywrch(int ch): 终端数据输出的底层实现,本实验里用串口实现其功能,同样是向串口里写入字符ch

    5void _sys_exit(int return_code):系统退出的底层实现,这儿直接是用死循环来模拟最后程序的退出。

    由于底层IO操作实现被重定向,基于这些底层IO的库也没有被引入,__FILE__stdout__stdin这些使用的结构体和变量就需要自己重新定义。其中__FILE就是FILE文件描述符。__stdout是标准输出文件描述符,__stdin是标准输入文件描述符。

    #include <stdio.h>

     

    extern void sendchar2( char ch );

    extern char recvchar(void);

     

    struct __FILE { int handle; };

    FILE __stdout;

    FILE __stdin;

     

     

    /* 底层IO函数,从串口取得一个字符 */

    int fgetc(FILE *f)

    {

             char ch;

             ch = recvchar();

             if ((ch == '/r') || (ch == '/n'))             // 接收到返回行首符与换行符时实现换行显示

             {

                     fputc('/n', NULL);

                     fputc('/r', NULL);

             }

             fputc(ch, NULL);

             return ch;

    }

     

    /* 底层IO函数,打印一个字符,将字符打印到串口 */

    int fputc(int ch, FILE *f)

    {

        char tempch = ch;

        if (ch == '/n')                   // 发送换行符时,先发送返回行首符号/r,再发送换行符

        sendchar2('/r');

        sendchar2(tempch);

        return ch;

    }

     

    /* 底层IO函数 */

    int ferror(FILE *f)

    { 

        return EOF;

    }

     

    /* 底层IO函数终端打印函数 */

    void _ttywrch(int ch)

    {

        char tempch = ch;

        sendchar2( tempch );

    }

     

    /* 底层IO函数程序退出处理函数 */

    void _sys_exit(int return_code)

    {

        label:  goto label;

    }

    main.c

    本程序文件主要调用串口驱动程序,驱动串口,驱动LED,获得用户输入点亮对应LED灯。

    #include <stdio.h>

    #include <stdlib.h>

    #include <math.h>

    extern void init_serial_A(void);

    #define        GPBCON           (*(volatile unsigned long *)0x56000010)

    #define        GPBDAT            (*(volatile unsigned long *)0x56000014)

    #define LEDS   (1<<5|1<<6|1<<7|1<<8)

     

    int main(void)

    {

    int a,b;

             int i;

             float c,d;

             void *p1, *p2;

             #pragma import(__use_no_semihosting_swi) // 不使用软件中断响应semihosting请求

     

             init_serial_A();

     

             GPBCON  = 0x00015400;

             while (1)

             {

                   printf("please input led number: ");

                   scanf("%d", &i);

                   switch (i)

                   {

                          case 1:

                                  GPBDAT=(GPBDAT&(~LEDS)) | (1<<6|1<<7|1<<8);

                                  printf("led1 on /n");

                                  break;

                          case 2:

                                  GPBDAT=(GPBDAT&(~LEDS)) | (1<<5|1<<7|1<<8);

                                  printf("led2 on /n");

                                  break;

                          case 3:

                                  GPBDAT=(GPBDAT&(~LEDS)) | (1<<5|1<<6|1<<8);

                                  printf("led3 on /n");

                                  break;

                          case 4:

                                  GPBDAT=(GPBDAT&(~LEDS)) | (1<<5|1<<6|1<<7);

                                  printf("led4 on/n");

                                  break;

                          default:

                                  printf("input error, please input 1 to 4/n");

                                  break;

                      }

             }

             return 0;

    }

  • 相关阅读:
    c# 使用ajaxfileupload上传文件,通过一般处理程序(Handler)接收文件 ashx 图片 Excel文件都可以
    C#+aspx+ajaxfileupload 实现文件上传
    Java中的int与String互相转换方式
    简述 readyonly 与 disabled 的区别
    was应用服务器搭建
    MVC中贫血模型与充血模型
    npm安装教程 Vue环境搭建
    使用vs Code从0开始搭建一个vue项目(手把手教会你,包会)
    使用VS code 打开Vue项目
    Task , Thread 学习
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2458059.html
Copyright © 2011-2022 走看看