Skip to content

Commit baf7047

Browse files
committed
bricks/ev3: Add hooks for a clock.
This may be a useful starting point for contributors who are familiar with cpus like TI AM1808 even if they are not familiar with the Pybricks codebase. The initial goal is to fill in the gaps designated by // TODO: TIAM1808. This implements the clock driver. When this is done, the baked-in MicroPython code would print something like: Hello, world at time (ms): 0 Hello, world at time (ms): 1000 Hello, world at time (ms): 2000 instead of Hello, world at time (ms): 0 Hello, world at time (ms): 0 Hello, world at time (ms): 0
1 parent bc843db commit baf7047

File tree

9 files changed

+198
-72
lines changed

9 files changed

+198
-72
lines changed

.vscode/c_cpp_properties.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,34 @@
5555
"cStandard": "c11",
5656
"intelliSenseMode": "gcc-arm"
5757
},
58+
{
59+
"name": "ev3",
60+
"includePath": [
61+
"${workspaceFolder}/lib/contiki-core",
62+
"${workspaceFolder}/lib/lego",
63+
"${workspaceFolder}/lib/lwrb/src/include",
64+
"${workspaceFolder}/lib/pbio/include",
65+
"${workspaceFolder}/lib/pbio/platform/ev3",
66+
"${workspaceFolder}",
67+
"${workspaceFolder}/bricks/ev3",
68+
"${workspaceFolder}/bricks/ev3/build",
69+
"${workspaceFolder}/micropython",
70+
],
71+
"defines": [
72+
"MICROPY_MODULE_FROZEN_MPY",
73+
"MICROPY_ROM_TEXT_COMPRESSION",
74+
],
75+
"compilerArgs": [
76+
"-Wall",
77+
"-Werror",
78+
"-Wextra",
79+
"-Wno-unused-parameter",
80+
"-Wdouble-promotion",
81+
"-nostdlib"
82+
],
83+
"cStandard": "c11",
84+
"intelliSenseMode": "gcc-arm"
85+
},
5886
{
5987
"name": "ev3rt",
6088
"includePath": [

bricks/_common/sources.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
143143
drv/clock/clock_nxt.c \
144144
drv/clock/clock_stm32.c \
145145
drv/clock/clock_test.c \
146+
drv/clock/clock_tiam1808.c \
146147
drv/clock/clock_virtual.c \
147148
drv/core.c \
148149
drv/counter/counter_ev3dev_stretch_iio.c \

bricks/ev3/README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,23 @@ OK
114114
115115
Starting kernel ...
116116
117-
Hello!
118-
World!
117+
System init in platform.c called from startup.s
118+
119+
Hello, world at time (ms): 0
120+
Hello, world at time (ms): 0
121+
Hello, world at time (ms): 0
122+
Hello, world at time (ms): 0
123+
Hello, world at time (ms): 0
124+
Hello, world at time (ms): 0
125+
Hello, world at time (ms): 0
126+
Hello, world at time (ms): 0
127+
Hello, world at time (ms): 0
128+
Hello, world at time (ms): 0
119129
Traceback (most recent call last):
120130
121-
File "%q", line %dhello.py", line %d8D��D�, in %q
131+
File "%q", line %dhello.py", line %d9���D�, in %q
122132
<module>
123-
KeyboardInterrupt:
133+
KeyboardInterrupt:
124134
Pybricks MicroPython v1.20.0-23-g6c633a8dd on 2024-06-08; MINDSTORMS EV3 Brick with TI Sitara AM1808
125135
Type "help()" for more information.
126136
>>>

bricks/ev3/mphalport.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <contiki.h>
88

99
#include <pbdrv/config.h>
10+
#include <pbdrv/clock.h>
1011
#include <pbio/main.h>
1112
#include <pbsys/bluetooth.h>
1213

@@ -25,11 +26,43 @@ void pb_stack_get_info(char **sstack, char **estack) {
2526
}
2627

2728
void pb_event_poll_hook_leave(void) {
29+
// There is a possible race condition where an interrupt occurs and sets the
30+
// Contiki poll_requested flag after all events have been processed. So we
31+
// have a critical section where we disable interrupts and check see if there
32+
// are any last second events. If not, we can call __WFI(), which still wakes
33+
// up the CPU on interrupt even though interrupts are otherwise disabled.
34+
35+
36+
// TODO: TIAM1808 Implement commented out parts
37+
38+
// mp_uint_t state = disable_irq();
39+
if (!process_nevents()) {
40+
// __WFI();
41+
}
42+
// enable_irq(state);
2843
}
2944

45+
// Core delay function that does an efficient sleep and may switch thread context.
46+
// If IRQs are enabled then we must have the GIL.
3047
void mp_hal_delay_ms(mp_uint_t Delay) {
31-
}
3248

49+
// TODO: TIAM1808 implement IRQ enabled check
50+
51+
if (/*__get_PRIMASK() == 0*/ 0) {
52+
// IRQs enabled, so can use systick counter to do the delay
53+
uint32_t start = pbdrv_clock_get_ms();
54+
// Wraparound of tick is taken care of by 2's complement arithmetic.
55+
do {
56+
// This macro will execute the necessary idle behaviour. It may
57+
// raise an exception, switch threads or enter sleep mode (waiting
58+
// for (at least) the SysTick interrupt).
59+
MICROPY_EVENT_POLL_HOOK
60+
} while (pbdrv_clock_get_ms() - start < Delay);
61+
} else {
62+
// IRQs disabled, so need to use a busy loop for the delay.
63+
// TODO: TIAM1808
64+
}
65+
}
3366

3467
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
3568
uintptr_t ret = 0;
@@ -49,8 +82,7 @@ typedef struct {
4982
// Sensor port 1
5083
static pb_hal_uart_t UART0 = { .thr = (volatile uint8_t *)0x01D0C000, .lsr = (volatile uint8_t *)0x01D0C014 };
5184

52-
// Define the write_str function
53-
static void write_str(pb_hal_uart_t *uart, const char *s) {
85+
static void debug(pb_hal_uart_t *uart, const char *s) {
5486
while (*s) {
5587
while ((*uart->lsr & (1 << 5)) == 0) {
5688
}
@@ -59,7 +91,7 @@ static void write_str(pb_hal_uart_t *uart, const char *s) {
5991
}
6092

6193
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
62-
write_str(&UART0, str);
94+
debug(&UART0, str);
6395
MICROPY_EVENT_POLL_HOOK
6496
}
6597

lib/pbio/drv/block_device/block_device_test.c

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,43 @@
1919
#include <pbsys/storage.h>
2020

2121
/**
22-
* The following script is compiled using pybricksdev compile hello.py
23-
* in MULTI_MPY_V6.
24-
*
25-
* from pybricks.tools import wait
26-
*
27-
* print("Hello!")
28-
* wait(1000)
29-
* print("World!")
30-
* wait(1000)
31-
*
32-
* raise KeyboardInterrupt
22+
The following script is compiled using pybricksdev compile hello.py in MULTI_MPY_V6.
23+
24+
from pybricks.tools import StopWatch, wait
25+
26+
timer = StopWatch()
27+
28+
for i in range(10):
29+
print("Hello, world at time (ms):", timer.time())
30+
wait(1000)
31+
32+
raise KeyboardInterrupt
3333
*/
3434
const uint8_t script[] = {
35-
0x73, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x6D, 0x61,
35+
0xAC, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x6D, 0x61,
3636
0x69, 0x6E, 0x5F, 0x5F, 0x00, 0x4D, 0x06, 0x00,
37-
0x1F, 0x08, 0x00, 0x10, 0x68, 0x65, 0x6C, 0x6C,
38-
0x6F, 0x2E, 0x70, 0x79, 0x00, 0x0F, 0x08, 0x77,
39-
0x61, 0x69, 0x74, 0x00, 0x1C, 0x70, 0x79, 0x62,
40-
0x72, 0x69, 0x63, 0x6B, 0x73, 0x2E, 0x74, 0x6F,
41-
0x6F, 0x6C, 0x73, 0x00, 0x0C, 0x48, 0x65, 0x6C,
42-
0x6C, 0x6F, 0x21, 0x00, 0x0C, 0x57, 0x6F, 0x72,
43-
0x6C, 0x64, 0x21, 0x00, 0x81, 0x77, 0x55, 0x83,
44-
0x38, 0x08, 0x0C, 0x01, 0x4C, 0x27, 0x28, 0x27,
45-
0x48, 0x80, 0x10, 0x02, 0x2A, 0x01, 0x1B, 0x03,
46-
0x1C, 0x02, 0x16, 0x02, 0x59, 0x11, 0x06, 0x10,
47-
0x04, 0x34, 0x01, 0x59, 0x11, 0x02, 0x22, 0x87,
48-
0x68, 0x34, 0x01, 0x59, 0x11, 0x06, 0x10, 0x05,
49-
0x34, 0x01, 0x59, 0x11, 0x02, 0x22, 0x87, 0x68,
50-
0x34, 0x01, 0x59, 0x11, 0x07, 0x65, 0x51, 0x63,
37+
0x1F, 0x0A, 0x01, 0x10, 0x68, 0x65, 0x6C, 0x6C,
38+
0x6F, 0x2E, 0x70, 0x79, 0x00, 0x0F, 0x12, 0x53,
39+
0x74, 0x6F, 0x70, 0x57, 0x61, 0x74, 0x63, 0x68,
40+
0x00, 0x08, 0x77, 0x61, 0x69, 0x74, 0x00, 0x1C,
41+
0x70, 0x79, 0x62, 0x72, 0x69, 0x63, 0x6B, 0x73,
42+
0x2E, 0x74, 0x6F, 0x6F, 0x6C, 0x73, 0x00, 0x08,
43+
0x74, 0x69, 0x6D, 0x65, 0x00, 0x0A, 0x74, 0x69,
44+
0x6D, 0x65, 0x72, 0x00, 0x02, 0x69, 0x00, 0x81,
45+
0x77, 0x55, 0x05, 0x1A, 0x48, 0x65, 0x6C, 0x6C,
46+
0x6F, 0x2C, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64,
47+
0x20, 0x61, 0x74, 0x20, 0x74, 0x69, 0x6D, 0x65,
48+
0x20, 0x28, 0x6D, 0x73, 0x29, 0x3A, 0x00, 0x84,
49+
0x40, 0x20, 0x0C, 0x01, 0x52, 0x46, 0x26, 0x2D,
50+
0x50, 0x80, 0x10, 0x02, 0x10, 0x03, 0x2A, 0x02,
51+
0x1B, 0x04, 0x1C, 0x02, 0x16, 0x02, 0x1C, 0x03,
52+
0x16, 0x03, 0x59, 0x11, 0x02, 0x34, 0x00, 0x16,
53+
0x06, 0x80, 0x42, 0x5A, 0x57, 0x16, 0x07, 0x11,
54+
0x08, 0x23, 0x00, 0x11, 0x06, 0x14, 0x05, 0x36,
55+
0x00, 0x34, 0x02, 0x59, 0x11, 0x03, 0x22, 0x87,
56+
0x68, 0x34, 0x01, 0x59, 0x81, 0xE5, 0x57, 0x8A,
57+
0xD7, 0x43, 0x21, 0x59, 0x11, 0x09, 0x65, 0x51,
58+
0x63,
5159
};
5260

5361
static union {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2024 The Pybricks Authors
3+
4+
#include <pbdrv/config.h>
5+
6+
#if PBDRV_CONFIG_CLOCK_TIAM1808
7+
8+
#include <stdint.h>
9+
10+
void pbdrv_clock_init(void) {
11+
// Actual low level clocks should probably be configured at the very
12+
// start of in SystemInit in platform.c instead.
13+
// But optionally, additional things can be initialized here.
14+
}
15+
16+
uint32_t pbdrv_clock_get_us(void) {
17+
// TODO: TIAM1808 implementation.
18+
return 0;
19+
}
20+
21+
uint32_t pbdrv_clock_get_ms(void) {
22+
// TODO: TIAM1808 implementation.
23+
return 0;
24+
}
25+
26+
uint32_t pbdrv_clock_get_100us(void) {
27+
// TODO: TIAM1808 implementation (1 count = 100us, so 10 counts per millisecond.)
28+
return 0;
29+
}
30+
31+
#endif // PBDRV_CONFIG_CLOCK_TIAM1808

lib/pbio/platform/ev3/pbdrvconfig.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
// platform-specific configuration for LEGO MINDSTORMS EV3
55

66
#define PBDRV_CONFIG_CLOCK (1)
7-
#define PBDRV_CONFIG_CLOCK_NONE (1)
7+
#define PBDRV_CONFIG_CLOCK_TIAM1808 (1)
88

99
#define PBDRV_CONFIG_BLOCK_DEVICE (1)
1010
#define PBDRV_CONFIG_BLOCK_DEVICE_TEST (1)
1111
#define PBDRV_CONFIG_BLOCK_DEVICE_TEST_SIZE (8 * 1024)
1212
#define PBDRV_CONFIG_BLOCK_DEVICE_TEST_SIZE_USER (512)
1313

14-
// FIXME: Can't build without a port
1514
#define PBDRV_CONFIG_HAS_PORT_A (1)
1615
#define PBDRV_CONFIG_HAS_PORT_B (1)
1716
#define PBDRV_CONFIG_HAS_PORT_C (1)

lib/pbio/platform/ev3/platform.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2022 The Pybricks Authors
2+
// Copyright (c) 2024 The Pybricks Authors
33

4-
// This file is unused, but required for the common make file.
4+
5+
#include <stdint.h>
6+
7+
typedef struct {
8+
volatile uint8_t *thr;
9+
volatile uint8_t *lsr;
10+
} debug_uart_t;
11+
12+
// Sensor port 1
13+
static debug_uart_t UART0 = { .thr = (volatile uint8_t *)0x01D0C000, .lsr = (volatile uint8_t *)0x01D0C014 };
14+
15+
static void debug(debug_uart_t *uart, const char *s) {
16+
while (*s) {
17+
while ((*uart->lsr & (1 << 5)) == 0) {
18+
}
19+
*uart->thr = *s++;
20+
}
21+
}
22+
23+
// Called from assembly code in startup.s. After this, the "main" function in
24+
// lib/pbio/sys/main.c is called. That contains all calls to the driver
25+
// initialization (low level in pbdrv, high level in pbio), and system level
26+
// functions for running user code (currently a hardcoded MicroPython script).
27+
void SystemInit(void) {
28+
debug(&UART0, "System init in platform.c called from startup.s\n\n");
29+
// TODO: TIAM1808 system init
30+
}

lib/pbio/platform/ev3/startup.s

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,36 @@
44
// Make _start global.
55
.globl _start
66
7-
// Entry point for the kernel.
8-
// r15 -> should begin execution at 0x8000.
9-
// r0 -> 0x00000000
10-
// r1 -> 0x00000C42
11-
// r2 -> 0x00000100 - start of ATAGS
12-
// preserve these registers as argument for kernel_main
137
_start:
14-
// Setup the stack.
15-
ldr sp, =__bss_end
8+
// Setup the stack.
9+
ldr sp, =__bss_end
1610
17-
// Clear out bss.
18-
ldr r4, =__bss_start
19-
ldr r9, =__bss_end
20-
mov r5, #0
21-
mov r6, #0
22-
mov r7, #0
23-
mov r8, #0
24-
b 2f
11+
// Clear out bss.
12+
ldr r4, =__bss_start
13+
ldr r9, =__bss_end
14+
mov r5, #0
15+
mov r6, #0
16+
mov r7, #0
17+
mov r8, #0
18+
b 2f
2519
2620
1:
27-
// store multiple at r4.
28-
stmia r4!, {r5-r8}
21+
// store multiple at r4.
22+
stmia r4!, {r5-r8}
2923
30-
// If we are still below bss_end, loop.
24+
// If we are still below bss_end, loop.
3125
2:
32-
cmp r4, r9
33-
blo 1b
34-
35-
//poke serial register
36-
//ldr r3, =#0x01D0C000
37-
//ldr r3, =#0x101f1000
38-
//mov r4, #'a'
39-
//strb r4, [r3]
26+
cmp r4, r9
27+
blo 1b
28+
29+
// Call SystemInit
30+
ldr r3, =SystemInit
31+
blx r3
32+
33+
// Call main
34+
ldr r3, =main
35+
blx r3
4036

41-
// Call main
42-
ldr r3, =main
43-
blx r3
44-
45-
// halt
4637
halt:
47-
wfe
48-
b halt
38+
wfe
39+
b halt

0 commit comments

Comments
 (0)