이 함수들은 바이트 단위로 값을 출력하는거기 때문에 아주 가볍다.
펌웨어 프로그래밍에서는 디버깅 할 때 말고는 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 파일에 다 적혀있다.
ubuntu@ubuntu14:~/pi_bsp/u-boot$ vi u-boot.map
이번 과제에서 만들었던 함수들이 실제로 메모리의 몇번지에 적재되어있는지가 다 적혀있다. 그리고 0x4c, 0x24, 0x38, ... 등등의 정보를 통해 해당 함수가 기계어로 몇바이트의 크기를 차지하고 있는지에 대한 정보도 알 수 있다.