目的
GBAのボタン入力を識別する仕組みを整える。
ビルド
リンカスクリプト及びROMのヘッダファイルは以下の記事のものを使用する。
ビルドの手順は筆者の以下の記事を参考
GBA自作コードを実機で動作させる手順
arm-none-eabi-as header.s -o header.o
arm-none-eabi-gcc -c main.c -o main.o -nostdlib -ffreestanding
arm-none-eabi-gcc -c font.c -o font.o -nostdlib -ffreestanding
arm-none-eabi-ld header.o main.o font.o -T link.ld -o out.elf
arm-none-eabi-objcopy -O binary out.elf out.gba
結果
ボタンを押す毎に対応する番号を表示していく。
写真は全てのボタンを押した後の様子。
ボタン判定の原理
0x04000130から16ビットの値を読み取る。
0から9ビット目がそれぞれのボタンに対応している。
押していない時は1、押している時は0となる。
具体例を下に挙げる。
Aを押してない key=1111 1111 1111 1111
key & KEY_A
1111 1111 1111 1111
0000 0000 0000 0001
--------------------
0000 0000 0000 0001
!(key & KEY_A) = !(1) → false
Aを押している key=1111 1111 1111 1110
key & KEY_A
1111 1111 1111 1110
0000 0000 0000 0001
--------------------
0000 0000 0000 0000
結果 = 0(押している)
検証コード
main.c
#include "font.h"
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define REG_DISPCNT (*(volatile unsigned int*)0x04000000)
#define MODE3 3
#define BG2_ENABLE (1 << 10)
#define VRAM ((volatile uint16_t*)0x06000000)
#define KEYINPUT (*(volatile unsigned short*)0x04000130) // 各ボタン押下状況が返る
// 各ボタン押下有無判別用マスク
#define KEY_A (1 << 0) // 0000 0000 0000 0001
#define KEY_B (1 << 1) // 0000 0000 0000 0010
#define KEY_SELECT (1 << 2) // 0000 0000 0000 0100
#define KEY_START (1 << 3) // 0000 0000 0000 1000
#define KEY_RIGHT (1 << 4) // 0000 0000 0001 0000
#define KEY_LEFT (1 << 5) // 0000 0000 0010 0000
#define KEY_UP (1 << 6) // 0000 0000 0100 0000
#define KEY_DOWN (1 << 7) // 0000 0000 1000 0000
#define KEY_R (1 << 8) // 0000 0001 0000 0000
#define KEY_L (1 << 9) // 0000 0010 0000 0000
static inline void putpixel(int x, int y, uint16_t c) {
VRAM[y * 240 + x] = c;
}
void draw_hex(int x, int y, int v, uint16_t color) {
for (int row = 0; row < 8; row++) {
uint8_t bits = font[v][row];
for (int col = 0; col < 8; col++) {
if (bits & (1 << (7 - col))) {
putpixel(x + col, y + row, color);
}
}
}
}
int main(void) {
REG_DISPCNT = MODE3 | BG2_ENABLE;
for (int i = 0; i < 240 * 160; i++)VRAM[i] = 0;
while (1) {
unsigned short key = KEYINPUT;
if (!(key & KEY_A)) { // Aボタン押下
draw_hex(10, 10, 0, 0xFFFF);
}
if (!(key & KEY_B)) {
draw_hex(20, 10, 1, 0xFFFF);
}
if (!(key & KEY_SELECT)) {
draw_hex(30, 10, 2, 0xFFFF);
}
if (!(key & KEY_START)) {
draw_hex(40, 10, 3, 0xFFFF);
}
if (!(key & KEY_RIGHT)) {
draw_hex(50, 10, 4, 0xFFFF);
}
if (!(key & KEY_LEFT)) {
draw_hex(60, 10, 5, 0xFFFF);
}
if (!(key & KEY_RIGHT)) {
draw_hex(70, 10, 6, 0xFFFF);
}
if (!(key & KEY_UP)) {
draw_hex(80, 10, 7, 0xFFFF);
}
if (!(key & KEY_DOWN)) {
draw_hex(90, 10, 8, 0xFFFF);
}
if (!(key & KEY_R)) {
draw_hex(100, 10, 9, 0xFFFF);
}
if (!(key & KEY_L)) {
draw_hex(110, 10, 10, 0xFFFF);
}
}
}
font.h
#ifndef FONT_H
#define FONT_H
typedef unsigned char uint8_t;
extern const uint8_t font[16][8];
#endif
font.c
font.c
#include "font.h"
const uint8_t font[16][8] = {
// 0
{0b00111100, // ████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ████
0b00000000}, //
// 1
{0b00011000, // ██
0b00111000, // ███
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00111100, // ████
0b00000000}, //
// 2
{0b00111100, // ██████
0b01100110, // ██ ██
0b00000110, // ██
0b00011100, // ██
0b00110000, // ██
0b01100000, // ██
0b01111110, // ████████
0b00000000}, //
// 3
{0b00111100, // ██████
0b01100110, // ██ ██
0b00000110, // ██
0b00011100, // ███
0b00000110, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 4
{0b00001100, // ██
0b00011100, // ███
0b00111100, // ████
0b01101100, // ██ ██
0b01111110, // ████████
0b00001100, // ██
0b00001100, // ██
0b00000000}, //
// 5
{0b01111110, // ████████
0b01100000, // ██
0b01111100, // ██████
0b00000110, // ██
0b00000110, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 6
{0b00011100, // ████
0b00110000, // ██
0b01100000, // ██
0b01111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 7
{0b01111110, // ████████
0b00000110, // ██
0b00001100, // ██
0b00011000, // ██
0b00110000, // ██
0b00110000, // ██
0b00110000, // ██
0b00000000}, //
// 8
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 9
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111110, // ██████
0b00000110, // ██
0b00001100, // ██
0b00111000, // ████
0b00000000}, //
// A
{0b00011000, // ██
0b00111100, // ████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111110, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00000000}, //
// B
{0b01111100, // █████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111100, // █████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111100, // █████
0b00000000}, //
// C
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// D
{0b01111000, // █████
0b01101100, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01101100, // ██ ██
0b01111000, // █████
0b00000000}, //
// E
{0b01111110, // ████████
0b01100000, // ██
0b01100000, // ██
0b01111100, // ██████
0b01100000, // ██
0b01100000, // ██
0b01111110, // ████████
0b00000000}, //
// F
{0b01111110, // ████████
0b01100000, // ██
0b01100000, // ██
0b01111100, // ██████
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b00000000}, //
};