diff --git a/Documentation/L4-programming-intro.pdf b/Documentation/L4-programming-intro.pdf new file mode 100644 index 00000000..64fcbf72 Binary files /dev/null and b/Documentation/L4-programming-intro.pdf differ diff --git a/Documentation/l4uman-n1.pdf b/Documentation/l4uman-n1.pdf new file mode 100644 index 00000000..9e0ca819 Binary files /dev/null and b/Documentation/l4uman-n1.pdf differ diff --git a/mk/rules/symmap.mk b/mk/rules/symmap.mk index ee4c10fd..2bbe7f7a 100644 --- a/mk/rules/symmap.mk +++ b/mk/rules/symmap.mk @@ -12,7 +12,8 @@ cmd_elf_to_symmap = $(NM) $< | sort | cut -d' ' -f1,3 | \ { \ SYM = SYM "{ (void*) (0x"$$1"), "STRCOUNT" },\n"; \ STRCOUNT += length($$2) + 1;\ - STRNAME = STRNAME "\"" $$2 "\\0" "\"" "\n"; \ + MPOLIA = substr($$2, 1, length($$2)-1); \ + STRNAME = STRNAME "\"" MPOLIA "\\0" "\"" "\n"; \ COUNT++; \ } \ END { \ diff --git a/user/apps/3ping/build.mk b/user/apps/3ping/build.mk new file mode 100644 index 00000000..cce6c07d --- /dev/null +++ b/user/apps/3ping/build.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +user-apps-3ping-y = \ + main.o diff --git a/user/apps/3ping/main.c b/user/apps/3ping/main.c new file mode 100644 index 00000000..25b282ba --- /dev/null +++ b/user/apps/3ping/main.c @@ -0,0 +1,219 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define STACK_SIZE 512 + +enum { PING_THREAD, PONG_THREAD, PUNG_THREAD }; + +typedef struct thread_info_s { + L4_ThreadId_t thread_id; + char *name; +} thread_info_t; + +static thread_info_t thread_info[3] __USER_DATA; + +#define LABEL 0x1 + + +#if 0 +#define __L4_NUM_MRS 16 +typedef unsigned long L4_Word_t; +/* + * Message objects + */ +typedef union { + L4_Word_t raw[__L4_NUM_MRS]; + L4_Word_t msg[__L4_NUM_MRS]; + L4_MsgTag_t tag; +} L4_Msg_t; +#endif + +__USER_TEXT +void *ping_thread(void *arg) +{ + L4_MsgTag_t tag; + L4_Msg_t msg; + L4_Word_t count = 0; + + printf("start %s()\n", thread_info[PING_THREAD].name); + + while (1) { + tag = L4_Receive_Timeout(thread_info[PUNG_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + L4_MsgStore(tag, &msg); + count = L4_MsgWord(&msg, 0); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: recv ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + + printf("\%s(%d)\t", thread_info[PING_THREAD].name, count); + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, ++count); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(thread_info[PONG_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: send ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + } +} + +__USER_TEXT +void *pong_thread(void *arg) +{ + L4_MsgTag_t tag; + L4_Msg_t msg; + L4_Word_t label; + L4_Word_t count; + L4_Word_t u; + + printf("start %s()\n", thread_info[PONG_THREAD].name); + + while (1) { + tag = L4_Receive_Timeout(thread_info[PING_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + L4_MsgStore(tag, &msg); + label = L4_Label(tag); + u = L4_UntypedWords(tag); + count = L4_MsgWord(&msg, 0); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: recv ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + printf("%s %d : %d : %d\t", thread_info[PONG_THREAD].name, label, u, count); + + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, ++count); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(thread_info[PUNG_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: send ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + } +} + +__USER_TEXT +void *pung_thread(void *arg) +{ + L4_MsgTag_t tag; + L4_Msg_t msg; + L4_Word_t label; + L4_Word_t count; + L4_Word_t u; + + printf("start %s()\n", thread_info[PUNG_THREAD].name); + + while (1) { + tag = L4_Receive_Timeout(thread_info[PONG_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + L4_MsgStore(tag, &msg); + label = L4_Label(tag); + u = L4_UntypedWords(tag); + count = L4_MsgWord(&msg, 0); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: recv ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + printf("%s %d : %d : %d\n", thread_info[PUNG_THREAD].name, label, u, count); + + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, ++count); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(thread_info[PING_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: send ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + } +} + +__USER_TEXT +static void *main(void *user) +{ + // = { {PING_THREAD, "PING", 0}, {PONG_THREAD, "PONG", 0}, {PUNG_THREAD, "PUNG", 0} } + + thread_info[PUNG_THREAD].thread_id = pager_create_thread(); + thread_info[PONG_THREAD].thread_id = pager_create_thread(); + thread_info[PING_THREAD].thread_id = pager_create_thread(); + + thread_info[PING_THREAD].name = "PING_THREAD"; + thread_info[PONG_THREAD].name = "PONG_THREAD"; + thread_info[PUNG_THREAD].name = "PUNG_THREAD"; + + pager_start_thread(thread_info[PUNG_THREAD].thread_id, pung_thread, NULL); + pager_start_thread(thread_info[PONG_THREAD].thread_id, pong_thread, NULL); + pager_start_thread(thread_info[PING_THREAD].thread_id, ping_thread, NULL); + + // Prime the pump: + { + L4_MsgTag_t tag; + L4_Msg_t msg; + L4_Word_t count = 0; + + printf("\nPrime the pump %d\n", count); + + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, count); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(thread_info[PONG_THREAD].thread_id, + L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: send ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + else { + printf("\nPump is primed %d\n", count); + } + } + + printf("\nEXITING main()\n"); + return 0; +} + +// DECLARE_FPAGE(0x0, (number_of_threads * 2 * UTCB_SIZE) + (number_of_threads * 2 * STACK_SIZE)) +DECLARE_USER( + 0, + 3ping, + main, + DECLARE_FPAGE(0x0, 6 * UTCB_SIZE + 6 * STACK_SIZE) + DECLARE_FPAGE(0x0, 512) +); diff --git a/user/apps/altpingpong/build.mk b/user/apps/altpingpong/build.mk new file mode 100644 index 00000000..c46f012b --- /dev/null +++ b/user/apps/altpingpong/build.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +user-apps-altpingpong-y = \ + main.o diff --git a/user/apps/altpingpong/main.c b/user/apps/altpingpong/main.c new file mode 100644 index 00000000..ad7b9f89 --- /dev/null +++ b/user/apps/altpingpong/main.c @@ -0,0 +1,146 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +#define STACK_SIZE 256 + +enum { GPIOER_THREAD, BUTTON_MONITOR_THREAD }; + +static L4_ThreadId_t threads[2] __USER_DATA; + +static L4_Word_t last_thread __USER_DATA; +static L4_Word_t free_mem __USER_DATA; + +#define LABEL 0x1 + +__USER_TEXT +void gpioer_thread(void) +{ + L4_Msg_t msg; + L4_MsgTag_t tag; + + L4_Word_t count = 0; + + printf("ping_thread(): built-in leds blinking\n"); + //led_init(); + + while (1) { + printf("ping_thread(%d)\t", count); + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, count++); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(threads[BUTTON_MONITOR_THREAD], + L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: send ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + } +} + + +/* STM32F407-Discovery + * User Button connected on PA0 + * as result, for this demo app, + * Because USART4 (PA0, PA1) is conflict, + * choose USART1 (PA9,PA10) or USART2 (PA2,PA3) instead. + **/ + +#define BUTTON_USER_PIN 0 + +/* if you use external button, please + * update the BUTTON_CUSTOM_PIN with your own number + **/ + +#define BUTTON_CUSTOM_PIN BUTTON_USER_PIN + +__USER_TEXT +void button_monitor_thread(void) +{ + L4_MsgTag_t tag; + L4_Msg_t msg; + L4_Word_t label; + L4_Word_t count; + L4_Word_t u; + + while (1) { + tag = L4_Receive_Timeout(threads[GPIOER_THREAD], + L4_TimePeriod(1000 * 1000)); + L4_MsgStore(tag, &msg); + label = L4_Label(tag); + u = L4_UntypedWords(tag); + count = L4_MsgWord(&msg, 0); + + if (!L4_IpcSucceeded(tag)) { + printf("%p: recv ipc fails\n", L4_MyGlobalId()); + printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + printf("pong_thread %d : %d : %d\n", label, u, count); + } +} + +static void __USER_TEXT start_thread(L4_ThreadId_t t, L4_Word_t ip, + L4_Word_t sp, L4_Word_t stack_size) +{ + L4_Msg_t msg; + + L4_MsgClear(&msg); + L4_MsgAppendWord(&msg, ip); + L4_MsgAppendWord(&msg, sp); + L4_MsgAppendWord(&msg, stack_size); + L4_MsgLoad(&msg); + + L4_Send(t); +} + +static L4_ThreadId_t __USER_TEXT create_thread(user_struct *user, void (*func)(void)) +{ + L4_ThreadId_t myself = L4_MyGlobalId(); + L4_ThreadId_t child; + + child.raw = myself.raw + (++last_thread << 14); + + L4_ThreadControl(child, myself, L4_nilthread, myself, (void *) free_mem); + free_mem += UTCB_SIZE + STACK_SIZE; + + start_thread(child, (L4_Word_t)func, free_mem, STACK_SIZE); + + return child; +} + +__USER_TEXT +static void *main(void *p) +{ + user_struct *user = (user_struct *)p; + free_mem = user->fpages[0].base; + + threads[GPIOER_THREAD] = create_thread(user, gpioer_thread); + threads[BUTTON_MONITOR_THREAD] = create_thread(user, button_monitor_thread); + + return 0; +} + +#define DEV_SIZE 0x3c00 +#define AHB1_1DEV 0x40020000 + +DECLARE_USER( + 0, + altpingpong, + main, + DECLARE_FPAGE(0x0, 2 * UTCB_SIZE + 2 * STACK_SIZE) + /* map thread with AHB DEVICE for gpio accessing */ + DECLARE_FPAGE(AHB1_1DEV, DEV_SIZE) +); diff --git a/user/apps/build.mk b/user/apps/build.mk index 6790f14d..4d3c24f5 100644 --- a/user/apps/build.mk +++ b/user/apps/build.mk @@ -3,8 +3,14 @@ # found in the LICENSE file. user-apps-dirs = \ - l4test \ - pingpong + gpioer + +# gpioer \ +# l4test \ +# pingpong +# altpingpong +# 3ping +# generic_thread ifdef CONFIG_EXTI_INTERRUPT_TEST diff --git a/user/apps/generic_thread/build.mk b/user/apps/generic_thread/build.mk new file mode 100644 index 00000000..e37a4f47 --- /dev/null +++ b/user/apps/generic_thread/build.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +user-apps-generic_thread-y = \ + main.o diff --git a/user/apps/generic_thread/main.c b/user/apps/generic_thread/main.c new file mode 100644 index 00000000..bb39e3f1 --- /dev/null +++ b/user/apps/generic_thread/main.c @@ -0,0 +1,194 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define STACK_SIZE 512 + +enum { PING_THREAD = 0, PONG_THREAD, PUNG_THREAD, BOSS_THREAD, THREAD_COUNT}; +static L4_ThreadId_t threads[THREAD_COUNT] __USER_DATA; + +#define LABEL 0x1 + + +#if 0 +#define __L4_NUM_MRS 16 +typedef unsigned long L4_Word_t; +/* + * Message objects + */ +typedef union { + L4_Word_t raw[__L4_NUM_MRS]; + L4_Word_t msg[__L4_NUM_MRS]; + L4_MsgTag_t tag; +} L4_Msg_t; +#endif + +__USER_TEXT +void *ping_thread(void *arg) +{ + L4_MsgTag_t tag; + L4_Msg_t msg; + L4_Word_t count = 0; + + L4_Word_t my_thread_id = 0; + L4_Word_t prev_thread_id = 0; + L4_Word_t next_thread_id = 0; + + printf("\nping_thread %p\n", L4_MyGlobalId()); + tag = L4_Receive(threads[BOSS_THREAD]); + + L4_MsgStore(tag, &msg); + my_thread_id = L4_MsgWord(&msg, 0); + prev_thread_id = L4_MsgWord(&msg, 1); + next_thread_id = L4_MsgWord(&msg, 2); + + if ( ( ! L4_IpcSucceeded(tag)) || (my_thread_id == prev_thread_id) ) { + printf("\nping_thread - %p: recv ipc fails %d, %d\n", L4_MyGlobalId(), my_thread_id, prev_thread_id); + printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode())); + + return 0; + } + else { + printf("\nping_thread %p %d is initialized : prev_thread_id %d, next_thread_id %d\n", L4_MyGlobalId(), my_thread_id, prev_thread_id, next_thread_id); + } + + /* WARNING !!! Cannot do this! Apparently, a message cannot be sent to a thread that is not already waiting for it. */ + // L4_Sleep(L4_TimePeriod(500 * 1000)); + + while (1) { + tag = L4_Receive_Timeout(threads[prev_thread_id], L4_TimePeriod(1000 * 1000)); + L4_MsgStore(tag, &msg); + count = L4_MsgWord(&msg, 0); + prev_thread_id = L4_MsgWord(&msg, 1); + + if (!L4_IpcSucceeded(tag)) { + printf("\nping_thread - %p: recv ipc fails\n", L4_MyGlobalId()); + printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode())); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + + printf("\nThread # %d received count %d from thread %d, next %d\n", my_thread_id, count, prev_thread_id, next_thread_id); + + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, ++count); + L4_MsgAppendWord(&msg, my_thread_id); // prev_thread_id for next thread in the sequence. + L4_MsgAppendWord(&msg, next_thread_id); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(threads[next_thread_id], + L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("\nping_thread - %p: send ipc fails\n", L4_MyGlobalId()); + printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode())); + } + /* FIXME: workaround solution to avoid scheduler starvation */ + L4_Sleep(L4_TimePeriod(500 * 1000)); + } +} + +__USER_TEXT +void *boss_thread(void *arg) +{ + L4_MsgTag_t tag; + L4_Msg_t msg; + + L4_Word_t this_thread; + + printf("\nboss_thread() %p is running\n", L4_MyGlobalId()); + + for (this_thread = PING_THREAD; this_thread < BOSS_THREAD; this_thread++) { + printf("\nCreate thread %d\n", this_thread); + threads[this_thread] = pager_create_thread(); + printf("\nStart thread %d\n", this_thread); + pager_start_thread(threads[this_thread], ping_thread, NULL); + } + + // Initialize each thread state. + // This is a work-around for lack of support for thread arg parameter. + L4_Word_t prev_thread_id = BOSS_THREAD; + L4_Word_t next_thread_id = PONG_THREAD; + for (this_thread = PING_THREAD; this_thread < BOSS_THREAD; this_thread++) { + + printf("\nInitialize thread state %d %d %d\n", prev_thread_id, this_thread, next_thread_id); + + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, this_thread); + L4_MsgAppendWord(&msg, prev_thread_id); + L4_MsgAppendWord(&msg, next_thread_id); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(threads[this_thread], L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("\nboss_thread() %p: send ipc fails\n", L4_MyGlobalId()); + printf("boss_thread() %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode())); + } + else { + printf("\nping thread %d %p is initialized by boss thread\n", this_thread, threads[this_thread]); + } + + prev_thread_id = ((++prev_thread_id >= BOSS_THREAD) ? PING_THREAD : prev_thread_id); + next_thread_id = ((++next_thread_id == BOSS_THREAD) ? PING_THREAD : next_thread_id); + } + + // Prime the pump - send a message to kick-off the round-robin pinging among the threads. + { + L4_Word_t count = 0; + + printf("\nPrime the pump %d\n", count); + + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, count); + L4_MsgAppendWord(&msg, PUNG_THREAD); + L4_MsgLoad(&msg); + + tag = L4_Send_Timeout(threads[PING_THREAD], L4_TimePeriod(1000 * 1000)); + + if (!L4_IpcSucceeded(tag)) { + printf("\nboss_thread() %p: send ipc fails\n", L4_MyGlobalId()); + printf("boss_thread() %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode())); + } + else { + printf("\nPump is primed %d\n", count); + } + } + + printf("\nEXITING boot_thread()\n"); + return 0; +} + +__USER_TEXT +static void *main(void *user) +{ + printf("\nmain()\n"); + + threads[BOSS_THREAD] = pager_create_thread(); + pager_start_thread(threads[BOSS_THREAD], boss_thread, NULL); + + printf("\nEXITING main()\n"); + return 0; +} + +// DECLARE_FPAGE(0x0, (number_of_threads * 2 * UTCB_SIZE) + (number_of_threads * 2 * STACK_SIZE)) +DECLARE_USER( + 0, + generic_thread, + main, + DECLARE_FPAGE(0x0, 8 * UTCB_SIZE + 8 * STACK_SIZE) + DECLARE_FPAGE(0x0, 512) +); diff --git a/user/apps/gpioer/build.mk b/user/apps/gpioer/build.mk new file mode 100644 index 00000000..aa6d7599 --- /dev/null +++ b/user/apps/gpioer/build.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +user-apps-gpioer-y = \ + main.o diff --git a/user/apps/gpioer/main.c b/user/apps/gpioer/main.c new file mode 100644 index 00000000..38b2deab --- /dev/null +++ b/user/apps/gpioer/main.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +/* Changed stack size from 256 to 512. */ +#define STACK_SIZE 512 + +enum { GPIOER_THREAD, BUTTON_MONITOR_THREAD }; + +static L4_ThreadId_t threads[2] __USER_DATA; + +/* Remove last_thread and free_mem as they are no longer + required to launch and manage the threads. */ +#define BOARD_LED_PORT GPIOD +#define BOARD_LED_NUM 4 + +#define BOARD_LED_PIN1 12 +#define BOARD_LED_PIN2 13 +#define BOARD_LED_PIN3 14 +#define BOARD_LED_PIN4 15 + +static uint8_t board_leds[BOARD_LED_NUM] __USER_DATA; + +static inline void __USER_TEXT led_init(void) +{ + + board_leds[0] = BOARD_LED_PIN1; + board_leds[1] = BOARD_LED_PIN2; + board_leds[2] = BOARD_LED_PIN3; + board_leds[3] = BOARD_LED_PIN4; + + for (int i = 0; i < BOARD_LED_NUM; ++i) + { + gpio_config_output(BOARD_LED_PORT, + board_leds[i], + GPIO_PUPDR_UP, + GPIO_OSPEEDR_50M); + } +} + +static inline void __USER_TEXT leds_onoff(int count) +{ + for (int i = 0; i < BOARD_LED_NUM; ++i) + { + if ((count % 4) == i) + gpio_out_high(BOARD_LED_PORT, board_leds[i]); + else + gpio_out_low(BOARD_LED_PORT, board_leds[i]); + } +} + +/* Thread function signature changed to confirm to pager_start_thread(). */ +__USER_TEXT +void *gpioer_thread(void *arg) +{ + int count = 0; + + printf("gpioer thread: built-in leds blinking\n"); + led_init(); + while (1) + { + printf("gpioer thread: built-in leds blinking - count %d\n", count); + leds_onoff(count++); + L4_Sleep(L4_TimePeriod(500 * 1000)); + } +} + + +/* STM32F407-Discovery + * User Button connected on PA0 + * as result, for this demo app, + * Because USART4 (PA0, PA1) is conflict, + * choose USART1 (PA9,PA10) or USART2 (PA2,PA3) instead. + **/ + +#define BUTTON_USER_PIN 0 + +/* if you use external button, please + * update the BUTTON_CUSTOM_PIN with your own number + **/ + +#define BUTTON_CUSTOM_PIN BUTTON_USER_PIN + +/* Thread function signature changed to confirm to pager_start_thread(). */ +__USER_TEXT +void *button_monitor_thread(void *arg) +{ + int count = 1; + +// gpio_config_input(GPIOA, BUTTON_CUSTOM_PIN, GPIO_PUPDR_DOWN); + printf("thread: built-in user button detection\n"); + while (1) + { + uint8_t state = gpio_input_bit(GPIOA, BUTTON_CUSTOM_PIN); + if (state != 0) { + printf("button %s %d times\n", state == 0 ? "open" : "pushed", count); + count++; + } + L4_Sleep(L4_TimePeriod(1000 * 200)); + } +} + +/* main() signature changed. */ +__USER_TEXT +static void *main(void *user) +{ + threads[GPIOER_THREAD] = pager_create_thread(); + threads[BUTTON_MONITOR_THREAD] = pager_create_thread(); + + pager_start_thread(threads[GPIOER_THREAD], gpioer_thread, NULL); + pager_start_thread(threads[BUTTON_MONITOR_THREAD], button_monitor_thread, NULL); + + /* Return statement required. */ + return 0; +} + +/* Function start_thread() no longer required because we are using pager_start_thread(). */ + +/* Function create_thread() no longer required because we are using pager_start_thread(). */ + +#define DEV_SIZE 0x3c00 +#define AHB1_1DEV 0x40020000 + +DECLARE_USER( + 0, + gpioer, + main, + /* was DECLARE_FPAGE(0x0, 2 * UTCB_SIZE + 2 * STACK_SIZE) */ + DECLARE_FPAGE(0x0, 6 * UTCB_SIZE + 6 * STACK_SIZE) + /* Added this next line. */ + DECLARE_FPAGE(0x0, 512) + /* map thread with AHB DEVICE for gpio accessing */ + DECLARE_FPAGE(AHB1_1DEV, DEV_SIZE) +); diff --git a/user/apps/pingpong/main.c b/user/apps/pingpong/main.c index d7e6fba7..bd9d8e8f 100644 --- a/user/apps/pingpong/main.c +++ b/user/apps/pingpong/main.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -13,9 +14,69 @@ #define STACK_SIZE 512 -enum { PING_THREAD, PONG_THREAD }; +enum { PING_THREAD, PONG_THREAD, BUTTON_MONITOR_THREAD }; -static L4_ThreadId_t threads[2] __USER_DATA; +static L4_ThreadId_t threads[3] __USER_DATA; + +#define LABEL 0x1 + +#define BOARD_LED_PORT GPIOD +#define BOARD_LED_NUM 4 + +#define BOARD_LED_PIN1 12 +#define BOARD_LED_PIN2 13 +#define BOARD_LED_PIN3 14 +#define BOARD_LED_PIN4 15 + +static uint8_t board_leds[BOARD_LED_NUM] __USER_DATA; + +__USER_TEXT +static inline void led_init(void) +{ + + printf("led_init(0)\n"); + board_leds[0] = BOARD_LED_PIN1; + board_leds[1] = BOARD_LED_PIN2; + board_leds[2] = BOARD_LED_PIN3; + board_leds[3] = BOARD_LED_PIN4; + + printf("led_init(1)\n"); + for (int i = 0; i < BOARD_LED_NUM; ++i) + { + //RCC_AHB1PeriphClockCmd(LCD_NCS_GPIO_CLK | LCD_WRX_GPIO_CLK, 1); + printf("led_init(%d)\n", i); + gpio_config_output(BOARD_LED_PORT, + board_leds[i], + GPIO_PUPDR_UP, + GPIO_OSPEEDR_50M); + } + printf("led_init(9)\n"); +} + +__USER_TEXT +static inline void leds_onoff(int count) +{ + for (int i = 0; i < BOARD_LED_NUM; ++i) + { + if ((count % 4) == i) + gpio_out_high(BOARD_LED_PORT, board_leds[i]); + else + gpio_out_low(BOARD_LED_PORT, board_leds[i]); + } +} + +#if 0 +#define __L4_NUM_MRS 16 +typedef unsigned long L4_Word_t; +/* + * Message objects + */ +typedef union { + L4_Word_t raw[__L4_NUM_MRS]; + L4_Word_t msg[__L4_NUM_MRS]; + L4_MsgTag_t tag; +} L4_Msg_t; +#endif __USER_TEXT void *ping_thread(void *arg) @@ -23,10 +84,20 @@ void *ping_thread(void *arg) L4_Msg_t msg; L4_MsgTag_t tag; - L4_MsgClear(&msg); - L4_MsgLoad(&msg); + L4_Word_t count = 0; + +// bool flag = true; + + printf("ping_thread(): built-in leds blinking\n"); + led_init(); while (1) { + printf("ping_thread(%d)\t", count); + L4_MsgClear(&msg); + L4_Set_MsgLabel(&msg, LABEL); + L4_MsgAppendWord(&msg, count++); + L4_MsgLoad(&msg); + tag = L4_Send_Timeout(threads[PONG_THREAD], L4_TimePeriod(1000 * 1000)); @@ -34,19 +105,66 @@ void *ping_thread(void *arg) printf("%p: send ipc fails\n", L4_MyGlobalId()); printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); } + + leds_onoff(count); + L4_Sleep(L4_TimePeriod(1000 * 1000)); +// flag=!flag; } } + +/* STM32F407-Discovery + * User Button connected on PA0 + * as result, for this demo app, + * Because USART4 (PA0, PA1) is conflict, + * choose USART1 (PA9,PA10) or USART2 (PA2,PA3) instead. + **/ + +#define BUTTON_USER_PIN 0 + +/* if you use external button, please + * update the BUTTON_CUSTOM_PIN with your own number + **/ + +#define BUTTON_CUSTOM_PIN BUTTON_USER_PIN + +__USER_TEXT +void *button_monitor_thread(void *arg) +{ + int count = 1; + + printf("button_monitor_thread(0): built-in user button detection\n"); + L4_Sleep(L4_TimePeriod(500 * 1000)); + printf("button_monitor_thread(1): built-in user button detection\n"); + gpio_config_input(GPIOA, BUTTON_CUSTOM_PIN, GPIO_PUPDR_DOWN); + printf("button_monitor_thread(2): built-in user button detection\n"); + while (1) + { + uint8_t state = gpio_input_bit(GPIOA, BUTTON_CUSTOM_PIN); + if (state != 0) { + printf("button %s %d times\n", state == 0 ? "open" : "pushed", count); + count++; + } + L4_Sleep(L4_TimePeriod(1000 * 200)); + } +} + __USER_TEXT void *pong_thread(void *arg) { L4_MsgTag_t tag; L4_Msg_t msg; + L4_Word_t label; + L4_Word_t count; + L4_Word_t u; while (1) { tag = L4_Receive_Timeout(threads[PING_THREAD], L4_TimePeriod(1000 * 1000)); L4_MsgStore(tag, &msg); + label = L4_Label(tag); + u = L4_UntypedWords(tag); + count = L4_MsgWord(&msg, 0); if (!L4_IpcSucceeded(tag)) { printf("%p: recv ipc fails\n", L4_MyGlobalId()); @@ -54,6 +172,7 @@ void *pong_thread(void *arg) } /* FIXME: workaround solution to avoid scheduler starvation */ L4_Sleep(L4_TimePeriod(500 * 1000)); + printf("pong_thread %d : %d : %d\n", label, u, count); } } @@ -62,15 +181,24 @@ static void *main(void *user) { threads[PING_THREAD] = pager_create_thread(); threads[PONG_THREAD] = pager_create_thread(); + threads[BUTTON_MONITOR_THREAD] = pager_create_thread(); + pager_start_thread(threads[PING_THREAD], ping_thread, NULL); pager_start_thread(threads[PONG_THREAD], pong_thread, NULL); +// pager_start_thread(threads[BUTTON_MONITOR_THREAD], button_monitor_thread, NULL); + return 0; } +#define DEV_SIZE 0x3c00 +#define AHB1_1DEV 0x40020000 + DECLARE_USER( 0, pingpong, main, - DECLARE_FPAGE(0x0, 4 * UTCB_SIZE + 4 * STACK_SIZE) + DECLARE_FPAGE(0x0, 6 * UTCB_SIZE + 6 * STACK_SIZE) DECLARE_FPAGE(0x0, 512) + /* map thread with AHB DEVICE for gpio accessing */ + DECLARE_FPAGE(AHB1_1DEV, DEV_SIZE) ); diff --git a/user/include/gpioer.h b/user/include/gpioer.h new file mode 100644 index 00000000..55dca541 --- /dev/null +++ b/user/include/gpioer.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef PLATFORM_STM32F4_GPIO_H_ +#define PLATFORM_STM32F4_GPIO_H_ + +#include + +enum { + AF0 = 0, + AF1, + AF2, + AF3, + AF4, + AF5, + AF6, + AF7, + AF8, + AF9, + AF10, + AF11, + AF12, + AF13, + AF14, + AF15, +}; + +struct gpio_cfg { + uint8_t port; + uint8_t pin; + uint8_t pupd; + uint8_t speed; + uint8_t type; + uint8_t func; + uint8_t o_type; +}; + +/* GPIO Alternative Function */ +#define af_system AF0 +#define af_tim1 AF1 +#define af_tim2 AF1 +#define af_tim3 AF2 +#define af_tim4 AF2 +#define af_tim5 AF2 +#define af_tim8 AF3 +#define af_tim9 AF3 +#define af_tim10 AF3 +#define af_tim11 AF3 +#define af_i2c1 AF4 +#define af_i2c2 AF4 +#define af_i2c3 AF4 +#define af_spi1 AF5 +#define af_spi2 AF5 +#define af_spi3 AF6 +#define af_usart1 AF7 +#define af_usart2 AF7 +#define af_usart3 AF7 +#define af_uart4 AF8 +#define af_uart5 AF8 +#define af_usart6 AF8 +#define af_can1 AF9 +#define af_can2 AF9 +#define af_tim12 AF9 +#define af_tim13 AF9 +#define af_tim14 AF9 +#define af_otg_fs AF10 +#define af_otg_hs AF10 +#define af_eth AF11 +#define af_fsmc AF12 +#define af_sdio AF12 +#define af_dcmi AF13 +#define af_eventout AF15 + +void gpio_config(struct gpio_cfg *cfg); +void gpio_config_output(uint8_t port, uint8_t pin, uint8_t pupd, uint8_t speed); +void gpio_config_input(uint8_t port, uint8_t pin, uint8_t pupd); +void gpio_out_high(uint8_t port, uint8_t pin); +void gpio_out_low(uint8_t port, uint8_t pin); +uint8_t gpio_input_bit(uint8_t port, uint8_t pin); + +#endif /* PLATFORM_STM32F4_GPIO_H_ */