반응형
구현 목표는 led 0xff 명령어를 치면 이름 이니셜을 띄워주면서 led 작동시키고
button을 누르면 8개의 버튼 중 해당 버튼에 맞게 O X를 출력해주고
해당 버튼에 맞는 led만 on시켜주기
+ 8번 버튼 누르면 프로그램 종료시키기
#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 0x00000249
#define GPIO16_19_SIG_OUTPUT 0x00000000
#define GPIO20_23_SIG_OUTPUT 0x00000000
#define LED_6_9_SIG_MASK 0x0003ffff
#define LED_10_13_SIG_MASK 0x3ffff000
#define KEY_16_19_SIG_MASK 0x0003ffff
#define KEY_20_23_SIG_MASK 0x3ffff000
#define LED6_13_STATUS_MASK 0x00003fc0
#define KEY16_23_STATUS_MASK 0x00ff0000
void led_init(void)
{
unsigned long led_data;
led_data = readl(BCM2711_GPIO_GPFSEL0);
led_data = led_data & LED_6_9_SIG_MASK;
led_data = led_data | GPIO6_9_SIG_OUTPUT;
writel(led_data,BCM2711_GPIO_GPFSEL0);
led_data = readl(BCM2711_GPIO_GPFSEL1);
led_data = led_data & LED_10_13_SIG_MASK;
led_data = led_data | GPIO10_13_SIG_OUTPUT;
writel(led_data,BCM2711_GPIO_GPFSEL1);
}
void key_init(void)
{
unsigned long key_data;
key_data = readl(BCM2711_GPIO_GPFSEL1);
key_data = key_data & KEY_16_19_SIG_MASK;
key_data = key_data | GPIO16_19_SIG_OUTPUT;
writel(key_data, BCM2711_GPIO_GPFSEL1);
key_data = readl(BCM2711_GPIO_GPFSEL2);
key_data = key_data & KEY_20_23_SIG_MASK;
key_data = key_data | GPIO20_23_SIG_OUTPUT;
writel(key_data, BCM2711_GPIO_GPFSEL2);
}
void led_write(unsigned long led_data)
{
writel(0x3fc0, BCM2711_GPIO_GPCLR0);
// unsigned long original_data = readl(BCM2711_GPIO_GPCLR0) & LED6_13_STATUS_MASK;
//writel(led_data, BCM2711_GPIO_GPCLR0);
// led_data = original_data | led_data;
writel(led_data, BCM2711_GPIO_GPSET0);
}
void key_read(unsigned long* key_data)
{
*key_data = readl(BCM2711_GPIO_GPLEV0) & KEY16_23_STATUS_MASK;
}
static int do_KCCI_LED(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
unsigned long led_data;
unsigned long key_data;
uint16_t curr_key=0xff;
uint16_t prev_key=0x00;
bool end_flag = false;
if(argc != 2)
{
cmd_usage(cmdtp);
return 1;
}
printf("*LED TEST START(WCM)\n");
led_init();
led_data = simple_strtoul(argv[1],NULL,16);
led_write(led_data << 6);
key_init();
do{
key_read(&key_data);
curr_key = (key_data >> 16) & 0xFF;
if((curr_key != prev_key) && (curr_key != 0x00))
{
printf("0:1:2:3:4:5:6:7\n");
prev_key = curr_key;
// printf("\n\n*(curr key : %#02x) ", (unsigned int)curr_key);
for(int i = 0; i < 8; i++)
{
if(curr_key & (1 << i)) {
printf("O ");
if(i==7){
end_flag = true;
}
// printf("*(led_data : %#lx) ", (unsigned long)key_data >> 10);
led_write(key_data >> 10);
}
else
{
printf("X ");
}
}
printf("\n");
}
}while(!end_flag);
printf("*LED TEST END(key : %#02x)\n\n ", (unsigned int)curr_key);
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");
비트를 왜 그렇게 부여했는지 보고싶다면 아래 링크랑 사진 참고
실제 동작 영상임.
아래는 좀 더 펌웨어적으로 구현한 코드임.
구현 중점은
1. printf의 지연시간을 줄이기 위해 putc나 puts 사용
2. 코드에는 적용안되어 있지만 가독성 향상을 위해 마스크 연산자는 사용자가 건드릴 비트를 1 해놓고 사용할 때 ~로 not해주기
3. 불필요한 변수는 최대한 생략
4. for 문 안에 index 같은 경우도 for문과 함께 선언하지 말고 지역변수로 선언할 것.
#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 0x00000249
struct cmd_tbl_t;
void led_init(void)
{
unsigned long temp;
temp = readl(BCM2711_GPIO_GPFSEL0);
temp = temp & 0x0003ffff;
// temp = temp & ~0xfffc0000;
temp = temp | GPIO6_9_SIG_OUTPUT;
writel(temp,BCM2711_GPIO_GPFSEL0);
// writel(GPIO6_9_SIG_OUTPUT,BCM2711_GPIO_GPFSEL0);
temp = readl(BCM2711_GPIO_GPFSEL1); //gpio10~13 read
temp = temp & 0x3ffff000; //gpio10~13 clear
temp = temp | GPIO10_13_SIG_OUTPUT;//gpio10~13 output
writel(temp,BCM2711_GPIO_GPFSEL1); //gpio10~13 write
// writel(GPIO10_13_SIG_OUTPUT,BCM2711_GPIO_GPFSEL1);
}
void led_write(unsigned long led_data)
{
writel(0x3fc0,BCM2711_GPIO_GPCLR0); //led all off
led_data = led_data << 6;
writel(led_data,BCM2711_GPIO_GPSET0); //ledX on
}
void key_init(void)
{
unsigned long temp;
temp = readl(BCM2711_GPIO_GPFSEL1);
temp = temp & 0x0003ffff; //gpio16~20 input
writel(temp,BCM2711_GPIO_GPFSEL1);
temp = readl(BCM2711_GPIO_GPFSEL2);
temp = temp & 0x3ffff000; //gpio21~23 input
writel(temp,BCM2711_GPIO_GPFSEL2);
}
void key_read(unsigned long * key_data)
{
*key_data =(readl(BCM2711_GPIO_GPLEV0) >> 16) & 0x000000ff;
}
static int do_KCCI_LED(struct cmd_tbl *cmdtp,int flag, int argc, char * const argv[])
{
unsigned long led_data;
unsigned long key_data;
unsigned long key_data_old=0;
unsigned long i;
if(argc != 2)
{
cmd_usage(cmdtp);
return 1;
}
printf("*LED TEST START\n");
led_init();
led_data = simple_strtoul(argv[1],NULL,16);
led_write(led_data);
key_init();
do {
key_read(&key_data);
if(key_data != key_data_old)
{
if(key_data)
{
led_write(key_data);
puts("0:1:2:3:4:5:6:7\n");
for(i=0;i<8;i++)
{
if(key_data & (0x01 << i))
putc('O');
else
putc('X');
if(i !=7 )
putc(':');
else
putc('\n');
}
putc('\n');
}
key_data_old = key_data;
if(key_data == 0x80)
break;
}
} while(1);
printf("*LED TEST END(%s : %#04x)\n\n ",argv[0],(unsigned int)key_data);
return 0;
}
U_BOOT_CMD(
led,2,0,do_KCCI_LED,
"kcci LED Test.(WCM)",
"number - Input argument is only one.(led [0x00~0xff])\n");
번외로 아래 명령어 쳐보면
ubuntu@ubuntu8:~/pi_bsp/u-boot$ vi u-boot.map
각각의 파일(좌측)과 메모리주소(우측)가 저장되어 있는 것을 볼 수 있음.
여기까지 하면서 배울건 우리가 평소에 주변 입출력장치, GPIO를 다루면서 편하게 썼던 라이브러리들의 LOW LEVEL단에는 이러한 코드들이 돌아가고 있다. 정도 알면 될 듯
반응형
'Firmware Programming' 카테고리의 다른 글
[ARM] ARM 어셈블리어 분석 (0) | 2024.02.13 |
---|---|
[ARM] ARM 프로세서 기초 (0) | 2024.02.13 |
[Firmware Programming] C++ ESP32-CAM 보드 UDP camera frame 패킷 순서 제어 및 실시간 전송 (2) | 2024.02.10 |
[Firmware Programming] ESP32-CAM 보드 UDP camera frame 패킷 순서 제어 및 실시간 전송 (1) | 2024.02.10 |
[Firmware Programming] ESP32-CAM 보드 usb로 upload 하기 (1) | 2024.02.08 |