레지스터 조작을 통한 HW제어 [펌웨어프로그래밍 과제]

kenGwon·2024년 2월 14일
0

[Embedded Linux] BSP

목록 보기
10/36

펌웨어 프로그래밍에서는 printf() 쓰는거 아니다.

putc(), puts()

이 함수들은 바이트 단위로 값을 출력하는거기 때문에 아주 가볍다.

printf()

펌웨어 프로그래밍에서는 디버깅 할 때 말고는 printf()를 사용하면 안된다. printf()는 굉장히 무거운 함수이다. printf()를 추가하는 순간 코드 사이즈가 엄청 커지고, 컴퓨팅 파워가 같은 머신의 경우 딜레이도 엄청 걸리게 된다.


과제 결과코드

#include <common.h>
#include <command.h>
#include <asm/io.h>

#define BCM2711_GPIO_GPFSEL0    0xFE200000
#define BCM2711_GPIO_GPFSEL1    0xFE200004
#define BCM2711_GPIO_GPFSEL2    0xFE200008
#define BCM2711_GPIO_GPSET0     0xFE20001C
#define BCM2711_GPIO_GPCLR0     0xFE200028
#define BCM2711_GPIO_GPLEV0     0xFE200034

#define GPIO6_9_SIG_OUTPUT      0x09240000
#define GPIO10_13_SIG_OUTPUT    0x00012249  //txd, rxd //GPIO16~19: input(000)

#define GPIO16_19_SIG_INPUT     0x00000000
#define GPIO20_23_SIG_INPUT     0x00000000

void led_init(void)
{
    unsigned long temp;
    // step 1: Read
    temp = readl(BCM2711_GPIO_GPFSEL0);
    temp = temp & 0x0003ffff;   // 관심영역을 0으로, 건드리면안되는 영역을 1로 마스킹
    // step 2: Modify
    temp = temp | GPIO6_9_SIG_OUTPUT;   // 관심영역에는 0x0924로, 건드리면 안되는 영역은 0으로 마스킹
    // step 3: Write
    writel(temp, BCM2711_GPIO_GPFSEL0);     //writel(GPIO6_9_SIG_OUTPUT, BCM2711_GPIO_GPFSEL0);


    // step 1: Read
    temp = readl(BCM2711_GPIO_GPFSEL1);
    temp = temp & 0xfffc0000;
    // step 2: Modify
    temp = temp | GPIO10_13_SIG_OUTPUT;
    // step 3: Write
    writel(temp, BCM2711_GPIO_GPFSEL1);
}

void led_write(unsigned long led_data)
{
    //클리어 레지스터는 내가 희망하는 비트에만 1을 쓰면 되기 때문에, 위와 같은 비트미스킹이 필요없다.
    writel(0x3fc0, BCM2711_GPIO_GPCLR0);    //led all off
    led_data = led_data << 6;   // GPIO 6번부터 LED이고 GPIO 1~5는 건드리면 안되기 때문에 시프트한다.
    //셋 레지스터는 내가 희망하는 비트에만 1을 쓰면 되기 때문에, 위와 같은 비트미스킹이 필요없다.
    writel(led_data, BCM2711_GPIO_GPSET0);  //ledX on
}

void key_init(void)
{
    unsigned long temp;
    temp = readl(BCM2711_GPIO_GPFSEL1);
//  temp = temp & 0x0003ffff;
    temp = temp & ~0xfffc0000;      // 보통 코드 가독성을 위해, 관심영역을 1로 표현해주는 보수를 취해준다
    temp = temp | GPIO16_19_SIG_INPUT;
    writel(temp, BCM2711_GPIO_GPFSEL1);

    temp = readl(BCM2711_GPIO_GPFSEL2);
//  temp = temp & 0x3ffff000;
    temp = temp & ~0x00000fff;
    temp = temp | GPIO20_23_SIG_INPUT;
    writel(temp, BCM2711_GPIO_GPFSEL2);
}

void key_read(unsigned long* key_data)
{
    unsigned long temp;
    temp = readl(BCM2711_GPIO_GPLEV0);
    temp = temp & 0x00ff0000;
    *key_data = temp >> 16;
}

static int do_KCCI_LED(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
{
    unsigned long led_data;
    unsigned long key_data, past_key_data, target_key_data;

    if (argc != 2)
    {
        cmd_usage(cmdtp);
        return 1;
    }

    printf("*LED TEST START(KGH)\n");
    led_init();
    led_data = simple_strtoul(argv[1], NULL, 16);
    led_write(led_data);

    key_init();
    key_read(&past_key_data);

    do
    {
        key_read(&key_data);

        if (key_data != past_key_data)
        {
            if (past_key_data == 0x00)
            {
                target_key_data = key_data;
                past_key_data = key_data;
            }
            else
            {
                puts("0:1:2:3:4:5:6:7\n");

                for (int i = 0; i < 8; i++)
                {
                    int bit = (target_key_data >> i) & 1;
                    if (bit == 1)
                        putc('O');
                    else
                        putc('X');

                    if (i < 7)
                        putc(':');
                }
                puts("\n\n");


                writel(0x3fc0, BCM2711_GPIO_GPCLR0);    //led all off
                writel(target_key_data << 6, BCM2711_GPIO_GPSET0);  //ledX on

                past_key_data = key_data;

                if (target_key_data == 0x80)
                {
                    break;
                }
            }
        }
    } while(1);


    printf("*LED TEST END(key : %#04x)\n\n ", (unsigned int)target_key_data);
    return 0;
}

U_BOOT_CMD(
        led, 2, 0, do_KCCI_LED,
        "led - kcci LED Test.",
        "number - Input argument is only one.(led [0x00~0xff])\n"
        );


동작 검증


u-boot.map

코드들이 실제 메모리에 배치된 정보는 u-boot.map 파일에 다 적혀있다.

ubuntu@ubuntu14:~/pi_bsp/u-boot$ vi u-boot.map

이번 과제에서 만들었던 함수들이 실제로 메모리의 몇번지에 적재되어있는지가 다 적혀있다. 그리고 0x4c, 0x24, 0x38, ... 등등의 정보를 통해 해당 함수가 기계어로 몇바이트의 크기를 차지하고 있는지에 대한 정보도 알 수 있다.

profile
스펀지맨

0개의 댓글