Skip to content

Commit 6bbd509

Browse files
committed
move frame buffer cursor using tv remote controller
1 parent baa7cbd commit 6bbd509

File tree

11 files changed

+438
-98
lines changed

11 files changed

+438
-98
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
zig logo is displayed
22

3+
The frame buffer cursor moves around the screen in response to the tv remote controller buttons. This requires a Cosumer Electronics Control (CEC) on the tv.
4+
35
Successfully tested on rpi3b, rpi3b+
46

57
Not yet working on armv6 raspberry pi models
8+
9+
Building
10+
--------
11+
12+
Requires the following patch to lib/zig/std/fmt.zig:
13+
14+
replace
15+
16+
const digit = a % base;
17+
18+
with
19+
const digit = a - base * (a / base);
20+

build.zig

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const builtin = @import("builtin");
44

55
pub fn build(b: *Builder) void {
66
const mode = b.standardReleaseOptions();
7-
const want_armv6 = b.option(bool, "armv6", "Build armv6 instead of armv7 (armv7 is default)") orelse false;
8-
const want_armv7 = b.option(bool, "armv7", "Build armv7 instead of armv6 (armv7 is default)") orelse false;
7+
const want_armv6 = b.option(bool, "armv6", "Build armv6") orelse false;
8+
const want_armv7 = b.option(bool, "armv7", "Build armv7 (default)") orelse false;
99

1010
const exec_name = "zig-bare-metal-raspberry-pi";
1111
const exe = b.addExecutable(exec_name, "src/main.zig");
@@ -26,11 +26,9 @@ pub fn build(b: *Builder) void {
2626
}
2727
const os = builtin.Os.freestanding;
2828
const environ = builtin.Abi.eabihf;
29-
exe.setTarget(arch, builtin.Os.freestanding, environ);
29+
exe.setTarget(arch, os, environ);
3030
exe.addBuildOption(u32, "subarch", subarch);
31-
32-
const linker_script = "src/linker.ld";
33-
exe.setLinkerScriptPath(linker_script);
31+
exe.setLinkerScriptPath("src/linker.ld");
3432

3533
const run_objcopy = b.addSystemCommand([_][]const u8{
3634
"llvm-objcopy-6.0", exe.getOutputPath(),

release-message.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
* connect the pi to the tv using the hdmi cable
1515
* turn on the tv
1616
* apply power to the pi
17-
* you should see the zig logo displayed along a changing banner of colored lines
17+
* you should see the zig logo displayed along with a changing banner of colored lines
18+
* if your tv has CEC (Consumer Electronics Control) then the frame buffer cursor will move in response to tv remote controller buttons

src/arm_assembly_code.zig

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,11 @@ pub fn panicf(comptime fmt: []const u8, args: ...) noreturn {
88
}
99
already_panicking = true;
1010

11-
serial.log("panic: " ++ fmt, args);
11+
serial.log("\npanic: " ++ fmt, args);
1212
hang("panic completed");
1313
}
1414

15-
pub fn io(offset: u32) *volatile u32 {
16-
return @intToPtr(*volatile u32, PERIPHERAL_BASE + offset);
17-
}
18-
19-
pub fn ioStruct(comptime StructType: type, offset: u32) *volatile StructType {
15+
pub fn io(comptime StructType: type, offset: u32) *volatile StructType {
2016
return @intToPtr(*volatile StructType, PERIPHERAL_BASE + offset);
2117
}
2218

@@ -97,6 +93,25 @@ pub fn setVectorBaseAddressRegister(address: u32) void {
9793
);
9894
}
9995

96+
pub fn cntpct32() u32 {
97+
return asm("mrrc p15, 0, %[cntpct_low], r1, c14"
98+
: [cntpct_low] "=r" (-> usize)
99+
:
100+
: "r1");
101+
}
102+
103+
var last_low: u32 = 0;
104+
var overflow: u32 = 0;
105+
pub fn seconds() u32 {
106+
const frequency = 1*1000*1000;
107+
const low = cntpct32();
108+
if (low < last_low) {
109+
overflow += 0xffffffff / frequency;
110+
}
111+
last_low = low;
112+
return low / frequency + overflow;
113+
}
114+
100115
// The linker will make the address of these global variables equal
101116
// to the value we are interested in. The memory at the address
102117
// could alias any uninitialized global variable in the kernel.

src/gpio.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub fn setAlt5(pin_number: u32) void {
1+
pub fn useAsAlt5(pin_number: u32) void {
22
setPinPull(pin_number, Pull.None);
33
setPinFunction(pin_number, GPIO_FUNCTION_ALT5);
44
}
@@ -65,7 +65,7 @@ const GPIO_MAX_PIN = 53;
6565
const GPFSEL0 = PERIPHERAL_BASE + 0x200000;
6666
const GPSET0 = PERIPHERAL_BASE + 0x20001C;
6767
const GPCLR0 = PERIPHERAL_BASE + 0x200028;
68-
const GPPUD = arm.io(0x200094);
68+
const GPPUD = arm.io(u32, 0x200094);
6969
const GPPUDCLK0 = PERIPHERAL_BASE + 0x200098;
7070

7171
const Pull = enum {

src/linker.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ SECTIONS {
66
.text : ALIGN(4K) {
77
KEEP(*(.text.boot))
88
. = 0x1000;
9-
KEEP(*(.text.exception_vector_table_at_0x1000))
9+
KEEP(*(.text.exception_vector_table))
1010
__end_init = .;
1111
*(.text)
1212
}

src/main.zig

Lines changed: 73 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,26 @@ export fn kernelMain() noreturn {
1717
arm.setBssToZero();
1818

1919
serial.init();
20-
serial.log("\n{} {} ...", name, release_tag);
20+
log("\n{} {} ...", name, release_tag);
2121

2222
fb.init();
23-
serial.log("drawing logo ...");
23+
log("drawing logo ...");
2424
var logo: Bitmap = undefined;
2525
var logo_bmp_file align(@alignOf(u32)) = @embedFile("../assets/zig-logo.bmp");
2626
logo.init(&fb, &logo_bmp_file);
2727
logo.drawRect(logo.width, logo.height, 0, 0, 0, 0);
2828

2929
screen_activity.init(logo.width, logo.height);
3030
serial_activity.init();
31+
vchi_activity.init();
3132

3233
while (true) {
3334
screen_activity.update();
3435
serial_activity.update();
36+
vchi_activity.update();
3537
}
3638
}
3739

38-
fn hex(message :[] const u8, x: u32) void {
39-
var buf: [8]u8 = undefined;
40-
for (buf) |_, i| {
41-
const digit: u8 = @intCast(u8, (x >> @intCast(u5, (buf.len - 1 - i) * 4)) & 0xF);
42-
buf[i] = if (digit < 9) digit + '0' else digit - 10 + 'A';
43-
}
44-
serial.log("0x{} {}", buf, message);
45-
}
46-
4740
const ScreenActivity = struct {
4841
width: u32,
4942
height: u32,
@@ -64,8 +57,11 @@ const ScreenActivity = struct {
6457
}
6558

6659
fn update (self: *ScreenActivity) void {
67-
fb.drawPixel32(self.x, self.y, self.color32);
68-
self.x += 1;
60+
var batch: u32 = 0;
61+
while (batch < 20 and self.x < self.width) : (batch += 1) {
62+
fb.drawPixel32(self.x, self.y, self.color32);
63+
self.x += 1;
64+
}
6965
if (self.x == self.width) {
7066
self.x = 0;
7167
self.y += 1;
@@ -87,7 +83,7 @@ const ScreenActivity = struct {
8783

8884
const SerialActivity = struct {
8985
fn init(self: *SerialActivity) void {
90-
serial.log("now echoing input on uart1 ...");
86+
log("now echoing input on uart1 ...");
9187
}
9288

9389
fn update(self: *SerialActivity) void {
@@ -98,11 +94,60 @@ const SerialActivity = struct {
9894
switch (byte) {
9995
'!' => {
10096
var x = @intToPtr(*u32, 2).*;
97+
log("ok {x}", x);
10198
},
10299
'\r' => {
103100
serial.writeText("\n");
104101
},
105-
else => serial.writeByte(byte),
102+
else => serial.writeByteBlocking(byte),
103+
}
104+
}
105+
};
106+
107+
const VchiActivity = struct {
108+
vchi: Vchi,
109+
cursor_x: u32,
110+
cursor_y: u32,
111+
112+
fn init(self: *VchiActivity) void {
113+
self.vchi.init();
114+
self.cursor_x = fb.physical_width / 2;
115+
self.cursor_y = fb.physical_height / 2;
116+
fb.moveCursor(self.cursor_x, self.cursor_y);
117+
self.vchi.cecOpenNotificationService();
118+
}
119+
120+
fn update(self: *VchiActivity) void {
121+
while (self.vchi.wasButtonPressedReceived()) {
122+
const button_code = self.vchi.receiveButtonPressedBlocking();
123+
var dx: i32 = 0;
124+
var dy: i32 = 0;
125+
const delta = switch (button_code) {
126+
0x01 => {
127+
dy = -1;
128+
},
129+
0x02 => {
130+
dy = 1;
131+
},
132+
0x03 => {
133+
dx = -1;
134+
},
135+
0x04 => {
136+
dx = 1;
137+
},
138+
else => {
139+
},
140+
};
141+
const scale = 64;
142+
const x = @intCast(i32, self.cursor_x) + dx * scale;
143+
if (x > 0 and x < @intCast(i32, fb.physical_width) - 1) {
144+
self.cursor_x = @intCast(u32, x);
145+
}
146+
const y = @intCast(i32, self.cursor_y) + dy * scale;
147+
if (y > 0 and y < @intCast(i32, fb.physical_height) - 1) {
148+
self.cursor_y = @intCast(u32, y);
149+
}
150+
fb.moveCursor(self.cursor_x, self.cursor_y);
106151
}
107152
}
108153
};
@@ -133,10 +178,8 @@ comptime {
133178
\\ cps #0x1f // enter system mode
134179
\\ mov sp,#0x08000000
135180
\\ bl kernelMain
136-
);
137-
138-
asm(
139-
\\.section .text.exception_vector_table_at_0x1000
181+
\\
182+
\\.section .text.exception_vector_table
140183
\\.balign 0x80
141184
\\exception_vector_table:
142185
\\ b exceptionEntry0x00
@@ -183,23 +226,23 @@ export fn exceptionEntry0x07() noreturn {
183226
}
184227

185228
fn exceptionHandler(entry: u32) noreturn {
186-
serial.log("arm exception taken");
187-
hex("vector", entry);
188-
hex("spsr", arm.spsr());
189-
hex("cpsr", arm.cpsr());
190-
hex("scr", arm.scr());
191-
hex("sp", arm.sp());
192-
hex("sctlr", arm.sctlr());
229+
log("arm exception taken");
230+
log("entry {}", entry);
231+
log("spsr 0x{x}", arm.spsr());
232+
log("cpsr 0x{x}", arm.cpsr());
233+
log("sp 0x{x}", arm.sp());
234+
log("sctlr 0x{x}", arm.sctlr());
193235
arm.hang("execution is now stopped in arm exception handler");
194236
}
195237

196238
pub fn panic(message: []const u8, trace: ?*builtin.StackTrace) noreturn {
197239
panicf("main.zig pub fn panic(): {}", message);
198240
}
199241

242+
var fb: FrameBuffer = undefined;
200243
var screen_activity: ScreenActivity = undefined;
201244
var serial_activity: SerialActivity = undefined;
202-
var fb: FrameBuffer = undefined;
245+
var vchi_activity: VchiActivity = undefined;
203246

204247
const margin = 10;
205248

@@ -210,15 +253,16 @@ const color_yellow = Color{ .red = 255, .green = 255, .blue = 0, .alpha = 255 };
210253
const color_white = Color{ .red = 255, .green = 255, .blue = 255, .alpha = 255 };
211254

212255
const name = "zig-bare-metal-raspberry-pi";
213-
const release_tag = "0.1";
256+
const release_tag = "0.2";
214257

215258
const arm = @import("arm_assembly_code.zig");
216259
const build_options = @import("build_options");
217260
const builtin = @import("builtin");
218261
const Bitmap = @import("video_core_frame_buffer.zig").Bitmap;
219262
const Color = @import("video_core_frame_buffer.zig").Color;
220263
const FrameBuffer = @import("video_core_frame_buffer.zig").FrameBuffer;
221-
const gpio2 = @import("gpio2.zig");
264+
const log = serial.log;
222265
const panicf = arm.panicf;
223266
const serial = @import("serial.zig");
224267
const std = @import("std");
268+
const Vchi = @import("video_core_vchi.zig").Vchi;

0 commit comments

Comments
 (0)