초기화 시 arm 명령어가 되고 thumb명령어로 가고싶으면 위의 BX를 사용한다
<vectors.S> 테이블
줄당 4번지가 바뀐다
power on reset
BOD reset
reset
프로세서가 작업을 하는데 사용되는 값을 임시저장하는 공간
cpu 속도와 동일한 고속
실사용 16개, 모드마다 shadow 레지스터가 따로있다, 총 37개
30개의 범용
1개의 PC - R15번(코드의 주소를 불러옴)
1개의 CPSR - 상태 레지스터
5개의 SPSR
ARM state
16개의 범용
R13(stack point)
R14(link register)
R15(program counter)
FIQ가 IRQ보다 빠르다
SP : 프로그램에서 사용하는 스택의 위치를 저장하는 레지스터(R13)
최초에 할당되지 않은 4바이트를 가리키고 있다
arm은 별도의 스택 명령이 없음
지역변수는 자동으로 메모리 관리(free 안해도 된다)
push, pop 없음
LR : 서브루틴에서 되돌아 갈 위치 정보를 저장하고 있는 레지스터(R14)
BL 명령으로 PC값을 자동으로 LR에 저장
PC : 프로그램 수행하는 위치 저장하는 레지스터(R15)
$ cd pi_bsp/u-boot/arch/arm/cpu/armv7
$ cp start.S /srv/samba/
$ arm-linux-gnueabihf-objdump -S start.o > start.txt
$ vi start.txt
접미사 S를 붙이면 상태 레지스터에 반영해라
없으면 항상(무조건, AL) 실행
mov r2, #8
0xe3a02008 = 1110 0011 1010 0000 0010 0000 0000 1000
AL
2번째의 00은 데이터 프로세스 명령어라는 뜻
뒤의 1이
위 사진에서 1임을 알 수 있다
그리고 4개 읽으면 1101이다
접미사를 안썼기 때문에 다음에 0이 와서 unset이다
16~19는 소스레지스터인데 우리는 상수를 썼기 때문에 0이다
12~16는 2인데, 이것이 r2를 의미한다
나머지 12개는 적치 상수인데, 8이므로 8을 의미한다 -> #8
.71에서 파일을 내 우분투 삼바로 가져와서 복사한 뒤
원래 있던 start.S를 다른 이름으로 변경하고 가져온 파일을 start.S로 이름 바꾼 뒤
armv7에 복사한다
그리고 u-boot에서 ./build.sh로 실행하면 start.o가 생기고 u-boot.bin을 nfs로 파이에 보낸다
그 뒤에 /boot/firmware에 옮기고 재부팅하면
이 화면에서 멈추고
LED가 좌우로 왔다갔다 하며, 버튼 S7을 누르면 부팅이 시작된다!
새 명령어 추가하기
~/pi_bsp/u-boot/common$ vi cmd_kcci_led.c
#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
void led_init(void)
{
writel(GPIO6_9_SIG_OUTPUT, BCM2711_GPIO_GPFSEL0);
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
}
static int do_KCCI_LED(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
{
unsigned long led_data;
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);
printf("*LED TEST END(%s : %#04x)\n\n", argv[0], (unsigned int)led_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");
작성을 해주고
$ vi Makefile
8번째 줄에
obj-y += cmd_kcci_led.o
를 추가해준다
이후 cd ..
$ ./build.sh
$ cp u-boot.bin /srv/nfs
해준 뒤
라즈베리파이 측에서
$ cp /mnt/ubuntu_nfs/u-boot.bin /boot/firmware
옮기고
라즈베리를 다시 시작해서 u-boot로 진입한다
그 이후
led 0x55, led oxff, led 0x00 등 명령을 입력해서 led를 키고 끈다
부트로드, 커널은 동적으로 사용할 수 없다
펌웨어에서 주의할 점
GPIO를 이미 사용중인데, 0으로 바꿔버리면 안된다
read modify write의 순서를 가져야함
32비트의 값을 read 하고, 기존에 사용중인 것은 두고 나머지를 0으로 설정한 뒤(00001111과 and 연산자) 원하는 값으로 바꿔준다(10110000과 or 연산자)(modify)그리고 write를 해야한다
예)10110100 and 00001111 = 00000100 / 00000100 or 10110000 = 10110100
여태는 라이브러리만 사용해왔어서 됐지만 원래는 안된다
비트 밴딩 >> 클럭 소모가 많이 되므로 남은 주소의 일부분을 한개의 비트에 한개의 주소를 다 주었다 그래서 속도가 빨라짐(MCU마다 지원될 수도 있고 안될 수도 있다)
CLR, set는 1일 때 clear, set 한다
11111111000000 = 0x3fc0