30 Commits

Author SHA1 Message Date
NIIBE Yutaka
d8df82badf Version 1.4. 2017-08-11 19:57:57 +09:00
NIIBE Yutaka
f51a54e4c6 Version 1.4.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-11 19:50:56 +09:00
Jeremy Drake
5fe5ff36c4 Allow compile-time override of detected flash size.
On the STM32F103C8, as used in the "blue pill" boards, it has been
determined that, despite these only officially having 64KiB flash, it is
possible to actually use 128KiB of flash.

This commit allows for a preprocessor define
STM32F103_OVERRIDE_FLASH_SIZE which, when set, is used as the size of
flash in KiB instead of reading it from the FLASH_SIZE_REG.
2017-08-03 20:48:13 +09:00
NIIBE Yutaka
a4f28ee176 Add adc-gnu-linux driver.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-02 14:19:10 +09:00
NIIBE Yutaka
87767f1be5 Fix error handling of USB-USBIP driver. 2017-07-07 15:46:37 +09:00
NIIBE Yutaka
8b018df382 Add EXAMPLE-README. 2017-07-06 16:06:46 +09:00
NIIBE Yutaka
5d9802388c Fix USB driver on GNU/Linux. 2017-07-06 15:52:46 +09:00
NIIBE Yutaka
478dd2c784 Add example-fraucheky. 2017-07-05 19:37:41 +09:00
NIIBE Yutaka
6f7a591417 Fix usb-usbip.c. 2017-06-28 16:23:41 +09:00
NIIBE Yutaka
d142cbbea3 Added CDC-ACM sample of USBIP. 2017-06-27 15:46:04 +09:00
NIIBE Yutaka
f011d643e9 Add board-gnu-linux.h for emulation. 2017-06-26 19:53:26 +09:00
NIIBE Yutaka
1fbbf66e8e Fix for GNU/Linux emulation. 2017-06-26 19:52:19 +09:00
NIIBE Yutaka
1f7d4a6aac Fix usb drivers. 2017-06-26 19:50:55 +09:00
NIIBE Yutaka
526b8fec2a Added USBIP driver for emulation. 2017-06-26 19:32:43 +09:00
NIIBE Yutaka
5419580519 Support emulation on GNU/Linux. 2017-06-26 19:32:23 +09:00
NIIBE Yutaka
78c825afe8 Add GNU/Linux support (not yet makefile). 2017-06-23 09:05:11 +09:00
NIIBE Yutaka
1bd14d8d40 Factor out arch dependent code. 2017-06-23 09:03:26 +09:00
NIIBE Yutaka
80258ba7c7 Remove naked attribute from chopstx_exit. 2017-06-22 10:04:45 +09:00
NIIBE Yutaka
ca1b22c3eb Use ->V for the return value of chx_sched. 2017-06-21 20:48:50 +09:00
NIIBE Yutaka
6c68c55301 Change exit value access. 2017-06-21 17:16:01 +09:00
NIIBE Yutaka
d941299149 Fix chx_wakeup. 2017-06-16 10:31:40 +09:00
NIIBE Yutaka
b2b0eb7418 Fix MKL27Z USB. 2017-06-16 10:29:00 +09:00
NIIBE Yutaka
7798e620a6 Fix access to REG_R0 at chx_wakeup. 2017-05-18 11:09:03 +09:00
NIIBE Yutaka
89eb54929e Version 1.3. 2017-02-02 12:56:13 +09:00
NIIBE Yutaka
a96f84ff74 Add Blue Pill support. 2017-02-01 17:31:52 +09:00
Szczepan Zalega
9d84537c13 Switch off red LED for Nitrokey Start.
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2017-02-01 15:24:55 +09:00
NIIBE Yutaka
d448d3c678 Version 1.2 2016-10-13 10:18:47 +09:00
NIIBE Yutaka
bc664fe943 chopstx_join is cancellation point. 2016-10-12 12:06:37 +09:00
NIIBE Yutaka
08cca6b9f8 stackaddr/size change 2016-07-11 17:21:32 +09:00
NIIBE Yutaka
c9d59a3f3f mcu/stm32f103.h: Add more constants from Gnuk 1.1.9 2016-07-11 11:38:58 +09:00
46 changed files with 6106 additions and 859 deletions

25
AUTHORS
View File

@@ -2,6 +2,10 @@ Aidan Thornton:
Added Maple Mini support.
board/board-maple-mini.h
Jeremy Drake:
Modified STM32F103 support.
mcu/sys-stm32f103.c
Kaz Kojima:
Added STM32 Primer2 support.
board/board-stm32-primer2.h
@@ -22,18 +26,18 @@ Mateusz Zalega:
board/board-nitrokey-start.h
NIIBE Yutaka:
Write the library:
Wrote the library:
chopstx.c, entry.c, eventflag.c,
chopstx.h, eventflag.h
Write the drivers mcu/*:
Wrote the drivers mcu/*:
clk_gpio_init-mkl27z.c, clk_gpio_init-stm32.c,
sys-stm32f103.c, sys-stm32f030.c, sys-mkl27z.c,
adc-stm32f103.c, adc-mkl27z.c
Draw the logo:
Drew the logo:
chopstx.svg, chopstx.png
Write examples:
Wrote examples:
example-led, example-cdc, example-fsm-55, example-fs-bb48
Write board/*:
Wrote board/*:
board-fst-01.h, board-fst-01-00.h,
board-olimex-stm32-h103.h, board-stm8s-discovery.h
board-cq-starm.h, board-stbee-mini.h, board-stbee.h,
@@ -41,3 +45,14 @@ NIIBE Yutaka:
board-stm32f0-discovery.h, board-fsm-55.h,
board-fs-bb48.h
Under contract of g10 Code GmbH, wrote:
mcu/usb-usbip.c
Paul Fertser:
Added Blue Pill support.
board/board-blue-pill.h
Szczepan Zalega:
Modified Nitrokey-Start support.
board/board-nitrokey-start.h

122
ChangeLog
View File

@@ -1,3 +1,125 @@
2017-08-11 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.4.
* doc/chopstx.texi (VERSION): 1.4.
2017-08-03 Jeremy Drake <jeremydrake+gnuk@eacceleration.com>
* mcu/sys-stm32f103.c (flash_write): Allow compile time
flash size definition by STM32F103_OVERRIDE_FLASH_SIZE_KB.
2017-08-02 NIIBE Yutaka <gniibe@fsij.org>
* contrib/adc-gnu-linux.c: New.
2017-07-07 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-usbip.c (usbip_handle_data_urb): Fix error return value.
(notify_hostcontroller): New.
(usb_lld_stall_tx, usb_lld_stall_rx): Notify host controller side.
2017-07-06 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-usbip.c (hc_handle_data_urb): Fix the condition of the
end of transaction.
(read_data_transaction): Allow partial read by host.
2017-07-05 NIIBE Yutaka <gniibe@fsij.org>
* example-fraucheky: New.
2017-06-28 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-usbip.c (struct usbip_msg_cmd, struct usbip_msg_rep):
Use different struct for command and reply.
2017-06-27 NIIBE Yutaka <gniibe@fsij.org>
* example-cdc-gnu-linux/README: New.
2017-06-26 NIIBE Yutaka <gniibe@fsij.org>
* board/board-gnu-linux.h: New.
* mcu/usb-usbip.c: New.
* rules.mk: Support EMULATION.
* entry.c (main): Support GNU_LINUX_EMULATION.
2017-06-23 NIIBE Yutaka <gniibe@fsij.org>
* chopstx-gnu-linux.c, chopstx-gnu-linux.h: New.
* chopstx.c (chx_init): Use chx_init_arch.
(chopstx_create): Use chopstx_create_arch.
(chx_systick_reset, chx_systick_reload, chx_systick_get)
(usec_to_ticks, chx_enable_intr, chx_clr_intr, chx_disable_intr)
(chx_set_intr_prio, chx_prio_init, chx_cpu_sched_lock)
(chx_cpu_sched_unlock, idle, chx_handle_intr)
(chx_request_preemption, chx_sched, preempt, svc): Move to...
* chopstx-cortex-m.c: ... here.
(chx_init_arch, chopstx_create_arch): New.
* chopstx-cortex-m.h: New for tcontext_t.
2017-06-22 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_sched): Use ->V for return value.
(svc): Ditto.
(chx_wakeup): Set -> for the return value of chx_sched.
(chopstx_mutex_lock, chopstx_cancel): Likewise.
(chopstx_exit): Remove naked attribute.
2017-06-21 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (struct chx_pq): Use uintptr_t for V.
(struct chx_px): Likewise.
(struct chx_thread): Likewise.
(chx_sched): Use uintptr_t for the return value.
(chx_exit): Use the field V for holding exit value.
(chopstx_create): Use uintptr_t for STACK_ADDR.
(chopstx_join): Use the field V for exit value.
2017-06-16 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_wakeup): Fix for RUNNING==NULL.
* mcu/usb-mkl27z.c (std_get_status): Use staic var, not auto.
2017-05-18 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_wakeup): Fix access to REG_R0.
2017-02-02 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.3.
* doc/chopstx.texi (VERSION): 1.3.
2017-02-01 Paul Fertser <fercerpav@gmail.com>
* board/board-blue-pill.h: New.
2016-12-08 Szczepan Zalega <szczepan@nitrokey.com>
* board/board-nitrokey-start.h (VAL_GPIO_USB_ODR): Switch off red
LED for Nitrokey Start.
2016-10-13 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.2.
* doc/chopstx.texi (VERSION): 1.2.
2016-10-12 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_join, chopstx_cancel): chopstx_join is
cancellation point.
2016-07-11 NIIBE Yutaka <gniibe@fsij.org>
* mcu/stm32f103.h: Add more from Gnuk 1.1.9.
* example-cdc, example-fs-bb48, example-fsm-55, example-led:
Update for stack addr/size.
2016-07-01 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.1.

25
NEWS
View File

@@ -1,6 +1,31 @@
NEWS - Noteworthy changes
* Major changes in Chopstx 1.4
Released 2017-08-11
** New port: Emulation on GNU/Linux
Now, user can run Chopstx application on GNU/Linux. Its USB driver is
by USBIP. Its ADC driver is dummy with random(3).
* Major changes in Chopstx 1.3
Released 2017-02-02
** New board support: Blue Pill
It is contributed by Paul Fertser.
* Major changes in Chopstx 1.2
Released 2016-10-13
** Fix: chopstx_join
chopstx_join is now cancellation point.
* Major changes in Chopstx 1.1
Released 2016-07-01

7
README
View File

@@ -1,6 +1,6 @@
Chopstx - Threads and only Threads
Version 1.1
2016-07-01
Version 1.4
2017-08-11
Niibe Yutaka
Flying Stone Technology
@@ -8,7 +8,8 @@ What's Chopstx?
===============
Chopstx is an RT thread library for STM32F103 (ARM Cortex-M3),
STM32F030 (ARM Cortex-M0), and MKL27Z (ARM Cortex-M0plus).
STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus), and
emulation on GNU/Linux.
While most RTOSes come with many features, drivers, and stacks,
Chopstx just offers a simple RT thread library.

View File

@@ -1 +1 @@
release/1.1
release/1.4

36
board/board-blue-pill.h Normal file
View File

@@ -0,0 +1,36 @@
#define BOARD_NAME "Blue Pill"
/* http://wiki.stm32duino.com/index.php?title=Blue_Pill */
/* echo -n "Blue Pill" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
#define BOARD_ID 0xa1099d43
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
#define STM32_HSECLK 8000000
#define GPIO_LED_BASE GPIOC_BASE
#define GPIO_LED_CLEAR_TO_EMIT 13
#define GPIO_USB_BASE GPIOA_BASE
#define GPIO_USB_SET_TO_ENABLE 12
#undef GPIO_OTHER_BASE
/*
* Port A setup.
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
* PC13 - Push pull output 50MHz (LED 1:ON 0:OFF)
* ------------------------ Default
* PAx - input with pull-up
* PCx - input with pull-up
*/
#define VAL_GPIO_USB_ODR 0xFFFFE7FF
#define VAL_GPIO_USB_CRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIO_USB_CRH 0x88811888 /* PA15...PA8 */
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
#define VAL_GPIO_LED_CRL 0x88888888 /* PC7...PC0 */
#define VAL_GPIO_LED_CRH 0x88388888 /* PC15...PC8 */
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN)
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPCRST)

4
board/board-gnu-linux.h Normal file
View File

@@ -0,0 +1,4 @@
#define BOARD_NAME "GNU/Linux"
/* Emulation on GNU/Linux */
/* echo -n "GNU/Linux" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
#define BOARD_ID 0x7ec86145

View File

@@ -22,7 +22,7 @@
* PA4 - floating input
* PA5 - floating input
* PA6 - floating input
* PA7 - Push pull output (LED1 1:ON 0:OFF)
* PA7 - Push pull output (Red LED1 1:ON 0:OFF)
* PA8 - floating input (smartcard, SCDSA)
* PA9 - floating input
* PA10 - floating input
@@ -37,13 +37,13 @@
* PA14 - input with pull-up.
* PA15 - Push pull output (USB 1:ON 0:OFF)
*/
#define VAL_GPIO_USB_ODR 0xFFFFE7FF
#define VAL_GPIO_USB_ODR 0xFFFFE77F
#define VAL_GPIO_USB_CRL 0x34444488 /* PA7...PA0 */
#define VAL_GPIO_USB_CRH 0x38811444 /* PA15...PA8 */
/*
* Port B setup.
* PB0 - Push pull output (LED2 1:ON 0:OFF)
* PB0 - Push pull output (Green LED2 1:ON 0:OFF)
* ------------------------ Default
* PBx - input with pull-up.
*/

707
chopstx-cortex-m.c Normal file
View File

@@ -0,0 +1,707 @@
/*
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
* for Cortex-M0/M3
*
* Copyright (C) 2013, 2014, 2015, 2016, 2017
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* receipents of GNU GPL by a written offer.
*
*/
/* Saved registers on the stack. */
struct chx_stack_regs {
uint32_t reg[8]; /* r0, r1, r2, r3, r12, lr, pc, xpsr */
};
/*
* Constants for ARM.
*/
#define REG_SP 8
#define REG_R0 0
#define REG_LR 5
#define REG_PC 6
#define REG_XPSR 7
#define INITIAL_XPSR 0x01000000 /* T=1 */
/*
* Exception priority: lower has higher precedence.
*
* Cortex-M3
* =====================================
* Prio 0x30: svc
* ---------------------
* Prio 0x40: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0xb0: systick, external interrupt
* Prio 0xc0: pendsv
* =====================================
*
* Cortex-M0
* =====================================
* Prio 0x00: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0x40: systick, external interrupt
* Prio 0x80: pendsv
* Prio 0x80: svc
* =====================================
*/
#define CPU_EXCEPTION_PRIORITY_CLEAR 0
#if defined(__ARM_ARCH_6M__)
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
#elif defined(__ARM_ARCH_7M__)
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0xb0
#define CPU_EXCEPTION_PRIORITY_PENDSV 0xc0
#else
#error "no support for this arch"
#endif
/*
* Lower layer architecture specific functions.
*
* system tick and interrupt
*/
/*
* System tick
*/
/* SysTick registers. */
static volatile uint32_t *const SYST_CSR = (uint32_t *)0xE000E010;
static volatile uint32_t *const SYST_RVR = (uint32_t *)0xE000E014;
static volatile uint32_t *const SYST_CVR = (uint32_t *)0xE000E018;
static void
chx_systick_reset (void)
{
*SYST_RVR = 0;
*SYST_CVR = 0;
*SYST_CSR = 7;
}
static void
chx_systick_reload (uint32_t ticks)
{
*SYST_RVR = ticks;
*SYST_CVR = 0; /* write (any) to clear the counter to reload. */
*SYST_RVR = 0;
}
static uint32_t
chx_systick_get (void)
{
return *SYST_CVR;
}
static uint32_t usec_to_ticks (uint32_t usec)
{
return usec * MHZ;
}
/*
* Interrupt Handling
*/
/* NVIC: Nested Vectored Interrupt Controller. */
struct NVIC {
volatile uint32_t ISER[8];
uint32_t unused1[24];
volatile uint32_t ICER[8];
uint32_t unused2[24];
volatile uint32_t ISPR[8];
uint32_t unused3[24];
volatile uint32_t ICPR[8];
uint32_t unused4[24];
volatile uint32_t IABR[8];
uint32_t unused5[56];
volatile uint32_t IPR[60];
};
static struct NVIC *const NVIC = (struct NVIC *)0xE000E100;
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
#define NVIC_ICER(n) (NVIC->ICER[n >> 5])
#define NVIC_ICPR(n) (NVIC->ICPR[n >> 5])
#define NVIC_IPR(n) (NVIC->IPR[n >> 2])
static void
chx_enable_intr (uint8_t irq_num)
{
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_clr_intr (uint8_t irq_num)
{ /* Clear pending interrupt. */
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_disable_intr (uint8_t irq_num)
{
NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_set_intr_prio (uint8_t n)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh))
| (CPU_EXCEPTION_PRIORITY_INTERRUPT << sh);
}
static volatile uint32_t *const ICSR = (uint32_t *)0xE000ED04;
/* Priority control. */
static uint32_t *const AIRCR = (uint32_t *)0xE000ED0C;
static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
static void
chx_prio_init (void)
{
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
*SHPR3 = ((CPU_EXCEPTION_PRIORITY_SYSTICK << 24)
| (CPU_EXCEPTION_PRIORITY_PENDSV << 16));
}
static void
chx_cpu_sched_lock (void)
{
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
{
#if defined(__ARM_ARCH_6M__)
asm volatile ("cpsid i" : : : "memory");
#else
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
#endif
}
}
static void
chx_cpu_sched_unlock (void)
{
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
{
#if defined(__ARM_ARCH_6M__)
asm volatile ("cpsie i" : : : "memory");
#else
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
#endif
}
}
static void __attribute__((naked, used))
idle (void)
{
#if defined(USE_WFI_FOR_IDLE)
for (;;)
asm volatile ("wfi" : : : "memory");
#else
for (;;);
#endif
}
void
chx_handle_intr (void)
{
struct chx_pq *p;
register uint32_t irq_num;
asm volatile ("mrs %0, IPSR\n\t"
"sub %0, #16" /* Exception # - 16 = interrupt number. */
: "=r" (irq_num) : /* no input */ : "memory");
chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock);
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
if (p->v == irq_num)
{ /* should be one at most. */
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p);
chx_wakeup (p);
chx_request_preemption (px->master->prio);
break;
}
chx_spin_unlock (&q_intr.lock);
}
static void
chx_init_arch (struct chx_thread *tp)
{
memset (&tp->tc, 0, sizeof (tp->tc));
}
static void
chx_request_preemption (uint16_t prio)
{
if (running == NULL || (uint16_t)running->prio < prio)
{
*ICSR = (1 << 28);
asm volatile ("" : : : "memory");
}
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* For Cortex-M0, this should be AAPCS-compliant function entry, so we
* put "noinline" attribute.
*
* AAPCS: ARM Architecture Procedure Call Standard
*
* Returns:
* 1 on wakeup by others.
* 0 on normal wakeup.
* -1 on cancellation.
*/
static uintptr_t __attribute__ ((naked, noinline))
chx_sched (uint32_t yield)
{
register struct chx_thread *tp asm ("r0");
#if defined(__ARM_ARCH_7M__)
asm volatile (
"svc #0\n\t"
"bx lr"
: "=r" (tp) : "0" (yield): "memory");
#else
register uint32_t arg_yield asm ("r1");
/* Build stack data as if it were an exception entry. */
/*
* r0: 0 scratch
* r1: 0 scratch
* r2: 0 scratch
* r3: 0 scratch
* r12: 0 scratch
* lr as-is
* pc: return address (= lr)
* psr: INITIAL_XPSR scratch
*/
asm ("mov r1, lr\n\t"
"mov r2, r1\n\t"
"mov r3, #128\n\t"
"lsl r3, #17\n\t"
"push {r1, r2, r3}\n\t"
"mov r1, #0\n\t"
"mov r2, r1\n\t"
"mov r3, r1\n\t"
"push {r1, r2, r3}\n\t"
"push {r1, r2}"
: /* no output*/
: /* no input */
: "r1", "r2", "r3", "memory");
/* Save registers onto CHX_THREAD struct. */
asm ("mov r1, r0\n\t"
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"add r0, #20\n\t"
"stm r0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mov r6, sp\n\t"
"stm r0!, {r2, r3, r4, r5, r6}\n\t"
"sub r0, #56"
: "=r" (tp), "=r" (arg_yield)
: "0" (yield)
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (arg_yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
if (tp && tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
tp = chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
asm volatile (/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
"cmp r0, #0\n\t"
"bne 0f\n\t"
/* Spawn an IDLE thread. */
"ldr r1, =__main_stack_end__\n\t"
"mov sp, r1\n\t"
"ldr r0, =idle\n\t" /* PC = idle */
/**/
/* Unmask interrupts. */
"cpsie i\n\t"
"bx r0\n"
/* Normal context switch */
"0:\n\t"
"add r0, #16\n\t" /* ->V */
"ldr r1, [r0]\n\t"
"str r1, [sp]\n\t"
/**/
"add r0, #4\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"mov sp, r2\n\t"
"sub r0, #45\n\t"
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
"cmp r1, #247\n\t"
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
/**/
/* Unmask interrupts. */
"cpsie i\n"
/**/
"1:\n\t"
/*
0: r0
4: r1
8: r2
12: r3
16: r12
20: lr
24: pc
28: psr
32: possibly exists for alignment
[28 or 32] <-- pc
*/
"ldr r0, [sp, #28]\n\t"
"lsl r1, r0, #23\n\t"
"bcc 2f\n\t"
/**/
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #32]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
"ldr r0, [sp, #20]\n\t"
"mov lr, r0\n\t"
"ldr r0, [sp, #16]\n\t"
"mov r12, r0\n\t"
"pop {r0, r1, r2, r3}\n\t"
"add sp, #16\n\t"
"pop {pc}\n"
"2:\n\t"
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #28]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
"ldr r0, [sp, #20]\n\t"
"mov lr, r0\n\t"
"ldr r0, [sp, #16]\n\t"
"mov r12, r0\n\t"
"pop {r0, r1, r2, r3}\n\t"
"add sp, #12\n\t"
"pop {pc}"
: "=r" (tp) /* Return value in R0 */
: "0" (tp)
: "memory");
#endif
return (uintptr_t)tp;
}
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
static struct chx_thread *
chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
voidfunc thread_entry, void *arg)
{
struct chx_thread *tp;
void *stack;
struct chx_stack_regs *p;
if (CHOPSTX_THREAD_SIZE != sizeof(struct chx_thread))
cause_link_time_error_unexpected_size_of_struct_chx_thread ();
if (stack_size < sizeof (struct chx_thread) + 8 * sizeof (uint32_t))
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
stack = (void *)(stack_addr + stack_size - sizeof (struct chx_thread)
- sizeof (struct chx_stack_regs));
memset (stack, 0, sizeof (struct chx_stack_regs));
tp = (struct chx_thread *)(stack + sizeof (struct chx_stack_regs));
p = (struct chx_stack_regs *)stack;
p->reg[REG_R0] = (uint32_t)arg;
p->reg[REG_LR] = (uint32_t)chopstx_exit;
p->reg[REG_PC] = (uint32_t)thread_entry;
p->reg[REG_XPSR] = INITIAL_XPSR;
memset (&tp->tc, 0, sizeof (tp->tc));
tp->tc.reg[REG_SP] = (uint32_t)stack;
return tp;
}
/*
* Lower layer architecture specific exception handling entries.
*
*/
void __attribute__ ((naked))
preempt (void)
{
register struct chx_thread *tp asm ("r0");
register struct chx_thread *cur asm ("r1");
asm volatile (
#if defined(__ARM_ARCH_6M__)
"cpsid i\n\t"
#else
"msr BASEPRI, r0\n\t"
#endif
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"mov r1, r0"
: "=r" (tp), "=r" (cur)
: "0" (CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED)
: "r2");
if (!cur)
/* It's idle thread. It's ok to clobber registers. */
;
else
{
/* Save registers onto CHX_THREAD struct. */
asm volatile (
"add %0, #20\n\t"
"stm %0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm %0!, {r2, r3, r4, r5, r6}"
: "=r" (cur)
: "0" (cur)
/*
* Memory clobber constraint here is not accurate, but this
* works. R7 keeps its value, but having "r7" here prevents
* use of R7 before this asm statement.
*/
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (tp)
{
if (tp->flag_sched_rr)
{
if (tp->state == THREAD_RUNNING)
{
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
/*
* It may be THREAD_READY after chx_timer_expired.
* Then, do nothing.
*/
}
else
chx_ready_push (tp);
running = NULL;
}
}
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
tp = chx_ready_pop ();
if (tp && tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
tp = chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
asm volatile (
".L_CONTEXT_SWITCH:\n\t"
/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
#if defined(__ARM_ARCH_6M__)
"cmp r0, #0\n\t"
"beq 1f\n\t"
#else
"cbz r0, 1f\n\t"
#endif
/**/
"add r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
#if defined(__ARM_ARCH_6M__)
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"msr PSP, r2\n\t"
#else
"ldr r8, [r0], #4\n\t"
"ldr r9, [r0], #4\n\t"
"ldr r10, [r0], #4\n\t"
"ldr r11, [r0], #4\n\t"
"ldr r1, [r0], #4\n\t"
"msr PSP, r1\n\t"
#endif
"sub r0, #45\n\t"
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
"mov r0, #0\n\t"
"cmp r1, #247\n\t"
"bhi 0f\n\t" /* Leave interrupt disabled if >= 248 */
/**/
/* Unmask interrupts. */
#if defined(__ARM_ARCH_6M__)
"cpsie i\n"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"0:\n\t"
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0\n"
"1:\n\t"
/* Spawn an IDLE thread. */
"ldr r0, =__main_stack_end__-32\n\t"
"msr PSP, r0\n\t"
"mov r1, #0\n\t"
"mov r2, #0\n\t"
"mov r3, #0\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"ldr r1, =idle\n\t" /* PC = idle */
"mov r2, #0x010\n\t"
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
"stm r0!, {r1, r2}\n\t"
/**/
/* Unmask interrupts. */
"mov r0, #0\n\t"
#if defined(__ARM_ARCH_6M__)
"cpsie i\n\t"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /* no output */ : "r" (tp) : "memory");
}
#if defined(__ARM_ARCH_7M__)
/*
* System call: switch to another thread.
* There are two cases:
* ORIG_R0=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* ORIG_R0=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*/
void __attribute__ ((naked))
svc (void)
{
register struct chx_thread *tp asm ("r0");
register uint32_t orig_r0 asm ("r1");
asm ("ldr r1, =running\n\t"
"ldr r0, [r1]\n\t"
"add r1, r0, #20\n\t"
/* Save registers onto CHX_THREAD struct. */
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"ldr r1, [r6]"
: "=r" (tp), "=r" (orig_r0)
: /* no input */
: "r2", "r3", "r4", "r5", "r6", "memory");
if (orig_r0) /* yield */
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
running = NULL;
}
tp = chx_ready_pop ();
if (tp && tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
asm volatile (
"cbz r0, 0f\n\t"
"ldr r1, [r0, #16]\n\t" /* ->V */
"str r1, [sp]\n\t"
"0:\n\t"
"b .L_CONTEXT_SWITCH"
: /* no output */ : "r" (tp) : "memory");
}
#endif

12
chopstx-cortex-m.h Normal file
View File

@@ -0,0 +1,12 @@
/*
* The thread context: specific to ARM Cortex-M0/M3.
*
* In this structure, it's only partial information; Other part of the
* context is on the stack.
*
*/
struct tcontext {
uint32_t reg[9]; /* r4, r5, r6, r7, r8, r9, r10, r11, r13(sp) */
};
typedef struct tcontext tcontext_t;

344
chopstx-gnu-linux.c Normal file
View File

@@ -0,0 +1,344 @@
/*
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
* for GNU/Linux emulation
*
* Copyright (C) 2017 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* receipents of GNU GPL by a written offer.
*
*/
#include <unistd.h>
#include <ucontext.h>
#include <signal.h>
#include <sys/time.h>
static sigset_t ss_cur;
static void
chx_systick_reset (void)
{
const struct itimerval it = { {0, 0}, {0, 0} };
setitimer (ITIMER_REAL, &it, 0);
}
static void
chx_systick_reload (uint32_t ticks)
{
struct itimerval it;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = (ticks / MHZ);
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &it, 0);
}
static uint32_t
chx_systick_get (void)
{
struct itimerval it;
getitimer (ITIMER_REAL, &it);
return it.it_value.tv_usec * 72;
}
static uint32_t
usec_to_ticks (uint32_t usec)
{
return usec * MHZ;
}
static void
chx_enable_intr (uint8_t irq_num)
{
sigdelset (&ss_cur, irq_num);
}
static void
chx_clr_intr (uint8_t irq_num)
{ /* Clear pending interrupt. */
(void)irq_num;
}
static void
chx_disable_intr (uint8_t irq_num)
{
sigaddset (&ss_cur, irq_num);
}
static void
chx_set_intr_prio (uint8_t n)
{
(void)n;
}
static void
chx_prio_init (void)
{
}
static void
chx_cpu_sched_lock (void)
{
sigset_t ss;
sigfillset (&ss);
pthread_sigmask (SIG_BLOCK, &ss, &ss_cur);
}
static void
chx_cpu_sched_unlock (void)
{
pthread_sigmask (SIG_SETMASK, &ss_cur, NULL);
}
static void
idle (void)
{
for (;;)
pause ();
}
void
chx_handle_intr (uint32_t irq_num)
{
struct chx_pq *p;
chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock);
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
if (p->v == irq_num)
{ /* should be one at most. */
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p);
chx_wakeup (p);
chx_spin_unlock (&q_intr.lock);
chx_request_preemption (px->master->prio);
return;
}
chx_spin_unlock (&q_intr.lock);
}
static ucontext_t idle_tc;
static char idle_stack[4096];
struct chx_thread main_thread;
void
chx_sigmask (ucontext_t *uc)
{
/* Modify oldmask to SS_CUR, so that the signal mask will
* be set to SS_CUR.
*
* In user-level, sigset_t is big, but only the first word
* is used by the kernel.
*/
memcpy (&uc->uc_sigmask, &ss_cur, sizeof (uint64_t));
}
static void
sigalrm_handler (int sig, siginfo_t *siginfo, void *arg)
{
extern void chx_timer_expired (void);
ucontext_t *uc = arg;
(void)sig;
(void)siginfo;
chx_timer_expired ();
chx_sigmask (uc);
}
static void
chx_init_arch (struct chx_thread *tp)
{
struct sigaction sa;
sigemptyset (&ss_cur);
sa.sa_sigaction = sigalrm_handler;
sigfillset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO|SA_RESTART;
sigaction (SIGALRM, &sa, NULL);
getcontext (&idle_tc);
idle_tc.uc_stack.ss_sp = idle_stack;
idle_tc.uc_stack.ss_size = sizeof (idle_stack);
idle_tc.uc_link = NULL;
makecontext (&idle_tc, idle, 0);
getcontext (&tp->tc);
}
static void
chx_request_preemption (uint16_t prio)
{
struct chx_thread *tp, *tp_prev;
ucontext_t *tcp;
if (running && (uint16_t)running->prio >= prio)
return;
/* Change the context to another thread with higher priority. */
tp = tp_prev = running;
if (tp)
{
if (tp->flag_sched_rr)
{
if (tp->state == THREAD_RUNNING)
{
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
}
else
chx_ready_push (tp);
running = NULL;
}
tp = running = chx_ready_pop ();
if (tp)
{
tcp = &tp->tc;
if (tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
tp = chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
}
else
tcp = &idle_tc;
if (tp_prev)
{
/*
* The swapcontext implementation may reset sigmask in the
* middle of its execution, unfortunately. It is best if
* sigmask restore is done at the end of the routine, but we
* can't assume that.
*
* Thus, there might be a race condition with regards to the
* user context TCP, if signal mask is cleared and signal comes
* in. To avoid this situation, we block signals.
*
* We don't need to fill the mask here. It keeps the condition
* of blocking signals before&after swapcontext call. It is
* done by the signal mask for sigaction, the initial creation
* of the thread, and the condition of chx_sched function which
* mandates holding cpu_sched_lock.
*/
swapcontext (&tp_prev->tc, tcp);
}
else if (tp)
{
setcontext (tcp);
}
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* Returns:
* 1 on wakeup by others.
* 0 on normal wakeup.
* -1 on cancellation.
*/
static uintptr_t
chx_sched (uint32_t yield)
{
struct chx_thread *tp, *tp_prev;
uintptr_t v;
ucontext_t *tcp;
tp = tp_prev = running;
if (yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
running = tp = chx_ready_pop ();
if (tp)
{
v = tp->v;
if (tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
tp = chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
tcp = &tp->tc;
}
else
{
v = 0;
tcp = &idle_tc;
}
swapcontext (&tp_prev->tc, tcp);
chx_cpu_sched_unlock ();
return v;
}
static void __attribute__((__noreturn__))
chx_thread_start (voidfunc thread_entry, void *arg)
{
chx_cpu_sched_unlock ();
thread_entry (arg);
chopstx_exit (0);
}
static struct chx_thread *
chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
voidfunc thread_entry, void *arg)
{
struct chx_thread *tp;
tp = malloc (sizeof (struct chx_thread));
if (!tp)
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
/*
* Calling getcontext with sched_lock held, the context is with
* signal blocked. The sigmask will be cleared in chx_thread_start.
*/
chx_cpu_sched_lock ();
getcontext (&tp->tc);
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
tp->tc.uc_stack.ss_size = stack_size;
tp->tc.uc_link = NULL;
makecontext (&tp->tc, (void (*)(void))chx_thread_start,
4, thread_entry, arg);
chx_cpu_sched_unlock ();
return tp;
}

10
chopstx-gnu-linux.h Normal file
View File

@@ -0,0 +1,10 @@
#include <ucontext.h>
/*
* The thread context: specific to GNU/Linux.
*
* We use the type ucontext_t, which includes all registers;
* Note that signal mask is also included in ucontext_t.
*
*/
typedef ucontext_t tcontext_t;

747
chopstx.c
View File

@@ -1,7 +1,7 @@
/*
* chopstx.c - Threads and only threads.
*
* Copyright (C) 2013, 2014, 2015, 2016
* Copyright (C) 2013, 2014, 2015, 2016, 2017
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -34,7 +34,7 @@
#include <chopstx.h>
/*
* Thread priority: higer has higher precedence.
* Thread priority: greater (as integer) has higher precedence.
*/
#if !defined(CHX_PRIO_MAIN_INIT)
#define CHX_PRIO_MAIN_INIT 1
@@ -50,163 +50,11 @@
#define MAX_PRIO (255+1)
/*
* Exception priority: lower has higher precedence.
*
* Cortex-M3
* =====================================
* Prio 0x30: svc
* ---------------------
* Prio 0x40: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0xb0: systick, external interrupt
* Prio 0xc0: pendsv
* =====================================
*
* Cortex-M0
* =====================================
* Prio 0x00: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0x40: systick, external interrupt
* Prio 0x80: pendsv
* Prio 0x80: svc
* =====================================
*/
#define CPU_EXCEPTION_PRIORITY_CLEAR 0
#if defined(__ARM_ARCH_6M__)
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
#elif defined(__ARM_ARCH_7M__)
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0xb0
#define CPU_EXCEPTION_PRIORITY_PENDSV 0xc0
#else
#error "no support for this arch"
#endif
/*
* Lower layer architecture specific functions.
*
* system tick and interrupt
*/
/*
* System tick
*/
/* SysTick registers. */
static volatile uint32_t *const SYST_CSR = (uint32_t *)0xE000E010;
static volatile uint32_t *const SYST_RVR = (uint32_t *)0xE000E014;
static volatile uint32_t *const SYST_CVR = (uint32_t *)0xE000E018;
static void
chx_systick_reset (void)
{
*SYST_RVR = 0;
*SYST_CVR = 0;
*SYST_CSR = 7;
}
static void
chx_systick_reload (uint32_t ticks)
{
*SYST_RVR = ticks;
*SYST_CVR = 0; /* write (any) to clear the counter to reload. */
*SYST_RVR = 0;
}
static uint32_t
chx_systick_get (void)
{
return *SYST_CVR;
}
#ifndef MHZ
#define MHZ 72
#endif
static uint32_t usec_to_ticks (uint32_t usec)
{
return usec * MHZ;
}
/*
* Interrupt Handling
*/
/* NVIC: Nested Vectored Interrupt Controller. */
struct NVIC {
volatile uint32_t ISER[8];
uint32_t unused1[24];
volatile uint32_t ICER[8];
uint32_t unused2[24];
volatile uint32_t ISPR[8];
uint32_t unused3[24];
volatile uint32_t ICPR[8];
uint32_t unused4[24];
volatile uint32_t IABR[8];
uint32_t unused5[56];
volatile uint32_t IPR[60];
};
static struct NVIC *const NVIC = (struct NVIC *)0xE000E100;
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
#define NVIC_ICER(n) (NVIC->ICER[n >> 5])
#define NVIC_ICPR(n) (NVIC->ICPR[n >> 5])
#define NVIC_IPR(n) (NVIC->IPR[n >> 2])
static void
chx_enable_intr (uint8_t irq_num)
{
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_clr_intr (uint8_t irq_num)
{ /* Clear pending interrupt. */
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_disable_intr (uint8_t irq_num)
{
NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_set_intr_prio (uint8_t n)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh))
| (CPU_EXCEPTION_PRIORITY_INTERRUPT << sh);
}
static volatile uint32_t *const ICSR = (uint32_t *)0xE000ED04;
/* Priority control. */
static uint32_t *const AIRCR = (uint32_t *)0xE000ED0C;
static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
static void
chx_prio_init (void)
{
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
*SHPR3 = ((CPU_EXCEPTION_PRIORITY_SYSTICK << 24)
| (CPU_EXCEPTION_PRIORITY_PENDSV << 16));
}
typedef void *(voidfunc) (void *);
void __attribute__((weak)) chx_fatal (uint32_t err_code);
@@ -224,6 +72,12 @@ chx_fatal (uint32_t err_code)
for (;;);
}
/* Include the definition of thread context structure. */
#ifdef GNU_LINUX_EMULATION
#include "chopstx-gnu-linux.h"
#else
#include "chopstx-cortex-m.h"
#endif
/* RUNNING: the current thread. */
struct chx_thread *running;
@@ -242,10 +96,15 @@ static struct chx_queue q_timer;
/* Queue of threads which wait for the exit of some thread. */
static struct chx_queue q_join;
/* Queue of threads which wait for some interrupts. */
static struct chx_queue q_intr;
/* Forward declaration(s). */
static void chx_request_preemption (uint16_t prio);
static int chx_wakeup (struct chx_pq *p);
static struct chx_thread * chx_timer_insert (struct chx_thread *tp, uint32_t usec);
static void chx_timer_dequeue (struct chx_thread *tp);
/**************/
@@ -264,29 +123,6 @@ static void chx_spin_unlock (struct chx_spinlock *lk)
(void)lk;
}
/* The thread context: specific to ARM Cortex-M3 now. */
struct tcontext {
uint32_t reg[9]; /* r4, r5, r6, r7, r8, r9, r10, r11, r13(sp) */
};
/* Saved registers on the stack. */
struct chx_stack_regs {
uint32_t reg[8]; /* r0, r1, r2, r3, r12, lr, pc, xpsr */
};
/*
* Constants for ARM.
*/
#define REG_EXIT 4 /* R8 */
#define REG_SP 8
#define REG_R0 0
#define REG_LR 5
#define REG_PC 6
#define REG_XPSR 7
#define INITIAL_XPSR 0x01000000 /* T=1 */
/**************/
struct chx_pq {
struct chx_pq *next, *prev;
@@ -297,7 +133,7 @@ struct chx_pq {
uint32_t : 8;
uint32_t prio : 8;
struct chx_qh *parent;
uint32_t v;
uintptr_t v;
};
struct chx_px { /* inherits PQ */
@@ -309,7 +145,7 @@ struct chx_px { /* inherits PQ */
uint32_t : 8;
uint32_t prio : 8;
struct chx_qh *parent;
uint32_t v;
uintptr_t v;
struct chx_thread *master;
uint32_t *counter_p;
uint16_t *ready_p;
@@ -329,42 +165,13 @@ struct chx_thread { /* inherits PQ */
uint32_t prio_orig : 8;
uint32_t prio : 8;
struct chx_qh *parent;
uint32_t v;
struct tcontext tc;
uintptr_t v;
tcontext_t tc;
struct chx_mtx *mutex_list;
struct chx_cleanup *clp;
};
static void
chx_cpu_sched_lock (void)
{
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
{
#if defined(__ARM_ARCH_6M__)
asm volatile ("cpsid i" : : : "memory");
#else
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
#endif
}
}
static void
chx_cpu_sched_unlock (void)
{
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
{
#if defined(__ARM_ARCH_6M__)
asm volatile ("cpsie i" : : : "memory");
#else
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
#endif
}
}
/*
* Double linked list handling.
*/
@@ -483,18 +290,16 @@ chx_ready_enqueue (struct chx_thread *tp)
chx_spin_unlock (&q_ready.lock);
}
static void __attribute__((naked, used))
idle (void)
{
#if defined(USE_WFI_FOR_IDLE)
for (;;)
asm volatile ("wfi" : : : "memory");
/*
* Here comes architecture specific code.
*/
#ifdef GNU_LINUX_EMULATION
#include "chopstx-gnu-linux.c"
#else
for (;;);
#include "chopstx-cortex-m.c"
#endif
}
static void
chx_set_timer (struct chx_thread *tp, uint32_t ticks)
{
@@ -608,37 +413,10 @@ chx_timer_expired (void)
}
}
chx_request_preemption (prio);
chx_spin_unlock (&q_timer.lock);
chx_request_preemption (prio);
}
/* Queue of threads which wait for some interrupts. */
static struct chx_queue q_intr;
void
chx_handle_intr (void)
{
struct chx_pq *p;
register uint32_t irq_num;
asm volatile ("mrs %0, IPSR\n\t"
"sub %0, #16" /* Exception # - 16 = interrupt number. */
: "=r" (irq_num) : /* no input */ : "memory");
chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock);
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
if (p->v == irq_num)
{ /* should be one at most. */
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p);
chx_wakeup (p);
chx_request_preemption (px->master->prio);
break;
}
chx_spin_unlock (&q_intr.lock);
}
void
chx_systick_init (void)
@@ -661,7 +439,8 @@ void
chx_init (struct chx_thread *tp)
{
chx_prio_init ();
memset (&tp->tc, 0, sizeof (tp->tc));
chx_init_arch (tp);
q_ready.q.next = q_ready.q.prev = (struct chx_pq *)&q_ready.q;
chx_spin_init (&q_ready.lock);
q_timer.q.next = q_timer.q.prev = (struct chx_pq *)&q_timer.q;
@@ -693,200 +472,9 @@ chx_init (struct chx_thread *tp)
chopstx_main = (chopstx_t)tp;
}
static void
chx_request_preemption (uint16_t prio)
{
if (running == NULL || (uint16_t)running->prio < prio)
{
*ICSR = (1 << 28);
asm volatile ("" : : : "memory");
}
}
#define CHX_SLEEP 0
#define CHX_YIELD 1
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* For Cortex-M0, this should be AAPCS-compliant function entry, so we
* put "noinline" attribute.
*
* AAPCS: ARM Architecture Procedure Call Standard
*
* Returns:
* 1 on wakeup by others.
* 0 on normal wakeup.
* -1 on cancellation.
*/
static int __attribute__ ((naked, noinline))
chx_sched (uint32_t yield)
{
register struct chx_thread *tp asm ("r0");
#if defined(__ARM_ARCH_7M__)
asm volatile (
"svc #0\n\t"
"bx lr"
: "=r" (tp) : "0" (yield): "memory");
#else
register uint32_t arg_yield asm ("r1");
/* Build stack data as if it were an exception entry. */
/*
* r0: 0 scratch
* r1: 0 scratch
* r2: 0 scratch
* r3: 0 scratch
* r12: 0 scratch
* lr as-is
* pc: return address (= lr)
* psr: INITIAL_XPSR scratch
*/
asm ("mov r1, lr\n\t"
"mov r2, r1\n\t"
"mov r3, #128\n\t"
"lsl r3, #17\n\t"
"push {r1, r2, r3}\n\t"
"mov r1, #0\n\t"
"mov r2, r1\n\t"
"mov r3, r1\n\t"
"push {r1, r2, r3}\n\t"
"push {r1, r2}"
: /* no output*/
: /* no input */
: "r1", "r2", "r3", "memory");
/* Save registers onto CHX_THREAD struct. */
asm ("mov r1, r0\n\t"
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"add r0, #20\n\t"
"stm r0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mov r6, sp\n\t"
"stm r0!, {r2, r3, r4, r5, r6}\n\t"
"sub r0, #56"
: "=r" (tp), "=r" (arg_yield)
: "0" (yield)
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (arg_yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
if (tp && tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
tp = chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
asm volatile (/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
"cmp r0, #0\n\t"
"bne 0f\n\t"
/* Spawn an IDLE thread. */
"ldr r1, =__main_stack_end__\n\t"
"mov sp, r1\n\t"
"ldr r0, =idle\n\t" /* PC = idle */
/**/
/* Unmask interrupts. */
"cpsie i\n\t"
"bx r0\n"
/* Normal context switch */
"0:\n\t"
/**/
"add r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"mov sp, r2\n\t"
"sub r0, #45\n\t"
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
"cmp r1, #247\n\t"
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
/**/
/* Unmask interrupts. */
"cpsie i\n"
/**/
"1:\n\t"
/*
0: r0
4: r1
8: r2
12: r3
16: r12
20: lr
24: pc
28: psr
32: possibly exists for alignment
[28 or 32] <-- pc
*/
"ldr r0, [sp, #28]\n\t"
"lsl r1, r0, #23\n\t"
"bcc 2f\n\t"
/**/
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #32]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
"ldr r0, [sp, #20]\n\t"
"mov lr, r0\n\t"
"ldr r0, [sp, #16]\n\t"
"mov r12, r0\n\t"
"pop {r0, r1, r2, r3}\n\t"
"add sp, #16\n\t"
"pop {pc}\n"
"2:\n\t"
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #28]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
"ldr r0, [sp, #20]\n\t"
"mov lr, r0\n\t"
"ldr r0, [sp, #16]\n\t"
"mov r12, r0\n\t"
"pop {r0, r1, r2, r3}\n\t"
"add sp, #12\n\t"
"pop {pc}"
: "=r" (tp) /* Return value in R0 */
: "0" (tp)
: "memory");
#endif
return (uint32_t)tp;
}
/*
* Wakeup the thread TP. Called with schedule lock held.
@@ -907,21 +495,21 @@ chx_wakeup (struct chx_pq *pq)
tp = px->master;
if (tp->state == THREAD_WAIT_POLL)
{
((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = 1;
tp->v = (uintptr_t)1;
if (tp->parent == &q_timer.q)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
if (tp->prio > running->prio)
if (!running || tp->prio > running->prio)
yield = 1;
}
chx_spin_unlock (&px->lock);
}
else
{
((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = 1;
tp = (struct chx_thread *)pq;
tp->v = (uintptr_t)1;
chx_ready_enqueue (tp);
if (tp->prio > running->prio)
if (!running || tp->prio > running->prio)
yield = 1;
}
@@ -929,21 +517,18 @@ chx_wakeup (struct chx_pq *pq)
}
/* The RETVAL is saved into register R8. */
/* The RETVAL is saved into ->v. */
static void __attribute__((noreturn))
chx_exit (void *retval)
{
register uint32_t r8 asm ("r8");
struct chx_pq *p;
asm volatile ("mov %0, %1" : "=r" (r8) : "r" (retval));
chx_cpu_sched_lock ();
if (running->flag_join_req)
{ /* wake up a thread which requests to join */
chx_spin_lock (&q_join.lock);
for (p = q_join.q.next; p != (struct chx_pq *)&q_join.q; p = p->next)
if (p->v == (uint32_t)running)
if (p->v == (uintptr_t)running)
{ /* should be one at most. */
ll_dequeue (p);
chx_wakeup (p);
@@ -958,7 +543,7 @@ chx_exit (void *retval)
running->state = THREAD_FINISHED;
else
running->state = THREAD_EXITED;
asm volatile ("" : : "r" (r8) : "memory");
running->v = (uintptr_t)retval;
chx_sched (CHX_SLEEP);
/* never comes here. */
for (;;);
@@ -1003,10 +588,6 @@ chx_mutex_unlock (chopstx_mutex_t *mutex)
#define CHOPSTX_PRIO_MASK ((1 << CHOPSTX_PRIO_BITS) - 1)
typedef void *(voidfunc) (void *);
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
/**
* chopstx_create - Create a thread
* @flags_and_prio: Flags and priority
@@ -1019,32 +600,14 @@ extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
*/
chopstx_t
chopstx_create (uint32_t flags_and_prio,
uint32_t stack_addr, size_t stack_size,
uintptr_t stack_addr, size_t stack_size,
voidfunc thread_entry, void *arg)
{
struct chx_thread *tp;
void *stack;
struct chx_stack_regs *p;
chopstx_prio_t prio = (flags_and_prio & CHOPSTX_PRIO_MASK);
if (CHOPSTX_THREAD_SIZE != sizeof(struct chx_thread))
cause_link_time_error_unexpected_size_of_struct_chx_thread ();
if (stack_size < sizeof (struct chx_thread) + 8 * sizeof (uint32_t))
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
stack = (void *)(stack_addr + stack_size - sizeof (struct chx_thread)
- sizeof (struct chx_stack_regs));
memset (stack, 0, sizeof (struct chx_stack_regs));
tp = (struct chx_thread *)(stack + sizeof (struct chx_stack_regs));
p = (struct chx_stack_regs *)stack;
p->reg[REG_R0] = (uint32_t)arg;
p->reg[REG_LR] = (uint32_t)chopstx_exit;
p->reg[REG_PC] = (uint32_t)thread_entry;
p->reg[REG_XPSR] = INITIAL_XPSR;
memset (&tp->tc, 0, sizeof (tp->tc));
tp->tc.reg[REG_SP] = (uint32_t)stack;
tp = chopstx_create_arch (stack_addr, stack_size, thread_entry,
arg);
tp->next = tp->prev = (struct chx_pq *)tp;
tp->mutex_list = NULL;
tp->clp = NULL;
@@ -1232,7 +795,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
if (tp0->state == THREAD_WAIT_TIME
|| tp0->state == THREAD_WAIT_POLL)
{
((struct chx_stack_regs *)tp0->tc.reg[REG_SP])->reg[REG_R0] = 1;
tp0->v = (uintptr_t)1;
if (tp0->parent == &q_timer.q)
chx_timer_dequeue (tp0);
@@ -1497,12 +1060,6 @@ chopstx_cleanup_pop (int execute)
}
/*
* We put "naked" attribute to chopstx_exit function. Since it never
* returns, function prologue is not needed.
*/
void chopstx_exit (void *retval) __attribute__ ((naked));
/**
* chopstx_exit - Terminate the execution of running thread
* @retval: Return value (to be caught by a joining thread)
@@ -1559,6 +1116,8 @@ chopstx_join (chopstx_t thd, void **ret)
* We don't offer deadlock detection. It's users' responsibility.
*/
chopstx_testcancel ();
chx_cpu_sched_lock ();
if (tp->flag_detached)
{
@@ -1574,7 +1133,7 @@ chopstx_join (chopstx_t thd, void **ret)
chx_timer_dequeue (running);
chx_spin_lock (&q_join.lock);
ll_prio_enqueue ((struct chx_pq *)running, &q_join.q);
running->v = (uint32_t)tp;
running->v = (uintptr_t)tp;
running->state = THREAD_WAIT_EXIT;
tp->flag_join_req = 1;
@@ -1598,7 +1157,7 @@ chopstx_join (chopstx_t thd, void **ret)
{
tp->state = THREAD_FINISHED;
if (ret)
*ret = (void *)tp->tc.reg[REG_EXIT]; /* R8 */
*ret = (void *)tp->v;
}
return r;
@@ -1631,7 +1190,7 @@ chx_join_hook (struct chx_px *px, struct chx_poll_head *pd)
{ /* Not yet exited.
* Register the proxy to wait for TP's exit.
*/
px->v = (uint32_t)tp;
px->v = (uintptr_t)tp;
chx_spin_lock (&q_join.lock);
ll_prio_enqueue ((struct chx_pq *)px, &q_join.q);
chx_spin_unlock (&q_join.lock);
@@ -1661,7 +1220,7 @@ chopstx_cancel (chopstx_t thd)
return;
}
/* Cancellation points: cond_wait, usec_wait, and poll. */
/* Cancellation points: cond_wait, usec_wait, join, and poll. */
if (tp->state == THREAD_WAIT_CND)
{
struct chx_cond *cond = (struct chx_cond *)tp->parent;
@@ -1672,6 +1231,12 @@ chopstx_cancel (chopstx_t thd)
}
else if (tp->state == THREAD_WAIT_TIME)
chx_timer_dequeue (tp);
else if (tp->state == THREAD_WAIT_EXIT)
{
chx_spin_lock (&q_join.lock);
ll_dequeue ((struct chx_pq *)tp);
chx_spin_unlock (&q_join.lock);
}
else if (tp->state == THREAD_WAIT_POLL)
{
if (tp->parent == &q_timer.q)
@@ -1683,7 +1248,7 @@ chopstx_cancel (chopstx_t thd)
return;
}
((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = -1;
tp->v = (uintptr_t)-1;
chx_ready_enqueue (tp);
if (tp->prio > running->prio)
chx_sched (CHX_YIELD);
@@ -1904,209 +1469,3 @@ chopstx_setpriority (chopstx_prio_t prio_new)
return prio_orig;
}
/*
* Lower layer architecture specific exception handling entries.
*
*/
void __attribute__ ((naked))
preempt (void)
{
register struct chx_thread *tp asm ("r0");
register struct chx_thread *cur asm ("r1");
asm volatile (
#if defined(__ARM_ARCH_6M__)
"cpsid i\n\t"
#else
"msr BASEPRI, r0\n\t"
#endif
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"mov r1, r0"
: "=r" (tp), "=r" (cur)
: "0" (CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED)
: "r2");
if (!cur)
/* It's idle thread. It's ok to clobber registers. */
;
else
{
/* Save registers onto CHX_THREAD struct. */
asm volatile (
"add %0, #20\n\t"
"stm %0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm %0!, {r2, r3, r4, r5, r6}"
: "=r" (cur)
: "0" (cur)
/*
* Memory clobber constraint here is not accurate, but this
* works. R7 keeps its value, but having "r7" here prevents
* use of R7 before this asm statement.
*/
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (tp)
{
if (tp->flag_sched_rr)
{
if (tp->state == THREAD_RUNNING)
{
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
/*
* It may be THREAD_READY after chx_timer_expired.
* Then, do nothing.
*/
}
else
chx_ready_push (tp);
running = NULL;
}
}
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
tp = chx_ready_pop ();
if (tp && tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
tp = chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
asm volatile (
".L_CONTEXT_SWITCH:\n\t"
/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
#if defined(__ARM_ARCH_6M__)
"cmp r0, #0\n\t"
"beq 1f\n\t"
#else
"cbz r0, 1f\n\t"
#endif
/**/
"add r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
#if defined(__ARM_ARCH_6M__)
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"msr PSP, r2\n\t"
#else
"ldr r8, [r0], #4\n\t"
"ldr r9, [r0], #4\n\t"
"ldr r10, [r0], #4\n\t"
"ldr r11, [r0], #4\n\t"
"ldr r1, [r0], #4\n\t"
"msr PSP, r1\n\t"
#endif
"sub r0, #45\n\t"
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
"mov r0, #0\n\t"
"cmp r1, #247\n\t"
"bhi 0f\n\t" /* Leave interrupt disabled if >= 248 */
/**/
/* Unmask interrupts. */
#if defined(__ARM_ARCH_6M__)
"cpsie i\n"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"0:\n\t"
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0\n"
"1:\n\t"
/* Spawn an IDLE thread. */
"ldr r0, =__main_stack_end__-32\n\t"
"msr PSP, r0\n\t"
"mov r1, #0\n\t"
"mov r2, #0\n\t"
"mov r3, #0\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"ldr r1, =idle\n\t" /* PC = idle */
"mov r2, #0x010\n\t"
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
"stm r0!, {r1, r2}\n\t"
/**/
/* Unmask interrupts. */
"mov r0, #0\n\t"
#if defined(__ARM_ARCH_6M__)
"cpsie i\n\t"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /* no output */ : "r" (tp) : "memory");
}
#if defined(__ARM_ARCH_7M__)
/*
* System call: switch to another thread.
* There are two cases:
* ORIG_R0=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* ORIG_R0=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*/
void __attribute__ ((naked))
svc (void)
{
register struct chx_thread *tp asm ("r0");
register uint32_t orig_r0 asm ("r1");
asm ("ldr r1, =running\n\t"
"ldr r0, [r1]\n\t"
"add r1, r0, #20\n\t"
/* Save registers onto CHX_THREAD struct. */
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"ldr r1, [r6]"
: "=r" (tp), "=r" (orig_r0)
: /* no input */
: "r2", "r3", "r4", "r5", "r6", "memory");
if (orig_r0) /* yield */
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
running = NULL;
}
tp = chx_ready_pop ();
if (tp && tp->flag_sched_rr)
{
chx_spin_lock (&q_timer.lock);
chx_timer_insert (tp, PREEMPTION_USEC);
chx_spin_unlock (&q_timer.lock);
}
asm volatile (
"b .L_CONTEXT_SWITCH"
: /* no output */ : "r" (tp) : "memory");
}
#endif

View File

@@ -30,7 +30,7 @@ struct chx_qh {
struct chx_pq *next, *prev;
};
typedef uint32_t chopstx_t;
typedef uintptr_t chopstx_t;
typedef uint8_t chopstx_prio_t;
extern chopstx_t chopstx_main;
@@ -39,7 +39,7 @@ extern chopstx_t chopstx_main;
/* NOTE: This signature is different to PTHREAD's one. */
chopstx_t
chopstx_create (uint32_t flags_and_prio,
uint32_t stack_addr, size_t stack_size,
uintptr_t stack_addr, size_t stack_size,
void *(thread_entry) (void *), void *);
#define CHOPSTX_PRIO_BITS 8
#define CHOPSTX_DETACHED 0x10000

77
contrib/adc-gnu-linux.c Normal file
View File

@@ -0,0 +1,77 @@
/*
* adc-gnu-linux.c - ADC driver for GNU/Linux emulation.
* This ADC driver just fills pseudo random values.
* It's completely useless other than for NeuG.
*
* Copyright (C) 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* receipents of GNU GPL by a written offer.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include "adc.h"
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */
/*
* Do calibration for ADC.
*/
int
adc_init (void)
{
srandom (ADC_RANDOM_SEED);
return 0;
}
void
adc_start (void)
{
}
uint32_t adc_buf[64];
void
adc_start_conversion (int offset, int count)
{
while (count--)
adc_buf[offset++] = random ();
}
void
adc_stop (void)
{
}
/*
* Return 0 on success.
* Return 1 on error.
*/
int
adc_wait_completion (void)
{
return 0;
}

View File

@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename chopstx.info
@set VERSION 1.1
@set VERSION 1.4
@settitle Chopstx Reference Manual
@c Unify some of the indices.
@syncodeindex tp fn

18
entry.c
View File

@@ -1,7 +1,7 @@
/*
* entry.c - Entry routine when reset and interrupt vectors.
*
* Copyright (C) 2013, 2014, 2015, 2016
* Copyright (C) 2013, 2014, 2015, 2016, 2017
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -32,6 +32,21 @@
#include <chopstx.h>
#include "board.h"
#ifdef GNU_LINUX_EMULATION
int emulated_main (int, const char **);
void chx_init (struct chx_thread *);
void chx_systick_init (void);
extern struct chx_thread main_thread;
int
main (int argc, const char *argv[])
{
chx_init (&main_thread);
chx_systick_init ();
emulated_main (argc, argv);
}
#else
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
#include "sys.h"
@@ -225,3 +240,4 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
chx_handle_intr, chx_handle_intr, chx_handle_intr,
#endif
};
#endif

View File

@@ -0,0 +1,36 @@
# Makefile for example application of Chopstx
PROJECT = sample
### This is for GNU/Linux
CHOPSTX = ..
LDSCRIPT=
CSRC = sample.c usb-cdc.c
CHIP=gnu-linux
# USE_SYS = yes
USE_SYS =
USE_USB = yes
EMULATION=yes
###################################
CROSS =
CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = none
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DGNU_LINUX_EMULATION
OPT = -g # -O3 -Os
LIBS = -lpthread
####################
include ../rules.mk
board.h:
@echo Please make a symbolic link \'board.h\' to a file in ../board;
@exit 1
distclean: clean

View File

@@ -0,0 +1,35 @@
(1) preparation as root
Don't run ModemManager
# systemctl stop ModemManager
Install USBIP host module
# modprobe vhci_hcd
(2) Run sample program of USBIP server
$ ./sample
(3) Use the USB device as root
Attach the Chopstx application program (USBIP device) to USBIP host.
# usbip attach -r 127.0.0.1 -b 1-1
(4) Connect CDC-ACM device
$ cu -l /dev/ttyACM0
Then, you see the message from Chopstx. As you type lines, it echos.
Type RET, ~ then . , you can terminate the session.
(5) Detach the USBIP device as root
# usbip detach -p 0

View File

@@ -0,0 +1 @@
../board/board-gnu-linux.h

View File

@@ -0,0 +1,197 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <chopstx.h>
#include "usb_lld.h"
#include "tty.h"
#include <unistd.h>
#include <stdio.h>
static void
set_led (int on)
{
#if 0
/* For debugging, no output of LED. */
#if 1
if (on)
write (1, "********\x08\x08\x08\x08\x08\x08\x08\x08", 16);
else
write (1, " \x08\x08\x08\x08\x08\x08\x08\x08", 16);
#else
if (on)
puts ("!");
else
puts ("");
#endif
#else
(void)on;
#endif
}
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0;
static chopstx_cond_t cnd1;
static uint8_t u, v;
static uint8_t m; /* 0..100 */
static void *
pwm (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd0, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
set_led (u&v);
chopstx_usec_wait (m);
set_led (0);
chopstx_usec_wait (100-m);
}
return NULL;
}
static void *
blk (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd1, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
v = 0;
chopstx_usec_wait (200*1000);
v = 1;
chopstx_usec_wait (200*1000);
}
return NULL;
}
#define PRIO_PWM 3
#define PRIO_BLK 2
static char __process1_stack_base__[4096];
static char __process2_stack_base__[4096];
#define STACK_ADDR_PWM ((uintptr_t)__process1_stack_base__)
#define STACK_SIZE_PWM (sizeof __process1_stack_base__)
#define STACK_ADDR_BLK ((uintptr_t)__process2_stack_base__)
#define STACK_SIZE_BLK (sizeof __process2_stack_base__)
static char hexchar (uint8_t x)
{
x &= 0x0f;
if (x <= 0x09)
return '0' + x;
else if (x <= 0x0f)
return 'a' + x - 10;
else
return '?';
}
#ifdef GNU_LINUX_EMULATION
#define main emulated_main
#endif
int
main (int argc, const char *argv[])
{
struct tty *tty;
uint8_t count;
(void)argc;
(void)argv;
chopstx_mutex_init (&mtx);
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
m = 10;
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);
chopstx_mutex_lock (&mtx);
chopstx_cond_signal (&cnd0);
chopstx_cond_signal (&cnd1);
chopstx_mutex_unlock (&mtx);
u = 1;
tty = tty_open ();
tty_wait_configured (tty);
count = 0;
m = 50;
while (1)
{
char s[LINEBUFSIZE];
u = 1;
tty_wait_connection (tty);
chopstx_usec_wait (50*1000);
puts("send ZLP");
/* Send ZLP at the beginning. */
tty_send (tty, s, 0);
memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32);
s[0] = hexchar (count >> 4);
s[1] = hexchar (count & 0x0f);
count++;
puts("send hello");
if (tty_send (tty, s, 32) < 0)
continue;
while (1)
{
int size;
uint32_t usec;
puts("recv msg");
usec = 3000000; /* 3.0 seconds */
size = tty_recv (tty, s + 4, &usec);
if (size < 0)
break;
if (size)
{
size--;
puts("send msg");
s[0] = hexchar (size >> 4);
s[1] = hexchar (size & 0x0f);
s[2] = ':';
s[3] = ' ';
s[size + 4] = '\r';
s[size + 5] = '\n';
if (tty_send (tty, s, size + 6) < 0)
break;
}
u ^= 1;
}
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#define LINEBUFSIZE 128
struct tty;
struct tty *tty_open (void);
void tty_wait_configured (struct tty *tty);
void tty_wait_connection (struct tty *tty);
int tty_send (struct tty *tty, const char *buf, int count);
int tty_recv (struct tty *tty, char *buf, uint32_t *timeout);

View File

@@ -0,0 +1,953 @@
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <string.h>
#include "usb_lld.h"
#include "tty.h"
static chopstx_intr_t usb_intr;
struct line_coding
{
uint32_t bitrate;
uint8_t format;
uint8_t paritytype;
uint8_t datatype;
} __attribute__((packed));
static const struct line_coding line_coding0 = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
/*
* Currently, we only support a single TTY.
*
* It is possible to extend to support multiple TTYs, for multiple
* interfaces.
*
* In that case, add argument to TTY_OPEN function and
* modify TTY_GET function to get the TTY structure. Functions which
* directy accesses TTY0 (usb_device_reset and usb_set_configuration)
* should be modified, too.
*
* Modification of TTY_MAIN thread will be also needed to echo back
* input for each TTY, and the thread should run if one of TTY is
* opened.
*/
struct tty {
chopstx_mutex_t mtx;
chopstx_cond_t cnd;
uint8_t inputline[LINEBUFSIZE]; /* Line editing is supported */
uint8_t send_buf[LINEBUFSIZE]; /* Sending ring buffer for echo back */
uint8_t send_buf0[64];
uint8_t recv_buf0[64];
uint32_t inputline_len : 8;
uint32_t send_head : 8;
uint32_t send_tail : 8;
uint32_t flag_connected : 1;
uint32_t flag_send_ready : 1;
uint32_t flag_input_avail : 1;
uint32_t : 2;
uint32_t device_state : 3; /* USB device status */
struct line_coding line_coding;
};
static struct tty tty0;
/*
* Locate TTY structure from interface number or endpoint number.
* Currently, it always returns tty0, because we only have the one.
*/
static struct tty *
tty_get (int interface, uint8_t ep_num)
{
struct tty *t = &tty0;
if (interface >= 0)
{
if (interface == 0)
t = &tty0;
}
else
{
if (ep_num == ENDP1 || ep_num == ENDP2 || ep_num == ENDP3)
t = &tty0;
}
return t;
}
#define USB_CDC_REQ_SET_LINE_CODING 0x20
#define USB_CDC_REQ_GET_LINE_CODING 0x21
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
#define USB_CDC_REQ_SEND_BREAK 0x23
/* USB Device Descriptor */
static const uint8_t vcom_device_desc[18] = {
18, /* bLength */
DEVICE_DESCRIPTOR, /* bDescriptorType */
0x10, 0x01, /* bcdUSB = 1.1 */
0x02, /* bDeviceClass (CDC). */
0x00, /* bDeviceSubClass. */
0x00, /* bDeviceProtocol. */
0x40, /* bMaxPacketSize. */
0xFF, 0xFF, /* idVendor */
0x01, 0x00, /* idProduct */
0x00, 0x01, /* bcdDevice */
1, /* iManufacturer. */
2, /* iProduct. */
3, /* iSerialNumber. */
1 /* bNumConfigurations. */
};
#define VCOM_FEATURE_BUS_POWERED 0x80
/* Configuration Descriptor tree for a CDC.*/
static const uint8_t vcom_config_desc[67] = {
9,
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
/* Configuration Descriptor.*/
67, 0x00, /* wTotalLength. */
0x02, /* bNumInterfaces. */
0x01, /* bConfigurationValue. */
0, /* iConfiguration. */
VCOM_FEATURE_BUS_POWERED, /* bmAttributes. */
50, /* bMaxPower (100mA). */
/* Interface Descriptor.*/
9,
INTERFACE_DESCRIPTOR,
0x00, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x01, /* bNumEndpoints. */
0x02, /* bInterfaceClass (Communications Interface Class,
CDC section 4.2). */
0x02, /* bInterfaceSubClass (Abstract Control Model, CDC
section 4.3). */
0x01, /* bInterfaceProtocol (AT commands, CDC section
4.4). */
0, /* iInterface. */
/* Header Functional Descriptor (CDC section 5.2.3).*/
5, /* bLength. */
0x24, /* bDescriptorType (CS_INTERFACE). */
0x00, /* bDescriptorSubtype (Header Functional Descriptor). */
0x10, 0x01, /* bcdCDC. */
/* Call Management Functional Descriptor. */
5, /* bFunctionLength. */
0x24, /* bDescriptorType (CS_INTERFACE). */
0x01, /* bDescriptorSubtype (Call Management Functional
Descriptor). */
0x03, /* bmCapabilities (D0+D1). */
0x01, /* bDataInterface. */
/* ACM Functional Descriptor.*/
4, /* bFunctionLength. */
0x24, /* bDescriptorType (CS_INTERFACE). */
0x02, /* bDescriptorSubtype (Abstract Control Management
Descriptor). */
0x02, /* bmCapabilities. */
/* Union Functional Descriptor.*/
5, /* bFunctionLength. */
0x24, /* bDescriptorType (CS_INTERFACE). */
0x06, /* bDescriptorSubtype (Union Functional
Descriptor). */
0x00, /* bMasterInterface (Communication Class
Interface). */
0x01, /* bSlaveInterface0 (Data Class Interface). */
/* Endpoint 2 Descriptor.*/
7,
ENDPOINT_DESCRIPTOR,
ENDP2|0x80, /* bEndpointAddress. */
0x03, /* bmAttributes (Interrupt). */
0x08, 0x00, /* wMaxPacketSize. */
0xFF, /* bInterval. */
/* Interface Descriptor.*/
9,
INTERFACE_DESCRIPTOR, /* bDescriptorType: */
0x01, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x02, /* bNumEndpoints. */
0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
0x00, /* bInterfaceSubClass (CDC section 4.6). */
0x00, /* bInterfaceProtocol (CDC section 4.7). */
0x00, /* iInterface. */
/* Endpoint 3 Descriptor.*/
7,
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
ENDP3, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
0x00, /* bInterval. */
/* Endpoint 1 Descriptor.*/
7,
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
ENDP1|0x80, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
0x00 /* bInterval. */
};
/*
* U.S. English language identifier.
*/
static const uint8_t vcom_string0[4] = {
4, /* bLength */
STRING_DESCRIPTOR,
0x09, 0x04 /* LangID = 0x0409: US-English */
};
static const uint8_t vcom_string1[] = {
23*2+2, /* bLength */
STRING_DESCRIPTOR, /* bDescriptorType */
/* Manufacturer: "Flying Stone Technology" */
'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0,
't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0,
'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0,
};
static const uint8_t vcom_string2[] = {
14*2+2, /* bLength */
STRING_DESCRIPTOR, /* bDescriptorType */
/* Product name: "Chopstx Sample" */
'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0,
'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0,
};
/*
* Serial Number string.
*/
static const uint8_t vcom_string3[28] = {
28, /* bLength */
STRING_DESCRIPTOR, /* bDescriptorType */
'0', 0, '.', 0, '0', 0, '0', 0, /* Version number */
};
#define NUM_INTERFACES 2
static void
usb_device_reset (struct usb_dev *dev)
{
usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
/* Initialize Endpoint 0 */
usb_lld_setup_endp (dev, ENDP0, 1, 1);
chopstx_mutex_lock (&tty0.mtx);
tty0.inputline_len = 0;
tty0.send_head = tty0.send_tail = 0;
tty0.flag_connected = 0;
tty0.flag_send_ready = 1;
tty0.flag_input_avail = 0;
tty0.device_state = ATTACHED;
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
chopstx_mutex_unlock (&tty0.mtx);
}
#define CDC_CTRL_DTR 0x0001
static void
usb_ctrl_write_finish (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
&& USB_SETUP_SET (arg->type)
&& arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
{
struct tty *t = tty_get (arg->index, 0);
/* Open/close the connection. */
chopstx_mutex_lock (&t->mtx);
t->flag_connected = ((arg->value & CDC_CTRL_DTR) != 0);
chopstx_cond_signal (&t->cnd);
chopstx_mutex_unlock (&t->mtx);
}
/*
* The transaction was already finished. So, it is no use to call
* usb_lld_ctrl_error when the condition does not match.
*/
}
static int
vcom_port_data_setup (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
if (USB_SETUP_GET (arg->type))
{
struct tty *t = tty_get (arg->index, 0);
if (arg->request == USB_CDC_REQ_GET_LINE_CODING)
return usb_lld_ctrl_send (dev, &t->line_coding,
sizeof (struct line_coding));
}
else /* USB_SETUP_SET (req) */
{
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
&& arg->len == sizeof (struct line_coding))
{
struct tty *t = tty_get (arg->index, 0);
return usb_lld_ctrl_recv (dev, &t->line_coding,
sizeof (struct line_coding));
}
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
return usb_lld_ctrl_ack (dev);
}
return -1;
}
static int
usb_setup (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
return vcom_port_data_setup (dev);
return -1;
}
static int
usb_get_descriptor (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
uint8_t desc_type = (arg->value >> 8);
uint8_t desc_index = (arg->value & 0xff);
if (rcp != DEVICE_RECIPIENT)
return -1;
if (desc_type == DEVICE_DESCRIPTOR)
return usb_lld_ctrl_send (dev,
vcom_device_desc, sizeof (vcom_device_desc));
else if (desc_type == CONFIG_DESCRIPTOR)
return usb_lld_ctrl_send (dev,
vcom_config_desc, sizeof (vcom_config_desc));
else if (desc_type == STRING_DESCRIPTOR)
{
const uint8_t *str;
int size;
switch (desc_index)
{
case 0:
str = vcom_string0;
size = sizeof (vcom_string0);
break;
case 1:
str = vcom_string1;
size = sizeof (vcom_string1);
break;
case 2:
str = vcom_string2;
size = sizeof (vcom_string2);
break;
case 3:
str = vcom_string3;
size = sizeof (vcom_string3);
break;
default:
return -1;
}
return usb_lld_ctrl_send (dev, str, size);
}
return -1;
}
static void
vcom_setup_endpoints_for_interface (struct usb_dev *dev,
uint16_t interface, int stop)
{
if (interface == 0)
{
if (!stop)
usb_lld_setup_endp (dev, ENDP2, 0, 1);
else
usb_lld_stall_tx (ENDP2);
}
else if (interface == 1)
{
if (!stop)
{
usb_lld_setup_endp (dev, ENDP1, 0, 1);
usb_lld_setup_endp (dev, ENDP3, 1, 0);
/* Start with no data receiving (ENDP3 not enabled)*/
}
else
{
usb_lld_stall_tx (ENDP1);
usb_lld_stall_rx (ENDP3);
}
}
}
static int
usb_set_configuration (struct usb_dev *dev)
{
int i;
uint8_t current_conf;
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (dev, 1);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (dev, i, 0);
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = CONFIGURED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
}
else if (current_conf != dev->dev_req.value)
{
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (dev, 0);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (dev, i, 1);
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = ADDRESSED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
}
return usb_lld_ctrl_ack (dev);
}
static int
usb_set_interface (struct usb_dev *dev)
{
uint16_t interface = dev->dev_req.index;
uint16_t alt = dev->dev_req.value;
if (interface >= NUM_INTERFACES)
return -1;
if (alt != 0)
return -1;
else
{
vcom_setup_endpoints_for_interface (dev, interface, 0);
return usb_lld_ctrl_ack (dev);
}
}
static int
usb_get_interface (struct usb_dev *dev)
{
const uint8_t zero = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
/* We don't have alternate interface, so, always return 0. */
return usb_lld_ctrl_send (dev, &zero, 1);
}
static int
usb_get_status_interface (struct usb_dev *dev)
{
const uint16_t status_info = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &status_info, 2);
}
/*
* Put a character into the ring buffer to be send back.
*/
static void
put_char_to_ringbuffer (struct tty *t, int c)
{
uint32_t next = (t->send_tail + 1) % LINEBUFSIZE;
if (t->send_head == next)
/* full */
/* All that we can do is ignore this char. */
return;
t->send_buf[t->send_tail] = c;
t->send_tail = next;
}
/*
* Get characters from ring buffer into S.
*/
static int
get_chars_from_ringbuffer (struct tty *t, uint8_t *s, int len)
{
int i = 0;
if (t->send_head == t->send_tail)
/* Empty */
return i;
do
{
s[i++] = t->send_buf[t->send_head];
t->send_head = (t->send_head + 1) % LINEBUFSIZE;
}
while (t->send_head != t->send_tail && i < len);
return i;
}
static void
tty_echo_char (struct tty *t, int c)
{
put_char_to_ringbuffer (t, c);
}
static void
usb_tx_done (uint8_t ep_num, uint16_t len)
{
struct tty *t = tty_get (-1, ep_num);
(void)len;
if (ep_num == ENDP1)
{
chopstx_mutex_lock (&t->mtx);
if (t->flag_send_ready == 0)
{
t->flag_send_ready = 1;
chopstx_cond_signal (&t->cnd);
}
chopstx_mutex_unlock (&t->mtx);
}
else if (ep_num == ENDP2)
{
/* Nothing */
}
}
static int
tty_input_char (struct tty *t, int c)
{
unsigned int i;
int r = 0;
/* Process DEL, C-U, C-R, and RET as editing command. */
chopstx_mutex_lock (&t->mtx);
switch (c)
{
case 0x0d: /* Control-M */
t->inputline[t->inputline_len++] = '\n';
tty_echo_char (t, 0x0d);
tty_echo_char (t, 0x0a);
t->flag_input_avail = 1;
r = 1;
chopstx_cond_signal (&t->cnd);
break;
case 0x12: /* Control-R */
tty_echo_char (t, '^');
tty_echo_char (t, 'R');
tty_echo_char (t, 0x0d);
tty_echo_char (t, 0x0a);
for (i = 0; i < t->inputline_len; i++)
tty_echo_char (t, t->inputline[i]);
break;
case 0x15: /* Control-U */
for (i = 0; i < t->inputline_len; i++)
{
tty_echo_char (t, 0x08);
tty_echo_char (t, 0x20);
tty_echo_char (t, 0x08);
}
t->inputline_len = 0;
break;
case 0x7f: /* DEL */
if (t->inputline_len > 0)
{
tty_echo_char (t, 0x08);
tty_echo_char (t, 0x20);
tty_echo_char (t, 0x08);
t->inputline_len--;
}
break;
default:
if (t->inputline_len < sizeof (t->inputline) - 1)
{
tty_echo_char (t, c);
t->inputline[t->inputline_len++] = c;
}
else
/* Beep */
tty_echo_char (t, 0x0a);
break;
}
chopstx_mutex_unlock (&t->mtx);
return r;
}
static void
usb_rx_ready (uint8_t ep_num, uint16_t len)
{
struct tty *t = tty_get (-1, ep_num);
if (ep_num == ENDP3)
{
int i;
for (i = 0; i < len; i++)
if (tty_input_char (t, t->recv_buf0[i]))
break;
chopstx_mutex_lock (&t->mtx);
if (t->flag_input_avail == 0)
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64);
chopstx_mutex_unlock (&t->mtx);
}
}
static void *tty_main (void *arg);
#include <signal.h>
#define INTR_REQ_USB SIGUSR1
#define PRIO_TTY 4
static char __process3_stack_base__[4096];
#define STACK_ADDR_TTY ((uintptr_t)__process3_stack_base__)
#define STACK_SIZE_TTY (sizeof __process3_stack_base__)
struct tty *
tty_open (void)
{
chopstx_mutex_init (&tty0.mtx);
chopstx_cond_init (&tty0.cnd);
tty0.inputline_len = 0;
tty0.send_head = tty0.send_tail = 0;
tty0.flag_connected = 0;
tty0.flag_send_ready = 1;
tty0.flag_input_avail = 0;
tty0.device_state = UNCONNECTED;
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
return &tty0;
}
static void *
tty_main (void *arg)
{
struct tty *t = arg;
struct usb_dev dev;
int e;
#if defined(OLDER_SYS_H)
/*
* Historically (before sys < 3.0), NVIC priority setting for USB
* interrupt was done in usb_lld_sys_init. Thus this code.
*
* When USB interrupt occurs between usb_lld_init (which assumes
* ISR) and chopstx_claim_irq (which clears pending interrupt),
* invocation of usb_lld_event_handler won't occur.
*
* Calling usb_lld_event_handler is no harm even if there were no
* interrupts, thus, we call it unconditionally here, just in case
* if there is a request.
*
* We can't call usb_lld_init after chopstx_claim_irq, as
* usb_lld_init does its own setting for NVIC. Calling
* chopstx_claim_irq after usb_lld_init overrides that.
*
*/
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
goto event_handle;
#else
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
#endif
while (1)
{
chopstx_intr_wait (&usb_intr);
if (usb_intr.ready)
{
uint8_t ep_num;
#if defined(OLDER_SYS_H)
event_handle:
#endif
/*
* When interrupt is detected, call usb_lld_event_handler.
* The event may be one of following:
* (1) Transfer to endpoint (bulk or interrupt)
* In this case EP_NUM is encoded in the variable E.
* (2) "NONE" event: some trasfer was done, but all was
* done by lower layer, no other work is needed in
* upper layer.
* (3) Device events: Reset or Suspend
* (4) Device requests to the endpoint zero.
*
*/
e = usb_lld_event_handler (&dev);
ep_num = USB_EVENT_ENDP (e);
if (ep_num != 0)
{
if (USB_EVENT_TXRX (e))
usb_tx_done (ep_num, USB_EVENT_LEN (e));
else
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
}
else
switch (USB_EVENT_ID (e))
{
case USB_EVENT_DEVICE_RESET:
usb_device_reset (&dev);
continue;
case USB_EVENT_DEVICE_ADDRESSED:
/* The addres is assigned to the device. We don't
* need to do anything for this actually, but in this
* application, we maintain the USB status of the
* device. Usually, just "continue" as EVENT_OK is
* OK.
*/
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = ADDRESSED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
continue;
case USB_EVENT_GET_DESCRIPTOR:
if (usb_get_descriptor (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_CONFIGURATION:
if (usb_set_configuration (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_INTERFACE:
if (usb_set_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_CTRL_REQUEST:
/* Device specific device request. */
if (usb_setup (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_GET_STATUS_INTERFACE:
if (usb_get_status_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_GET_INTERFACE:
if (usb_get_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_FEATURE_DEVICE:
case USB_EVENT_SET_FEATURE_ENDPOINT:
case USB_EVENT_CLEAR_FEATURE_DEVICE:
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
usb_lld_ctrl_ack (&dev);
continue;
case USB_EVENT_CTRL_WRITE_FINISH:
/* Control WRITE transfer finished. */
usb_ctrl_write_finish (&dev);
continue;
case USB_EVENT_OK:
case USB_EVENT_DEVICE_SUSPEND:
default:
continue;
}
}
chopstx_mutex_lock (&t->mtx);
if (t->device_state == CONFIGURED && t->flag_connected
&& t->flag_send_ready)
{
uint8_t line[32];
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
if (len)
{
memcpy (t->send_buf0, line, len);
usb_lld_tx_enable_buf (ENDP1, t->send_buf0, len);
t->flag_send_ready = 0;
}
}
chopstx_mutex_unlock (&t->mtx);
}
return NULL;
}
void
tty_wait_configured (struct tty *t)
{
chopstx_mutex_lock (&t->mtx);
while (t->device_state != CONFIGURED)
chopstx_cond_wait (&t->cnd, &t->mtx);
chopstx_mutex_unlock (&t->mtx);
}
void
tty_wait_connection (struct tty *t)
{
chopstx_mutex_lock (&t->mtx);
while (t->flag_connected == 0)
chopstx_cond_wait (&t->cnd, &t->mtx);
t->flag_send_ready = 1;
t->flag_input_avail = 0;
t->send_head = t->send_tail = 0;
t->inputline_len = 0;
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64); /* Accept input for line */
chopstx_mutex_unlock (&t->mtx);
}
static int
check_tx (struct tty *t)
{
if (t->flag_send_ready)
/* TX done */
return 1;
if (t->flag_connected == 0)
/* Disconnected */
return -1;
return 0;
}
int
tty_send (struct tty *t, const char *buf, int len)
{
int r;
const char *p;
int count;
p = buf;
count = len >= 64 ? 64 : len;
while (1)
{
chopstx_mutex_lock (&t->mtx);
while ((r = check_tx (t)) == 0)
chopstx_cond_wait (&t->cnd, &t->mtx);
if (r > 0)
{
usb_lld_tx_enable_buf (ENDP1, p, count);
t->flag_send_ready = 0;
}
chopstx_mutex_unlock (&t->mtx);
len -= count;
p += count;
if (len == 0 && count != 64)
/*
* The size of the last packet should be != 0
* If 64, send ZLP (zelo length packet)
*/
break;
count = len >= 64 ? 64 : len;
}
/* Wait until all sent. */
chopstx_mutex_lock (&t->mtx);
while ((r = check_tx (t)) == 0)
chopstx_cond_wait (&t->cnd, &t->mtx);
chopstx_mutex_unlock (&t->mtx);
return r;
}
static int
check_rx (void *arg)
{
struct tty *t = arg;
if (t->flag_input_avail)
/* RX */
return 1;
if (t->flag_connected == 0)
/* Disconnected */
return 1;
return 0;
}
/*
* Returns -1 on connection close
* 0 on timeout.
* >0 length of the inputline (including final \n)
*
*/
int
tty_recv (struct tty *t, char *buf, uint32_t *timeout)
{
int r;
chopstx_poll_cond_t poll_desc;
poll_desc.type = CHOPSTX_POLL_COND;
poll_desc.ready = 0;
poll_desc.cond = &t->cnd;
poll_desc.mutex = &t->mtx;
poll_desc.check = check_rx;
poll_desc.arg = t;
while (1)
{
struct chx_poll_head *pd_array[1] = {
(struct chx_poll_head *)&poll_desc
};
chopstx_poll (timeout, 1, pd_array);
chopstx_mutex_lock (&t->mtx);
r = check_rx (t);
chopstx_mutex_unlock (&t->mtx);
if (r || (timeout != NULL && *timeout == 0))
break;
}
chopstx_mutex_lock (&t->mtx);
if (t->flag_connected == 0)
r = -1;
else if (t->flag_input_avail)
{
r = t->inputline_len;
memcpy (buf, t->inputline, r);
t->flag_input_avail = 0;
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64);
t->inputline_len = 0;
}
else
r = 0;
chopstx_mutex_unlock (&t->mtx);
return r;
}

View File

@@ -61,14 +61,14 @@ blk (void *arg)
#define PRIO_PWM 3
#define PRIO_BLK 2
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
static char hexchar (uint8_t x)
@@ -98,8 +98,8 @@ main (int argc, const char *argv[])
m = 10;
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);

View File

@@ -642,9 +642,9 @@ static void *tty_main (void *arg);
#define INTR_REQ_USB 20
#define PRIO_TTY 4
extern uint8_t __process3_stack_base__, __process3_stack_size__;
const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__;
const size_t __stacksize_tty = (size_t)&__process3_stack_size__;
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
#define STACK_ADDR_TTY ((uint32_t)__process3_stack_base__)
#define STACK_SIZE_TTY ((uint32_t)__process3_stack_size__)
struct tty *
tty_open (void)
@@ -659,7 +659,7 @@ tty_open (void)
tty0.device_state = UNCONNECTED;
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0);
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
return &tty0;
}

View File

@@ -0,0 +1,43 @@
(0) configure and make
This example assumes that you have fraucheky source code
along with chopstx.
--- chopstx --- chostx --- example-fraucheky
|
\- fraucheky
If you use vendor id and product id of 234b:0004 under
the condition of FSIJ, you can configure this program as:
$ ./configure --vidpid=234b:0004
then, invoke make.
$ make
(1) preparation as root
Install USBIP host module
# modprobe vhci_hcd
(2) Run sample program of USBIP server
$ ./sample-msc
(3) Use the USB device as root
Attach the Chopstx application program (USBIP device) to USBIP host.
# usbip attach -r 127.0.0.1 -b 1-1
(4) Use the USB Mass Storage Class device
You can mount the storage.
Unmounting the storage, the program will exit.

View File

@@ -0,0 +1,62 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head><title>How to use this device</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<h1>How to use this device</h1>
<h2>Introduction</h2>
<p>This is an example program for GNU/Linux to see how
Chopstx works with USB emulation by USBIP.</p>
<p>Now, you are accessing this file.
It means that the device is running as USB memory
(USB Mass Storage Class device).</p>
<h2>README, GNU GPL and Corresponding Source code</h2>
<p>In this program, it contains copyrighted software that is licensed under
the GPLv3. Please see README for the explanation of the software and see
GNU GPLv3 for terms and conditions.</p>
<p>You may obtain the complete Corresponding Source code from git repositories.
This program uses Chopstx for RTOS, and Fraucheky for
GPL container. Those code are availabe in the Chopstx repository.</p>
<p>You can also download tarballs from the repository.</p>
<ul>
<li><a href="README">README</a></li>
<li><a href="COPYING">GNU GPLv3</a></li>
<li><a href="https://anonscm.debian.org/cgit/gnuk/chopstx/">Chopstx Repository</a></li>
<li><a href="https://git.gniibe.org/gitweb/?p=chopstx/chopstx.git;a=snapshot;h=@REVISION_CHOPSTX@;sf=tgz">Chopstx tarball</a></li>
<li><a href="https://git.gniibe.org/gitweb/?p=chopstx/fraucheky.git;a=snapshot;h=@REVISION_FRAUCHEKY@;sf=tgz">Fraucheky tarball</a></li>
</ul>
<h3>Source code by physical media</h3>
<p>For those who want source code by physical media, Flying Stone Technology sells a microSD card (with SD card adapter) which contains all repositories at git.gniibe.org.</p>
<p>The price is JPY1000 for a single media including tax and shipment in Japan. Please use YUUBIN-FURIKAE account of Flying Stone Technology below. Note that the account name is in Japanese (which means: Flying Stone Technology).</p>
<p>On the form of YUUBIN-FURIKAE, you specify your address and you can write some message. The media will be sent to your address written in the form.</p>
<ul>
<li>Account No: 00110-2-346446</li>
<li>Account name: Tobiishi Gijutsu</li>
</ul>
<p>If it is difficult for you to use YUUBIN-FURIKAE, please write to the following address.</p>
<ul>
<li>Niibe Yutaka</li>
<li>Flying Stone Technology</li>
<li>1-5-14 Iwagami, Maebashi</li>
<li>Gunma, 371-0031 JAPAN</li>
</ul>
<p>This source code offer will be valid for three years after the shipment of this device or at least until 2021-03-31.</p>
<h2>Links</h2>
<ul>
<li><a href="https://www.gniibe.org/category/fst-01.html">
FST-01 support pages</a></li>
<li><a href="https://lists.alioth.debian.org/mailman/listinfo/gnuk-users">
Mailing list: Gnuk Users</a></li>
<li><a href="https://www.gnu.org/gnu/manifesto.ja.html">
GNU Manifesto (Japanese Translation)</a></li>
</ul>
</body>
</html>

View File

@@ -0,0 +1,45 @@
# Makefile for NeuG
# Define project name here
PROJECT = sample-msc
CHOPSTX = ..
FRAUCHEKY = ../../fraucheky
LDSCRIPT=
CSRC = main.c
CHIP=gnu-linux
USE_SYS =
USE_USB = yes
EMULATION=yes
# USE_ADC = yes
include $(FRAUCHEKY)/src.mk
###################################
CROSS =
CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = none
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DGNU_LINUX_EMULATION
OPT = -O3 -g
LIBS = -lpthread
BFDNAME_OBJ=elf64-x86-64
BFDARCH=i386:x86-64
#######################
include $(CHOPSTX)/rules.mk
include $(FRAUCHEKY)/build.mk
###################################
board.h:
@echo Please run configure to have a symbolic link \'board.h\'
@exit 1
distclean:: clean
-rm -f config.h

1
example-fraucheky/board.h Symbolic link
View File

@@ -0,0 +1 @@
../board/board-gnu-linux.h

View File

@@ -0,0 +1,2 @@
@FRAUCHEKY_DEFINE@
@FRAUCHEKY_MSC_DEFINE@

137
example-fraucheky/configure vendored Executable file
View File

@@ -0,0 +1,137 @@
#! /bin/bash
# This is bash which supports ANSI-C Quoting
nl=$'\n'
# Default settings
help=no
vidpid=none
verbose=no
debug=no
with_fraucheky=yes
with_index=./INDEX.HTM
if test -d ../.git; then
REVISION=`git describe --dirty="-modified"`
REVISION_CHOPSTX=`cd .. && git describe --dirty="-modified"`
REVISION_FRAUCHEKY=`cd ../../fraucheky &&git describe --dirty="-modified"`
else
REVISION=`cat ../VERSION`
REVISION_CHOPSTX=`cat ../VERSION`
REVISION_FRAUCHEKY=`cat ../../fraucheky/VERSION`
fi
# Process each option
for option; do
case $option in
*=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;;
*) optarg=yes ;;
esac
case $option in
-h | --help)
help=yes ;;
-v | --verbose)
verbose=yes ;;
--vidpid=*)
vidpid=$optarg ;;
*)
echo "Unrecognized option \`$option'" >&2
echo "Try \`$0 --help' for more information." >&2
exit 1
;;
esac
done
if test "$help" = "yes"; then
cat <<EOF
Usage: $0 [OPTION]...
Defaults for the options are specified in brackets.
Configuration:
-h, --help display this help and exit [no]
--vidpid=VID:PID specify vendor/product ID [<NONE>]
--with-index=INDEX specify INDEX file [none]
EOF
exit 0
fi
if test "$vidpid" = "none"; then
echo "Please specify Vendor ID and Product ID by --vidpid option." >&2
exit 1
fi
VIDPID="$vidpid"
VERSION="0100"
PRODUCT="Fraucheky"
VENDOR="Free Software Initiative of Japan"
SERIALNO="FSIJ-`cat ../VERSION | sed -e 's%^[^/]*/%%'`-"
../../fraucheky/configure "$vidpid" $with_index $REVISION $REVISION_CHOPSTX $REVISION_FRAUCHEKY
ENABLE_FRAUCHEKY=""
FRAUCHEKY_DEFINE="#define FRAUCHEKY_SUPPORT 1"
FRAUCHEKY_MSC_DEFINE="#define MSC_INTERFACE_NO 2"
if ! test -f ../../fraucheky/build.mk; then
echo "'fraucheky' not found" >&2
exit 1
fi
output_vid_pid_version () {
echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\\${nl} 0x\4, 0x\3, /* idProduct */%p"
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
}
output_vendor_product_serial_strings () {
prefix=$1
echo "static const uint8_t ${prefix}string_vendor[] = {"
echo " ${#VENDOR}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Manufacturer: \"$VENDOR\" */"
echo $VENDOR | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
echo
echo "static const uint8_t ${prefix}string_product[] = {"
echo " ${#PRODUCT}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Product name: \"$PRODUCT\" */"
echo $PRODUCT | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
if test -n "$prefix"; then
echo
echo "static uint8_t ${prefix}string_serial[] = {"
echo " ${#SERIALNO}*2+2+16, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* Serial number: \"$SERIALNO\" */"
echo $SERIALNO | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
echo '};'
echo
echo "static const uint8_t ${prefix}revision_detail[] = {"
echo " ${#REVISION}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* revision detail: \"$REVISION\" */"
echo $REVISION | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
echo
echo "static const uint8_t ${prefix}config_options[] = {"
echo " ${#CONFIG}*2+2, /* bLength */"
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
echo " /* configure options: \"$CONFIG\" */"
echo $CONFIG | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
echo '};'
fi
}
output_vid_pid_version > fraucheky-vid-pid-ver.c.inc
output_vendor_product_serial_strings >fraucheky-usb-strings.c.inc
sed -e "s/@FRAUCHEKY_DEFINE@/$FRAUCHEKY_DEFINE/" \
-e "s/@FRAUCHEKY_MSC_DEFINE@/$FRAUCHEKY_MSC_DEFINE/" \
< config.h.in > config.h
exit 0

320
example-fraucheky/main.c Normal file
View File

@@ -0,0 +1,320 @@
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <chopstx.h>
#include "config.h"
#include "usb_lld.h"
#define NUM_INTERFACES 1
#define FEATURE_BUS_POWERED 0x80
static chopstx_mutex_t usb_mtx;
static chopstx_cond_t usb_cnd;
static uint32_t bDeviceState = UNCONNECTED; /* USB device status */
extern void EP6_IN_Callback (uint16_t len);
extern void EP6_OUT_Callback (uint16_t len);
#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
extern int fraucheky_enabled (void);
extern void fraucheky_main (void);
extern void fraucheky_setup_endpoints_for_interface (struct usb_dev *dev, int stop);
extern int fraucheky_setup (struct usb_dev *dev);
extern int fraucheky_get_descriptor (struct usb_dev *dev);
static void
setup_endpoints_for_interface (struct usb_dev *dev, uint16_t interface, int stop)
{
if (interface == 0)
fraucheky_setup_endpoints_for_interface (dev, stop);
}
static void
usb_device_reset (struct usb_dev *dev)
{
int i;
usb_lld_reset (dev, FEATURE_BUS_POWERED);
/* Initialize Endpoint 0. */
usb_lld_setup_endp (dev, ENDP0, 1, 1);
/* Stop the interface */
for (i = 0; i < NUM_INTERFACES; i++)
setup_endpoints_for_interface (dev, i, 1);
/* Notify upper layer. */
chopstx_mutex_lock (&usb_mtx);
bDeviceState = ATTACHED;
chopstx_cond_signal (&usb_cnd);
chopstx_mutex_unlock (&usb_mtx);
}
static void
usb_ctrl_write_finish (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
&& USB_SETUP_SET (arg->type))
{
if (arg->request == MSC_MASS_STORAGE_RESET_COMMAND)
fraucheky_setup_endpoints_for_interface (dev, 0);
}
}
static int
usb_setup (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
&& arg->index == 0)
return fraucheky_setup (dev);
return -1;
}
static int
usb_set_configuration (struct usb_dev *dev)
{
int i;
uint8_t current_conf;
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (dev, 1);
for (i = 0; i < NUM_INTERFACES; i++)
setup_endpoints_for_interface (dev, i, 0);
chopstx_mutex_lock (&usb_mtx);
bDeviceState = CONFIGURED;
chopstx_mutex_unlock (&usb_mtx);
}
else if (current_conf != dev->dev_req.value)
{
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (dev, 0);
for (i = 0; i < NUM_INTERFACES; i++)
setup_endpoints_for_interface (dev, i, 1);
chopstx_mutex_lock (&usb_mtx);
bDeviceState = ADDRESSED;
chopstx_cond_signal (&usb_cnd);
chopstx_mutex_unlock (&usb_mtx);
}
/* Do nothing when current_conf == value */
return usb_lld_ctrl_ack (dev);
}
static int
usb_set_interface (struct usb_dev *dev)
{
uint16_t interface = dev->dev_req.index;
uint16_t alt = dev->dev_req.value;
if (interface >= NUM_INTERFACES)
return -1;
if (alt != 0)
return -1;
else
{
setup_endpoints_for_interface (dev, interface, 0);
return usb_lld_ctrl_ack (dev);
}
}
static int
usb_get_interface (struct usb_dev *dev)
{
const uint8_t zero = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &zero, 1);
}
static int
usb_get_status_interface (struct usb_dev *dev)
{
const uint16_t status_info = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &status_info, 2);
}
static void usb_tx_done (uint8_t ep_num, uint16_t len);
static void usb_rx_ready (uint8_t ep_num, uint16_t len);
#define INTR_REQ_USB SIGUSR1
#define PRIO_USB 3
static void *
usb_main (void *arg)
{
chopstx_intr_t interrupt;
struct usb_dev dev;
int e;
(void)arg;
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
usb_lld_init (&dev, FEATURE_BUS_POWERED);
goto event_handle; /* For old SYS < 3.0 */
while (1)
{
chopstx_intr_wait (&interrupt);
if (interrupt.ready)
{
uint8_t ep_num;
event_handle:
e = usb_lld_event_handler (&dev);
ep_num = USB_EVENT_ENDP (e);
if (ep_num != 0)
{
if (USB_EVENT_TXRX (e))
usb_tx_done (ep_num, USB_EVENT_LEN (e));
else
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
}
else
switch (USB_EVENT_ID (e))
{
case USB_EVENT_DEVICE_RESET:
usb_device_reset (&dev);
continue;
case USB_EVENT_DEVICE_ADDRESSED:
chopstx_mutex_lock (&usb_mtx);
bDeviceState = ADDRESSED;
chopstx_cond_signal (&usb_cnd);
chopstx_mutex_unlock (&usb_mtx);
continue;
case USB_EVENT_GET_DESCRIPTOR:
if (fraucheky_get_descriptor (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_CONFIGURATION:
if (usb_set_configuration (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_INTERFACE:
if (usb_set_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_CTRL_REQUEST:
/* Device specific device request. */
if (usb_setup (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_GET_STATUS_INTERFACE:
if (usb_get_status_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_GET_INTERFACE:
if (usb_get_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_FEATURE_DEVICE:
case USB_EVENT_SET_FEATURE_ENDPOINT:
case USB_EVENT_CLEAR_FEATURE_DEVICE:
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
usb_lld_ctrl_ack (&dev);
continue;
case USB_EVENT_CTRL_WRITE_FINISH:
/* Control WRITE transfer finished. */
usb_ctrl_write_finish (&dev);
continue;
case USB_EVENT_OK:
case USB_EVENT_DEVICE_SUSPEND:
default:
continue;
}
}
}
return NULL;
}
static void
usb_tx_done (uint8_t ep_num, uint16_t len)
{
if (ep_num == ENDP6)
EP6_IN_Callback (len);
}
static void
usb_rx_ready (uint8_t ep_num, uint16_t len)
{
if (ep_num == ENDP6)
EP6_OUT_Callback (len);
}
static char __process3_stack_base__[4096];
#define STACK_ADDR_USB ((uintptr_t)__process3_stack_base__)
#define STACK_SIZE_USB (sizeof __process3_stack_base__)
#ifdef GNU_LINUX_EMULATION
#define main emulated_main
#endif
/*
* Entry point.
*
* NOTE: the main function is already a thread in the system on entry.
*/
int
main (int argc, char **argv)
{
chopstx_t usb_thd;
(void)argc;
(void)argv;
chopstx_mutex_init (&usb_mtx);
chopstx_cond_init (&usb_cnd);
bDeviceState = UNCONNECTED;
usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB,
usb_main, NULL);
while (bDeviceState != CONFIGURED)
chopstx_usec_wait (250*1000);
fraucheky_main ();
chopstx_cancel (usb_thd);
chopstx_join (usb_thd, NULL);
usb_lld_shutdown ();
bDeviceState = UNCONNECTED;
return 0;
}

View File

@@ -75,14 +75,14 @@ blk (void *arg)
#define PRIO_PWM 3
#define PRIO_BLK 2
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
static char hexchar (uint8_t x)
@@ -114,8 +114,8 @@ main (int argc, const char *argv[])
m = 10;
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);

View File

@@ -629,9 +629,9 @@ static void *tty_main (void *arg);
#define INTR_REQ_USB 24
#define PRIO_TTY 4
extern uint8_t __process3_stack_base__, __process3_stack_size__;
const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__;
const size_t __stacksize_tty = (size_t)&__process3_stack_size__;
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
#define STACK_ADDR_TTY ((uint32_t)__process3_stack_base__)
#define STACK_SIZE_TTY ((uint32_t)__process3_stack_size__)
struct tty *
tty_open (void)
@@ -646,7 +646,7 @@ tty_open (void)
tty0.device_state = UNCONNECTED;
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0);
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
return &tty0;
}

View File

@@ -166,14 +166,14 @@ button (void *arg)
#define PRIO_LED 3
#define PRIO_BUTTON 2
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
#define STACK_ADDR_LED ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_LED ((uint32_t)__process1_stack_size__)
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
#define STACK_ADDR_BUTTON ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_BUTTON ((uint32_t)__process2_stack_size__)
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
@@ -382,10 +382,10 @@ main (int argc, const char *argv[])
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
__stacksize_led, led, NULL);
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
__stacksize_button, button, NULL);
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
STACK_SIZE_LED, led, NULL);
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
STACK_SIZE_BUTTON, button, NULL);
chopstx_usec_wait (200*1000);

View File

@@ -166,14 +166,14 @@ button (void *arg)
#define PRIO_LED 3
#define PRIO_BUTTON 2
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
#define STACK_ADDR_LED ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_LED ((uint32_t)__process1_stack_size__)
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
#define STACK_ADDR_BUTTON ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_BUTTON ((uint32_t)__process2_stack_size__)
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
@@ -370,10 +370,10 @@ main (int argc, const char *argv[])
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
__stacksize_led, led, NULL);
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
__stacksize_button, button, NULL);
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
STACK_SIZE_LED, led, NULL);
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
STACK_SIZE_BUTTON, button, NULL);
chopstx_usec_wait (200*1000);

View File

@@ -88,10 +88,10 @@ led_enable_column (uint8_t col)
#define PRIO_LED 3
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
const uint32_t stackaddr_led = (uint32_t)&__process1_stack_base__;
const size_t stacksize_led = (size_t)&__process1_stack_size__;
#define STACK_ADDR_LED ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_LED ((uint32_t)__process1_stack_size__)
static void *
led (void *arg)
@@ -119,10 +119,10 @@ led (void *arg)
#define PRIO_SPK 4
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
const uint32_t stackaddr_spk = (uint32_t)&__process2_stack_base__;
const size_t stacksize_spk = (size_t)&__process2_stack_size__;
#define STACK_ADDR_SPK ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_SPK ((uint32_t)__process2_stack_size__)
static chopstx_mutex_t spk_mtx;
static chopstx_cond_t spk_cnd;
@@ -193,10 +193,10 @@ spk (void *arg)
#define PRIO_MUSIC 2
extern uint8_t __process3_stack_base__, __process3_stack_size__;
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
const uint32_t stackaddr_music = (uint32_t)&__process3_stack_base__;
const size_t stacksize_music = (size_t)&__process3_stack_size__;
#define STACK_ADDR_MUSIC ((uint32_t)__process3_stack_base__)
#define STACK_SIZE_MUSIC ((uint32_t)__process3_stack_size__)
#define C 0
#define D 1
@@ -254,7 +254,7 @@ music (void *arg)
chopstx_cond_init (&spk_cnd);
chopstx_cond_init (&spk_cnd_no_tone);
chopstx_create (PRIO_SPK, stackaddr_spk, stacksize_spk, spk, NULL);
chopstx_create (PRIO_SPK, STACK_ADDR_SPK, STACK_SIZE_SPK, spk, NULL);
while (1)
{
@@ -350,8 +350,8 @@ main (int argc, const char *argv[])
chopstx_mutex_init (&mtx);
chopstx_cond_init (&cnd);
chopstx_create (PRIO_LED, stackaddr_led, stacksize_led, led, NULL);
chopstx_create (PRIO_MUSIC, stackaddr_music, stacksize_music, music, NULL);
chopstx_create (PRIO_LED, STACK_ADDR_LED, STACK_SIZE_LED, led, NULL);
chopstx_create (PRIO_MUSIC, STACK_ADDR_MUSIC, STACK_SIZE_MUSIC, music, NULL);
chopstx_usec_wait (200*1000);

View File

@@ -72,14 +72,14 @@ blk (void *arg)
#define PRIO_BLK 2
#endif
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
int
@@ -94,8 +94,8 @@ main (int argc, const char *argv[])
m = 10;
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);

View File

@@ -1,10 +1,8 @@
#define PERIPH_BASE 0x40000000
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_APB2RSTR_ADC1RST 0x00000200
#define RCC_APB2RSTR_ADC2RST 0x00000400
struct RCC {
volatile uint32_t CR;
volatile uint32_t CFGR;
@@ -26,6 +24,17 @@ static struct RCC *const RCC = (struct RCC *)RCC_BASE;
#define RCC_APB2ENR_ADC1EN 0x00000200
#define RCC_APB2ENR_ADC2EN 0x00000400
#define RCC_APB2ENR_TIM1EN 0x00000800
#define RCC_APB1ENR_TIM2EN 0x00000001
#define RCC_APB1ENR_TIM3EN 0x00000002
#define RCC_APB1ENR_TIM4EN 0x00000004
#define RCC_APB2RSTR_ADC1RST 0x00000200
#define RCC_APB2RSTR_ADC2RST 0x00000400
#define RCC_APB2RSTR_TIM1RST 0x00000800
#define RCC_APB1RSTR_TIM2RST 0x00000001
#define RCC_APB1RSTR_TIM3RST 0x00000002
#define RCC_APB1RSTR_TIM4RST 0x00000004
#define CRC_CR_RESET 0x00000001
@@ -202,3 +211,490 @@ struct SCB
#define SCS_BASE 0xE000E000
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = (struct SCB *)SCB_BASE;
/* Timer */
struct TIM
{
volatile uint16_t CR1; uint16_t RESERVED0;
volatile uint16_t CR2; uint16_t RESERVED1;
volatile uint16_t SMCR; uint16_t RESERVED2;
volatile uint16_t DIER; uint16_t RESERVED3;
volatile uint16_t SR; uint16_t RESERVED4;
volatile uint16_t EGR; uint16_t RESERVED5;
volatile uint16_t CCMR1; uint16_t RESERVED6;
volatile uint16_t CCMR2; uint16_t RESERVED7;
volatile uint16_t CCER; uint16_t RESERVED8;
volatile uint16_t CNT; uint16_t RESERVED9;
volatile uint16_t PSC; uint16_t RESERVED10;
volatile uint16_t ARR; uint16_t RESERVED11;
volatile uint16_t RCR; uint16_t RESERVED12;
volatile uint16_t CCR1; uint16_t RESERVED13;
volatile uint16_t CCR2; uint16_t RESERVED14;
volatile uint16_t CCR3; uint16_t RESERVED15;
volatile uint16_t CCR4; uint16_t RESERVED16;
volatile uint16_t BDTR; uint16_t RESERVED17;
volatile uint16_t DCR; uint16_t RESERVED18;
volatile uint16_t DMAR; uint16_t RESERVED19;
};
#define TIM2_BASE 0x40000000
#define TIM3_BASE 0x40000400
#define TIM4_BASE 0x40000800
static struct TIM *const TIM2 = (struct TIM *)TIM2_BASE;
static struct TIM *const TIM3 = (struct TIM *)TIM3_BASE;
static struct TIM *const TIM4 = (struct TIM *)TIM4_BASE;
#define TIM_CR1_CEN 0x0001
#define TIM_CR1_UDIS 0x0002
#define TIM_CR1_URS 0x0004
#define TIM_CR1_OPM 0x0008
#define TIM_CR1_DIR 0x0010
#define TIM_CR1_CMS 0x0060
#define TIM_CR1_CMS_0 0x0020
#define TIM_CR1_CMS_1 0x0040
#define TIM_CR1_ARPE 0x0080
#define TIM_CR1_CKD 0x0300
#define TIM_CR1_CKD_0 0x0100
#define TIM_CR1_CKD_1 0x0200
#define TIM_CR2_CCPC 0x0001
#define TIM_CR2_CCUS 0x0004
#define TIM_CR2_CCDS 0x0008
#define TIM_CR2_MMS 0x0070
#define TIM_CR2_MMS_0 0x0010
#define TIM_CR2_MMS_1 0x0020
#define TIM_CR2_MMS_2 0x0040
#define TIM_CR2_TI1S 0x0080
#define TIM_CR2_OIS1 0x0100
#define TIM_CR2_OIS1N 0x0200
#define TIM_CR2_OIS2 0x0400
#define TIM_CR2_OIS2N 0x0800
#define TIM_CR2_OIS3 0x1000
#define TIM_CR2_OIS3N 0x2000
#define TIM_CR2_OIS4 0x4000
#define TIM_SMCR_SMS 0x0007
#define TIM_SMCR_SMS_0 0x0001
#define TIM_SMCR_SMS_1 0x0002
#define TIM_SMCR_SMS_2 0x0004
#define TIM_SMCR_TS 0x0070
#define TIM_SMCR_TS_0 0x0010
#define TIM_SMCR_TS_1 0x0020
#define TIM_SMCR_TS_2 0x0040
#define TIM_SMCR_MSM 0x0080
#define TIM_SMCR_ETF 0x0F00
#define TIM_SMCR_ETF_0 0x0100
#define TIM_SMCR_ETF_1 0x0200
#define TIM_SMCR_ETF_2 0x0400
#define TIM_SMCR_ETF_3 0x0800
#define TIM_SMCR_ETPS 0x3000
#define TIM_SMCR_ETPS_0 0x1000
#define TIM_SMCR_ETPS_1 0x2000
#define TIM_SMCR_ECE 0x4000
#define TIM_SMCR_ETP 0x8000
#define TIM_DIER_UIE 0x0001
#define TIM_DIER_CC1IE 0x0002
#define TIM_DIER_CC2IE 0x0004
#define TIM_DIER_CC3IE 0x0008
#define TIM_DIER_CC4IE 0x0010
#define TIM_DIER_COMIE 0x0020
#define TIM_DIER_TIE 0x0040
#define TIM_DIER_BIE 0x0080
#define TIM_DIER_UDE 0x0100
#define TIM_DIER_CC1DE 0x0200
#define TIM_DIER_CC2DE 0x0400
#define TIM_DIER_CC3DE 0x0800
#define TIM_DIER_CC4DE 0x1000
#define TIM_DIER_COMDE 0x2000
#define TIM_DIER_TDE 0x4000
#define TIM_SR_UIF 0x0001
#define TIM_SR_CC1IF 0x0002
#define TIM_SR_CC2IF 0x0004
#define TIM_SR_CC3IF 0x0008
#define TIM_SR_CC4IF 0x0010
#define TIM_SR_COMIF 0x0020
#define TIM_SR_TIF 0x0040
#define TIM_SR_BIF 0x0080
#define TIM_SR_CC1OF 0x0200
#define TIM_SR_CC2OF 0x0400
#define TIM_SR_CC3OF 0x0800
#define TIM_SR_CC4OF 0x1000
#define TIM_EGR_UG 0x01
#define TIM_EGR_CC1G 0x02
#define TIM_EGR_CC2G 0x04
#define TIM_EGR_CC3G 0x08
#define TIM_EGR_CC4G 0x10
#define TIM_EGR_COMG 0x20
#define TIM_EGR_TG 0x40
#define TIM_EGR_BG 0x80
#define TIM_CCMR1_CC1S 0x0003
#define TIM_CCMR1_CC1S_0 0x0001
#define TIM_CCMR1_CC1S_1 0x0002
#define TIM_CCMR1_OC1FE 0x0004
#define TIM_CCMR1_OC1PE 0x0008
#define TIM_CCMR1_OC1M 0x0070
#define TIM_CCMR1_OC1M_0 0x0010
#define TIM_CCMR1_OC1M_1 0x0020
#define TIM_CCMR1_OC1M_2 0x0040
#define TIM_CCMR1_OC1CE 0x0080
#define TIM_CCMR1_CC2S 0x0300
#define TIM_CCMR1_CC2S_0 0x0100
#define TIM_CCMR1_CC2S_1 0x0200
#define TIM_CCMR1_OC2FE 0x0400
#define TIM_CCMR1_OC2PE 0x0800
#define TIM_CCMR1_OC2M 0x7000
#define TIM_CCMR1_OC2M_0 0x1000
#define TIM_CCMR1_OC2M_1 0x2000
#define TIM_CCMR1_OC2M_2 0x4000
#define TIM_CCMR1_OC2CE 0x8000
#define TIM_CCMR1_IC1PSC 0x000C
#define TIM_CCMR1_IC1PSC_0 0x0004
#define TIM_CCMR1_IC1PSC_1 0x0008
#define TIM_CCMR1_IC1F 0x00F0
#define TIM_CCMR1_IC1F_0 0x0010
#define TIM_CCMR1_IC1F_1 0x0020
#define TIM_CCMR1_IC1F_2 0x0040
#define TIM_CCMR1_IC1F_3 0x0080
#define TIM_CCMR1_IC2PSC 0x0C00
#define TIM_CCMR1_IC2PSC_0 0x0400
#define TIM_CCMR1_IC2PSC_1 0x0800
#define TIM_CCMR1_IC2F 0xF000
#define TIM_CCMR1_IC2F_0 0x1000
#define TIM_CCMR1_IC2F_1 0x2000
#define TIM_CCMR1_IC2F_2 0x4000
#define TIM_CCMR1_IC2F_3 0x8000
#define TIM_CCMR2_CC3S 0x0003
#define TIM_CCMR2_CC3S_0 0x0001
#define TIM_CCMR2_CC3S_1 0x0002
#define TIM_CCMR2_OC3FE 0x0004
#define TIM_CCMR2_OC3PE 0x0008
#define TIM_CCMR2_OC3M 0x0070
#define TIM_CCMR2_OC3M_0 0x0010
#define TIM_CCMR2_OC3M_1 0x0020
#define TIM_CCMR2_OC3M_2 0x0040
#define TIM_CCMR2_OC3CE 0x0080
#define TIM_CCMR2_CC4S 0x0300
#define TIM_CCMR2_CC4S_0 0x0100
#define TIM_CCMR2_CC4S_1 0x0200
#define TIM_CCMR2_OC4FE 0x0400
#define TIM_CCMR2_OC4PE 0x0800
#define TIM_CCMR2_OC4M 0x7000
#define TIM_CCMR2_OC4M_0 0x1000
#define TIM_CCMR2_OC4M_1 0x2000
#define TIM_CCMR2_OC4M_2 0x4000
#define TIM_CCMR2_OC4CE 0x8000
#define TIM_CCMR2_IC3PSC 0x000C
#define TIM_CCMR2_IC3PSC_0 0x0004
#define TIM_CCMR2_IC3PSC_1 0x0008
#define TIM_CCMR2_IC3F 0x00F0
#define TIM_CCMR2_IC3F_0 0x0010
#define TIM_CCMR2_IC3F_1 0x0020
#define TIM_CCMR2_IC3F_2 0x0040
#define TIM_CCMR2_IC3F_3 0x0080
#define TIM_CCMR2_IC4PSC 0x0C00
#define TIM_CCMR2_IC4PSC_0 0x0400
#define TIM_CCMR2_IC4PSC_1 0x0800
#define TIM_CCMR2_IC4F 0xF000
#define TIM_CCMR2_IC4F_0 0x1000
#define TIM_CCMR2_IC4F_1 0x2000
#define TIM_CCMR2_IC4F_2 0x4000
#define TIM_CCMR2_IC4F_3 0x8000
#define TIM_CCER_CC1E 0x0001
#define TIM_CCER_CC1P 0x0002
#define TIM_CCER_CC1NE 0x0004
#define TIM_CCER_CC1NP 0x0008
#define TIM_CCER_CC2E 0x0010
#define TIM_CCER_CC2P 0x0020
#define TIM_CCER_CC2NE 0x0040
#define TIM_CCER_CC2NP 0x0080
#define TIM_CCER_CC3E 0x0100
#define TIM_CCER_CC3P 0x0200
#define TIM_CCER_CC3NE 0x0400
#define TIM_CCER_CC3NP 0x0800
#define TIM_CCER_CC4E 0x1000
#define TIM_CCER_CC4P 0x2000
#define TIM_CNT_CNT 0xFFFF
#define TIM_PSC_PSC 0xFFFF
#define TIM_ARR_ARR 0xFFFF
#define TIM_RCR_REP 0xFF
#define TIM_CCR1_CCR1 0xFFFF
#define TIM_CCR2_CCR2 0xFFFF
#define TIM_CCR3_CCR3 0xFFFF
#define TIM_CCR4_CCR4 0xFFFF
#define TIM_BDTR_DTG 0x00FF
#define TIM_BDTR_DTG_0 0x0001
#define TIM_BDTR_DTG_1 0x0002
#define TIM_BDTR_DTG_2 0x0004
#define TIM_BDTR_DTG_3 0x0008
#define TIM_BDTR_DTG_4 0x0010
#define TIM_BDTR_DTG_5 0x0020
#define TIM_BDTR_DTG_6 0x0040
#define TIM_BDTR_DTG_7 0x0080
#define TIM_BDTR_LOCK 0x0300
#define TIM_BDTR_LOCK_0 0x0100
#define TIM_BDTR_LOCK_1 0x0200
#define TIM_BDTR_OSSI 0x0400
#define TIM_BDTR_OSSR 0x0800
#define TIM_BDTR_BKE 0x1000
#define TIM_BDTR_BKP 0x2000
#define TIM_BDTR_AOE 0x4000
#define TIM_BDTR_MOE 0x8000
#define TIM_DCR_DBA 0x001F
#define TIM_DCR_DBA_0 0x0001
#define TIM_DCR_DBA_1 0x0002
#define TIM_DCR_DBA_2 0x0004
#define TIM_DCR_DBA_3 0x0008
#define TIM_DCR_DBA_4 0x0010
#define TIM_DCR_DBL 0x1F00
#define TIM_DCR_DBL_0 0x0100
#define TIM_DCR_DBL_1 0x0200
#define TIM_DCR_DBL_2 0x0400
#define TIM_DCR_DBL_3 0x0800
#define TIM_DCR_DBL_4 0x1000
#define TIM_DMAR_DMAB 0xFFFF
struct EXTI
{
volatile uint32_t IMR;
volatile uint32_t EMR;
volatile uint32_t RTSR;
volatile uint32_t FTSR;
volatile uint32_t SWIER;
volatile uint32_t PR;
};
#define EXTI_BASE 0x40010400
static struct EXTI *const EXTI = (struct EXTI *)EXTI_BASE;
#define EXTI_IMR_MR0 0x00000001
#define EXTI_IMR_MR1 0x00000002
#define EXTI_IMR_MR2 0x00000004
#define EXTI_IMR_MR3 0x00000008
#define EXTI_IMR_MR4 0x00000010
#define EXTI_IMR_MR5 0x00000020
#define EXTI_IMR_MR6 0x00000040
#define EXTI_IMR_MR7 0x00000080
#define EXTI_IMR_MR8 0x00000100
#define EXTI_IMR_MR9 0x00000200
#define EXTI_IMR_MR10 0x00000400
#define EXTI_IMR_MR11 0x00000800
#define EXTI_IMR_MR12 0x00001000
#define EXTI_IMR_MR13 0x00002000
#define EXTI_IMR_MR14 0x00004000
#define EXTI_IMR_MR15 0x00008000
#define EXTI_IMR_MR16 0x00010000
#define EXTI_IMR_MR17 0x00020000
#define EXTI_IMR_MR18 0x00040000
#define EXTI_IMR_MR19 0x00080000
#define EXTI_EMR_MR0 0x00000001
#define EXTI_EMR_MR1 0x00000002
#define EXTI_EMR_MR2 0x00000004
#define EXTI_EMR_MR3 0x00000008
#define EXTI_EMR_MR4 0x00000010
#define EXTI_EMR_MR5 0x00000020
#define EXTI_EMR_MR6 0x00000040
#define EXTI_EMR_MR7 0x00000080
#define EXTI_EMR_MR8 0x00000100
#define EXTI_EMR_MR9 0x00000200
#define EXTI_EMR_MR10 0x00000400
#define EXTI_EMR_MR11 0x00000800
#define EXTI_EMR_MR12 0x00001000
#define EXTI_EMR_MR13 0x00002000
#define EXTI_EMR_MR14 0x00004000
#define EXTI_EMR_MR15 0x00008000
#define EXTI_EMR_MR16 0x00010000
#define EXTI_EMR_MR17 0x00020000
#define EXTI_EMR_MR18 0x00040000
#define EXTI_EMR_MR19 0x00080000
#define EXTI_RTSR_TR0 0x00000001
#define EXTI_RTSR_TR1 0x00000002
#define EXTI_RTSR_TR2 0x00000004
#define EXTI_RTSR_TR3 0x00000008
#define EXTI_RTSR_TR4 0x00000010
#define EXTI_RTSR_TR5 0x00000020
#define EXTI_RTSR_TR6 0x00000040
#define EXTI_RTSR_TR7 0x00000080
#define EXTI_RTSR_TR8 0x00000100
#define EXTI_RTSR_TR9 0x00000200
#define EXTI_RTSR_TR10 0x00000400
#define EXTI_RTSR_TR11 0x00000800
#define EXTI_RTSR_TR12 0x00001000
#define EXTI_RTSR_TR13 0x00002000
#define EXTI_RTSR_TR14 0x00004000
#define EXTI_RTSR_TR15 0x00008000
#define EXTI_RTSR_TR16 0x00010000
#define EXTI_RTSR_TR17 0x00020000
#define EXTI_RTSR_TR18 0x00040000
#define EXTI_RTSR_TR19 0x00080000
#define EXTI_FTSR_TR0 0x00000001
#define EXTI_FTSR_TR1 0x00000002
#define EXTI_FTSR_TR2 0x00000004
#define EXTI_FTSR_TR3 0x00000008
#define EXTI_FTSR_TR4 0x00000010
#define EXTI_FTSR_TR5 0x00000020
#define EXTI_FTSR_TR6 0x00000040
#define EXTI_FTSR_TR7 0x00000080
#define EXTI_FTSR_TR8 0x00000100
#define EXTI_FTSR_TR9 0x00000200
#define EXTI_FTSR_TR10 0x00000400
#define EXTI_FTSR_TR11 0x00000800
#define EXTI_FTSR_TR12 0x00001000
#define EXTI_FTSR_TR13 0x00002000
#define EXTI_FTSR_TR14 0x00004000
#define EXTI_FTSR_TR15 0x00008000
#define EXTI_FTSR_TR16 0x00010000
#define EXTI_FTSR_TR17 0x00020000
#define EXTI_FTSR_TR18 0x00040000
#define EXTI_FTSR_TR19 0x00080000
#define EXTI_SWIER_SWIER0 0x00000001
#define EXTI_SWIER_SWIER1 0x00000002
#define EXTI_SWIER_SWIER2 0x00000004
#define EXTI_SWIER_SWIER3 0x00000008
#define EXTI_SWIER_SWIER4 0x00000010
#define EXTI_SWIER_SWIER5 0x00000020
#define EXTI_SWIER_SWIER6 0x00000040
#define EXTI_SWIER_SWIER7 0x00000080
#define EXTI_SWIER_SWIER8 0x00000100
#define EXTI_SWIER_SWIER9 0x00000200
#define EXTI_SWIER_SWIER10 0x00000400
#define EXTI_SWIER_SWIER11 0x00000800
#define EXTI_SWIER_SWIER12 0x00001000
#define EXTI_SWIER_SWIER13 0x00002000
#define EXTI_SWIER_SWIER14 0x00004000
#define EXTI_SWIER_SWIER15 0x00008000
#define EXTI_SWIER_SWIER16 0x00010000
#define EXTI_SWIER_SWIER17 0x00020000
#define EXTI_SWIER_SWIER18 0x00040000
#define EXTI_SWIER_SWIER19 0x00080000
#define EXTI_PR_PR0 0x00000001
#define EXTI_PR_PR1 0x00000002
#define EXTI_PR_PR2 0x00000004
#define EXTI_PR_PR3 0x00000008
#define EXTI_PR_PR4 0x00000010
#define EXTI_PR_PR5 0x00000020
#define EXTI_PR_PR6 0x00000040
#define EXTI_PR_PR7 0x00000080
#define EXTI_PR_PR8 0x00000100
#define EXTI_PR_PR9 0x00000200
#define EXTI_PR_PR10 0x00000400
#define EXTI_PR_PR11 0x00000800
#define EXTI_PR_PR12 0x00001000
#define EXTI_PR_PR13 0x00002000
#define EXTI_PR_PR14 0x00004000
#define EXTI_PR_PR15 0x00008000
#define EXTI_PR_PR16 0x00010000
#define EXTI_PR_PR17 0x00020000
#define EXTI_PR_PR18 0x00040000
#define EXTI_PR_PR19 0x00080000
#define EXTI0_IRQ 6
#define EXTI1_IRQ 7
#define EXTI2_IRQ 8
#define EXTI9_5_IRQ 23
#define TIM2_IRQ 28
#define TIM3_IRQ 29
#define TIM4_IRQ 30
struct AFIO
{
volatile uint32_t EVCR;
volatile uint32_t MAPR;
volatile uint32_t EXTICR[4];
uint32_t RESERVED0;
volatile uint32_t MAPR2;
};
#define AFIO_BASE 0x40010000
static struct AFIO *const AFIO = (struct AFIO *)AFIO_BASE;
#define AFIO_EXTICR1_EXTI0_PA 0x0000
#define AFIO_EXTICR1_EXTI0_PB 0x0001
#define AFIO_EXTICR1_EXTI0_PC 0x0002
#define AFIO_EXTICR1_EXTI0_PD 0x0003
#define AFIO_EXTICR1_EXTI1_PA 0x0000
#define AFIO_EXTICR1_EXTI1_PB 0x0010
#define AFIO_EXTICR1_EXTI1_PC 0x0020
#define AFIO_EXTICR1_EXTI1_PD 0x0030
#define AFIO_EXTICR1_EXTI2_PA 0x0000
#define AFIO_EXTICR1_EXTI2_PB 0x0100
#define AFIO_EXTICR1_EXTI2_PC 0x0200
#define AFIO_EXTICR1_EXTI2_PD 0x0300
#define AFIO_EXTICR1_EXTI3_PA 0x0000
#define AFIO_EXTICR1_EXTI3_PB 0x1000
#define AFIO_EXTICR1_EXTI3_PC 0x2000
#define AFIO_EXTICR1_EXTI3_PD 0x3000
#define AFIO_EXTICR2_EXTI4_PA 0x0000
#define AFIO_EXTICR2_EXTI4_PB 0x0001
#define AFIO_EXTICR2_EXTI4_PC 0x0002
#define AFIO_EXTICR2_EXTI4_PD 0x0003
#define AFIO_EXTICR2_EXTI5_PA 0x0000
#define AFIO_EXTICR2_EXTI5_PB 0x0010
#define AFIO_EXTICR2_EXTI5_PC 0x0020
#define AFIO_EXTICR2_EXTI5_PD 0x0030
#define AFIO_EXTICR2_EXTI6_PA 0x0000
#define AFIO_EXTICR2_EXTI6_PB 0x0100
#define AFIO_EXTICR2_EXTI6_PC 0x0200
#define AFIO_EXTICR2_EXTI6_PD 0x0300
#define AFIO_EXTICR2_EXTI7_PA 0x0000
#define AFIO_EXTICR2_EXTI7_PB 0x1000
#define AFIO_EXTICR2_EXTI7_PC 0x2000
#define AFIO_EXTICR2_EXTI7_PD 0x3000
#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
#define AFIO_MAPR_SWJ_CFG_DISABLE 0x04000000

View File

@@ -213,7 +213,11 @@ static int
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
{
int status;
#if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB)
uint32_t flash_end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024;
#else
uint32_t flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
#endif
if (dst_addr < FLASH_START || dst_addr + len > flash_end)
return 0;
@@ -269,7 +273,11 @@ static void __attribute__((naked))
flash_erase_all_and_exec (void (*entry)(void))
{
uint32_t addr = FLASH_START;
#if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB)
uint32_t end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024;
#else
uint32_t end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
#endif
uint32_t page_size = 1024;
int r;

View File

@@ -272,43 +272,7 @@ kl27z_ep_clear_dtog (int rx, uint8_t n)
kl27z_ep_clear_stall (n);
}
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
enum STANDARD_REQUESTS {
GET_STATUS = 0,
CLEAR_FEATURE,
RESERVED1,
SET_FEATURE,
RESERVED2,
SET_ADDRESS,
GET_DESCRIPTOR,
SET_DESCRIPTOR,
GET_CONFIGURATION,
SET_CONFIGURATION,
GET_INTERFACE,
SET_INTERFACE,
SYNCH_FRAME,
TOTAL_REQUEST /* Total number of Standard request */
};
enum FEATURE_SELECTOR {
FEATURE_ENDPOINT_HALT=0,
FEATURE_DEVICE_REMOTE_WAKEUP=1
};
/* The state machine states of a control pipe */
enum {
WAIT_SETUP,
IN_DATA,
OUT_DATA,
LAST_IN_DATA,
WAIT_STATUS_IN,
WAIT_STATUS_OUT,
STALLED,
PAUSE
};
#include "usb_lld_driver.h"
static int handle_transaction (struct usb_dev *dev, uint8_t stat);
@@ -445,7 +409,7 @@ handle_datastage_in (struct usb_dev *dev, uint8_t stat)
{
/* No more data to send, proceed to receive OUT acknowledge. */
dev->state = WAIT_STATUS_OUT;
kl27z_prepare_ep0_out (&dev->dev_req, 8, DATA1);
kl27z_prepare_ep0_out (&dev->dev_req, 0, DATA1);
}
return;
@@ -470,12 +434,13 @@ std_none (struct usb_dev *dev)
return -1;
}
static uint16_t status_info;
static int
std_get_status (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
uint16_t status_info = 0;
if (arg->value != 0 || arg->len != 2 || (arg->index >> 8) != 0
|| USB_SETUP_SET (arg->type))
@@ -1000,8 +965,7 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
dev->state = IN_DATA;
}
if (len)
kl27z_prepare_ep0_in (data_p->addr, len, DATA1);
kl27z_prepare_ep0_in (data_p->addr, len, DATA1);
data_p->len -= len;
data_p->addr += len;

View File

@@ -31,44 +31,7 @@
#include "sys-stm32f103.h"
#include "usb_lld.h"
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
enum STANDARD_REQUESTS
{
GET_STATUS = 0,
CLEAR_FEATURE,
RESERVED1,
SET_FEATURE,
RESERVED2,
SET_ADDRESS,
GET_DESCRIPTOR,
SET_DESCRIPTOR,
GET_CONFIGURATION,
SET_CONFIGURATION,
GET_INTERFACE,
SET_INTERFACE,
SYNCH_FRAME,
TOTAL_REQUEST /* Total number of Standard request */
};
/* The state machine states of a control pipe */
enum CONTROL_STATE
{
WAIT_SETUP,
IN_DATA,
OUT_DATA,
LAST_IN_DATA,
WAIT_STATUS_IN,
WAIT_STATUS_OUT,
STALLED,
};
enum FEATURE_SELECTOR
{
FEATURE_ENDPOINT_HALT=0,
FEATURE_DEVICE_REMOTE_WAKEUP=1
};
#include "usb_lld_driver.h"
#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */
#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */

2180
mcu/usb-usbip.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,11 @@ ifneq ($(USE_SYS),)
CSRC += $(CHOPSTX)/mcu/sys-$(CHIP).c
endif
ifneq ($(USE_USB),)
ifeq ($(EMULATION),)
CSRC += $(CHOPSTX)/mcu/usb-$(CHIP).c
else
CSRC += $(CHOPSTX)/mcu/usb-usbip.c
endif
endif
ifneq ($(USE_ADC),)
CSRC += $(CHOPSTX)/contrib/adc-$(CHIP).c
@@ -19,10 +23,14 @@ endif
INCDIR += $(CHOPSTX)
BUILDDIR = build
ifeq ($(EMULATION),)
OUTFILES = $(BUILDDIR)/$(PROJECT).elf $(BUILDDIR)/$(PROJECT).bin
ifneq ($(ENABLE_OUTPUT_HEX),)
OUTFILES += $(BUILDDIR)/$(PROJECT).hex
endif
else
OUTFILES = $(BUILDDIR)/$(PROJECT)
endif
OPT += -ffunction-sections -fdata-sections -fno-common
@@ -34,14 +42,23 @@ LLIBDIR = $(patsubst %,-L%,$(LIBDIR))
VPATH = $(sort $(dir $(CSRC)))
###
ifeq ($(EMULATION),)
MCFLAGS = -mcpu=$(MCU)
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) \
-Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections
else
MCFLAGS =
LDFLAGS =
DEFS += -D_GNU_SOURCE
endif
CFLAGS = $(MCFLAGS) $(OPT) $(CWARN) -Wa,-alms=$(BUILDDIR)/$(notdir $(<:.c=.lst)) $(DEFS)
LDFLAGS += $(LLIBDIR)
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections $(LLIBDIR)
ifeq ($(EMULATION),)
CFLAGS += -mthumb -mno-thumb-interwork -DTHUMB
LDFLAGS += -mthumb -mno-thumb-interwork
endif
CFLAGS += -MD -MP -MF .dep/$(@F).d
@@ -56,6 +73,7 @@ $(OBJS) : $(BUILDDIR)/%.o : %.c Makefile
@echo
$(CC) -c $(CFLAGS) -I. $(IINCDIR) $< -o $@
ifeq ($(EMULATION),)
%.elf: $(OBJS) $(OBJS_ADD) $(LDSCRIPT)
@echo
$(LD) $(OBJS) $(OBJS_ADD) $(LDFLAGS) $(LIBS) -o $@
@@ -65,6 +83,11 @@ $(OBJS) : $(BUILDDIR)/%.o : %.c Makefile
%.hex: %.elf $(LDSCRIPT)
$(OBJCOPY) -O ihex $< $@
else
$(BUILDDIR)/$(PROJECT): $(OBJS) $(OBJS_ADD)
@echo
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(OBJS_ADD) $(LIBS)
endif
clean:
-rm -f -r .dep $(BUILDDIR)

View File

@@ -134,12 +134,19 @@ uint8_t usb_lld_current_configuration (struct usb_dev *dev);
void usb_lld_prepare_shutdown (void);
void usb_lld_shutdown (void);
#ifdef MCU_KINETIS_L
#if defined(MCU_KINETIS_L)
void usb_lld_tx_enable_buf (int ep_num, const void *buf, size_t len);
void usb_lld_rx_enable_buf (int ep_num, void *buf, size_t len);
void usb_lld_setup_endp (struct usb_dev *dev, int ep_num, int rx_en, int tx_en);
void usb_lld_stall (int ep_num);
#elif defined(GNU_LINUX_EMULATION)
void usb_lld_tx_enable_buf (int ep_num, const void *buf, size_t len);
void usb_lld_rx_enable_buf (int ep_num, void *buf, size_t len);
void usb_lld_setup_endp (struct usb_dev *dev, int ep_num, int rx_en, int tx_en);
void usb_lld_stall_tx (int ep_num);
void usb_lld_stall_rx (int ep_num);
#else
/* EP_TYPE[1:0] EndPoint TYPE */
#define EP_BULK (0x0000) /* EndPoint BULK */

37
usb_lld_driver.h Normal file
View File

@@ -0,0 +1,37 @@
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
enum STANDARD_REQUESTS
{
GET_STATUS = 0,
CLEAR_FEATURE,
RESERVED1,
SET_FEATURE,
RESERVED2,
SET_ADDRESS,
GET_DESCRIPTOR,
SET_DESCRIPTOR,
GET_CONFIGURATION,
SET_CONFIGURATION,
GET_INTERFACE,
SET_INTERFACE,
SYNCH_FRAME,
TOTAL_REQUEST /* Total number of Standard request */
};
/* The state machine states of a control pipe */
enum CONTROL_STATE
{
WAIT_SETUP,
IN_DATA,
OUT_DATA,
LAST_IN_DATA,
WAIT_STATUS_IN,
WAIT_STATUS_OUT,
STALLED,
};
enum FEATURE_SELECTOR
{
FEATURE_ENDPOINT_HALT=0,
FEATURE_DEVICE_REMOTE_WAKEUP=1
};