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/README.md b/README.md index 85c1cd9e..7aacf3c8 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ communications) for ARM Cortex-M series microprocessors with efficiency (performance + power consumption) and security (memory protection + isolated execution) in mind. +Includes enhancements and modifications from master branch. + Characteristics of F9 Microkernel ================================= 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/platform/stm32f4/build.mk b/platform/stm32f4/build.mk index e93c0b42..9cc0f949 100644 --- a/platform/stm32f4/build.mk +++ b/platform/stm32f4/build.mk @@ -2,7 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -chip-y = +chip-y = \ + i2c.o \ loader-chip-y = \ gpio.loader.o \ diff --git a/platform/stm32f4/i2c.c b/platform/stm32f4/i2c.c new file mode 100644 index 00000000..df7bff20 --- /dev/null +++ b/platform/stm32f4/i2c.c @@ -0,0 +1,181 @@ +#include +#include + +/* I2C register mask */ +#define CR1_CLEAR_MASK ((uint16_t)0xFBF5) +/* Flag mask */ +#define FLAG_MASK ((uint32_t)0x00FFFFFF) + +void __USER_TEXT i2c_reset(uint32_t i2cx) +{ + /* TODO: assertion */ + + if (i2cx == I2C1_BASE) { + RCC_APB1PeriphResetCmd(RCC_APB1RSTR_I2C1RST, 1); + RCC_APB1PeriphResetCmd(RCC_APB1RSTR_I2C1RST, 0); + } else if (i2cx == I2C2_BASE) { + RCC_APB1PeriphResetCmd(RCC_APB1RSTR_I2C2RST, 1); + RCC_APB1PeriphResetCmd(RCC_APB1RSTR_I2C2RST, 0); + } else if (i2cx == I2C3_BASE) { + RCC_APB1PeriphResetCmd(RCC_APB1RSTR_I2C2RST, 1); + RCC_APB1PeriphResetCmd(RCC_APB1RSTR_I2C2RST, 0); + } +} + +void __USER_TEXT i2c_config(uint32_t i2cx, struct i2c_cfg* cfg) +{ + uint16_t tmpreg = 0, freqrange = 0; + uint16_t result = 0x04; + uint32_t pclk1 = 8000000; + struct rcc_clocks clocks; + /* TODO: assertion */ + + tmpreg = *I2C_CR2(i2cx); + tmpreg &= (uint16_t)~((uint16_t)I2C_CR2_FREQ_ALL); + + RCC_GetClocksFreq(&clocks); + pclk1 = clocks.pclk1_freq; + + freqrange = (uint16_t)(pclk1 / 1000000); + tmpreg |= freqrange; + + *I2C_CR2(i2cx) = tmpreg; + + *I2C_CR1(i2cx) &= (uint16_t)~((uint16_t)I2C_CR1_PE); + tmpreg = 0; + + if (cfg->clock_speed <= 100000) { + result = (uint16_t)(pclk1 / (cfg->clock_speed << 1)); + + if (result < 0x04) + result = 0x04; + + tmpreg |= result; + *I2C_TRISE(i2cx) = freqrange + 1; + } else { + if (cfg->duty_cycle == I2C_DutyCycle_2) { + result = (uint16_t)(pclk1 / (cfg->clock_speed * 3)); + } else { + result = (uint16_t)(pclk1 / (cfg->clock_speed * 25)); + result |= I2C_DutyCycle_16_9; + } + + if ((I2C_CCR_CCR(result)) == 0) + result |= (uint16_t)0x0001; + + tmpreg |= (uint16_t)(result | I2C_CCR_FS); + *I2C_TRISE(i2cx) = (uint16_t)(((freqrange * (uint16_t)300) / (uint16_t)1000) + (uint16_t)1); + } + *I2C_CCR(i2cx) = tmpreg; + *I2C_CR1(i2cx) |= I2C_CR1_PE; + + tmpreg = *I2C_CR1(i2cx); + tmpreg &= CR1_CLEAR_MASK; + + tmpreg |= (uint16_t)((uint32_t)cfg->mode | cfg->ack); + *I2C_CR1(i2cx) = tmpreg; + + *I2C_OAR1(i2cx) = (cfg->acknowledged_address | cfg->own_address); +} + +void __USER_TEXT i2c_cmd(uint32_t i2cx, uint8_t enable) +{ + /* TODO: assertion */ + + if (enable != 0) + *I2C_CR1(i2cx) |= I2C_CR1_PE; + else + *I2C_CR1(i2cx) &= (uint16_t)~((uint16_t)I2C_CR1_PE); +} + +void __USER_TEXT i2c_generate_start(uint32_t i2cx, uint8_t enable) +{ + /* TODO: assertion */ + + if (enable != 0) + *I2C_CR1(i2cx) |= I2C_CR1_START; + else + *I2C_CR1(i2cx) &= (uint16_t)~((uint16_t)I2C_CR1_START); +} + +uint8_t __USER_TEXT i2c_get_flag(uint32_t i2cx, uint32_t flag) +{ + uint8_t bitstatus = 0; + volatile uint32_t i2creg = 0, i2cxbase = 0; + + /* TODO: assertion */ + + i2cxbase = (uint32_t)i2cx; + i2creg = flag >> 28; + + flag &= FLAG_MASK; + + if (i2creg != 0) { + i2cxbase += 0x14; + } else { + flag = (uint32_t)(flag >> 16); + i2cxbase += 0x18; + } + + if (((*(volatile uint32_t *)i2cxbase) & flag) != (uint32_t)0) + bitstatus = 1; + else + bitstatus = 0; + + return bitstatus; +} + +void __USER_TEXT i2c_acknowledge_config(uint32_t i2cx, uint8_t enable) +{ + /* TODO: assertion */ + if (enable != 0) + *I2C_CR1(i2cx) |= I2C_CR1_ACK; + else + *I2C_CR1(i2cx) &= (uint16_t)~((uint16_t)I2C_CR1_ACK); +} + +void __USER_TEXT i2c_send_7bit_address(uint32_t i2cx, uint8_t address, uint8_t direction) +{ + /* TODO: assertion */ + + if (direction != I2C_Direction_Transmitter) + address |= I2C_OAR1_ADD(0); + else + address &= (uint8_t)~((uint8_t)I2C_OAR1_ADD(0)); + + *I2C_DR(i2cx) = address; +} + +void __USER_TEXT i2c_generate_stop(uint32_t i2cx, uint8_t enable) +{ + /* TODO: assertion */ + + if (enable != 0) + *I2C_CR1(i2cx) |= I2C_CR1_STOP; + else + *I2C_CR1(i2cx) &= (uint16_t)~((uint16_t)I2C_CR1_STOP); +} + +void __USER_TEXT i2c_software_reset_cmd(uint32_t i2cx, uint8_t enable) +{ + /* TODO: assertion */ + + if (enable != 0) + *I2C_CR1(i2cx) |= I2C_CR1_SWRST; + else + *I2C_CR1(i2cx) &= (uint16_t)~((uint16_t)I2C_CR1_SWRST); +} + +void __USER_TEXT i2c_send(uint32_t i2cx, uint8_t data) +{ + /* TODO: assertion */ + + *I2C_DR(i2cx) = data; +} + +uint8_t __USER_TEXT i2c_receive(uint32_t i2cx) +{ + /* TODO: assertion */ + + return (uint8_t)(*I2C_DR(i2cx)); +} 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..da8e8ccd 100644 --- a/user/apps/build.mk +++ b/user/apps/build.mk @@ -3,9 +3,17 @@ # found in the LICENSE file. user-apps-dirs = \ - l4test \ pingpong +# gpioer \ +# l4test \ +# pingpong +# altpingpong +# 3ping +# generic_thread +# i2c +# generic_thread_arg + ifdef CONFIG_EXTI_INTERRUPT_TEST user-apps-dirs += \ 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/generic_thread_arg/build.mk b/user/apps/generic_thread_arg/build.mk new file mode 100644 index 00000000..11adc8f5 --- /dev/null +++ b/user/apps/generic_thread_arg/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_arg-y = \ + main.o diff --git a/user/apps/generic_thread_arg/main.c b/user/apps/generic_thread_arg/main.c new file mode 100644 index 00000000..3c30b0fc --- /dev/null +++ b/user/apps/generic_thread_arg/main.c @@ -0,0 +1,183 @@ +/* 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 + +typedef struct thread_initialization_s { + L4_Word_t this_thread; + L4_Word_t prev_thread_id; + L4_Word_t next_thread_id; +} thread_initialization_t; + +static thread_initialization_t thread_initialization[THREAD_COUNT] __USER_DATA; + + +#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()); + + thread_initialization_t *thread_initialization_p = (thread_initialization_t *)arg; + my_thread_id = thread_initialization_p->this_thread; + prev_thread_id = thread_initialization_p->prev_thread_id; + next_thread_id = thread_initialization_p->next_thread_id; + + 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)); + + if (!L4_IpcSucceeded(tag)) { + printf("\nping_thread - %p, %d: recv ipc fails\n", L4_MyGlobalId(), my_thread_id); + printf("ping_thread - %p: ErrorCode = 0x%x %s\n", L4_MyGlobalId(), L4_ErrorCode(), L4_ErrorCode_String(L4_ErrorCode())); + // If there is no message for us then back to the top of this loop to wait again for a message. + continue; + } + else { + // Cannot call L4_MsgStore(tag, &msg) or L4_MsgWord(&msg, 0) + // in the event of an IPC receive timeout condition. + L4_MsgStore(tag, &msg); + count = L4_MsgWord(&msg, 0); + prev_thread_id = L4_MsgWord(&msg, 1); + } + + /* 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()); + + // Initialize each thread state. + 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); + thread_initialization[this_thread].this_thread = this_thread; + thread_initialization[this_thread].prev_thread_id = prev_thread_id; + thread_initialization[this_thread].next_thread_id = next_thread_id; + + 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, &thread_initialization[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 boss_thread()\n"); + return 0; +} + +__USER_TEXT +static void *main(void *user) +{ + printf("\nENTERING main()\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..74d10b18 --- /dev/null +++ b/user/apps/gpioer/main.c @@ -0,0 +1,148 @@ +/* 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 int count __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) +{ + printf("\nENTER gpioer_thread(%p)\n", arg); + 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)); + } + printf("\nEXIT gpioer_thread()\n"); +} + + +/* 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) +{ + printf("\nENTER button_monitor_thread(%p)\n", arg); + 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)); + } + printf("\nEXIT button_monitor_thread()\n"); +} + +/* main() signature changed. */ +__USER_TEXT +static void *main(void *user) +{ + printf("\nENTER main(%p)\n", user); + count = 0; + + threads[GPIOER_THREAD] = pager_create_thread(); + threads[BUTTON_MONITOR_THREAD] = pager_create_thread(); + + pager_start_thread(threads[GPIOER_THREAD], gpioer_thread, gpioer_thread); + pager_start_thread(threads[BUTTON_MONITOR_THREAD], button_monitor_thread, button_monitor_thread); + + /* Return statement required. */ + printf("\nEXIT main()\n"); + 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/i2c/build.mk b/user/apps/i2c/build.mk new file mode 100644 index 00000000..31b85238 --- /dev/null +++ b/user/apps/i2c/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-i2c-y = \ + main.o diff --git a/user/apps/i2c/main.c b/user/apps/i2c/main.c new file mode 100644 index 00000000..6de60670 --- /dev/null +++ b/user/apps/i2c/main.c @@ -0,0 +1,201 @@ +/* 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 +#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 int count __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) +{ + printf("\nENTER gpioer_thread(%p)\n", arg); + 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)); + } + printf("\nEXIT gpioer_thread()\n"); +} + + +/* 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) +{ + printf("\nENTER button_monitor_thread(%p)\n", arg); + 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)); + } + printf("\nEXIT button_monitor_thread()\n"); +} + +/* main() signature changed. */ +__USER_TEXT +static void *main(void *user) +{ + printf("\nENTER main(%p)\n", user); + count = 0; + + threads[GPIOER_THREAD] = pager_create_thread(); + threads[BUTTON_MONITOR_THREAD] = pager_create_thread(); + + pager_start_thread(threads[GPIOER_THREAD], gpioer_thread, gpioer_thread); + pager_start_thread(threads[BUTTON_MONITOR_THREAD], button_monitor_thread, button_monitor_thread); +#if 1 + { + struct i2c_cfg i2c_init; +#if 0 + printf("main(%d)\n", __LINE__); + i2c_generate_stop(I2C3_BASE, 1); + printf("main(%d)\n", __LINE__); + i2c_software_reset_cmd(I2C3_BASE, 1); + printf("main(%d)\n", __LINE__); + i2c_software_reset_cmd(I2C3_BASE, 0); +#endif + printf("main(%d)\n", __LINE__); + +// ioe_gpio_init(); + RCC_AHB1PeriphClockCmd(RCC_APB1ENR_I2C3EN, 1); + + i2c_reset(I2C3_BASE); + printf("main(%d)\n", __LINE__); + + i2c_init.mode = I2C_Mode_I2C; + printf("main(%d)\n", __LINE__); + + i2c_init.duty_cycle = I2C_DutyCycle_2; + printf("main(%d)\n", __LINE__); + + i2c_init.own_address = 0x00; + printf("main(%d)\n", __LINE__); + + i2c_init.ack = I2C_Ack_Enable; + printf("main(%d)\n", __LINE__); + + i2c_init.acknowledged_address = I2C_AcknowledgedAddress_7bit; + printf("main(%d)\n", __LINE__); + + i2c_init.clock_speed = I2C_SPEED; + printf("main(%d)\n", __LINE__); + + i2c_config(I2C3_BASE, &i2c_init); + printf("main(%d)\n", __LINE__); + + i2c_cmd(I2C3_BASE, 1); + printf("main(%d)\n", __LINE__); + } +#endif + /* Return statement required. */ + printf("\nEXIT main()\n"); + 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 + +#define APB1_DEV_SIZE 0x7800 +#define APB1DEV 0x40000000 + +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 APB DEVICE for I2C accessing */ + DECLARE_FPAGE(APB1DEV, APB1_DEV_SIZE) + /* 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..eecb7f75 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 // Grean +#define BOARD_LED_PIN2 13 // Orange +#define BOARD_LED_PIN3 14 // Red +#define BOARD_LED_PIN4 15 // Blue + +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_ */ diff --git a/user/lib/l4/pager.c b/user/lib/l4/pager.c index c5f02da3..a4f97366 100644 --- a/user/lib/l4/pager.c +++ b/user/lib/l4/pager.c @@ -150,7 +150,9 @@ void thread_container(kip_t *kip_ptr, utcb_t *utcb_ptr, L4_Word_t entry, L4_Word_t entry_arg) { L4_Msg_t msg; + printf("\nthread_container(0) %p %p\n", entry, entry_arg); ((thr_handler_t *)entry)((void *)entry_arg); + printf("\nthread_container(1) %p %p\n", entry, entry_arg); L4_MsgClear(&msg); L4_Set_MsgLabel(&msg, PAGER_REQUEST_LABEL); @@ -259,7 +261,7 @@ L4_Word_t pager_start_thread(L4_ThreadId_t tid, void * (*thr_routine)(void *), L4_MsgAppendWord(&msg, THREAD_START); L4_MsgAppendWord(&msg, (L4_Word_t)tid.raw); L4_MsgAppendWord(&msg, (L4_Word_t)thr_routine); - /* TODO: Ignore arg now */ + L4_MsgAppendWord(&msg, (L4_Word_t)arg); L4_MsgLoad(&msg); tag = L4_Call(L4_Pager()); @@ -334,14 +336,15 @@ void pager_thread(user_struct *user, break; case THREAD_START: { L4_Word_t entry; + L4_Word_t entry_arg; L4_ThreadId_t tid; L4_Word_t ret; tid.raw = L4_MsgWord(&msg, 1); entry = L4_MsgWord(&msg, 2); - /* TODO : ignore entry argument now */ + entry_arg = L4_MsgWord(&msg, 3); - ret = __thread_start(pool, tid, entry, 0); + ret = __thread_start(pool, tid, entry, entry_arg); L4_MsgClear(&msg); L4_Set_Label(&msg.tag, PAGER_REPLY_LABEL);