136 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
NIIBE Yutaka
09f27704f5 Version 1.1 2016-07-01 11:50:25 +09:00
NIIBE Yutaka
1f23bd4048 Change touch button for MKL27Z 2016-07-01 10:58:05 +09:00
NIIBE Yutaka
f5880ee5d5 Change API of chopstx_setpriority 2016-07-01 09:51:32 +09:00
NIIBE Yutaka
c7e571eca0 update doc 2016-06-30 16:41:32 +09:00
NIIBE Yutaka
0decd305b9 chopstx_poll example fix 2016-06-30 16:26:52 +09:00
NIIBE Yutaka
a2a29146a6 const pointer cleanup 2016-06-30 16:23:29 +09:00
NIIBE Yutaka
e7bd234a0d Update for MKL27Z 2016-06-30 16:16:39 +09:00
NIIBE Yutaka
c71a24ddcb MKL27Z touch 2016-06-29 17:05:33 +09:00
NIIBE Yutaka
663cbabe7c Fix MKL27Z TPM registers 2016-06-29 16:51:16 +09:00
NIIBE Yutaka
41ac81a66b Update example for fs-bb48 2016-06-29 16:38:18 +09:00
NIIBE Yutaka
986518fba7 fix setpriority 2016-06-29 16:36:53 +09:00
NIIBE Yutaka
15a4403f24 chopstx_poll change 2016-06-28 15:48:15 +09:00
Niibe Yutaka
40adf95c24 Version 1.0 2016-06-16 11:46:38 +09:00
Niibe Yutaka
5a7381ece6 Add FST-01G 2016-06-16 11:31:10 +09:00
Niibe Yutaka
52626a3368 chopstx_exit change 2016-06-15 12:41:12 +09:00
Niibe Yutaka
440188c373 Fix USB for STM32 2016-06-14 15:10:07 +09:00
NIIBE Yutaka
a6541cbcc6 NONE sounds bad, use OK instead 2016-06-10 08:25:00 +09:00
NIIBE Yutaka
74c7b5bcb3 minor comment change 2016-06-09 10:07:31 +09:00
NIIBE Yutaka
4d7e97028e More update of USB API 2016-06-09 09:53:15 +09:00
NIIBE Yutaka
d061e6f931 USB for FS-BB48 2016-06-08 15:43:11 +09:00
NIIBE Yutaka
5f1c26ff17 USB API major change 2016-06-08 15:40:55 +09:00
NIIBE Yutaka
78718e57df Move files 2016-06-02 11:01:11 +09:00
NIIBE Yutaka
a756987d2a Fix chx_fatal 2016-06-01 07:47:58 +09:00
NIIBE Yutaka
b6e3a1aba1 Relicense ADC driver with GPLv3+ plus EXCEPTION 2016-05-31 21:41:40 +09:00
NIIBE Yutaka
c79a41870a Version 0.12 2016-05-31 15:18:10 +09:00
NIIBE Yutaka
4889a5386b STM32F030: Fix use of vector on RAM 2016-05-31 15:12:55 +09:00
NIIBE Yutaka
e02f2e71e6 Fix f2a8b01607 2016-05-31 14:18:12 +09:00
NIIBE Yutaka
1fa89d1754 Change USB API a bit 2016-05-31 13:13:14 +09:00
NIIBE Yutaka
03a1d46c08 Fix sys-stm32f103.h 2016-05-31 12:00:25 +09:00
NIIBE Yutaka
3a4e1f2bd5 Cleanup of sys and its macro 2016-05-31 11:49:01 +09:00
NIIBE Yutaka
421fd8019b ; ABOUT-SYS 2016-05-30 20:34:06 +09:00
NIIBE Yutaka
e8eaeced77 Update USB for stm32f103 2016-05-30 20:11:18 +09:00
NIIBE Yutaka
1ae3caf7fc USB cleanup 2016-05-30 20:06:43 +09:00
NIIBE Yutaka
a933eebfd5 Update for STM32F103 2016-05-30 15:13:55 +09:00
NIIBE Yutaka
fae4c58d99 AES table is included in sys-stm32f103.c 2016-05-30 14:57:51 +09:00
NIIBE Yutaka
9f16e5e051 consolidate mcu-chip specific code 2016-05-30 14:57:10 +09:00
NIIBE Yutaka
b90e58f763 Move CHIP specific things to mcu/ 2016-05-30 14:39:02 +09:00
NIIBE Yutaka
8209f38755 example-fs-bb48: Add flash ROM handling 2016-05-30 14:06:18 +09:00
NIIBE Yutaka
781ad1847c example-fs-bb48: rm crc32.h 2016-05-27 17:29:36 +09:00
NIIBE Yutaka
8eb2130664 example-fs-bb48: rm crc32.h 2016-05-27 17:29:08 +09:00
NIIBE Yutaka
960921f537 example-fs-bb48: SYS implementation 2016-05-27 17:17:44 +09:00
NIIBE Yutaka
f2a8b01607 Fix IDLE thread 2016-05-27 16:19:02 +09:00
NIIBE Yutaka
890d108114 Add document for ABOUT-SYS 2016-05-27 11:22:29 +09:00
NIIBE Yutaka
5f57222b73 Move clk_gpio_init to mcu/ 2016-05-26 17:40:47 +09:00
NIIBE Yutaka
d81767b7c7 example-fs-bb48: Only use LS-8-bit 2016-05-26 17:29:06 +09:00
NIIBE Yutaka
91823d0fc1 Move kl_sim.h 2016-05-26 10:21:30 +09:00
NIIBE Yutaka
51cd47c3b7 example-fs-bb48: ADC use DIV1 2016-05-26 09:54:44 +09:00
NIIBE Yutaka
cf81e7a6dc example-fs-bb48: ADC added 2016-05-26 09:50:07 +09:00
NIIBE Yutaka
2578fc0f30 Update example-fs-bb48 2016-05-24 17:34:20 +09:00
NIIBE Yutaka
2704416c38 Fix PSR handling (ORRS instruction changes PSR) 2016-05-23 20:15:47 +09:00
NIIBE Yutaka
77255b0c1d Fix chopstx_poll 2016-05-23 17:45:10 +09:00
NIIBE Yutaka
eeb354119c Change example-cdc 2016-05-23 17:42:21 +09:00
NIIBE Yutaka
72c3d59555 Change example-fs-bb48 2016-05-23 17:42:01 +09:00
NIIBE Yutaka
8ba91f5db6 Fix example-fs-bb48 to support 16 endpoints 2016-05-23 17:36:31 +09:00
NIIBE Yutaka
b6603f6771 Update example-fs-bb48 2016-05-23 13:48:24 +09:00
NIIBE Yutaka
ee92bb15b3 Remove deprecated API 2016-05-23 13:00:33 +09:00
NIIBE Yutaka
5458b77d36 Version 0.11 2016-05-19 12:22:30 +09:00
NIIBE Yutaka
03bba13005 eventflag API addtiion 2016-05-19 11:48:01 +09:00
NIIBE Yutaka
1b0fe5a6e8 Add eventflag_set_poll_desc 2016-05-18 21:32:32 +09:00
NIIBE Yutaka
5e33e7f468 fix eventflag 2016-05-18 17:00:25 +09:00
NIIBE Yutaka
db413813b6 eventflag rewrite 2016-05-18 16:52:00 +09:00
NIIBE Yutaka
7f009dbb5d update ChangeLog 2016-05-18 14:43:30 +09:00
NIIBE Yutaka
cea3200e48 Cleanup chopstx.c 2016-05-18 13:27:00 +09:00
NIIBE Yutaka
d93206882d Fix mutex_lock and join 2016-05-18 11:40:15 +09:00
NIIBE Yutaka
a17d12192f Fix example-cdc more 2016-05-18 09:55:23 +09:00
NIIBE Yutaka
4c1aa50f13 Fix example-cdc 2016-05-18 08:51:50 +09:00
NIIBE Yutaka
cf76b0bf13 example-cdc cleanup more 2016-05-17 21:33:58 +09:00
NIIBE Yutaka
76cbff737b example-cdc cleanup 2016-05-17 20:49:17 +09:00
NIIBE Yutaka
dce6c70ffc more fix for chopstx_poll 2016-05-17 17:51:41 +09:00
NIIBE Yutaka
3651aa64b4 ll_dequeue for PX only when not ready 2016-05-16 20:37:33 +09:00
NIIBE Yutaka
98977937cb fix chx_wakeup 2016-05-16 18:00:41 +09:00
NIIBE Yutaka
06d046b963 Improve system routines API for STM32F103 2016-05-16 14:59:05 +09:00
NIIBE Yutaka
b7c6dadcfb Fix IRQ handling and improve cancellation implementation 2016-05-16 14:50:04 +09:00
NIIBE Yutaka
a82acac8df Bug fix for interrupt preemption 2016-05-13 22:27:56 +09:00
NIIBE Yutaka
206f2a5f07 Fix intr_wait 2016-05-13 17:51:12 +09:00
NIIBE Yutaka
5046dd45f2 IRQ handling is now merged into polling 2016-05-13 16:35:35 +09:00
NIIBE Yutaka
db6e668524 more fixes for chopstx_poll 2016-05-13 14:52:38 +09:00
NIIBE Yutaka
daa7aebd6f Add READY field for chx_poll_XXX so that we can check if it's ready 2016-05-13 14:22:12 +09:00
NIIBE Yutaka
5fc2617ae5 Fix changelog 2016-05-13 11:11:01 +09:00
NIIBE Yutaka
fabd271196 Update example-cdc 2016-05-12 18:14:47 +09:00
NIIBE Yutaka
5730641ffd Bug fixes for Cortex-M3 and chopstx_poll 2016-05-12 18:12:52 +09:00
NIIBE Yutaka
5c1638c023 Fix mutex init 2016-05-12 11:17:17 +09:00
NIIBE Yutaka
420bd135af Adding ADC example for FS-BB48 2016-05-11 12:34:17 +09:00
NIIBE Yutaka
a538113c07 change poll behavior 2016-04-24 12:24:36 +09:00
NIIBE Yutaka
8668c8a88a update sys.c in examples 2016-04-22 17:21:50 +09:00
NIIBE Yutaka
fba1dc05ea Clean up FS-BB48 example 2016-04-22 17:21:29 +09:00
NIIBE Yutaka
1b12a78054 Modify chopstx_poll API 2016-04-22 13:42:01 +09:00
NIIBE Yutaka
5d40ffbffa Implement chopstx_poll (2) 2016-04-21 16:10:06 +09:00
NIIBE Yutaka
06d28b62fb Implement chopstx_poll 2016-04-21 15:59:34 +09:00
NIIBE Yutaka
437b2dc43c Update for STM32 2016-04-20 17:30:41 +09:00
NIIBE Yutaka
3eac245981 fix 2016-04-19 16:40:25 +09:00
NIIBE Yutaka
7c2cdaa6e4 Example for FS-BB48 to compute CRC32. 2016-04-19 15:58:26 +09:00
NIIBE Yutaka
0bbb43dd3a Fix USB driver and example 2016-04-18 17:23:10 +09:00
NIIBE Yutaka
82749ab97a Add support for FS-BB48 2016-04-18 11:46:14 +09:00
NIIBE Yutaka
92e17d3bdf USB stack for STM32F103 improvement 2016-04-07 14:52:39 +09:00
NIIBE Yutaka
674c19c495 SVC is required for Cortex-M3 2016-04-07 14:36:41 +09:00
NIIBE Yutaka
35426d7715 Fix MSP initial value and improve chx_sched 2016-04-07 09:59:13 +09:00
NIIBE Yutaka
6db2dd96c5 New function: chopstx_poll 2016-04-06 21:04:24 +09:00
NIIBE Yutaka
5e6a433457 New struct: chx_qh 2016-04-06 20:34:28 +09:00
NIIBE Yutaka
fa8dd7afc8 Don't use SVC for context switch 2016-04-06 19:49:18 +09:00
NIIBE Yutaka
8e40065311 Initialization of chx_spinlock 2016-04-05 19:27:25 +09:00
NIIBE Yutaka
a99c5c6048 fix struct NVIC 2016-04-05 19:17:44 +09:00
NIIBE Yutaka
e092a56c17 Fix USB GET 2016-03-15 10:31:16 +09:00
NIIBE Yutaka
25e5f21847 AAPCS stack alignment 2016-03-08 20:27:24 +09:00
NIIBE Yutaka
90ac7f7c13 update usb stack from Gnuk development branch 2016-03-08 20:20:49 +09:00
NIIBE Yutaka
fd8aee3cb0 CDC to be echo service. 2015-11-05 13:54:49 +09:00
93 changed files with 13775 additions and 2983 deletions

35
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,16 +26,33 @@ Mateusz Zalega:
board/board-nitrokey-start.h
NIIBE Yutaka:
Write the library:
chopstx.c, eventflag.c, entry.c, clk_gpio_init.c
Wrote the library:
chopstx.c, entry.c, eventflag.c,
chopstx.h, eventflag.h
Draw the logo:
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
Drew the logo:
chopstx.svg, chopstx.png
Write examples:
example-led, example-cdc, example-fsm-55
Write board:
Wrote examples:
example-led, example-cdc, example-fsm-55, example-fs-bb48
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,
board-stm32f0-discovery.h, board-fsm-55.h
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

586
ChangeLog
View File

@@ -1,3 +1,583 @@
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.
* doc/chopstx.texi (VERSION): 1.1.
* chopstx.c (chopstx_setpriority): Change the API.
2016-06-30 NIIBE Yutaka <gniibe@fsij.org>
* example-cdc/usb-cdc.c (tty_recv, tty_main): Follow the change of
chopstx_poll.
2016-06-29 NIIBE Yutaka <gniibe@fsij.org>
* example-fs-bb48: Update.
* example-fs-bb48/touch.c: New.
* chopstx.c (chopstx_setpriority): Fix sched_lock/unlock.
2016-06-28 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.h (struct chx_poll_head): Declare here.
* chopstx.c (chopstx_poll): Don't use varargs, but use
an array of pointer.
(chopstx_intr_wait): Follow the change of chopstx_poll.
* eventflag.c (eventflag_wait_timeout): Likewise.
* contrib/adc-stm32f103.c (adc_wait_completion): Likewise.
* contrib/adc-mkl27z.c (adc_wait_completion): Likewise.
2016-06-16 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.0.
* doc/chopstx.texi (VERSION): 1.0.
* board/board-fst-01g.h: New.
2016-06-15 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_exit): Add "naked" attribute.
2016-06-14 Niibe Yutaka <gniibe@fsij.org>
* mcu/usb-stm32f103.c (usb_lld_ctrl_recv): Fix the state and make
the endpoint 0 RX_VALID.
2016-06-10 NIIBE Yutaka <gniibe@fsij.org>
* usb_lld.h (USB_EVENT_OK): Rename.
* mcu/usb-stm32f103.c: Update.
* mcu/usb-mkl27z.c: Likewise.
* example-cdc/usb-cdc.c: Follow the change of API.
* example-fs-bb48/usb-cdc.c: Likewise.
2016-06-09 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-stm32f103.c (usb_lld_ctrl_recv): Rename.
(usb_lld_ctrl_send): Rename.
(usb_lld_ctrl_ack): Rename and let have return value.
* mcu/usb-mkl27z.c: Likewise.
* example-cdc/usb-cdc.c: Follow the change of API.
* example-fs-bb48/usb-cdc.c: Likewise.
2016-06-08 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-stm32f103.c: Rewrite to be event driven API.
* mcu/usb-mkl27z.c: Likewise.
* example-cdc/usb-cdc.c: Update to new USB API.
* example-fs-bb48/usb-cdc.c: Likewise.
* example-cdc/tty.h: Change tty API to be C string (char*)
friendly.
* example-fs-bb48/tty.h: Ditto.
2016-06-02 Niibe Yutaka <gniibe@fsij.org>
* contrib/adc-mkl27z.c: Move from mcu.
* contrib/adc-stm32f103.c: Move from mcu.
* example-led/Makefile (CHIP): Define as stm32f0.
* mcu/sys-stm32f0.h: Rename from sys-stm32f030.h,
as we share it among STM32F030 and STM32F050.
* mcu/sys-stm32f0.c: Likewise.
* board/board-stm32f0-discovery.h (MCU_STM32F0): Define.
* sys.h: Support STM32F0.
2016-06-01 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.h (chx_fatal): Remove weak attribute from declaration.
* chopstx.c (chx_fatal): Add weak attribute to implementation.
2016-05-31 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 0.12.
* doc/chopstx.texi (VERSION): 0.12.
* sys.h: New.
* example-cdc, example-fs-bb48: Update.
* example-fsm-55, example-led: Update.
2016-05-30 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-stm32f103.c (usb_lld_setup_endpoint): Start with
EP_RX_NAK.
* mcu/usb-mkl27z.c (handle_transaction): Handle NAK case.
(usb_lld_setup_endp): Rename from usb_lld_setup_endpoint.
(usb_lld_rx_enable_buf): Rename from usb_lld_rx_enable.
(usb_lld_tx_enable_buf): Rename from usb_lld_tx_enable.
* mcu/adc-stm32f103.c: New from NeuG.
* mcu/stm32f103.h: New from NeuG.
* example-cdc: Update.
2016-05-30 NIIBE Yutaka <gniibe@fsij.org>
* mcu/adc-mkl27z.c, mcu/sys-mkl27z.c, mcu/usb-mkl27z.c: Moved from
example-fs-bb48.
* mcu/adc-stm32f103.c, mcu/sys-stm32f103.c, mcu/usb-stm32f103.c:
Moved from example-cdc.
2016-05-30 NIIBE Yutaka <gniibe@fsij.org>
* example-fs-bb48/sys.c (flash_do_internal, flash_do)
(flash_erase_page, flash_program_word): New.
* example-fs-bb48/command.c (cmd_fes, cmd_fww): New.
2016-05-27 NIIBE Yutaka <gniibe@fsij.org>
* example-fs-bb48/command.c (cmd_sysinfo): New.
* example-fs-bb48/sample.ld: Update.
* example-fs-bb48/sys.h: New.
Move crc32 functions declarations here.
* example-fs-bb48/sys.c: Rename from first-pages.c.
Include mcu/clk_gpio_init-kl.c to define clock_init and
gpio_init.
(set_led): New.
(reset): Initialize MSP.
(flash_config): Include comparison key.
(crc32_init, crc32_u8, crc32_u32): Change the API.
Write them in assembler so that the size of functions
keep unchanged.
(sys_version, sys_board_id, sys_board_name, sys_vector): New.
2016-05-26 NIIBE Yutaka <gniibe@fsij.org>
* entry.c: Follow the move of clk_gpio_init*.c
* example-cdc/sys.c: Likewise.
* example-led/sys.c: Likewise. Update to 3.0.
* example-primer2/sys.c: Update.
* mcu/clk_gpio_init-stm32.c: Moved.
* mcu/clk_gpio_init-kl.c: Moved.
* mcu/kl_sim.h: New (was in example-fs-bb48).
* example-fs-bb48/adc_kl27z.c: Use DMA0 and DMA1.
* example-fs-bb48/adc_kl27z.c (adc_wait_completion): Use only
least significant 8-bit (most significant for randomness).
* example-fs-bb48/command.c (cmd_adc): Rename from
cmd_temperature.
2016-05-24 NIIBE Yutaka <gniibe@fsij.org>
* example-fs-bb48/command.c: New.
* example-fs-bb48: Update example CDC device.
2016-05-23 NIIBE Yutaka <gniibe@fsij.org>
* chopst.x (chx_sched) [__ARM_ARCH_6M__]: Maintain PSR.
2016-05-23 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_poll): Fix a race. Check COUNTER.
* example-cdc/usb-cdc.c (tty_input_char): Include newline.
* example-cdc/sample.c: Handle newline.
* example-fs-bb48/usb-cdc.c: Update from example-cdc.
* example-fs-bb48/tty.h: Likewise.
* example-fs-bb48/sample.c: Follow the change.
2016-05-20 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_usec_wait_var): internal function.
(chopstx_wakeup_usec_wait): Remove.
2016-05-19 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 0.11.
* doc/chopstx.texi (VERSION): 0.11.
2016-05-18 NIIBE Yutaka <gniibe@fsij.org>
* eventflag.c: Update using chopstx_poll and offer API for poll.
* chopstx.c (requeue): New.
(chopstx_mutex_lock, chopstx_join): Fix by requeue.
(chopstx_main_init): Remove.
(chopstx_setpriority): New.
* example-cdc/usb-cdc.c: Prepare for multiple TTYs.
2016-05-17 NIIBE Yutaka <gniibe@fsij.org>
* example-cdc/usb-cdc.c: Update as TTY input/output with line
editing support.
* example-cdc/sample.c: Likewise.
* example-cdc/tty.h: Rename from stream.h.
* chopstx.c (chopstx_poll): Set ->ready = 0.
Add spinlock for ll_dequeue.
2016-05-16 NIIBE Yutaka <gniibe@fsij.org>
* example-cdc/sys.c (nvic_enable_vector): Remove.
(usb_lld_sys_init): Don't setup NVIC priority.
(sys_version): sys version 3.0.
2016-05-16 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.h (CHOPSTX_EXIT_SUCCESS, CHOPSTX_EXIT_CANCELED)
(CHOPSTX_EXIT_CANCELED_IN_SYNC): Remove.
(CHOPSTX_CANCELED): New.
* chopstx.c (chopstx_testcancel): Use CHOPSTX_CANCELED.
(chx_sched, chx_snooze): Re-define return values cleanly.
(chopstx_cancel): Use return value of chx_sched to cancel.
(chopstx_cond_wait, chopstx_join, chopstx_poll): Implement
cancellation rather easier way with return value of chx_sched.
2016-05-15 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_claim_irq): Don't register clean up function.
(chx_release_irq): Remove.
(chopstx_cancel): Disable IRQ when canceled at POLL.
(chopstx_poll): Fix IRQ handling.
2016-05-13 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_handle_intr): Call chx_request_preemption.
(chx_wakeup, chopstx_cond_signal, chopstx_cond_broadcast)
(chx_intr_hook, chopstx_poll): Cleanup.
2016-05-13 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_exit): Don't call chx_release_irq_thread.
(chx_release_irq_thread): Remove.
(q_intr): New variable.
(intr_top): Remove.
(chx_handle_intr, chx_init, chopstx_claim_irq)
(chopstx_intr_wait): Use Q_INTR.
(chx_intr_hook): New.
(chopstx_poll): Support CHOPSTX_POLL_INTR.
(chopstx_release_irq): Remove.
(chx_release_irq): New internal function.
(THREAD_WAIT_INT): Remove.
(chopstx_intr_wait): Rewrite by chopstx_poll.
2016-05-13 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_sched) [__ARM_ARCH_6M__]: Fix asm.
(chx_handle_intr, chx_wakeup, chopstx_cancel): Fix for polling
with no timeout.
* example-cdc/sample.c (main): Update chopstx_poll example.
* example-fs-bb48/sample.c (main): Ditto.
* chopstx.c (struct chx_px): Add READY_P and LOCK.
(chx_proxy_init): Add initialization of new members.
(chx_wakeup): Spinlock PX.
(chopstx_mutex_lock): Add protection by splinlock.
(chx_cond_hook, chx_join_hook): Change arguments.
(chx_cond_unhook, chx_join_unhook): Remove.
(chopstx_claim_irq): Compatible to chx_poll.
(chopstx_join): Fix spinlocking.
(chopstx_cancel): Fix spinlocking.
2016-05-12 NIIBE Yutaka <gniibe@fsij.org>
* example-cdc/sample.c: Update using chopstx_poll.
* example-cdc/sample.ld: Likewise.
* example-cdc/stream.h: Likewise.
* example-cdc/usb-cdc.c: Likewise.
* chopstx.c (chopstx_mutex_init): Initialize OWNER, too.
(preempt) [__ARM_ARCH_7M__]: Bug fix for register 0 to inhibit
scheduling.
(chx_sched) [__ARM_ARCH_6M__]: Return YIELD normally.
(MAX_USEC_FOR_TIMER): Guarantee 24-bit tick.
(chx_snooze): Revert the change of 2016-04-24 and modify
chopstx_poll instead.
(chopstx_poll): Support waiting forever.
2016-04-24 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (chx_snooze): Wait forever when it's POLL and usec==0.
2016-04-22 Niibe Yutaka <gniibe@fsij.org>
* example-fs-bb48/first-pages.c: Rename from reset.c and merge
crc32.c.
* example-fs-bb48/sample.ld: Define section for first two pages.
* example-fs-bb48/usb_kl27z.c (__usb_buf__): Remove.
* chopstx.c (chx_cond_hook): Rename from chopstx_cond_hook and make
it internal.
(chx_cond_unhook): Likewise.
(chx_join_hook, chx_join_unhook): New.
(chopstx_poll): Change API, not exposing internals of hook/unhook.
* example-fs-bb48/sample.c (main): Follow the API change of
chopstx_poll.
2016-04-21 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (chx_snooze, chx_wakeup): New.
(chopstx_cond_hook, chopstx_cond_unhook): New.
(chopstx_cond_signal, chopstx_cond_broadcast): Fix for poll.
(chx_proxy_init): Initialize with RUNNING.
(chopstx_poll): Fix with chx_snooze.
(chx_exit): Use chx_wakeup.
* example-fs-bb48/sample.c (main): Update with chopstx_poll.
* example-fs-bb48/usb-cdc.c (stream_recv): Fix the loop clear
FLAG_RECV_AVAIL only after we process it.
2016-04-20 Niibe Yutaka <gniibe@fsij.org>
* example-cdc/usb_stm32f103.c (usb_lld_reset): Supply FEATURE
argument. Call usb_lld_set_configuration internally and set
FEATURE.
(usb_lld_set_feature): Remove.
* example-cdc/usb-cdc.c (usb_cb_device_reset): Update with new
API.
* example-cdc/sys.c: Include clk_gpio_init-stm32.c.
* example-led/sys.c, example-primer2/sys.c: Ditto.
2016-04-19 Niibe Yutaka <gniibe@fsij.org>
* example-fs-bb48/sample.c (main): Change the example to display
CRC32 value from input line.
2016-04-18 Niibe Yutaka <gniibe@fsij.org>
* example-fs-bb48: New directory for FS-BB48.
* clk_gpio_init-kl.c: New.
* clk_gpio_init-stm32.c: Rename from clk_gpio_init.c.
2016-04-07 Niibe Yutaka <gniibe@fsij.org>
* example-fsm-55/sys.c: Update for non-SVC Chopstx.
2016-04-07 Niibe Yutaka <gniibe@fsij.org>
* example-cdc/usb-cdc.c: Update.
* example-cdc/usb_stm32f103.c (usb_handle_transfer): Don't use
weak symbols for callbacks, but use explicit callbacks of
usb_cb_tx_done and usb_cb_rx_ready.
* example-cdc/usb_lld.h (usb_cb_tx_done, usb_cb_rx_ready): New
callbacks.
2016-04-07 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (chx_cpu_sched_lock, chx_cpu_sched_unlock): Use SVC
for Cortex-M3, because of ICI/IT of ESPR.
(chx_sched): Invoke svc for Cortex-M3.
(preempt, svc): Change back for Cortex-M3.
2016-04-07 Niibe Yutaka <gniibe@fsij.org>
* entry.c (vector_table): Since IDLE thread runs with PSP now, use
different value for MSP.
* chopstx.c (chx_sched): Push LR value to PC slot on stack, so
that it returns directly to caller.
2016-04-06 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (struct chx_pq): New struct for priority queue.
(struct chx_px): New struct for proxy.
(struct chx_thread): New member FLAG_IS_PROXY.
(ll_dequeue, ll_insert, ll_pop, ll_prio_push, ll_prio_enqueue)
Change API.
(THREAD_WAIT_POLL): New thread status.
(chx_ready_pop, chx_ready_push, chx_ready_enqueue): Type coercion.
(chx_timer_insert, chx_timer_dequeue, chx_timer_expired): Use
chx_pq.
(chx_handle_intr, chopstx_cancel): Handle THREAD_WAIT_POLL.
(chx_init): Type coercion.
(chx_exit): Handle proxy for join.
(chopstx_create): Initialize the member FLAG_IS_PROXY.
(chopstx_cond_signal) Handle proxy.
(chx_proxy_init, chopstx_poll): New.
2016-04-06 Niibe Yutaka <gniibe@fsij.org>
* chopstx.h (struct chx_qh): New struct.
* chopstx.c (struct chx_queue): Use chx_qh.
(struct chx_thread): New member PARENT.
(ll_empty): Use chx_qh.
(ll_prio_push, ll_prio_enqueue): Set the member PARENT.
(chx_ready_pop, chx_ready_push, chx_ready_enqueue): Use the
member Q.
(chx_timer_insert): Return TP.
(chx_timer_dequeue, chx_timer_expired): Use the member Q.
(chx_init): Initialize change for Q_READY, Q_TIMER, Q_JOIN.
(chx_sched, preempt): Handle return value of chx_timer_insert.
(chx_exit, chopstx_mutex_init, chopstx_cond_init): Use the member Q.
(chx_mutex_unlock): Type coercion to CHX_THREAD.
(chopstx_create): Initialize PARENT field.
(chopstx_mutex_lock): Use the PARENT field.
(chopstx_join): Use ll_prio_enqueue, instead of ll_insert.
(chopstx_wakeup_usec_wait): Set REG_R0 on the stack.
2016-04-06 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (struct chx_thread): Move tcontext field.
(chx_cpu_sched_lock, chx_cpu_sched_unlock): Use CPSID/CPSIE.
(chx_sched): Don't use SVC. Return integer value.
(chopstx_usec_wait_var): Don't use R8.
(preempt): Modify so that we don't use SVC.
2016-04-05 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (struct NVIC): Add volatile qualifier to members.
(chx_spin_init): New.
(chopstx_mutex_init, chopstx_cond_init): Call chx_spin_init.
(chx_init): Initialize the spinlocks for INTR_LOCK, Q_READY,
Q_TIMER, and Q_JOIN.
2016-03-08 Niibe Yutaka <gniibe@fsij.org>
* chopstx.h (CHOPSTX_THREAD_SIZE): Align by 8.
* chopstx.c (struct chx_thread): Add W field to align. This is to
comply AAPCS (ARM Architecture Procedure Call Standard).
(chx_init): Initialize W.
* example-cdc/usb_stm32f103.c, usb_lld.h: Update from Gnuk.
* example-cdc/usb-cdc.c: Update.
2015-11-05 Niibe Yutaka <gniibe@fsij.org>
* example-cdc/sample.c: Enhanced to be echo service.
2015-09-15 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 0.10.
@@ -9,7 +589,7 @@
* chopstx.c (q_exit): Remove.
(chx_init, chx_exit): Remove access to Q_EXIT.
(chx_release_irq_thread): Fix removing form the list.
(chx_release_irq_thread): Fix removing from the list.
2015-09-11 Niibe Yutaka <gniibe@fsij.org>
@@ -79,7 +659,7 @@
* example-fsm-55/hacker-emblem.ld: Put vectors on ROM.
* example-fsm-55/sys.c: No system services.
* entry.c (entry): Can be public.
* clk_gpio_init.c [MCU_STM32F0] (clock_init): Don't change CFGR1.
* clk_gpio_init.c (clock_init) [MCU_STM32F0]: Don't change CFGR1.
2015-07-30 Niibe Yutaka <gniibe@fsij.org>
@@ -109,7 +689,7 @@
* example-cdc/sys.c (sys_board_id): New.
* example-cdc/sample.ld (.sys.board_id): New.
(__flash_start__, __flash_end__): Remove.
* entry.c [HAVE_SYS_H] (vector_table): By undefining STM32F10X_MD,
* entry.c (vector_table) [HAVE_SYS_H]: By undefining STM32F10X_MD,
prepare for high density device even compiled for MD device.
2015-07-13 Kaz Kojima <kkojima@rr.iij4u.or.jp>

127
NEWS
View File

@@ -1,6 +1,133 @@
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
** API change: chopstx_poll
In version 1.0, chopstx_poll has variable arguments. It found that
it's challenging for ffi or lower level C implementation, if C
compiler is new for the specific MCU target. Another example is that
a program touches FPU registers for varargs, even if no argument is
float. So, we decided to avoid use of varargs in Chopstx.
** API change: chopstx_setpriority
In version 1.0, chopstx_setpriority does not return value. It is
changed to return old value of the priority.
* Major changes in Chopstx 1.0
Released 2016-06-16
** New USB API
Now, USB driver is included in Chopstx. So, it should be good one.
It used to be the code which was derived from interrupt driven API
with callbacks. It's changed to event driven API, so that a user can
do as wish, beyond the restriction of callbacks.
** New board support: FST-01G
FST-01G is a new revision of original FST-01 with fixed pull-up of
D+ line.
* Major changes in Chopstx 0.12
Released 2016-05-31
** Provide drivers of SYS, USB and ADC
Those were only offered as examples, but now, Chopstx provides drivers
of SYS, USB, and ADC. Please note that the ADC driver is not for
general use (it's specific to NeuG to get noise). To use them, enable
variables in Makefile, like following.
------------
CHIP=stm32f103
USE_ADC = yes
USE_USB = yes
USE_SYS = yes
DEFS = -DUSE_SYS3
------------
** Removal of chopstx_usec_wait_var chopstx_wakeup_usec_wait
This API was used when we need to wait something with timeout.
Now, we have better API with chopstx_poll. Please use chopstx_poll
and chopstx_cond_signal.
* Major changes in Chopstx 0.11
Released 2016-05-19
** New feature: polling
New function chopstx_poll is added to watch multiple condition
variables, threads' exit, or IRQ, simultaneously with timeout.
** Change API of eventflag
The initialization function eventflag_init only has an argument of EV.
An eventflag can be waited with timeout or can be waited with no
timeout, as caller like. It is not determined at initialization time
now. Besides, the eventflag can be waited by any threads. Functions
to poll eventflag together with other events (cond, join, and IRQ) are
provided.
** Removal of the function chopstx_release_irq
IRQ is enabled only when a thread is blocked in polling. When it (the
thread in polling) is canceled, IRQ is disabled.
** Removal of the function chopstx_main_init
It is removed because it's too special. Please use
chopstx_setpriority instead.
** New function: chopstx_setpriority
This function is not recommended in general. It is only added to
support the usage when main thread wants to change the schedule
priority after creating other threads.
** Function chopstx_intr_wait is deprecated
Use of chopstx_poll is recommended.
** FS-BB48: Kinetis L MCU
Support for FS-BB48 board with Kinetis L MCU is added.
** No HardFault at context switch on Cortex-M0
By its design, Chopstx does context switch holding the scheduler lock.
This is implemented with the feature of BASEPRI on Cortex-M3. Because
Cortex-M0 doesn't have support of BASEPRI, the context switch (before
version 0.11) always caused HardFault exception. Since Cortex-M0
doesn't have complex exception mechism of ICI/IT (which is supported
on Cortex-M3), it is actually possible to implement the context switch
in user mode. This is done.
** New sys.c (3.0)
Don't touch NVIC in usb_lld_sys_init.
* Major changes in Chopstx 0.10
Released 2015-09-15

17
README
View File

@@ -1,14 +1,15 @@
Chopstx - Threads and only Threads
Version 0.10
2015-09-15
Version 1.4
2017-08-11
Niibe Yutaka
Flying Stone Technology
What's Chopstx?
===============
Chopstx is an RT thread library for STM32F103 (ARM Cortex-M3)
or STM32F0 (ARM Cortex-M0).
Chopstx is an RT thread library for STM32F103 (ARM Cortex-M3),
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.
@@ -45,7 +46,11 @@ For STM32 Primer2, see the directory: example-primer2.
Future Works
============
Convenience function to determine bottom of thread stack, thread local
storage and support of interface like poll/select would be next thing
Convenience function to determine the bottom of thread stack,
configuration of thread size by comiler's output would be next things
to be done.
Experimental SMP port for Cortex-A7 is under development. For SMP,
more careful considerations for shared access to objects of struct
chx_pq is needed. So, modifications required will not be small.
--

View File

@@ -1 +1 @@
release/0.10
release/1.4

8
adc.h Normal file
View File

@@ -0,0 +1,8 @@
int adc_init (void);
void adc_start (void);
void adc_stop (void);
extern uint32_t adc_buf[64];
void adc_start_conversion (int offset, int count);
int adc_wait_completion (void);

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)

5
board/board-fs-bb48.h Normal file
View File

@@ -0,0 +1,5 @@
#define BOARD_NAME "FS-BB48"
#define BOARD_ID 0xd1f5119c
/* echo -n "FST-01" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
#define MCU_KINETIS_L 1

84
board/board-fst-01g.h Normal file
View File

@@ -0,0 +1,84 @@
#define BOARD_NAME "FST-01G"
#define BOARD_ID 0x8801277f
/* echo -n "FST-01G" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
#define STM32_HSECLK 12000000
#define GPIO_LED_BASE GPIOB_BASE
#define GPIO_LED_SET_TO_EMIT 0
#define GPIO_USB_BASE GPIOA_BASE
#undef GPIO_OTHER_BASE
/*
* Port A setup.
* PA0 - input with pull-up (TIM2_CH1): AN0 for NeuG
* PA1 - input with pull-down (TIM2_CH2)
* PA2 - input with pull-up (TIM2_CH3) connected to CIR module
* PA3 - input with pull-up: external pin available to user
* PA4 - Push pull output (SPI1_NSS)
* PA5 - Alternate Push pull output (SPI1_SCK)
* PA6 - Alternate Push pull output (SPI1_MISO)
* PA7 - Alternate Push pull output (SPI1_MOSI)
* PA10 - Push pull output 1 default
* (so that binary for FST-01G also works on FST-01)
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
* ------------------------ Default
* PA8 - input with pull-up.
* PA9 - input with pull-up.
* PA13 - input with pull-up.
* PA14 - input with pull-up.
* PA15 - input with pull-up.
*/
#define VAL_GPIO_USB_ODR 0xFFFFE7FD
#define VAL_GPIO_USB_CRL 0xBBB38888 /* PA7...PA0 */
#define VAL_GPIO_USB_CRH 0x88811388 /* PA15...PA8 */
/*
* Port B setup.
* PB0 - Push pull output (LED 1:ON 0:OFF)
* PB1 - input with pull-up: AN9 for NeuG
* ------------------------ Default
* PBx - input with pull-up.
*/
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
#define VAL_GPIO_LED_CRL 0x88888883 /* PA7...PA0 */
#define VAL_GPIO_LED_CRH 0x88888888 /* PA15...PA8 */
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN)
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST)
/*
* Board specific information other than clock and GPIO initial
* setting should not be in board-*.h, but each driver should include
* information by itself.
*
* Please see NeuG's ADC driver how board specific handling is done.
*
* Given the situation of Chopstx's boards support, which is not that
* huge, this works well. If scalability and flexibility will matter,
* we will need something like device tree in which boot process can
* pass information to application program.
*
* Following constants are here, because experimental CIR driver is
* written before this design decision of Chopstx.
*
* Those will be removed soon, once such an driver will be improved
* in new style.
*/
/* For pin-cir settings of Gnuk */
#define TIMx TIM2
#define INTR_REQ_TIM TIM2_IRQ
#define AFIO_EXTICR_INDEX 0
#define AFIO_EXTICR1_EXTIx_Py AFIO_EXTICR1_EXTI2_PA
#define EXTI_PR EXTI_PR_PR2
#define EXTI_IMR EXTI_IMR_MR2
#define EXTI_FTSR_TR EXTI_FTSR_TR2
#define INTR_REQ_EXTI EXTI2_IRQ
#define ENABLE_RCC_APB1
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM2EN
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM2RST

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.
*/

View File

@@ -1,6 +1,8 @@
#define BOARD_NAME "STM32F0 Discovery"
#define BOARD_ID 0xde4b4bc1
#define MCU_STM32F0 1
/*
* Running at 48MHz with HSI as clock source.
*

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;

1416
chopstx.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* chopstx.h - Threads and only threads.
*
* Copyright (C) 2013 Flying Stone Technology
* Copyright (C) 2013, 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -26,17 +26,20 @@
*
*/
typedef uint32_t chopstx_t;
struct chx_qh {
struct chx_pq *next, *prev;
};
typedef uintptr_t chopstx_t;
typedef uint8_t chopstx_prio_t;
extern chopstx_t chopstx_main;
void chopstx_main_init (chopstx_prio_t);
/* 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
@@ -44,8 +47,6 @@ chopstx_create (uint32_t flags_and_prio,
#define CHOPSTX_PRIO_INHIBIT_PREEMPTION 248
void chopstx_usec_wait_var (uint32_t *arg);
void chopstx_usec_wait (uint32_t usec);
struct chx_spinlock {
@@ -53,9 +54,7 @@ struct chx_spinlock {
};
typedef struct chx_mtx {
struct {
struct chx_thread *next, *prev;
} q;
struct chx_qh q;
struct chx_spinlock lock;
struct chx_thread *owner;
struct chx_mtx *list;
@@ -69,9 +68,7 @@ void chopstx_mutex_lock (chopstx_mutex_t *mutex);
void chopstx_mutex_unlock (chopstx_mutex_t *mutex);
typedef struct chx_cond {
struct {
struct chx_thread *next, *prev;
} q;
struct chx_qh q;
struct chx_spinlock lock;
} chopstx_cond_t;
@@ -82,25 +79,13 @@ void chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex);
void chopstx_cond_signal (chopstx_cond_t *cond);
void chopstx_cond_broadcast (chopstx_cond_t *cond);
typedef struct chx_intr {
struct chx_intr *next;
struct chx_thread *tp;
uint32_t ready;
uint8_t irq_num;
} chopstx_intr_t;
void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num);
void chopstx_release_irq (chopstx_intr_t *intr);
void chopstx_intr_wait (chopstx_intr_t *intr);
/*
* Library provides default implementation as weak reference.
* User can replace it.
*/
void chx_fatal (uint32_t err_code) __attribute__((__weak__, __noreturn__));
void chx_fatal (uint32_t err_code) __attribute__((__noreturn__));
void chopstx_join (chopstx_t, void **);
int chopstx_join (chopstx_t, void **);
void chopstx_exit (void *retval) __attribute__((__noreturn__));
@@ -110,11 +95,7 @@ enum {
CHOPSTX_ERR_JOIN,
};
enum {
CHOPSTX_EXIT_SUCCESS = 0,
CHOPSTX_EXIT_CANCELED = 256,
CHOPSTX_EXIT_CANCELED_IN_SYNC = 257,
};
#define CHOPSTX_CANCELED ((void *) -1)
void chopstx_cancel (chopstx_t thd);
void chopstx_testcancel (void);
@@ -122,17 +103,61 @@ void chopstx_testcancel (void);
/* NOTE: This signature is different to PTHREAD's one. */
int chopstx_setcancelstate (int);
struct chx_cleanup {
typedef struct chx_cleanup {
struct chx_cleanup *next;
void (*routine) (void *);
void *arg;
};
} chopstx_cleanup_t;
/* NOTE: This signature is different to PTHREAD's one. */
void chopstx_cleanup_push (struct chx_cleanup *clp);
void chopstx_cleanup_push (chopstx_cleanup_t *clp);
void chopstx_cleanup_pop (int execute);
chopstx_prio_t chopstx_setpriority (chopstx_prio_t);
void chopstx_wakeup_usec_wait (chopstx_t thd);
enum {
CHOPSTX_POLL_COND = 0,
CHOPSTX_POLL_INTR,
CHOPSTX_POLL_JOIN,
};
#define CHOPSTX_THREAD_SIZE 60
struct chx_poll_head {
uint16_t type;
uint16_t ready;
};
struct chx_poll_cond {
uint16_t type;
uint16_t ready;
/**/
chopstx_cond_t *cond;
chopstx_mutex_t *mutex;
int (*check) (void *);
void *arg;
};
typedef struct chx_poll_cond chopstx_poll_cond_t;
struct chx_poll_join {
uint16_t type;
uint16_t ready;
/**/
chopstx_t thd;
};
typedef struct chx_poll_join chopstx_poll_join_t;
struct chx_intr {
uint16_t type;
uint16_t ready;
/**/
uint8_t irq_num;
};
typedef struct chx_intr chopstx_intr_t;
void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num);
void chopstx_intr_wait (chopstx_intr_t *intr); /* DEPRECATED */
int chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *pd_array[]);
#define CHOPSTX_THREAD_SIZE 64

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;
}

321
contrib/adc-mkl27z.c Normal file
View File

@@ -0,0 +1,321 @@
/*
* adc-mkl27z.c - ADC driver for MKL27Z
* In this ADC driver, there are NeuG specific parts.
* It only records lower 8-bit of 16-bit data.
* You need to modify to use this as generic ADC driver.
*
* Copyright (C) 2016 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 <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <mcu/mkl27z.h>
struct DMAMUX {
volatile uint32_t CHCFG0;
volatile uint32_t CHCFG1;
volatile uint32_t CHCFG2;
volatile uint32_t CHCFG3;
};
static struct DMAMUX *const DMAMUX = (struct DMAMUX *)0x40021000;
#define INTR_REQ_DMA0 0
struct DMA {
volatile uint32_t SAR;
volatile uint32_t DAR;
volatile uint32_t DSR_BCR;
volatile uint32_t DCR;
};
static struct DMA *const DMA0 = (struct DMA *)0x40008100;
static struct DMA *const DMA1 = (struct DMA *)0x40008110;
/* We don't use ADC interrupt. Just for reference. */
#define INTR_REQ_ADC 15
struct ADC {
volatile uint32_t SC1[2];/* Status and Control Registers 1 */
volatile uint32_t CFG1; /* Configuration Register 1 */
volatile uint32_t CFG2; /* Configuration Register 2 */
volatile uint32_t R[2]; /* Data Result Register */
/* Compare Value Registers 1, 2 */
volatile uint32_t CV1;
volatile uint32_t CV2;
volatile uint32_t SC2; /* Status and Control Register 2 */
volatile uint32_t SC3; /* Status and Control Register 3 */
volatile uint32_t OFS; /* Offset Correction Register */
volatile uint32_t PG; /* Plus-Side Gain Register */
volatile uint32_t MG; /* Minus-Side Gain Register */
/* Plus-Side General Calibration Value Registers */
volatile uint32_t CLPD;
volatile uint32_t CLPS;
volatile uint32_t CLP4;
volatile uint32_t CLP3;
volatile uint32_t CLP2;
volatile uint32_t CLP1;
volatile uint32_t CLP0;
uint32_t rsvd0;
/* Minus-Side General Calibration Value Registers */
volatile uint32_t CLMD;
volatile uint32_t CLMS;
volatile uint32_t CLM4;
volatile uint32_t CLM3;
volatile uint32_t CLM2;
volatile uint32_t CLM1;
volatile uint32_t CLM0;
};
static struct ADC *const ADC0 = (struct ADC *)0x4003B000;
/* SC1 */
#define ADC_SC1_DIFF (1 << 5)
#define ADC_SC1_AIEN (1 << 6)
#define ADC_SC1_COCO (1 << 7)
#define ADC_SC1_TEMPSENSOR 26
#define ADC_SC1_BANDGAP 27
#define ADC_SC1_ADCSTOP 31
/* CFG1 */
#define ADC_CLOCK_SOURCE_ASYNCH (3 << 0)
#define ADC_MODE_16BIT (3 << 2)
#define ADC_ADLSMP_SHORT (0 << 4)
#define ADC_ADLSMP_LONG (1 << 4)
#define ADC_ADIV_1 (0 << 5)
#define ADC_ADIV_8 (3 << 5)
#define ADC_ADLPC_NORMAL (0 << 7)
#define ADC_ADLPC_LOWPOWER (1 << 7)
/**/
#define ADC_CLOCK_SOURCE ADC_CLOCK_SOURCE_ASYNCH
#define ADC_MODE ADC_MODE_16BIT
#define ADC_ADLSMP ADC_ADLSMP_SHORT
#define ADC_ADIV ADC_ADIV_1
#define ADC_ADLPC ADC_ADLPC_LOWPOWER
/* CFG2 */
#define ADC_ADLSTS_DEFAULT 0 /* 24 cycles if CFG1.ADLSMP=1, 4 if not. */
#define ADC_ADHSC_NORMAL (0 << 2)
#define ADC_ADHSC_HIGHSPEED (1 << 2)
#define ADC_ADACK_DISABLE (0 << 3)
#define ADC_ADACK_ENABLE (1 << 3)
#define ADC_MUXSEL_A (0 << 4)
#define ADC_MUXSEL_B (1 << 4)
/**/
#define ADC_ADLSTS ADC_ADLSTS_DEFAULT
#define ADC_ADHSC ADC_ADHSC_NORMAL
#define ADC_ADACKEN ADC_ADACK_ENABLE
#define ADC_MUXSEL ADC_MUXSEL_A
/* SC2 */
#define ADC_SC2_REFSEL_DEFAULT 1 /* Internal Voltage Reference??? */
#define ADC_SC2_DMAEN (1 << 2)
#define ADC_SC2_ACREN (1 << 3)
#define ADC_SC2_ACFGT (1 << 4)
#define ADC_SC2_ACFE (1 << 5)
#define ADC_SC2_ADTRG (1 << 6) /* For hardware trigger */
/* SC3 */
#define ADC_SC3_AVGS11 0x03
#define ADC_SC3_AVGE (1 << 2)
#define ADC_SC3_ADCO (1 << 3)
#define ADC_SC3_CALF (1 << 6)
#define ADC_SC3_CAL (1 << 7)
#define ADC_DMA_SLOT_NUM 40
/*
* Buffer to save ADC data.
*/
uint32_t adc_buf[64];
static const uint32_t adc0_sc1_setting = ADC_SC1_TEMPSENSOR;
static chopstx_intr_t adc_intr;
struct adc_internal {
uint32_t buf[64];
uint8_t *p;
int phase : 8;
int count : 8;
};
struct adc_internal adc;
/*
* Initialize ADC module, do calibration.
*
* This is called by MAIN, only once, hopefully before creating any
* other threads (to be accurate).
*
* We configure ADC0 to kick DMA0, configure DMA0 to kick DMA1.
* DMA0 records output of ADC0 to the ADC.BUF.
* DMA1 kicks ADC0 again to get another value.
*
* ADC0 --[finish conversion]--> DMA0 --[Link channel 1]--> DMA1
*/
int
adc_init (void)
{
uint32_t v;
/* Enable ADC0 and DMAMUX clock. */
SIM->SCGC6 |= (1 << 27) | (1 << 1);
/* Enable DMA clock. */
SIM->SCGC7 |= (1 << 8);
/* ADC0 setting for calibration. */
ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC;
ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL;
ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT;
ADC0->SC3 = ADC_SC3_CAL | ADC_SC3_CALF | ADC_SC3_AVGE | ADC_SC3_AVGS11;
/* Wait ADC completion */
while ((ADC0->SC1[0] & ADC_SC1_COCO) == 0)
if ((ADC0->SC3 & ADC_SC3_CALF) != 0)
/* Calibration failure */
return -1;
if ((ADC0->SC3 & ADC_SC3_CALF) != 0)
/* Calibration failure */
return -1;
/* Configure PG by the calibration values. */
v = ADC0->CLP0 + ADC0->CLP1 + ADC0->CLP2 + ADC0->CLP3 + ADC0->CLP4 + ADC0->CLPS;
ADC0->PG = 0x8000 | (v >> 1);
/* Configure MG by the calibration values. */
v = ADC0->CLM0 + ADC0->CLM1 + ADC0->CLM2 + ADC0->CLM3 + ADC0->CLM4 + ADC0->CLMS;
ADC0->MG = 0x8000 | (v >> 1);
ADC0->SC1[0] = ADC_SC1_ADCSTOP;
/* DMAMUX setting. */
DMAMUX->CHCFG0 = (1 << 7) | ADC_DMA_SLOT_NUM;
/* DMA0 initial setting. */
DMA0->SAR = (uint32_t)&ADC0->R[0];
/* DMA1 initial setting. */
DMA1->SAR = (uint32_t)&adc0_sc1_setting;
DMA1->DAR = (uint32_t)&ADC0->SC1[0];
chopstx_claim_irq (&adc_intr, INTR_REQ_DMA0);
return 0;
}
/*
* Start using ADC.
*/
void
adc_start (void)
{
ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC;
ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL;
ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT | ADC_SC2_DMAEN;
ADC0->SC3 = 0;
}
/*
* Kick getting data for COUNT times.
* Data will be saved in ADC_BUF starting at OFFSET.
*/
static void
adc_start_conversion_internal (int count)
{
/* DMA0 setting. */
DMA0->DAR = (uint32_t)&adc.buf[0];
DMA0->DSR_BCR = 4 * count;
DMA0->DCR = (1 << 31) | (1 << 30) | (1 << 29) | (0 << 20) | (1 << 19)
| (0 << 17) | (1 << 7) | (2 << 4) | (1 << 2);
/* Kick DMA1. */
DMA1->DSR_BCR = 4 * count;
DMA1->DCR = (1 << 30) | (1 << 29) | (0 << 19) | (0 << 17) | (1 << 16) | (1 << 7);
}
/*
* Kick getting data for COUNT times.
* Data will be saved in ADC_BUF starting at OFFSET.
*/
void
adc_start_conversion (int offset, int count)
{
adc.p = (uint8_t *)&adc_buf[offset];
adc.phase = 0;
adc.count = count;
adc_start_conversion_internal (count);
}
static void
adc_stop_conversion (void)
{
ADC0->SC1[0] = ADC_SC1_ADCSTOP;
}
/*
* Stop using ADC.
*/
void
adc_stop (void)
{
SIM->SCGC6 &= ~(1 << 27);
}
/*
* Return 0 on success.
* Return 1 on error.
*/
int
adc_wait_completion (void)
{
struct chx_poll_head *pd_array[1] = { (struct chx_poll_head *)&adc_intr };
int i;
while (1)
{
/* Wait DMA completion */
chopstx_poll (NULL, 1, pd_array);
DMA0->DSR_BCR = (1 << 24);
DMA1->DSR_BCR = (1 << 24);
adc_stop_conversion ();
for (i = 0; i < adc.count; i++)
*adc.p++ = (uint8_t)adc.buf[i];
if (++adc.phase >= 4)
break;
adc_start_conversion_internal (adc.count);
}
return 0;
}

329
contrib/adc-stm32f103.c Normal file
View File

@@ -0,0 +1,329 @@
/*
* adc_stm32f103.c - ADC driver for STM32F103
* In this ADC driver, there are NeuG specific parts.
* You need to modify to use this as generic ADC driver.
*
* Copyright (C) 2011, 2012, 2013, 2015, 2016
* 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 <mcu/stm32f103.h>
#include "adc.h"
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#define ADC_SMPR1_SMP_VREF(n) ((n) << 21)
#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18)
#define ADC_SMPR1_SMP_AN10(n) ((n) << 0)
#define ADC_SMPR1_SMP_AN11(n) ((n) << 3)
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0)
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3)
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6)
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27)
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
#define ADC_SQR3_SQ1_N(n) ((n) << 0)
#define ADC_SQR3_SQ2_N(n) ((n) << 5)
#define ADC_SQR3_SQ3_N(n) ((n) << 10)
#define ADC_SQR3_SQ4_N(n) ((n) << 15)
#define ADC_SAMPLE_1P5 0
#define ADC_CHANNEL_IN0 0
#define ADC_CHANNEL_IN1 1
#define ADC_CHANNEL_IN2 2
#define ADC_CHANNEL_IN9 9
#define ADC_CHANNEL_IN10 10
#define ADC_CHANNEL_IN11 11
#define ADC_CHANNEL_SENSOR 16
#define ADC_CHANNEL_VREFINT 17
#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
#define DELIBARATELY_DO_IT_WRONG_START_STOP
#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
#define ADC_SAMPLE_SENSOR ADC_SAMPLE_1P5
#else
#define ADC_SAMPLE_VREF ADC_SAMPLE_239P5
#define ADC_SAMPLE_SENSOR ADC_SAMPLE_239P5
#endif
#define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1
#define NEUG_DMA_MODE \
( STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY) \
| STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD \
| STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE \
| STM32_DMA_CR_TEIE )
#define NEUG_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF) \
| ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR)
#define NEUG_ADC_SETTING1_SMPR2 0
#define NEUG_ADC_SETTING1_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) \
| ADC_SQR3_SQ3_N(ADC_CHANNEL_SENSOR) \
| ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT)
#define NEUG_ADC_SETTING1_NUM_CHANNELS 4
/*
* ADC finish interrupt
*/
#define INTR_REQ_DMA1_Channel1 11
static chopstx_intr_t adc_intr;
/*
* Do calibration for both of ADCs.
*/
int
adc_init (void)
{
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
RCC->APB2RSTR = (RCC_APB2RSTR_ADC1RST | RCC_APB2RSTR_ADC2RST);
RCC->APB2RSTR = 0;
ADC1->CR1 = 0;
ADC1->CR2 = ADC_CR2_ADON;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
;
ADC1->CR2 = 0;
ADC2->CR1 = 0;
ADC2->CR2 = ADC_CR2_ADON;
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC2->CR2 & ADC_CR2_CAL) != 0)
;
ADC2->CR2 = 0;
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
chopstx_claim_irq (&adc_intr, INTR_REQ_DMA1_Channel1);
return 0;
}
#include "board.h"
#include "sys.h"
static void
get_adc_config (uint32_t config[4])
{
config[2] = ADC_SQR1_NUM_CH(2);
switch (SYS_BOARD_ID)
{
case BOARD_ID_FST_01:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9);
break;
case BOARD_ID_OLIMEX_STM32_H103:
case BOARD_ID_STBEE:
config[0] = ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5)
| ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5);
config[1] = 0;
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11);
break;
case BOARD_ID_STBEE_MINI:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2);
break;
case BOARD_ID_CQ_STARM:
case BOARD_ID_FST_01_00:
case BOARD_ID_MAPLE_MINI:
case BOARD_ID_STM32_PRIMER2:
case BOARD_ID_STM8S_DISCOVERY:
case BOARD_ID_ST_DONGLE:
case BOARD_ID_ST_NUCLEO_F103:
case BOARD_ID_NITROKEY_START:
default:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1);
break;
}
}
void
adc_start (void)
{
uint32_t config[4];
get_adc_config (config);
/* Use DMA channel 1. */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE;
DMA1->IFCR = 0xffffffff;
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
| ADC_CR1_SCAN);
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1;
ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
ADC1->SQR2 = 0;
ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
| ADC_CR1_SCAN);
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC2->SMPR1 = config[0];
ADC2->SMPR2 = config[1];
ADC2->SQR1 = config[2];
ADC2->SQR2 = 0;
ADC2->SQR3 = config[3];
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
/*
* We could just let ADC run continuously always and only enable DMA
* to receive stable data from ADC. But our purpose is not to get
* correct data but noise. In fact, we can get more noise when we
* start/stop ADC each time.
*/
ADC2->CR2 = 0;
ADC1->CR2 = 0;
#else
/* Start conversion. */
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
#endif
}
uint32_t adc_buf[64];
void
adc_start_conversion (int offset, int count)
{
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
DMA1_Channel1->CMAR = (uint32_t)&adc_buf[offset]; /* SetMemory0 */
DMA1_Channel1->CNDTR = count; /* Counter */
DMA1_Channel1->CCR = NEUG_DMA_MODE | DMA_CCR1_EN; /* Mode */
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
/* Power on */
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
/*
* Start conversion. tSTAB is 1uS, but we don't follow the spec, to
* get more noise.
*/
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
#endif
}
static void adc_stop_conversion (void)
{
DMA1_Channel1->CCR &= ~DMA_CCR1_EN;
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
ADC2->CR2 = 0;
ADC1->CR2 = 0;
#endif
}
void
adc_stop (void)
{
ADC1->CR1 = 0;
ADC1->CR2 = 0;
ADC2->CR1 = 0;
ADC2->CR2 = 0;
RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
}
static uint32_t adc_err;
/*
* Return 0 on success.
* Return 1 on error.
*/
int
adc_wait_completion (void)
{
uint32_t flags;
struct chx_poll_head *pd_array[1] = { (struct chx_poll_head *)&adc_intr };
while (1)
{
chopstx_poll (NULL, 1, pd_array);
flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause. */
/*
* Clear interrupt cause of channel 1.
*
* Note that CGIFx=0, as CGIFx=1 clears all of GIF, HTIF, TCIF
* and TEIF.
*/
DMA1->IFCR = (flags & ~1);
if ((flags & STM32_DMA_ISR_TEIF) != 0) /* DMA errors */
{
/* Should never happened. If any, it's coding error. */
/* Access an unmapped address space or alignment violation. */
adc_err++;
adc_stop_conversion ();
return 1;
}
else if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
{
adc_stop_conversion ();
return 0;
}
}
}

View File

@@ -7,16 +7,6 @@ When it detects a coding error, this function will be called to
stop further execution of code. It never returns.
@end deftypefun
@subheading chopstx_main_init
@anchor{chopstx_main_init}
@deftypefun {void} {chopstx_main_init} (chopstx_prio_t @var{prio})
@var{prio}: priority
Initialize main thread with @var{prio}.
The thread main is created with priority CHX_PRIO_MAIN_INIT,
and it runs with that priority until this routine will is called.
@end deftypefun
@subheading chopstx_create
@anchor{chopstx_create}
@deftypefun {chopstx_t} {chopstx_create} (uint32_t @var{flags_and_prio}, uint32_t @var{stack_addr}, size_t @var{stack_size}, voidfunc @var{thread_entry}, void * @var{arg})
@@ -33,15 +23,6 @@ and it runs with that priority until this routine will is called.
Create a thread. Returns thread ID.
@end deftypefun
@subheading chopstx_usec_wait_var
@anchor{chopstx_usec_wait_var}
@deftypefun {void} {chopstx_usec_wait_var} (uint32_t * @var{var})
@var{var}: Pointer to usec
Sleep for micro seconds, specified by @var{var}.
Another thread can clear @var{var} to stop the caller going into sleep.
@end deftypefun
@subheading chopstx_usec_wait
@anchor{chopstx_usec_wait}
@deftypefun {void} {chopstx_usec_wait} (uint32_t @var{usec})
@@ -115,15 +96,7 @@ Wake up all threads waiting on @var{cond}.
@var{irq_num}: IRQ Number (hardware specific)
Claim interrupt @var{intr} with @var{irq_num} for this thread.
@end deftypefun
@subheading chopstx_release_irq
@anchor{chopstx_release_irq}
@deftypefun {void} {chopstx_release_irq} (chopstx_intr_t * @var{intr0})
@var{intr0}: Interrupt request to be unregistered
Release the interrupt request specified by @var{intr0}.
Claim interrupt @var{intr} with @var{irq_num}
@end deftypefun
@subheading chopstx_intr_wait
@@ -156,29 +129,21 @@ clean-up will be executed.
@deftypefun {void} {chopstx_exit} (void * @var{retval})
@var{retval}: Return value (to be caught by a joining thread)
Calling this function terminates the execution of thread, after
calling clean up functions. If the calling thread still holds
mutexes, they will be released. If the calling thread claiming
IRQ, it will be released, too. This function never returns.
Calling this function terminates the execution of running thread,
after calling clean up functions. If the calling thread still
holds mutexes, they will be released. This function never
returns.
@end deftypefun
@subheading chopstx_join
@anchor{chopstx_join}
@deftypefun {void} {chopstx_join} (chopstx_t @var{thd}, void ** @var{ret})
@deftypefun {int} {chopstx_join} (chopstx_t @var{thd}, void ** @var{ret})
@var{thd}: Thread to wait
@var{ret}: Pointer to void * to store return value
Waits for the thread of @var{thd} to terminate.
@end deftypefun
@subheading chopstx_wakeup_usec_wait
@anchor{chopstx_wakeup_usec_wait}
@deftypefun {void} {chopstx_wakeup_usec_wait} (chopstx_t @var{thd})
@var{thd}: Thread to be awakened
Canceling the timer, wake up the sleeping thread.
No return value.
Returns 0 on success, 1 when waiting is interrupted.
@end deftypefun
@subheading chopstx_cancel
@@ -209,3 +174,30 @@ Calling chopstx_setcancelstate sets cancelability state.
Returns old state which is 0 when it was enabled.
@end deftypefun
@subheading chopstx_poll
@anchor{chopstx_poll}
@deftypefun {int} {chopstx_poll} (uint32_t * @var{usec_p}, int @var{n}, struct chx_poll_head * [] @var{pd_array})
@var{usec_p}: Pointer to usec for timeout. Forever if NULL.
@var{n}: Number of poll descriptors
@var{pd_array}: Pointer to an array of poll descriptor pointer which
should be one of:
chopstx_poll_cond_t, chopstx_poll_join_t, or chopstx_intr_t.
Returns number of active descriptors.
@end deftypefun
@subheading chopstx_setpriority
@anchor{chopstx_setpriority}
@deftypefun {chopstx_prio_t} {chopstx_setpriority} (chopstx_prio_t @var{prio_new})
Change the schedule priority with @var{prio}.
Returns the old priority.
In general, it is not recommended to use this function because
dynamically changing schedule priorities complicates the system.
Only a possible valid usage of this function is in the main thread
which starts its execution with priority of CHX_PRIO_MAIN_INIT, and
let it change its priority after initialization of other threads.
@end deftypefun

View File

@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename chopstx.info
@set VERSION 0.10
@set VERSION 1.4
@settitle Chopstx Reference Manual
@c Unify some of the indices.
@syncodeindex tp fn
@@ -11,7 +11,7 @@
This manual is for Chopstx (version @value{VERSION}).
@noindent
Copyright @copyright{} 2013, 2015 Flying Stone Technology @*
Copyright @copyright{} 2013, 2015, 2016 Flying Stone Technology @*
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -83,8 +83,9 @@ Indexes
@node Introduction
@chapter Introduction
Chopstx is an RT thread library for ARM Cortex-M0 and Cortex-M3.
Specifically, it is used for STM32F030 and STM32F103.
Chopstx is an RT thread library for ARM Cortex-M0, Cortex-M0plus and
Cortex-M3. Specifically, it is used for STM32F030, MKL27Z and
STM32F103.
While most RTOSes come with many features, drivers, and stacks,
Chopstx just offers a RT thread library.

60
entry.c
View File

@@ -1,7 +1,8 @@
/*
* entry.c - Entry routine when reset and interrupt vectors.
*
* Copyright (C) 2013, 2014, 2015 Flying Stone Technology
* 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.
@@ -30,14 +31,36 @@
#include <stdlib.h>
#include <chopstx.h>
#ifdef HAVE_SYS_H
#define INLINE __attribute__ ((used))
#include "sys.h"
#include "board.h"
#undef STM32F10X_MD /* Prepare for high density device, too. */
#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
#include "board.h"
#include "clk_gpio_init.c"
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
#include "sys.h"
/*
* Avoid medium density specific code and prepare for high density
* device, too.
*/
#undef STM32F10X_MD
#else
#if defined (MCU_KINETIS_L)
#include "mcu/clk_gpio_init-mkl27z.c"
#else
#include "mcu/clk_gpio_init-stm32.c"
#endif
#endif
@@ -48,7 +71,9 @@
#endif
extern uint8_t __main_stack_end__;
#if defined(__ARM_ARCH_7M__)
extern void svc (void);
#endif
extern void preempt (void);
extern void chx_timer_expired (void);
extern void chx_handle_intr (void);
@@ -60,18 +85,7 @@ static void nmi (void)
static void hard_fault (void)
{
#if defined(__ARM_ARCH_6M__)
register uint32_t primask;
asm ("mrs %0, PRIMASK" : "=r" (primask));
if (primask)
asm volatile ("b svc");
else
for (;;);
#else
for (;;);
#endif
}
static void mem_manage (void)
@@ -105,7 +119,8 @@ uint32_t vectors_in_ram[48];
* This routine only changes PSP and not MSP.
*/
STATIC_ENTRY __attribute__ ((naked,section(".text.startup.0")))
void entry (void)
void
entry (void)
{
asm volatile ("bl clock_init\n\t"
/* Clear BSS section. */
@@ -169,7 +184,7 @@ void entry (void)
typedef void (*handler)(void);
handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
(handler)&__main_stack_end__,
(handler)(&__main_stack_end__ - 32),
entry,
nmi, /* nmi */
hard_fault, /* hard fault */
@@ -180,7 +195,11 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
none,
/* 0x20 */
none, none, none, /* reserved */
#if defined(__ARM_ARCH_6M__)
none, /* SVCall */
#elif defined(__ARM_ARCH_7M__)
svc, /* SVCall */
#endif
none, /* Debug */
none, /* reserved */
preempt, /* PendSV */
@@ -221,3 +240,4 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
chx_handle_intr, chx_handle_intr, chx_handle_intr,
#endif
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* eventflag.c - Eventflag with/without timeout
* eventflag.c - Eventflag
*
* Copyright (C) 2013 Flying Stone Technology
* Copyright (C) 2013, 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -31,24 +31,55 @@
#include <chopstx.h>
#include <eventflag.h>
enum {
EVENTFLAG_ERR_WAIT = CHOPSTX_ERR_JOIN + 1,
EVENTFLAG_ERR_TIMED_WAIT,
};
void
eventflag_init (struct eventflag *ev)
{
ev->flags = 0;
chopstx_cond_init (&ev->cond);
chopstx_mutex_init (&ev->mutex);
}
static int
eventflag_check (void *arg)
{
struct eventflag *ev = arg;
return ev->flags != 0;
}
void
eventflag_init (struct eventflag *ev, chopstx_t sleeper)
eventflag_prepare_poll (struct eventflag *ev, chopstx_poll_cond_t *poll_desc)
{
ev->sleeper = sleeper;
poll_desc->type = CHOPSTX_POLL_COND;
poll_desc->ready = 0;
poll_desc->cond = &ev->cond;
poll_desc->mutex = &ev->mutex;
poll_desc->check = eventflag_check;
poll_desc->arg = ev;
}
if (sleeper)
ev->u.wait_usec = 0;
eventmask_t
eventflag_get (struct eventflag *ev)
{
int n;
eventmask_t m;
chopstx_mutex_lock (&ev->mutex);
n = __builtin_ffs (ev->flags);
if (n)
{
m = (1 << (n - 1));
ev->flags &= ~m;
}
else
chopstx_cond_init (&ev->u.cond);
m = 0;
chopstx_mutex_unlock (&ev->mutex);
ev->flag = 0;
chopstx_mutex_init (&ev->mutex);
return m;
}
@@ -56,50 +87,35 @@ eventmask_t
eventflag_wait (struct eventflag *ev)
{
int n;
if (ev->sleeper)
chx_fatal (EVENTFLAG_ERR_WAIT);
eventmask_t m;
chopstx_mutex_lock (&ev->mutex);
if (!ev->flag)
chopstx_cond_wait (&ev->u.cond, &ev->mutex);
if (!ev->flags)
chopstx_cond_wait (&ev->cond, &ev->mutex);
n = __builtin_ffs (ev->flag);
ev->flag &= ~(1 << (n - 1));
n = __builtin_ffs (ev->flags);
if (n) /* Always n > 0 when waked up, but make sure no bad things. */
{
m = (1 << (n - 1));
ev->flags &= ~m;
}
else
m = 0;
chopstx_mutex_unlock (&ev->mutex);
return (1 << (n - 1));
return m;
}
eventmask_t
eventflag_wait_timeout (struct eventflag *ev, uint32_t usec)
{
eventmask_t em = 0;
int n;
chopstx_poll_cond_t poll_desc;
struct chx_poll_head *pd_array[1] = { (struct chx_poll_head *)&poll_desc };
if (ev->sleeper == 0)
chx_fatal (EVENTFLAG_ERR_TIMED_WAIT);
chopstx_mutex_lock (&ev->mutex);
if (!ev->flag)
{
ev->u.wait_usec = usec;
chopstx_mutex_unlock (&ev->mutex);
chopstx_usec_wait_var (&ev->u.wait_usec);
chopstx_mutex_lock (&ev->mutex);
ev->u.wait_usec = 0;
}
n = __builtin_ffs (ev->flag);
if (n)
{
em = (1 << (n - 1));
ev->flag &= ~em;
}
chopstx_mutex_unlock (&ev->mutex);
return em;
eventflag_prepare_poll (ev, &poll_desc);
chopstx_poll (&usec, 1, pd_array);
return eventflag_get (ev);
}
@@ -107,16 +123,7 @@ void
eventflag_signal (struct eventflag *ev, eventmask_t m)
{
chopstx_mutex_lock (&ev->mutex);
ev->flag |= m;
if (ev->sleeper)
{
if (ev->u.wait_usec)
{
ev->u.wait_usec = 0;
chopstx_wakeup_usec_wait (ev->sleeper);
}
}
else
chopstx_cond_signal (&ev->u.cond);
ev->flags |= m;
chopstx_cond_signal (&ev->cond);
chopstx_mutex_unlock (&ev->mutex);
}

View File

@@ -1,16 +1,16 @@
typedef uint32_t eventmask_t;
struct eventflag {
chopstx_t sleeper;
eventmask_t flag;
eventmask_t flags;
chopstx_mutex_t mutex;
union {
uint32_t wait_usec;
chopstx_cond_t cond;
} u;
};
void eventflag_init (struct eventflag *ev, chopstx_t owner);
void eventflag_init (struct eventflag *ev);
eventmask_t eventflag_wait (struct eventflag *ev);
eventmask_t eventflag_wait_timeout (struct eventflag *ev, uint32_t usec);
void eventflag_signal (struct eventflag *ev, eventmask_t m);
/* For polling */
void eventflag_prepare_poll (struct eventflag *ev, chopstx_poll_cond_t *p);
eventmask_t eventflag_get (struct eventflag *ev);

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

@@ -4,7 +4,12 @@ PROJECT = sample
CHOPSTX = ..
LDSCRIPT= sample.ld
CSRC = sys.c aes-constant-ft.c sample.c usb-cdc.c usb_stm32f103.c
CSRC = sample.c usb-cdc.c
CHIP=stm32f103
USE_SYS = yes
USE_USB = yes
###################################
CROSS = arm-none-eabi-
@@ -14,7 +19,7 @@ OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DHAVE_SYS_H -DFREE_STANDING
DEFS = -DUSE_SYS3 -DFREE_STANDING
OPT = -O3 -Os -g
LIBS =

View File

@@ -1,145 +0,0 @@
/*
* aes-constant-ft.c - AES forward tables.
*
* We need something useful for the initial flash ROM page (4 Ki
* bytes), which cannot be modified after installation. Even after
* upgrade of the firmware, it stays intact.
*
* We decide to put 3/4 of AES forward tables to fill 3 Ki bytes, as
* its useful and it won't change.
*
* The code was taken from aes.c of PolarSSL version 0.14, and then,
* modified to add section names.
*
* Since this is just a data, it wouldn't be copyright-able, but the
* original auther would claim so. Thus, we put original copyright
* notice here. It is highly likely that there will be no such a
* thing for copyright. Nevertheless, we think that PolarSSL is good
* software to address here, and encourage people using it.
*
*/
#include <stdint.h>
/*
* Original copyright notice is below:
*/
/*
* FIPS-197 compliant AES implementation
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
*
* http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
/*
* Forward tables
*/
#define FT \
\
V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
#define V(a,b,c,d) 0x##a##b##c##d
const uint32_t FT0[256] __attribute__((section(".sys.0"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
const uint32_t FT1[256] __attribute__((section(".sys.1"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
const uint32_t FT2[256] __attribute__((section(".sys.2"))) = { FT };
#undef V
#ifdef ORIGINAL_IMPLEMENTATION
#define V(a,b,c,d) 0x##d##a##b##c
const uint32_t FT3[256] = { FT };
#undef V
#endif

View File

@@ -2,16 +2,18 @@
#include <stdlib.h>
#include <string.h>
#include <chopstx.h>
#include "sys.h" /* for set_led */
#include "usb_lld.h" /* for set_led */
#include "usb_lld.h"
#include "tty.h"
/* For set_led */
#include "board.h"
#include "sys.h"
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0;
static chopstx_cond_t cnd1;
chopstx_mutex_t usb_mtx;
chopstx_cond_t cnd_usb;
static uint8_t u, v;
static uint8_t m; /* 0..100 */
@@ -55,67 +57,23 @@ blk (void *arg)
return NULL;
}
#define INTR_REQ_USB 20
static void *
usb_intr (void *arg)
{
extern void usb_lld_init (uint8_t feature);
extern void usb_interrupt_handler (void);
chopstx_intr_t interrupt;
(void)arg;
usb_lld_init (0x80); /* Bus powered. */
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
/*
* When USB interrupt occurs between usb_lld_init (which assumes
* ISR) and chopstx_claim_irq (which clears pending interrupt),
* invocation of usb_interrupt_handler won't occur.
*
* 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.
*
* Calling usb_interrupt_handler is no harm even if there were no
* interrupts, thus, we call it unconditionally here, just in case
* if there is a request.
*
*/
usb_interrupt_handler ();
while (1)
{
chopstx_intr_wait (&interrupt);
/* Process interrupt. */
usb_interrupt_handler ();
}
chopstx_release_irq (&interrupt);
return NULL;
}
#define PRIO_PWM 3
#define PRIO_BLK 2
#define PRIO_INTR 4
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
extern uint8_t __process3_stack_base__, __process3_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__)
const uint32_t __stackaddr_intr = (uint32_t)&__process3_stack_base__;
const size_t __stacksize_intr = (size_t)&__process3_stack_size__;
static char hexchar (uint8_t x)
{
x &= 0x0f;
if (x <= 0x09)
return '0' + x;
else if (x <= 0x0f)
@@ -128,6 +86,7 @@ static char hexchar (uint8_t x)
int
main (int argc, const char *argv[])
{
struct tty *tty;
uint8_t count;
(void)argc;
@@ -137,15 +96,10 @@ main (int argc, const char *argv[])
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
chopstx_mutex_init (&usb_mtx);
chopstx_cond_init (&cnd_usb);
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_INTR, __stackaddr_intr, __stacksize_intr,
usb_intr, 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);
@@ -154,41 +108,59 @@ main (int argc, const char *argv[])
chopstx_cond_signal (&cnd1);
chopstx_mutex_unlock (&mtx);
while (1)
{
extern uint8_t connected;
count= 0;
u = 1;
/* waiting USB connection */
chopstx_mutex_lock (&usb_mtx);
if (!connected)
chopstx_cond_wait (&cnd_usb, &usb_mtx);
chopstx_mutex_unlock (&usb_mtx);
tty = tty_open ();
tty_wait_configured (tty);
count = 0;
m = 50;
while (1)
{
char s[32];
char s[LINEBUFSIZE];
u ^= 1;
chopstx_usec_wait (200*1000*6);
u = 1;
tty_wait_connection (tty);
chopstx_usec_wait (50*1000);
/* 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++;
chopstx_mutex_lock (&usb_mtx);
if (connected)
if (tty_send (tty, s, 32) < 0)
continue;
while (1)
{
usb_lld_write (ENDP1, s, 32);
chopstx_cond_wait (&cnd_usb, &usb_mtx);
}
else
int size;
uint32_t usec;
usec = 3000000; /* 3.0 seconds */
size = tty_recv (tty, s + 4, &usec);
if (size < 0)
break;
if (size)
{
size--;
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;
chopstx_mutex_unlock (&usb_mtx);
}
chopstx_mutex_unlock (&usb_mtx);
u ^= 1;
}
}
return 0;

View File

@@ -1,11 +1,11 @@
/*
* ST32F103 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__process0_stack_size__ = 0x0100; /* Main program */
__process1_stack_size__ = 0x0100; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */
__process3_stack_size__ = 0x0100; /* third thread program */
__main_stack_size__ = 0x0100; /* Idle+Exception handlers */
__process0_stack_size__ = 0x0400; /* Main program */
__process1_stack_size__ = 0x0200; /* first thread program */
__process2_stack_size__ = 0x0200; /* second thread program */
__process3_stack_size__ = 0x0200; /* third thread program */
MEMORY
{
@@ -30,10 +30,10 @@ SECTIONS
KEEP(*(.sys.version))
KEEP(*(.sys.board_id))
KEEP(*(.sys.board_name))
build/sys.o(.text)
build/sys.o(.text.*)
build/sys.o(.rodata)
build/sys.o(.rodata.*)
build/sys-*.o(.text)
build/sys-*.o(.text.*)
build/sys-*.o(.rodata)
build/sys-*.o(.rodata.*)
. = ALIGN(1024);
*(.sys.0)
*(.sys.1)

9
example-cdc/tty.h Normal file
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

@@ -1,10 +1,84 @@
#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 */
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;
}
extern chopstx_mutex_t usb_mtx;
extern chopstx_cond_t cnd_usb;
#define ENDP0_RXADDR (0x40)
#define ENDP0_TXADDR (0x80)
@@ -20,7 +94,7 @@ extern chopstx_cond_t cnd_usb;
/* USB Device Descriptor */
static const uint8_t vcom_device_desc[18] = {
18, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
DEVICE_DESCRIPTOR, /* bDescriptorType */
0x10, 0x01, /* bcdUSB = 1.1 */
0x02, /* bDeviceClass (CDC). */
0x00, /* bDeviceSubClass. */
@@ -35,20 +109,22 @@ static const uint8_t vcom_device_desc[18] = {
1 /* bNumConfigurations. */
};
#define VCOM_FEATURE_BUS_POWERED 0x80
/* Configuration Descriptor tree for a CDC.*/
static const uint8_t vcom_config_desc[67] = {
9,
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
/* Configuration Descriptor.*/
67, 0x00, /* wTotalLength. */
0x02, /* bNumInterfaces. */
0x01, /* bConfigurationValue. */
0, /* iConfiguration. */
0x80, /* bmAttributes (bus powered). */
VCOM_FEATURE_BUS_POWERED, /* bmAttributes. */
50, /* bMaxPower (100mA). */
/* Interface Descriptor.*/
9,
USB_INTERFACE_DESCRIPTOR_TYPE,
INTERFACE_DESCRIPTOR,
0x00, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x01, /* bNumEndpoints. */
@@ -87,14 +163,14 @@ static const uint8_t vcom_config_desc[67] = {
0x01, /* bSlaveInterface0 (Data Class Interface). */
/* Endpoint 2 Descriptor.*/
7,
USB_ENDPOINT_DESCRIPTOR_TYPE,
ENDPOINT_DESCRIPTOR,
ENDP2|0x80, /* bEndpointAddress. */
0x03, /* bmAttributes (Interrupt). */
0x08, 0x00, /* wMaxPacketSize. */
0xFF, /* bInterval. */
/* Interface Descriptor.*/
9,
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
INTERFACE_DESCRIPTOR, /* bDescriptorType: */
0x01, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x02, /* bNumEndpoints. */
@@ -104,14 +180,14 @@ static const uint8_t vcom_config_desc[67] = {
0x00, /* iInterface. */
/* Endpoint 3 Descriptor.*/
7,
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
ENDP3, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
0x00, /* bInterval. */
/* Endpoint 1 Descriptor.*/
7,
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
ENDP1|0x80, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
@@ -124,13 +200,13 @@ static const uint8_t vcom_config_desc[67] = {
*/
static const uint8_t vcom_string0[4] = {
4, /* bLength */
USB_STRING_DESCRIPTOR_TYPE,
STRING_DESCRIPTOR,
0x09, 0x04 /* LangID = 0x0409: US-English */
};
static const uint8_t vcom_string1[] = {
23*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
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,
@@ -139,7 +215,7 @@ static const uint8_t vcom_string1[] = {
static const uint8_t vcom_string2[] = {
14*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
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,
@@ -150,119 +226,122 @@ static const uint8_t vcom_string2[] = {
*/
static const uint8_t vcom_string3[28] = {
28, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
STRING_DESCRIPTOR, /* bDescriptorType */
'0', 0, '.', 0, '0', 0, '0', 0, /* Version number */
};
#define NUM_INTERFACES 2
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
uint8_t connected;
void
usb_cb_device_reset (void)
static void
usb_device_reset (struct usb_dev *dev)
{
/* Set DEVICE as not configured */
usb_lld_set_configuration (0);
/* Current Feature initialization */
usb_lld_set_feature (vcom_config_desc[7]);
usb_lld_reset ();
usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
chopstx_mutex_lock (&usb_mtx);
connected = 0;
bDeviceState = ATTACHED;
chopstx_cond_signal (&cnd_usb);
chopstx_mutex_unlock (&usb_mtx);
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
void
usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value)
static void
usb_ctrl_write_finish (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
&& USB_SETUP_SET (req) && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
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 (&usb_mtx);
connected = ((value & CDC_CTRL_DTR) != 0)? 1 : 0;
chopstx_cond_signal (&cnd_usb);
chopstx_mutex_unlock (&usb_mtx);
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.
*/
}
struct line_coding
{
uint32_t bitrate;
uint8_t format;
uint8_t paritytype;
uint8_t datatype;
} __attribute__((packed));
static struct line_coding line_coding = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
static int
vcom_port_data_setup (uint8_t req, uint8_t req_no, struct control_info *detail)
vcom_port_data_setup (struct usb_dev *dev)
{
if (USB_SETUP_GET (req))
struct device_req *arg = &dev->dev_req;
if (USB_SETUP_GET (arg->type))
{
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
return usb_lld_reply_request (&line_coding, sizeof(line_coding), detail);
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 (req_no == USB_CDC_REQ_SET_LINE_CODING
&& detail->len == sizeof (line_coding))
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
&& arg->len == sizeof (struct line_coding))
{
usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
return USB_SUCCESS;
struct tty *t = tty_get (arg->index, 0);
return usb_lld_ctrl_recv (dev, &t->line_coding,
sizeof (struct line_coding));
}
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
return USB_SUCCESS;
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
return usb_lld_ctrl_ack (dev);
}
return USB_UNSUPPORT;
return -1;
}
int
usb_cb_setup (uint8_t req, uint8_t req_no, struct control_info *detail)
static int
usb_setup (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && detail->index == 0)
return vcom_port_data_setup (req, req_no, detail);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
return vcom_port_data_setup (dev);
return USB_UNSUPPORT;
return -1;
}
int
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
struct control_info *detail)
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 USB_UNSUPPORT;
return -1;
if (desc_type == DEVICE_DESCRIPTOR)
return usb_lld_reply_request (vcom_device_desc, sizeof (vcom_device_desc),
detail);
return usb_lld_ctrl_send (dev,
vcom_device_desc, sizeof (vcom_device_desc));
else if (desc_type == CONFIG_DESCRIPTOR)
return usb_lld_reply_request (vcom_config_desc, sizeof (vcom_config_desc),
detail);
return usb_lld_ctrl_send (dev,
vcom_config_desc, sizeof (vcom_config_desc));
else if (desc_type == STRING_DESCRIPTOR)
{
const uint8_t *str;
@@ -287,13 +366,13 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
size = sizeof (vcom_string3);
break;
default:
return USB_UNSUPPORT;
return -1;
}
return usb_lld_reply_request (str, size, detail);
return usb_lld_ctrl_send (dev, str, size);
}
return USB_UNSUPPORT;
return -1;
}
static void
@@ -312,6 +391,7 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
{
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
/* Start with no data receiving (ENDP3 not enabled)*/
}
else
{
@@ -321,94 +401,558 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
}
}
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
static int
usb_set_configuration (struct usb_dev *dev)
{
int i;
uint8_t current_conf;
switch (event_type)
{
case USB_EVENT_ADDRESS:
bDeviceState = ADDRESSED;
return USB_SUCCESS;
case USB_EVENT_CONFIG:
current_conf = usb_lld_current_configuration ();
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
if (value != 1)
return USB_UNSUPPORT;
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (1);
usb_lld_set_configuration (dev, 1);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (i, 0);
bDeviceState = CONFIGURED;
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = CONFIGURED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
}
else if (current_conf != value)
else if (current_conf != dev->dev_req.value)
{
if (value != 0)
return USB_UNSUPPORT;
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (0);
usb_lld_set_configuration (dev, 0);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (i, 1);
bDeviceState = ADDRESSED;
}
/* Do nothing when current_conf == value */
return USB_SUCCESS;
return USB_SUCCESS;
default:
break;
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = ADDRESSED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
}
return USB_UNSUPPORT;
usb_lld_ctrl_ack (dev);
return 0;
}
int usb_cb_interface (uint8_t cmd, struct control_info *detail)
static int
usb_set_interface (struct usb_dev *dev)
{
const uint8_t zero = 0;
uint16_t interface = detail->index;
uint16_t alt = detail->value;
uint16_t interface = dev->dev_req.index;
uint16_t alt = dev->dev_req.value;
if (interface >= NUM_INTERFACES)
return USB_UNSUPPORT;
return -1;
switch (cmd)
{
case USB_SET_INTERFACE:
if (alt != 0)
return USB_UNSUPPORT;
return -1;
else
{
vcom_setup_endpoints_for_interface (interface, 0);
return USB_SUCCESS;
usb_lld_ctrl_ack (dev);
return 0;
}
}
case USB_GET_INTERFACE:
return usb_lld_reply_request (&zero, 1, detail);
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:
case USB_QUERY_INTERFACE:
return USB_SUCCESS;
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)
{
uint8_t recv_buf[64];
struct tty *t = tty_get (-1, ep_num);
if (ep_num == ENDP3)
{
int i;
usb_lld_rxcpy (recv_buf, ep_num, 0, len);
for (i = 0; i < len; i++)
if (tty_input_char (t, recv_buf[i]))
break;
chopstx_mutex_lock (&t->mtx);
if (t->flag_input_avail == 0)
usb_lld_rx_enable (ENDP3);
chopstx_mutex_unlock (&t->mtx);
}
}
void
EP1_IN_Callback (void)
static void *tty_main (void *arg);
#define INTR_REQ_USB 20
#define PRIO_TTY 4
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)
{
chopstx_mutex_lock (&usb_mtx);
chopstx_cond_signal (&cnd_usb);
chopstx_mutex_unlock (&usb_mtx);
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;
}
void
EP2_IN_Callback (void)
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)
{
usb_lld_txcpy (line, ENDP1, 0, len);
usb_lld_tx_enable (ENDP1, len);
t->flag_send_ready = 0;
}
}
chopstx_mutex_unlock (&t->mtx);
}
return NULL;
}
void
EP3_OUT_Callback (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 (ENDP3); /* 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_txcpy (p, ENDP1, 0, count);
usb_lld_tx_enable (ENDP1, 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;
}
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 (ENDP3);
t->inputline_len = 0;
}
else
r = 0;
chopstx_mutex_unlock (&t->mtx);
return r;
}

View File

@@ -1,122 +0,0 @@
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define STANDARD_ENDPOINT_DESC_SIZE 0x09
/* endpoints enumeration */
#define ENDP0 ((uint8_t)0)
#define ENDP1 ((uint8_t)1)
#define ENDP2 ((uint8_t)2)
#define ENDP3 ((uint8_t)3)
#define ENDP4 ((uint8_t)4)
#define ENDP5 ((uint8_t)5)
#define ENDP6 ((uint8_t)6)
#define ENDP7 ((uint8_t)7)
/* EP_TYPE[1:0] EndPoint TYPE */
#define EP_BULK (0x0000) /* EndPoint BULK */
#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */
enum RECIPIENT_TYPE
{
DEVICE_RECIPIENT, /* Recipient device */
INTERFACE_RECIPIENT, /* Recipient interface */
ENDPOINT_RECIPIENT, /* Recipient endpoint */
OTHER_RECIPIENT
};
enum DESCRIPTOR_TYPE
{
DEVICE_DESCRIPTOR = 1,
CONFIG_DESCRIPTOR,
STRING_DESCRIPTOR,
INTERFACE_DESCRIPTOR,
ENDPOINT_DESCRIPTOR
};
#define REQUEST_DIR 0x80 /* Mask to get request dir */
#define REQUEST_TYPE 0x60 /* Mask to get request type */
#define STANDARD_REQUEST 0x00 /* Standard request */
#define CLASS_REQUEST 0x20 /* Class request */
#define VENDOR_REQUEST 0x40 /* Vendor request */
#define RECIPIENT 0x1F /* Mask to get recipient */
#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
enum
{
USB_UNSUPPORT = 0,
USB_SUCCESS = 1,
};
struct control_info {
uint16_t value;
uint16_t index;
uint16_t len;
};
void usb_cb_device_reset (void);
int usb_cb_setup (uint8_t req, uint8_t req_no, struct control_info *detail);
int usb_cb_interface (uint8_t cmd, struct control_info *detail);
int usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
struct control_info *detail);
int usb_cb_handle_event (uint8_t event_type, uint16_t value);
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value);
enum {
USB_EVENT_ADDRESS,
USB_EVENT_CONFIG,
USB_EVENT_SUSPEND,
USB_EVENT_WAKEUP,
USB_EVENT_STALL,
};
enum {
USB_SET_INTERFACE,
USB_GET_INTERFACE,
USB_QUERY_INTERFACE,
};
enum DEVICE_STATE
{
UNCONNECTED,
ATTACHED,
POWERED,
SUSPENDED,
ADDRESSED,
CONFIGURED
};
void usb_lld_init (uint8_t feature);
void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
void usb_lld_stall_tx (int ep_num);
void usb_lld_stall_rx (int ep_num);
int usb_lld_tx_data_len (int ep_num);
void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len);
void usb_lld_tx_enable (int ep_num, size_t len);
void usb_lld_write (uint8_t ep_num, const void *buf, size_t len);
int usb_lld_reply_request (const void *buf, size_t buflen,
struct control_info *ctrl);
void usb_lld_rx_enable (int ep_num);
int usb_lld_rx_data_len (int ep_num);
void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len);
void usb_lld_reset (void);
void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
int ep_rx_addr, int ep_tx_addr,
int ep_rx_memory_size);
void usb_lld_set_configuration (uint8_t config);
uint8_t usb_lld_current_configuration (void);
void usb_lld_set_feature (uint8_t feature);
void usb_lld_set_data_to_recv (const void *p, size_t len);
void usb_lld_prepare_shutdown (void);
void usb_lld_shutdown (void);
void usb_interrupt_handler (void);

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;
}

36
example-fs-bb48/Makefile Normal file
View File

@@ -0,0 +1,36 @@
# Makefile for example application of Chopstx
PROJECT = sample
### Currently, it's for FS-BB48.
CHOPSTX = ..
LDSCRIPT= sample.ld
CSRC = sample.c usb-cdc.c command.c touch.c
CHIP=mkl27z
USE_SYS = yes
USE_USB = yes
USE_ADC = yes
###################################
CROSS = arm-none-eabi-
CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = cortex-m0plus
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DFREE_STANDING -DMHZ=48 -DUSE_SYS3
OPT = -O3 -Os -g
LIBS =
####################
include ../rules.mk
board.h:
@echo Please make a symbolic link \'board.h\' to a file in ../board;
@exit 1
distclean: clean
rm -f board.h

1
example-fs-bb48/board.h Symbolic link
View File

@@ -0,0 +1 @@
../board/board-fs-bb48.h

542
example-fs-bb48/command.c Normal file
View File

@@ -0,0 +1,542 @@
#include <string.h>
#include <stdint.h>
#include <chopstx.h>
#include "tty.h"
#include "config.h"
#ifdef ADC_SUPPORT
#include "adc.h"
static int adc_initialized = 0;
#endif
#include "board.h"
#include "sys.h"
struct command_table
{
const char *name;
void (*handler) (struct tty *tty, const char *line);
};
/*
* Put a line (or lines) to TTY.
* LINE should be terminated with newline.
*/
static void
put_line (struct tty *tty, const char *line)
{
tty_send (tty, line, strlen (line));
}
static const char *help_string =
"mdw ADDR [COUNT]; memory display word\r\n"
"mww ADDR VALUE [COUNT]; memory write word\r\n"
"fes ADDR [COUNT]; flash erase sector\r\n"
"fww ADDR VALUE [COUNT]; flash write word\r\n"
#ifdef CRC32_SUPPORT
"crc32 string; CRC32 calc string\r\n"
#endif
#ifdef ADC_SUPPORT
"adc; get 256-byte from ADC\r\n"
#endif
"sysinfo; system information\r\n"
"help\r\n";
static char hexchar (uint8_t x)
{
x &= 0x0f;
if (x <= 0x09)
return '0' + x;
else if (x <= 0x0f)
return 'a' + x - 10;
else
return '?';
}
static char *
compose_decimal (char *s, int value)
{
uint32_t v;
int col = 1000000000;
int d;
int digit_output = 0;
if (value < 0)
{
*s++ = '-';
v = 1 + ~((uint32_t)value);
}
else
v = (uint32_t)value;
while (col >= 10)
{
if (v >= (uint32_t)col)
{
d = v / col;
v = v - d * col;
*s++ = d + '0';
digit_output = 1;
}
else if (digit_output)
*s++ = '0';
col = col / 10;
}
*s++ = v + '0';
return s;
}
static char *
compose_hex (char *s, uint32_t v)
{
s[0] = hexchar (v >> 28);
s[1] = hexchar (v >> 24);
s[2] = hexchar (v >> 20);
s[3] = hexchar (v >> 16);
s[4] = hexchar (v >> 12);
s[5] = hexchar (v >> 8);
s[6] = hexchar (v >> 4);
s[7] = hexchar (v);
return s+8;
}
static const char *
get_hex (struct tty *tty, const char *s, uint32_t *v_p)
{
uint32_t v = 0;
char c;
if (s[0] == '0' && s[1] == 'x')
s = s + 2;
while (1)
{
c = *s++;
if (c == 0)
{
s--;
break;
}
if (c == ' ')
break;
v = (v << 4);
if (c >= '0' && c <= '9')
v += (c - '0');
else if (c >= 'a' && c <= 'f')
v += (c - 'a') + 10;
else if (c >= 'A' && c <= 'F')
v += (c - 'A') + 10;
else
{
put_line (tty, "hex error\r\n");
return NULL;
}
}
*v_p = v;
return s;
}
#define TOUCH_VALUE_HIGH 100
#define TOUCH_VALUE_LOW 50
static void
cmd_button (struct tty *tty, const char *line)
{
int i = 0;
extern uint16_t touch_get (void);
uint16_t v0 = 0;
int touched = 0;
(void)line;
put_line (tty, "Please touch the bear.\r\n");
while (i < 16)
{
uint16_t v = touch_get ();
v0 = (v0 * 2 + v)/3;
if (touched == 0 && v0 > TOUCH_VALUE_HIGH)
{
tty_send (tty, "!", 1);
touched = 1;
}
else if (touched == 1 && v0 < TOUCH_VALUE_LOW)
{
tty_send (tty, ".", 1);
touched = 0;
i++;
}
chopstx_usec_wait (10*1000);
}
tty_send (tty, "\r\n", 2);
}
static void
cmd_touch (struct tty *tty, const char *line)
{
int i;
extern uint16_t touch_get (void);
(void)line;
put_line (tty, "Please touch the bear.\r\n");
for (i = 0; i < 20; i++)
{
uint16_t v;
char output[8];
char *s;
chopstx_usec_wait (1000*1000);
v = touch_get ();
s = compose_decimal (output, v);
*s++ = '\r';
*s++ = '\n';
tty_send (tty, output, s - output);
}
}
static void
cmd_mdw (struct tty *tty, const char *line)
{
int i;
uint32_t addr = 0;
int count = 0;
char c;
const char *s = line;
s = get_hex (tty, s, &addr);
addr &= ~3;
if (s == NULL)
return;
if (*s == 0)
count = 1;
else
{
while (1)
{
c = *s++;
if (c == 0 || c == ' ')
break;
count = count * 10;
if (c >= '0' && c <= '9')
count += c - '0';
else
{
put_line (tty, "mdw error\r\n");
return;
}
}
}
i = 0;
while (i < count)
{
uint32_t v;
char output[48];
char *s;
s = compose_hex (output, addr);
*s++ = ':';
*s++ = ' ';
while (1)
{
v = *(uint32_t *)addr;
s = compose_hex (s, v);
i++;
addr += 4;
if (i >= count || (i % 4) == 0)
break;
*s++ = ' ';
}
*s++ = '\r';
*s++ = '\n';
tty_send (tty, output, s - output);
}
}
static void
cmd_mww (struct tty *tty, const char *line)
{
(void)tty;
(void)line;
put_line (tty, "mww not yet supported\r\n");
}
static void
cmd_fes (struct tty *tty, const char *line)
{
int i;
uint32_t addr = 0;
int count = 0;
char c;
const char *s = line;
s = get_hex (tty, s, &addr);
if (s == NULL)
return;
if (*s == 0)
count = 1;
else
{
while (1)
{
c = *s++;
if (c == 0 || c == ' ')
break;
count = count * 10;
if (c >= '0' && c <= '9')
count += c - '0';
else
{
put_line (tty, "fww error\r\n");
return;
}
}
}
for (i = 0; i < count; i++)
{
flash_erase_page (addr);
addr += 1024;
}
}
static void
cmd_fww (struct tty *tty, const char *line)
{
int i;
uint32_t addr = 0;
uint32_t value = 0;
int count = 0;
char c;
const char *s = line;
s = get_hex (tty, s, &addr);
if (s == NULL)
return;
if (*s == 0)
return;
s = get_hex (tty, s, &value);
if (s == NULL)
return;
if (*s == 0)
count = 1;
else
{
while (1)
{
c = *s++;
if (c == 0 || c == ' ')
break;
count = count * 10;
if (c >= '0' && c <= '9')
count += c - '0';
else
{
put_line (tty, "fww error\r\n");
return;
}
}
}
for (i = 0; i < count; i++)
{
flash_program_word (addr, value);
addr += 4;
}
}
#ifdef CRC32_SUPPORT
static unsigned int crc_value;
static void
cmd_crc32 (struct tty *tty, const char *line)
{
uint32_t v;
char string[10];
char *s;
crc32_init (&crc_value);
while (*line)
crc32_u8 (&crc_value, *line++);
v = crc_value ^ 0xffffffff;
s = compose_hex (string, v);
*s++ = '\r';
*s++ = '\n';
tty_send (tty, string, sizeof (string));
}
#endif
#ifdef ADC_SUPPORT
static void
cmd_adc (struct tty *tty, const char *line)
{
int i;
char output[73];
char *s;
(void)line;
if (!adc_initialized)
{
if (adc_init ())
{
put_line (tty, "adc_init error\r\n");
return;
}
else
{
adc_start ();
adc_initialized = 1;
}
}
adc_start_conversion (0, 64);
adc_wait_completion ();
i = 0;
s = output;
while (1)
{
s = compose_hex (s, adc_buf[i]);
i++;
if ((i % 8))
*s++ = ' ';
else
{
*s++ = '\r';
*s++ = '\n';
tty_send (tty, output, s - output);
s = output;
if (i >= 64)
break;
}
}
}
#endif
static void
cmd_sysinfo (struct tty *tty, const char *line)
{
char output[73];
char *s;
int i;
(void)line;
memcpy (output, "SYS version: ", 13);
s = output + 13;
*s++ = sys_version[2];
*s++ = sys_version[4];
*s++ = sys_version[6];
*s++ = '\r';
*s++ = '\n';
tty_send (tty, output, s - output);
memcpy (output, "Board ID: ", 10);
s = output + 10;
s = compose_hex (s, sys_board_id);
*s++ = '\r';
*s++ = '\n';
tty_send (tty, output, s - output);
memcpy (output, "Board name: ", 12);
s = output + 12;
for (i = 0; i < (int)sizeof (output) - 2; i ++)
if ((*s = sys_board_name[i]) == 0)
break;
else
s++;
*s++ = '\r';
*s++ = '\n';
tty_send (tty, output, s - output);
}
static void
cmd_help (struct tty *tty, const char *line)
{
(void)line;
put_line (tty, help_string);
}
struct command_table command_table[] = {
{ "button", cmd_button },
{ "touch", cmd_touch },
{ "mdw", cmd_mdw },
{ "mww", cmd_mww },
{ "fes", cmd_fes },
{ "fww", cmd_fww },
#ifdef CRC32_SUPPORT
{ "crc32", cmd_crc32 },
#endif
#ifdef ADC_SUPPORT
{ "adc", cmd_adc },
#endif
{ "sysinfo", cmd_sysinfo },
{ "help", cmd_help },
};
#define N_CMDS (int)(sizeof (command_table) / sizeof (struct command_table))
/*
* Dispatch a command parsing LINE.
* Line is NULL terminated with no newline.
*/
void
cmd_dispatch (struct tty *tty, const char *line)
{
int i;
const char *p;
unsigned int n = 0;
p = line;
while (*p)
{
if (*p++ == ' ')
break;
n++;
}
for (i = 0; i < N_CMDS; i++)
if (n == strlen (command_table[i].name)
&& strncmp ((const char *)line, command_table[i].name, n) == 0)
break;
if (i != N_CMDS)
(*command_table[i].handler) (tty, p);
else
{
char crlf[] = { '\r', '\n' };
put_line (tty, "No such command: ");
tty_send (tty, line, n);
tty_send (tty, crlf, sizeof (crlf));
}
}

View File

@@ -0,0 +1 @@
void cmd_dispatch (struct tty *tty, const char *line);

2
example-fs-bb48/config.h Normal file
View File

@@ -0,0 +1,2 @@
#define CRC32_SUPPORT
#define ADC_SUPPORT

22
example-fs-bb48/crc32.c Normal file
View File

@@ -0,0 +1,22 @@
const unsigned int *const crc32_table= (const unsigned int *)0x00000480;
void
crc32_init (unsigned int *p)
{
*p = 0xffffffff;
}
static void
crc32_u8 (unsigned int *p, unsigned char v)
{
*p = crc32_table[(*p & 0xff) ^ v] ^ (*p >> 8);
}
void
crc32_u32 (unsigned int *p, unsigned int u)
{
crc32_u8 (p, u & 0xff);
crc32_u8 (p, (u >> 8)& 0xff);
crc32_u8 (p, (u >> 16)& 0xff);
crc32_u8 (p, (u >> 24)& 0xff);
}

View File

@@ -0,0 +1,22 @@
#
# Polynomial for CRC32:
# x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
#
# When it is represented in binary, it's:
# 0x04C11DB7
# =
# 0000 0100 1100 0001 0001 1101 1011 0111
#
# When we put in reverse bit-order, it's
# 0xedb88320
for i in range(0,256):
c = i
for j in range(0,8):
if (c&1):
c = 0xEDB88320 ^ (c >> 1)
else:
c = c >> 1
print("0x%08x," % c),
if (i % 6) == 5:
print("")

189
example-fs-bb48/sample.c Normal file
View File

@@ -0,0 +1,189 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <chopstx.h>
#include "usb_lld.h"
#include "tty.h"
#include "board.h"
#include "command.h"
#include <sys.h>
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0;
static chopstx_cond_t cnd1;
uint8_t u;
static uint8_t v;
static uint8_t m; /* 0..100 */
static void
wait_for (uint32_t usec)
{
#if defined(BUSY_LOOP)
uint32_t count = usec * 6;
uint32_t i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
#else
chopstx_usec_wait (usec);
#endif
}
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);
wait_for (m);
set_led (0);
wait_for (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;
wait_for (200*1000);
v = 1;
wait_for (200*1000);
}
return NULL;
}
#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__[];
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_PWM ((uint32_t)__process1_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)
{
x &= 0x0f;
if (x <= 0x09)
return '0' + x;
else if (x <= 0x0f)
return 'a' + x - 10;
else
return '?';
}
extern void touch_init (void);
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;
touch_init ();
tty = tty_open ();
tty_wait_configured (tty);
count = 0;
m = 50;
while (1)
{
char s[LINEBUFSIZE];
connection_loop:
u = 1;
tty_wait_connection (tty);
chopstx_usec_wait (50*1000);
/* 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++;
if (tty_send (tty, s, 32) < 0)
continue;
while (1)
{
uint32_t usec;
/* Prompt */
if (tty_send (tty, "> ", 2) < 0)
break;
usec = 3000000; /* 3.0 seconds */
while (1)
{
int size = tty_recv (tty, s, &usec);
u ^= 1;
if (size < 0)
goto connection_loop;
if (size == 1)
/* Do nothing but prompt again. */
break;
else if (size)
{
/* Newline into NUL */
s[size - 1] = 0;
cmd_dispatch (tty, (char *)s);
break;
}
}
}
}
return 0;
}

150
example-fs-bb48/sample.ld Normal file
View File

@@ -0,0 +1,150 @@
/*
* MK27Z memory setup.
*/
__main_stack_size__ = 0x0100; /* Idle+Exception handlers */
__process0_stack_size__ = 0x0300; /* Main program */
__process1_stack_size__ = 0x0200; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */
__process3_stack_size__ = 0x0200; /* third thread program */
MEMORY
{
flash : org = 0x00000000, len = 256k
ram : org = 0x1fffe000, len = 32k
}
__ram_start__ = ORIGIN(ram);
__ram_size__ = 32k;
__ram_end__ = __ram_start__ + __ram_size__;
SECTIONS
{
. = 0;
_text = .;
.text : ALIGN(16) SUBALIGN(8)
{
KEEP(*(.first_page.first_words))
KEEP(*(.sys.version))
KEEP(*(.sys.board_info))
KEEP(*(.sys.vectors))
build/sys-*.o(.text)
build/sys-*.o(.text.*)
build/sys-*.o(.rodata)
build/sys-*.o(.rodata.*)
. = ALIGN(1024);
KEEP(*(.flash_config))
KEEP(*(.fixed_function.reset))
KEEP(*(.fixed_function.flash_do_internal))
KEEP(*(.fixed_function.flash_do))
KEEP(*(.fixed_function.flash_erase_page))
KEEP(*(.fixed_function.flash_program_word))
KEEP(*(.fixed_function.crc32_init))
KEEP(*(.fixed_function.crc32_u8))
KEEP(*(.fixed_function.crc32_u32))
/*
* Because of alignment requirement
* of startup.vectors, align to 256.
*/
. = ALIGN(256);
KEEP(*(.crc32_table))
KEEP(*(.startup.vectors))
. = ALIGN(16);
*(.text.startup.*)
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
. = ALIGN(8);
} > flash =0xffffffff
/DISCARD/ :
{
*(.bss.startup.0)
}
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
.ARM.exidx : {
PROVIDE(__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE(__exidx_end = .);
} > flash =0xffffffff
.eh_frame_hdr : {*(.eh_frame_hdr)} > flash
.eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
.textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
_etext = .;
_textdata = _etext;
.process_stack :
{
. = ALIGN(8);
__process3_stack_base__ = .;
. += __process3_stack_size__;
. = ALIGN(8);
__process3_stack_end__ = .;
__process2_stack_base__ = .;
. += __process2_stack_size__;
. = ALIGN(8);
__process2_stack_end__ = .;
__process1_stack_base__ = .;
. += __process1_stack_size__;
. = ALIGN(8);
__process1_stack_end__ = .;
__process0_stack_base__ = .;
. += __process0_stack_size__;
. = ALIGN(8);
__process0_stack_end__ = .;
} > ram
.main_stack :
{
. = ALIGN(8);
__main_stack_base__ = .;
. += __main_stack_size__;
. = ALIGN(8);
__main_stack_end__ = .;
} > ram
.data :
{
. = ALIGN(4);
PROVIDE(_data = .);
*(.data)
. = ALIGN(4);
*(.data.*)
. = ALIGN(4);
*(.ramtext)
. = ALIGN(4);
PROVIDE(_edata = .);
} > ram AT > flash =0xffffffff
.bss :
{
. = ALIGN(4);
PROVIDE(_bss_start = .);
*(.bss)
. = ALIGN(4);
*(.bss.*)
. = ALIGN(4);
*(COMMON)
. = ALIGN(512);
__usb_bdt__ = .;
. += 512;
PROVIDE(_bss_end = .);
} > ram
PROVIDE(end = .);
_end = .;
}
__heap_base__ = _end;
__heap_end__ = __ram_end__;

98
example-fs-bb48/touch.c Normal file
View File

@@ -0,0 +1,98 @@
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <mcu/mkl27z.h>
struct TPM {
volatile uint32_t SC;
volatile uint32_t CNT;
volatile uint32_t MOD;
volatile uint32_t C0SC;
volatile uint32_t C0V;
volatile uint32_t C1SC;
volatile uint32_t C1V;
uint32_t rsvd0[13];
volatile uint32_t STATUS;
uint32_t rsvd1[7];
volatile uint32_t POL;
uint32_t rsvd2[4];
volatile uint32_t CONF;
};
static struct TPM *const TPM1 = (struct TPM *)0x40039000;
static chopstx_intr_t tpm1_intr;
#define INTR_REQ_TPM1 18
static void
gpio_assert_low (void)
{
/* Assert LOW. */
PORTB->PCR1 = (1<<8) /* GPIO */
| (0<<6) /* DriveStrengthEnable=0 */
| (0<<4) /* PassiveFilterEnable=0 */
| (1<<2) /* SlewRateEnable = slow */
| (0<<1) /* pull enable = 0 */
| (0<<0) /* pull up select= 0 */
;
GPIOB->PCOR = (1 << 1); /* PTB1: Clear: Output 0 */
}
uint16_t
touch_get (void)
{
chopstx_prio_t prio_old;
uint16_t v;
prio_old = chopstx_setpriority (CHOPSTX_PRIO_INHIBIT_PREEMPTION);
/*
* Start the timer's counter.
* TOF clear, TOIE=1, CPWMS=0, CMOD=1, PS=011.
*/
TPM1->SC = 0xcb;
/* Let the register to pull it up. */
PORTB->PCR1 = (3<<8) /* TPM1_CH1 */
| (0<<6) /* DriveStrengthEnable=0 */
| (0<<4) /* PassiveFilterEnable=0 */
| (1<<2) /* SlewRateEnable = slow */
| (0<<1) /* pull enable = 0 */
| (0<<0) /* pullup select= 0 */
;
chopstx_setpriority (prio_old);
chopstx_intr_wait (&tpm1_intr);
gpio_assert_low ();
v = TPM1->C1V;
/* Clear overflow and CH1 capture. */
TPM1->STATUS = 0x102;
/* Stop the timer. */
TPM1->SC = 0;
TPM1->CNT = 0xffff; /* Writing causes reset of the counter. */
return v;
}
void
touch_init (void)
{
chopstx_claim_irq (&tpm1_intr, INTR_REQ_TPM1);
/* Input capture mode: MSB = 0, MSA = 0 */
/* Rising edge: ELSB=0 ELSA=1 */
TPM1->C1SC = 0x84;
TPM1->POL=0;
/* No trigger. */
/* Stop on overflow: CSOO=1 */
/* Run the timer in the debug mode */
TPM1->CONF = 0x000200c0;
TPM1->CNT = 0xffff; /* Writing causes reset of the counter. */
gpio_assert_low ();
}

9
example-fs-bb48/tty.h Normal file
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);

952
example-fs-bb48/usb-cdc.c Normal file
View File

@@ -0,0 +1,952 @@
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <string.h>
#include "board.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);
}
}
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 (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 (ENDP1);
usb_lld_stall (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);
#define INTR_REQ_USB 24
#define PRIO_TTY 4
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)
{
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)
{
struct chx_poll_head *pd_array[1] = {
(struct chx_poll_head *)&usb_intr
};
chopstx_poll (NULL, 1, pd_array);
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

@@ -5,16 +5,16 @@ PROJECT = hacker-emblem
CHOPSTX = ..
LDSCRIPT= hacker-emblem.ld
CSRC = sys.c hh.c
CSRC = reset.c hh.c
# Hacker Emblem and "Happy Hacking!" demonstration
# CSRC = sys.c hh.c
# CSRC = reset.c hh.c
# Debian logo demonstration
# CSRC = sys.c debian-logo.c
# CSRC = reset.c debian-logo.c
# "Hiroshi & Ayumi with Tulip" demonstration
# CSRC = sys.c hiroshi-ayumi.c
# CSRC = reset.c hiroshi-ayumi.c
###################################
CROSS = arm-none-eabi-
@@ -36,7 +36,7 @@ board.h:
@echo Please make a symbolic link \'board.h\' to a file in ../board;
@exit 1
sys.c: board.h
reset.c: board.h
distclean: clean
rm -f board.h

View File

@@ -34,8 +34,8 @@ struct GPIO {
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
#define GPIOF ((struct GPIO *) GPIOF_BASE)
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0, cnd1;
@@ -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);
@@ -450,7 +450,7 @@ struct SCB
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
static struct SCB *const SCB = ((struct SCB *)SCB_BASE);
#define SCB_SCR_SLEEPDEEP (1 << 2)

View File

@@ -1,7 +1,7 @@
/*
* ST32F0 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__main_stack_size__ = 0x0100; /* Idle+Exception handlers */
__process0_stack_size__ = 0x0100; /* Main program */
__process1_stack_size__ = 0x0100; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */

View File

@@ -34,8 +34,8 @@ struct GPIO {
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
#define GPIOF ((struct GPIO *) GPIOF_BASE)
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0, cnd1;
@@ -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);
@@ -438,7 +438,7 @@ struct SCB
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
static struct SCB *const SCB = ((struct SCB *)SCB_BASE);
#define SCB_SCR_SLEEPDEEP (1 << 2)

View File

@@ -35,8 +35,8 @@ struct GPIO {
#define GPIO_SPEAKER_PIN 1
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd;
@@ -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

@@ -1,5 +1,5 @@
/*
* sys.c - No system routines, but only RESET handler for STM32F030.
* reset.c - No system routines, but only RESET handler for STM32F030.
*
* Copyright (C) 2015 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -31,7 +31,6 @@ reset (void)
}
extern uint8_t __main_stack_end__;
extern void svc (void);
extern void preempt (void);
extern void chx_timer_expired (void);
extern void chx_handle_intr (void);
@@ -44,13 +43,6 @@ static void nmi (void)
static void __attribute__ ((naked))
hard_fault (void)
{
register uint32_t primask;
asm ("mrs %0, PRIMASK" : "=r" (primask));
if (primask)
asm volatile ("b svc");
else
for (;;);
}
@@ -78,7 +70,7 @@ typedef void (*handler)(void);
extern uint8_t __main_stack_end__;
handler vector[] __attribute__ ((section(".vectors"))) = {
(handler)&__main_stack_end__,
(handler)(&__main_stack_end__ - 32),
reset,
nmi, /* nmi */
hard_fault, /* hard fault */
@@ -89,7 +81,7 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
none,
/* 0x20 */
none, none, none, /* reserved */
svc, /* SVCall */
none, /* SVCall */
none, /* Debug */
none, /* reserved */
preempt, /* PendSV */

View File

@@ -8,8 +8,10 @@ PROJECT = sample
CHOPSTX = ..
LDSCRIPT= sample.ld
### LDSCRIPT= sample.ld.m3
CSRC = sys.c sample.c
### CSRC = sys.c aes-constant-ft.c sample.c
CSRC = sample.c
CHIP=stm32f0
USE_SYS = yes
###################################
CROSS = arm-none-eabi-
@@ -20,8 +22,8 @@ OBJCOPY = $(CROSS)objcopy
### MCU = cortex-m3
MCU = cortex-m0
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DHAVE_SYS_H -DFREE_STANDING -DMHZ=48
### DEFS = -DFREE_STANDING -DHAVE_SYS_H -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=48
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
OPT = -O3 -Os -g
LIBS =

View File

@@ -1,145 +0,0 @@
/*
* aes-constant-ft.c - AES forward tables.
*
* We need something useful for the initial flash ROM page (4 Ki
* bytes), which cannot be modified after installation. Even after
* upgrade of the firmware, it stays intact.
*
* We decide to put 3/4 of AES forward tables to fill 3 Ki bytes, as
* its useful and it won't change.
*
* The code was taken from aes.c of PolarSSL version 0.14, and then,
* modified to add section names.
*
* Since this is just a data, it wouldn't be copyright-able, but the
* original auther would claim so. Thus, we put original copyright
* notice here. It is highly likely that there will be no such a
* thing for copyright. Nevertheless, we think that PolarSSL is good
* software to address here, and encourage people using it.
*
*/
#include <stdint.h>
/*
* Original copyright notice is below:
*/
/*
* FIPS-197 compliant AES implementation
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
*
* http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
/*
* Forward tables
*/
#define FT \
\
V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
#define V(a,b,c,d) 0x##a##b##c##d
const uint32_t FT0[256] __attribute__((section(".sys.0"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
const uint32_t FT1[256] __attribute__((section(".sys.1"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
const uint32_t FT2[256] __attribute__((section(".sys.2"))) = { FT };
#undef V
#ifdef ORIGINAL_IMPLEMENTATION
#define V(a,b,c,d) 0x##d##a##b##c
const uint32_t FT3[256] = { FT };
#undef V
#endif

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,7 +1,7 @@
/*
* ST32F0 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__main_stack_size__ = 0x0100; /* Idle+Exception handlers */
__process0_stack_size__ = 0x0100; /* Main program */
__process1_stack_size__ = 0x0100; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */
@@ -30,10 +30,10 @@ SECTIONS
KEEP(*(.sys.version))
KEEP(*(.sys.board_id))
KEEP(*(.sys.board_name))
build/sys.o(.text)
build/sys.o(.text.*)
build/sys.o(.rodata)
build/sys.o(.rodata.*)
build/sys-*.o(.text)
build/sys-*.o(.text.*)
build/sys-*.o(.rodata)
build/sys-*.o(.rodata.*)
. = ALIGN(1024);
/*
*(.sys.0)

View File

@@ -1,7 +1,7 @@
/*
* ST32F103 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__main_stack_size__ = 0x0100; /* Idle+Exception handlers */
__process0_stack_size__ = 0x0100; /* Main program */
__process1_stack_size__ = 0x0100; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */
@@ -30,10 +30,10 @@ SECTIONS
KEEP(*(.sys.version))
KEEP(*(.sys.board_id))
KEEP(*(.sys.board_name))
build/sys.o(.text)
build/sys.o(.text.*)
build/sys.o(.rodata)
build/sys.o(.rodata.*)
build/sys-*.o(.text)
build/sys-*.o(.text.*)
build/sys-*.o(.rodata)
build/sys-*.o(.rodata.*)
. = ALIGN(1024);
*(.sys.0)
*(.sys.1)

View File

@@ -5,8 +5,13 @@ PROJECT = lcd
CHOPSTX = ..
NEUGSRC = ./neug/src
LDSCRIPT= lcd.ld
CSRC = sys.c aes-constant-ft.c primer2-switches.c primer2-ts.c lcd.c main.c \
adc_stm32f103.c neug.c sha256.c
CSRC = primer2-switches.c primer2-ts.c lcd.c main.c \
neug.c sha256.c
CHIP=stm32f103
USE_SYS = yes
USE_USB = yes
USE_ADC = yes
###################################
CROSS = arm-none-eabi-
@@ -15,8 +20,8 @@ LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DHAVE_SYS_H -DFREE_STANDING -DMHZ=48
# DEFS = -DFREE_STANDING -DHAVE_SYS_H -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=48
# DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
OPT = -O3 -Os -g
INCDIR = $(NEUGSRC)
LIBS =

View File

@@ -1,145 +0,0 @@
/*
* aes-constant-ft.c - AES forward tables.
*
* We need something useful for the initial flash ROM page (4 Ki
* bytes), which cannot be modified after installation. Even after
* upgrade of the firmware, it stays intact.
*
* We decide to put 3/4 of AES forward tables to fill 3 Ki bytes, as
* its useful and it won't change.
*
* The code was taken from aes.c of PolarSSL version 0.14, and then,
* modified to add section names.
*
* Since this is just a data, it wouldn't be copyright-able, but the
* original auther would claim so. Thus, we put original copyright
* notice here. It is highly likely that there will be no such a
* thing for copyright. Nevertheless, we think that PolarSSL is good
* software to address here, and encourage people using it.
*
*/
#include <stdint.h>
/*
* Original copyright notice is below:
*/
/*
* FIPS-197 compliant AES implementation
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
*
* http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
/*
* Forward tables
*/
#define FT \
\
V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
#define V(a,b,c,d) 0x##a##b##c##d
const uint32_t FT0[256] __attribute__((section(".sys.0"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
const uint32_t FT1[256] __attribute__((section(".sys.1"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
const uint32_t FT2[256] __attribute__((section(".sys.2"))) = { FT };
#undef V
#ifdef ORIGINAL_IMPLEMENTATION
#define V(a,b,c,d) 0x##d##a##b##c
const uint32_t FT3[256] = { FT };
#undef V
#endif

View File

@@ -1,7 +1,7 @@
/*
* ST32F103 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__main_stack_size__ = 0x0100; /* Idle+Exception handlers */
__process0_stack_size__ = 0x0200; /* main */
__process1_stack_size__ = 0x0100; /* lcd init */
__process2_stack_size__ = 0x0180; /* rng */

View File

@@ -113,10 +113,6 @@ void adc3_conversion (uint32_t *result)
void adc3_stop (void)
{
#if USE_ADC3_INTR
chopstx_release_irq (&adc3_intr);
#endif
/* Power off. */
ADC3->CR1 = 0;
ADC3->CR2 = 0;

View File

@@ -1,467 +0,0 @@
/*
* sys.c - system routines for the initial page for STM32F103.
*
* Copyright (C) 2013, 2014, 2015 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*
* When the flash ROM is protected, we cannot modify the initial page.
* We put some system routines (which is useful for any program) here.
*/
#include <stdint.h>
#include <stdlib.h>
#include "board.h"
/* Adds port C for shutdown function. */
#undef RCC_ENR_IOP_EN
#undef RCC_RSTR_IOP_RST
#define RCC_ENR_IOP_EN \
(RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_IOPEEN \
| RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPBEN)
#define RCC_RSTR_IOP_RST \
(RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPDRST | RCC_APB2RSTR_IOPERST \
| RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPBRST)
#include "clk_gpio_init.c"
static struct GPIO *const GPIO_OTHER1 = ((struct GPIO *const) GPIOC_BASE);
static struct GPIO *const GPIO_OTHER2 = ((struct GPIO *const) GPIOB_BASE);
static void __attribute__((used))
gpio_init_primer2 (void)
{
gpio_init ();
/*
* Port C setup.
* Everything input with pull-up except:
* PC0 - Analog input (Touch panel L X+)
* PC1 - Analog input (Touch panel R X-)
* PC2 - Analog input (Touch panel U Y+)
* PC3 - Analog input (Touch panel D Y-)
* PC6 - Normal input because there is an external resistor.
* PC7 - Normal input because there is an external resistor.
* PC13 - Push Pull output (SHUTDOWN)
*/
GPIO_OTHER1->ODR = 0xffffdfff;
GPIO_OTHER1->CRL = 0x44880000;
GPIO_OTHER1->CRH = 0x88388888;
/*
* Port B setup.
* Everything input with pull-up except:
* PB8 - Backlight enable output.
* PB13 - Alternate output (AUDIO SPI2 SCK).
* PB14 - Normal input (AUDIO SPI2 MISO).
* PB15 - Alternate output (AUDIO SPI2 MOSI).
*/
GPIO_OTHER2->ODR = 0xffffffff;
GPIO_OTHER2->CRL = 0x88888888;
GPIO_OTHER2->CRH = 0xb4b88883;
}
#define CORTEX_PRIORITY_BITS 4
#define CORTEX_PRIORITY_MASK(n) ((n) << (8 - CORTEX_PRIORITY_BITS))
#define USB_LP_CAN1_RX0_IRQn 20
#define STM32_USB_IRQ_PRIORITY 11
struct NVIC {
uint32_t ISER[8];
uint32_t unused1[24];
uint32_t ICER[8];
uint32_t unused2[24];
uint32_t ISPR[8];
uint32_t unused3[24];
uint32_t ICPR[8];
uint32_t unused4[24];
uint32_t IABR[8];
uint32_t unused5[56];
uint32_t IPR[60];
};
static struct NVIC *const NVICBase = ((struct NVIC *const)0xE000E100);
#define NVIC_ISER(n) (NVICBase->ISER[n >> 5])
#define NVIC_ICPR(n) (NVICBase->ICPR[n >> 5])
#define NVIC_IPR(n) (NVICBase->IPR[n >> 2])
static void
nvic_enable_vector (uint32_t n, uint32_t prio)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh)) | (prio << sh);
NVIC_ICPR (n) = 1 << (n & 0x1F);
NVIC_ISER (n) = 1 << (n & 0x1F);
}
static void
usb_cable_config (int enable)
{
#if defined(GPIO_USB_SET_TO_ENABLE)
if (enable)
GPIO_USB->BSRR = (1 << GPIO_USB_SET_TO_ENABLE);
else
GPIO_USB->BRR = (1 << GPIO_USB_SET_TO_ENABLE);
#elif defined(GPIO_USB_CLEAR_TO_ENABLE)
if (enable)
GPIO_USB->BRR = (1 << GPIO_USB_CLEAR_TO_ENABLE);
else
GPIO_USB->BSRR = (1 << GPIO_USB_CLEAR_TO_ENABLE);
#else
(void)enable;
#endif
}
void
set_led (int on)
{
#if defined(GPIO_LED_CLEAR_TO_EMIT)
if (on)
GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
else
GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
#else
if (on)
GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT);
else
GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT);
#endif
}
static void wait (int count)
{
int i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
}
static void
usb_lld_sys_shutdown (void)
{
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
usb_cable_config (0);
}
static void
usb_lld_sys_init (void)
{
if ((RCC->APB1ENR & RCC_APB1ENR_USBEN)
&& (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0)
/* Make sure the device is disconnected, even after core reset. */
{
usb_lld_sys_shutdown ();
/* Disconnect requires SE0 (>= 2.5uS). */
wait (300);
}
usb_cable_config (1);
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
/*
* Note that we also have other IRQ(s):
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
* USBWakeUp_IRQn (suspend/resume)
*/
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
}
#define FLASH_KEY1 0x45670123UL
#define FLASH_KEY2 0xCDEF89ABUL
enum flash_status
{
FLASH_BUSY = 1,
FLASH_ERROR_PG,
FLASH_ERROR_WRP,
FLASH_COMPLETE,
FLASH_TIMEOUT
};
static void __attribute__ ((used))
flash_unlock (void)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
#define intr_disable() asm volatile ("cpsid i" : : : "memory")
#define intr_enable() asm volatile ("cpsie i" : : : "memory")
#define FLASH_SR_BSY 0x01
#define FLASH_SR_PGERR 0x04
#define FLASH_SR_WRPRTERR 0x10
#define FLASH_SR_EOP 0x20
#define FLASH_CR_PG 0x0001
#define FLASH_CR_PER 0x0002
#define FLASH_CR_MER 0x0004
#define FLASH_CR_OPTPG 0x0010
#define FLASH_CR_OPTER 0x0020
#define FLASH_CR_STRT 0x0040
#define FLASH_CR_LOCK 0x0080
#define FLASH_CR_OPTWRE 0x0200
#define FLASH_CR_ERRIE 0x0400
#define FLASH_CR_EOPIE 0x1000
static int
flash_wait_for_last_operation (uint32_t timeout)
{
int status;
do
{
status = FLASH->SR;
if (--timeout == 0)
break;
}
while ((status & FLASH_SR_BSY) != 0);
return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR);
}
#define FLASH_PROGRAM_TIMEOUT 0x00010000
#define FLASH_ERASE_TIMEOUT 0x01000000
static int
flash_program_halfword (uint32_t addr, uint16_t data)
{
int status;
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
intr_disable ();
if (status == 0)
{
FLASH->CR |= FLASH_CR_PG;
*(volatile uint16_t *)addr = data;
status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT);
FLASH->CR &= ~FLASH_CR_PG;
}
intr_enable ();
return status;
}
static int
flash_erase_page (uint32_t addr)
{
int status;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
intr_disable ();
if (status == 0)
{
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
FLASH->CR &= ~FLASH_CR_PER;
}
intr_enable ();
return status;
}
static int
flash_check_blank (const uint8_t *p_start, size_t size)
{
const uint8_t *p;
for (p = p_start; p < p_start + size; p++)
if (*p != 0xff)
return 0;
return 1;
}
extern uint8_t __flash_start__, __flash_end__;
static int
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
{
int status;
uint32_t flash_start = (uint32_t)&__flash_start__;
uint32_t flash_end = (uint32_t)&__flash_end__;
if (dst_addr < flash_start || dst_addr + len > flash_end)
return 0;
while (len)
{
uint16_t hw = *src++;
hw |= (*src++ << 8);
status = flash_program_halfword (dst_addr, hw);
if (status != 0)
return 0; /* error return */
dst_addr += 2;
len -= 2;
}
return 1;
}
#define OPTION_BYTES_ADDR 0x1ffff800
static int
flash_protect (void)
{
int status;
uint32_t option_bytes_value;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
intr_disable ();
if (status == 0)
{
FLASH->OPTKEYR = FLASH_KEY1;
FLASH->OPTKEYR = FLASH_KEY2;
FLASH->CR |= FLASH_CR_OPTER;
FLASH->CR |= FLASH_CR_STRT;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);
FLASH->CR &= ~FLASH_CR_OPTER;
}
intr_enable ();
if (status != 0)
return 0;
option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR;
return (option_bytes_value & 0xff) == 0xff ? 1 : 0;
}
static void __attribute__((naked))
flash_erase_all_and_exec (void (*entry)(void))
{
uint32_t addr = (uint32_t)&__flash_start__;
uint32_t end = (uint32_t)&__flash_end__;
int r;
while (addr < end)
{
r = flash_erase_page (addr);
if (r != 0)
break;
addr += FLASH_PAGE_SIZE;
}
if (addr >= end)
(*entry) ();
for (;;);
}
struct SCB
{
volatile uint32_t CPUID;
volatile uint32_t ICSR;
volatile uint32_t VTOR;
volatile uint32_t AIRCR;
volatile uint32_t SCR;
volatile uint32_t CCR;
volatile uint8_t SHP[12];
volatile uint32_t SHCSR;
volatile uint32_t CFSR;
volatile uint32_t HFSR;
volatile uint32_t DFSR;
volatile uint32_t MMFAR;
volatile uint32_t BFAR;
volatile uint32_t AFSR;
volatile uint32_t PFR[2];
volatile uint32_t DFR;
volatile uint32_t ADR;
volatile uint32_t MMFR[4];
volatile uint32_t ISAR[5];
};
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
#define SYSRESETREQ 0x04
static void
nvic_system_reset (void)
{
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ);
asm volatile ("dsb");
for (;;);
}
static void __attribute__ ((naked))
reset (void)
{
extern const unsigned long *FT0, *FT1, *FT2;
/*
* This code may not be at the start of flash ROM, because of DFU.
* So, we take the address from PC.
*/
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
"ldr r0, 1f\n\t" /* r0 = SCR */
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
"mov r2, #0x1000\n\t"
"add r1, r1, r2\n\t"
"sub r2, r2, #1\n\t"
"bic r1, r1, r2\n\t"
"str r1, [r0, #8]\n\t" /* Set SCR->VCR */
"ldr r0, [r1], #4\n\t"
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
"ldr r0, [r1]\n\t" /* Reset handler. */
"bx r0\n\t"
".align 2\n"
"1: .word 0xe000ed00"
: /* no output */ : /* no input */ : "memory");
/* Never reach here. */
/* Artificial entry to refer FT0, FT1, and FT2. */
asm volatile (""
: : "r" (FT0), "r" (FT1), "r" (FT2));
}
typedef void (*handler)(void);
extern uint8_t __ram_end__;
handler vector[] __attribute__ ((section(".vectors"))) = {
(handler)&__ram_end__,
reset,
(handler)set_led,
flash_unlock,
(handler)flash_program_halfword,
(handler)flash_erase_page,
(handler)flash_check_blank,
(handler)flash_write,
(handler)flash_protect,
(handler)flash_erase_all_and_exec,
usb_lld_sys_init,
usb_lld_sys_shutdown,
nvic_system_reset,
clock_init,
gpio_init_primer2,
NULL,
};
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/
/* sys version: "2.0" */
'2', 0, '.', 0, '0', 0,
};

View File

@@ -1,115 +0,0 @@
extern const uint8_t sys_version[8];
typedef void (*handler)(void);
extern handler vector[16];
static inline const uint8_t *
unique_device_id (void)
{
/* STM32F103 has 96-bit unique device identifier */
const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
return addr;
}
static inline void
set_led (int on)
{
void (*func) (int) = (void (*)(int))vector[2];
return (*func) (on);
}
static inline void
flash_unlock (void)
{
(*vector[3]) ();
}
static inline int
flash_program_halfword (uint32_t addr, uint16_t data)
{
int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4];
return (*func) (addr, data);
}
static inline int
flash_erase_page (uint32_t addr)
{
int (*func) (uint32_t) = (int (*)(uint32_t))vector[5];
return (*func) (addr);
}
static inline int
flash_check_blank (const uint8_t *p_start, size_t size)
{
int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6];
return (*func) (p_start, size);
}
static inline int
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
{
int (*func) (uint32_t, const uint8_t *, size_t)
= (int (*)(uint32_t, const uint8_t *, size_t))vector[7];
return (*func) (dst_addr, src, len);
}
static inline int
flash_protect (void)
{
int (*func) (void) = (int (*)(void))vector[8];
return (*func) ();
}
static inline void __attribute__((noreturn))
flash_erase_all_and_exec (void (*entry)(void))
{
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9];
(*func) (entry);
for (;;);
}
static inline void
usb_lld_sys_init (void)
{
(*vector[10]) ();
}
static inline void
usb_lld_sys_shutdown (void)
{
(*vector[11]) ();
}
static inline void
nvic_system_reset (void)
{
(*vector[12]) ();
}
/*
* Users can override INLINE by 'attribute((used))' to have an
* implementation defined.
*/
#if !defined(INLINE)
#define INLINE __inline__
#endif
static INLINE void
clock_init (void)
{
(*vector[13]) ();
}
static INLINE void
gpio_init (void)
{
(*vector[14]) ();
}

239
mcu/ABOUT-SYS Normal file
View File

@@ -0,0 +1,239 @@
Consideration about SYS and the first pages of flash ROM
========================================================
Now, I'm developing something like SYS for Kinetis L MCU, so, I write
this document.
* Compatibility
SYS 1.0: The first verson
SYS 2.0: Added clock_init, gpio_init
SYS 2.1: Added sys_board_id, sys_board_name
SYS 3.0: Don't setup NVIC priority by usb_lld_sys_init
* Macro definition by DEFS in Makefile
- USE_SYS_CLOCK_GPIO_SETTING
Define this macro to ask chopstx/entry.c (the runtime code before
MAIN function) to use function entries in SYS for clock_init and
gpio_init.
If not defined, entry.c includes the code for clock_init and
gpio_init which might be different to a board, and use them (entries
in SYS will not be used). This works well with the ROM of SYS
1.0.
Note that SYS entries of clock_init and gpio_init were introduced
in SYS 2.0. So, enable this macro only if the ROM is SYS 2.0 or
later.
- USE_SYS_BOARD_ID
Define this macro in a driver to get "sys_board_id" in SYS, so
that the driver can support various boards at runtime by changing
the settings according to the board.
A simple driver could only support a single board, by the compile
time (BOARD_ID in board-*.h) choice of of a settings.
Note that SYS entries of sys_board_id and sys_board_name were
introduced in SYS 2.1. So, enable this macro only if the ROM is
SYS 2.1 or later.
- USE_SYS3
By defining this, it will have same effect of defining both of
USE_SYS_CLOCK_GPIO_SETTING and USE_SYS_BOARD_ID internally.
About SYS on STM32F103
======================
In the development of Gnuk, we developed:
SYS: The system predefined routines for STM32F103
It is now maintained as example-cdc/sys.c.
There is another version in example-led/sys.c, which also support
STM32F030, as well as STM32F103. But, it wouldn't be useful for
STM32F030. In fact, the file example-fsm-55/sys.c has name sys.c
but it doesn't include any system routines.
The original issue was:
(1) When it's protected, STM32F103 can't change the first 4KiB of
flash ROM at run time.
(2) We want to support firmware upgrade through its USB.
Later on, we add another point.
(3) It is good if the executable of Gnuk could be shared among
different boards.
For (1) and (2), we decided put some useful routines and data which is
not need to be changed.
Now, the first 4KiB of flash ROM consists of:
1KiB: SYS
3KiB: 3/4 of AES forward tables
SYS consists of:
Internal: reset entry, end of RAM
Data: board identification
Routines: board specific
board independent
and here is the list of all.
* Internal routines
reset entry
end of RAM
* Board identification
sys_version
sys_board_id
sys_board_name
* Board specific routines
* led
set_led
* mcu/board lower level
clock_init
gpio_init
* usb
usb_lld_sys_init
usb_lld_sys_shutdown
* Board independent routines
* flash ROM access routines
unlock
write halfword
erase page
brank check
write page
protect
erase_all & exec to ram
* system reset routine
nvic_system_reset
The routines of clock_init and gpio_init are here because of some
historical reasons. (We could design a system with no such exported
routines: by defining: those things done internally after reset and
before calling the application.)
Those are exported as entries of SYS, and it is the responsibility of
the application which do initialize clock and GPIO, calling those
routines.
USB routines are needed because of hardware practice of STM32F103.
With STM32F103, each board has different way for handling the pull up
of USB D+ and how the device asks re-enumeration to host PC. In my
opinion, if it's defined as full speed device and it's OK for us not
to use high impedance (but asserting to LOW, instead) of D+ to ask
re-enumeration, we can just pull up D+ always. And we wouldn't need
such routines in SYS.
About SYS on Kinetis L
======================
For Kinetis L, because it's ROM has the original firmware upgrade
support by the vendor (though USB HID), all that we needed for
firmware upgrade would be just erasing to factory settings.
And it has no limitation like STM32F103's first 4KiB flash ROM.
All pages can be updated at run time.
Nevertheless, the first two pages (2KiB) of KL27Z is still difficult
to use.
So, I decide to introduce something like SYS for Kinetis L.
* Layout
Three pages (3KiB) usage:
------------ The first page
End of RAM <-- not used but hardware defines this
Address of reset entry
sys_version
sys_board_info (id, name)
sys_vector
other SYS routines and data...
------------ The second page
FLASH CONFIG: 16-byte
Reset entry function
flash routines
CRC-32 routines
CRC-32 table (768-byte of CRC-32 table)
------------ The third page
MAGIC 256-byte (256-byte of the last part of CRC-32 table)
...
vectors (initial MSP, reset, ...)
...
* data: Board identification
sys_version
sys_board_id
sys_board_name ; null terminated
* Board specific routines
* mcu/board lower level
clock_init
gpio_init
* led
set_led
* data: Board independent routines
* flash ROM access code to be loaded on to RAM
* system reset routine???
nvic_system_reset
* data: vectors for routines and data
sys_version
sys_board_id
address of sys_board_name
address of set_led
address of clock_init
address of gpio_init
address of ...
An Example of No-use of SYS
===========================
See example-fsm-55 for an example of no use of SYS.
While chopstx/entry.c defines vectors in ROM and RAM, those are simply
discarded by example-fsm-55/hacker-emblem.ld.
--

104
mcu/clk_gpio_init-mkl27z.c Normal file
View File

@@ -0,0 +1,104 @@
/*
* clk_gpio_init-mkl27z.c - Clock and GPIO initialization for Kinetis L.
*
* Copyright (C) 2016 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 <mcu/mkl27z.h>
struct MCG {
volatile uint8_t C1; /* MCG Control Register 1 */
volatile uint8_t C2; /* MCG Control Register 2 */
uint8_t reserved0[4]; /* */
volatile uint8_t S; /* MCG Status Register */
uint8_t reserved1[1]; /* */
volatile uint8_t SC; /* MCG Status and Control Register */
uint8_t reserved2[15]; /* */
volatile uint8_t MC; /* MCG Miscellaneous Control Register */
};
static struct MCG *const MCG = (struct MCG *)0x40064000;
struct USB_CLK_RECOVER {
volatile uint8_t CTRL; /* USB Clock */
uint8_t rsvd38[3]; /* recovery control */
volatile uint8_t IRC_EN; /* IRC48M oscillator */
uint8_t rsvd39[3]; /* enable register */
volatile uint8_t INT_EN; /* Clock recovery */
uint8_t rsvd40[3]; /* interrupt enable */
volatile uint8_t INT_STATUS; /* Clock recovery */
/* interrupt status */
};
static struct USB_CLK_RECOVER *const USB_CLK_RECOVER =
(struct USB_CLK_RECOVER *)0x40072140;
static void __attribute__((used))
clock_init (void)
{
SIM->CLKDIV1 = (SIM->CLKDIV1 & 0xF0070000)
| (1 << 16) /* OUTDIV4 = 001: Divide-by-2 */
;
MCG->MC = 0x80; /* HIRC Enable, LIRC_DIV2=000: Division factor=1 */
MCG->C1 = 0x00; /* Select HIRC clock, LIRC disabled. */
/* Make sure HIRC clock is selected. */
while ((MCG->S & 0x0c) != 0)
;
/* TPMSRC=IRC48M, USBSRC=IRC48M, CLOKOUTSEL=LPO, RTC-clock */
SIM->SOPT2 = 0x01040060;
SIM->SCGC4 = (1 << 18); /* Enable USB FS clock */
SIM->SCGC5 = (1 << 10); /* Enable Port B clock */
SIM->SCGC6 = (1 << 25)|1; /* Enable TPM1 clock */
SIM->COPC = 0; /* COP disabled */
/* Crystal-less USB setup. */
USB_CLK_RECOVER->IRC_EN = 0x02;
USB_CLK_RECOVER->CTRL = 0x80;
}
static void __attribute__((used))
gpio_init (void)
{
PORTB->PCR0 = (1<<8) /* GPIO */
| (0<<6) /* DriveStrengthEnable=0 */
| (0<<4) /* PassiveFilterEnable=0 */
| (1<<2) /* SlewRateEnable = slow */
| (0<<1) /* pull enable = 0 */
| (0<<0) /* pull up select= 0 */
;
PORTB->PCR1 = (1<<8) /* GPIO */
| (0<<6) /* DriveStrengthEnable=0 */
| (0<<4) /* PassiveFilterEnable=0 */
| (1<<2) /* SlewRateEnable = slow */
| (0<<1) /* pull enable = 0 */
| (0<<0) /* pull up select= 0 */
;
GPIOB->PDDR = (1 << 1) | (1 << 0); /* PTB0, PTB1 : Output */
GPIOB->PSOR = (1 << 0); /* PTB0: Set : Light off */
GPIOB->PCOR = (1 << 1); /* PTB1: Clear: Output 0 */
}

View File

@@ -1,5 +1,5 @@
/*
* clk_gpio_init.c - Clock and GPIO initialization.
* clk_gpio_init-stm32.c - Clock and GPIO initialization for STM32.
*
* Copyright (C) 2015 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -100,7 +100,7 @@ struct RCC {
};
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
static struct RCC *const RCC = (struct RCC *)RCC_BASE;
#define RCC_APB1ENR_USBEN 0x00800000
#define RCC_APB1RSTR_USBRST 0x00800000
@@ -163,7 +163,7 @@ struct SYSCFG {
#define SYSCFG_CFGR1_MEM_MODE 0x03
#define SYSCFG_BASE (APBPERIPH_BASE + 0x00010000)
static struct SYSCFG *const SYSCFG = ((struct SYSCFG *const) SYSCFG_BASE);
static struct SYSCFG *const SYSCFG = (struct SYSCFG *)SYSCFG_BASE;
#endif
struct FLASH {
@@ -179,7 +179,7 @@ struct FLASH {
};
#define FLASH_R_BASE (AHBPERIPH_BASE + 0x2000)
static struct FLASH *const FLASH = ((struct FLASH *const) FLASH_R_BASE);
static struct FLASH *const FLASH = (struct FLASH *)FLASH_R_BASE;
static void __attribute__((used))
clock_init (void)
@@ -231,7 +231,7 @@ clock_init (void)
RCC->APB2RSTR = RCC_APB2RSTR_SYSCFGRST;
RCC->APB2RSTR = 0;
# if defined(HAVE_SYS_H)
# if defined(STM32F0_USE_VECTOR_ON_RAM)
/* Use vectors on RAM */
SYSCFG->CFGR1 = (SYSCFG->CFGR1 & ~SYSCFG_CFGR1_MEM_MODE) | 3;
# endif
@@ -279,7 +279,7 @@ struct AFIO
};
#define AFIO_BASE 0x40010000
static struct AFIO *const AFIO = (struct AFIO *const)AFIO_BASE;
static struct AFIO *const AFIO = (struct AFIO *)AFIO_BASE;
#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
#define AFIO_MAPR_SWJ_CFG_DISABLE 0x04000000
@@ -308,12 +308,12 @@ struct GPIO {
#define GPIOE ((struct GPIO *) GPIOE_BASE)
#endif
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
static struct GPIO *const GPIO_LED = (struct GPIO *)GPIO_LED_BASE;
#ifdef GPIO_USB_BASE
static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE);
static struct GPIO *const GPIO_USB = (struct GPIO *)GPIO_USB_BASE;
#endif
#ifdef GPIO_OTHER_BASE
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
static struct GPIO *const GPIO_OTHER = (struct GPIO *)GPIO_OTHER_BASE;
#endif
static void __attribute__((used))

70
mcu/mkl27z.h Normal file
View File

@@ -0,0 +1,70 @@
/* System Integration Module. */
struct SIM {
volatile uint32_t SOPT1; /* System Options Register 1 */
volatile uint32_t SOPT1CFG; /* SOPT1 Configuration Register */
uint32_t reserved0[1023]; /* */
volatile uint32_t SOPT2; /* System Options Register 2 */
uint32_t reserved1[1]; /* */
volatile uint32_t SOPT4; /* System Options Register 4 */
volatile uint32_t SOPT5; /* System Options Register 5 */
uint32_t reserved2[1]; /* */
volatile uint32_t SOPT7; /* System Options Register 7 */
uint32_t reserved3[2]; /* */
volatile uint32_t SDID; /* System Device Identification Register */
uint32_t reserved4[3]; /* */
volatile uint32_t SCGC4; /* System Clock Gating Control Register 4 */
volatile uint32_t SCGC5; /* System Clock Gating Control Register 5 */
volatile uint32_t SCGC6; /* System Clock Gating Control Register 6 */
volatile uint32_t SCGC7; /* System Clock Gating Control Register 7 */
volatile uint32_t CLKDIV1; /* System Clock Divider Register 1 */
uint32_t reserved5[1]; /* */
volatile uint32_t FCFG1; /* Flash Configuration Register 1 */
volatile uint32_t FCFG2; /* Flash Configuration Register 2 */
uint32_t reserved6[1]; /* */
volatile uint32_t UIDMH; /* Unique Identification Register Mid-High */
volatile uint32_t UIDML; /* Unique Identification Register Mid Low */
volatile uint32_t UIDL; /* Unique Identification Register Low */
uint32_t reserved7[39]; /* */
volatile uint32_t COPC; /* COP Control Register */
volatile uint32_t SRVCOP; /* Service COP */
};
/* Port control. */
struct PORT {
volatile uint32_t PCR0; volatile uint32_t PCR1;
volatile uint32_t PCR2; volatile uint32_t PCR3;
volatile uint32_t PCR4; volatile uint32_t PCR5;
volatile uint32_t PCR6; volatile uint32_t PCR7;
volatile uint32_t PCR8; volatile uint32_t PCR9;
volatile uint32_t PCR10; volatile uint32_t PCR11;
volatile uint32_t PCR12; volatile uint32_t PCR13;
volatile uint32_t PCR14; volatile uint32_t PCR15;
volatile uint32_t PCR16; volatile uint32_t PCR17;
volatile uint32_t PCR18; volatile uint32_t PCR19;
volatile uint32_t PCR20; volatile uint32_t PCR21;
volatile uint32_t PCR22; volatile uint32_t PCR23;
volatile uint32_t PCR24; volatile uint32_t PCR25;
volatile uint32_t PCR26; volatile uint32_t PCR27;
volatile uint32_t PCR28; volatile uint32_t PCR29;
volatile uint32_t PCR30; volatile uint32_t PCR31;
volatile uint32_t GPCLR; volatile uint32_t GPCHR;
uint32_t reserved[6];
volatile uint32_t ISFR;
};
struct GPIO {
volatile uint32_t PDOR; /* Port Data Output Register */
volatile uint32_t PSOR; /* Port Set Output Register */
volatile uint32_t PCOR; /* Port Clear Output Register */
volatile uint32_t PTOR; /* Port Toggle Output Register */
volatile uint32_t PDIR; /* Port Data Input Register */
volatile uint32_t PDDR; /* Port Data Direction Register */
};
static struct SIM *const SIM = (struct SIM *)0x40047000;
static struct PORT *const PORTB = (struct PORT *)0x4004A000;
static struct PORT *const PORTD = (struct PORT *)0x4004C000;
static struct PORT *const PORTE = (struct PORT *)0x4004D000;
static struct GPIO *const GPIOB = (struct GPIO *)0x400FF040;
static struct GPIO *const GPIOD = (struct GPIO *)0x400FF0C0;
static struct GPIO *const GPIOE = (struct GPIO *)0x400FF100;

700
mcu/stm32f103.h Normal file
View File

@@ -0,0 +1,700 @@
#define PERIPH_BASE 0x40000000
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
struct RCC {
volatile uint32_t CR;
volatile uint32_t CFGR;
volatile uint32_t CIR;
volatile uint32_t APB2RSTR;
volatile uint32_t APB1RSTR;
volatile uint32_t AHBENR;
volatile uint32_t APB2ENR;
volatile uint32_t APB1ENR;
volatile uint32_t BDCR;
volatile uint32_t CSR;
};
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
static struct RCC *const RCC = (struct RCC *)RCC_BASE;
#define RCC_AHBENR_DMA1EN 0x00000001
#define RCC_AHBENR_CRCEN 0x00000040
#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
struct CRC {
volatile uint32_t DR;
volatile uint8_t IDR;
uint8_t RESERVED0;
uint16_t RESERVED1;
volatile uint32_t CR;
};
#define CRC_BASE (AHBPERIPH_BASE + 0x3000)
static struct CRC *const CRC = (struct CRC *)CRC_BASE;
struct ADC {
volatile uint32_t SR;
volatile uint32_t CR1;
volatile uint32_t CR2;
volatile uint32_t SMPR1;
volatile uint32_t SMPR2;
volatile uint32_t JOFR1;
volatile uint32_t JOFR2;
volatile uint32_t JOFR3;
volatile uint32_t JOFR4;
volatile uint32_t HTR;
volatile uint32_t LTR;
volatile uint32_t SQR1;
volatile uint32_t SQR2;
volatile uint32_t SQR3;
volatile uint32_t JSQR;
volatile uint32_t JDR1;
volatile uint32_t JDR2;
volatile uint32_t JDR3;
volatile uint32_t JDR4;
volatile uint32_t DR;
};
#define ADC1_BASE (APB2PERIPH_BASE + 0x2400)
#define ADC2_BASE (APB2PERIPH_BASE + 0x2800)
static struct ADC *const ADC1 = (struct ADC *)ADC1_BASE;
static struct ADC *const ADC2 = (struct ADC *)ADC2_BASE;
#define ADC_CR1_DUALMOD_0 0x00010000
#define ADC_CR1_DUALMOD_1 0x00020000
#define ADC_CR1_DUALMOD_2 0x00040000
#define ADC_CR1_DUALMOD_3 0x00080000
#define ADC_CR1_SCAN 0x00000100
#define ADC_CR2_ADON 0x00000001
#define ADC_CR2_CONT 0x00000002
#define ADC_CR2_CAL 0x00000004
#define ADC_CR2_RSTCAL 0x00000008
#define ADC_CR2_DMA 0x00000100
#define ADC_CR2_ALIGN 0x00000800
#define ADC_CR2_EXTSEL 0x000E0000
#define ADC_CR2_EXTSEL_0 0x00020000
#define ADC_CR2_EXTSEL_1 0x00040000
#define ADC_CR2_EXTSEL_2 0x00080000
#define ADC_CR2_EXTTRIG 0x00100000
#define ADC_CR2_SWSTART 0x00400000
#define ADC_CR2_TSVREFE 0x00800000
struct DMA_Channel {
volatile uint32_t CCR;
volatile uint32_t CNDTR;
volatile uint32_t CPAR;
volatile uint32_t CMAR;
};
struct DMA {
volatile uint32_t ISR;
volatile uint32_t IFCR;
};
#define STM32_DMA_CR_MINC DMA_CCR1_MINC
#define STM32_DMA_CR_MSIZE_WORD DMA_CCR1_MSIZE_1
#define STM32_DMA_CR_PSIZE_WORD DMA_CCR1_PSIZE_1
#define STM32_DMA_CR_TCIE DMA_CCR1_TCIE
#define STM32_DMA_CR_TEIE DMA_CCR1_TEIE
#define STM32_DMA_CR_HTIE DMA_CCR1_HTIE
#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1
#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1
#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1
#define STM32_DMA_ISR_MASK 0x0F
#define STM32_DMA_CCR_RESET_VALUE 0x00000000
#define STM32_DMA_CR_PL_MASK DMA_CCR1_PL
#define STM32_DMA_CR_PL(n) ((n) << 12)
#define DMA_CCR1_EN 0x00000001
#define DMA_CCR1_TCIE 0x00000002
#define DMA_CCR1_HTIE 0x00000004
#define DMA_CCR1_TEIE 0x00000008
#define DMA_CCR1_DIR 0x00000010
#define DMA_CCR1_CIRC 0x00000020
#define DMA_CCR1_PINC 0x00000040
#define DMA_CCR1_MINC 0x00000080
#define DMA_CCR1_PSIZE 0x00000300
#define DMA_CCR1_PSIZE_0 0x00000100
#define DMA_CCR1_PSIZE_1 0x00000200
#define DMA_CCR1_MSIZE 0x00000C00
#define DMA_CCR1_MSIZE_0 0x00000400
#define DMA_CCR1_MSIZE_1 0x00000800
#define DMA_CCR1_PL 0x00003000
#define DMA_CCR1_PL_0 0x00001000
#define DMA_CCR1_PL_1 0x00002000
#define DMA_CCR1_MEM2MEM 0x00004000
#define DMA_ISR_GIF1 0x00000001
#define DMA_ISR_TCIF1 0x00000002
#define DMA_ISR_HTIF1 0x00000004
#define DMA_ISR_TEIF1 0x00000008
#define DMA_ISR_GIF2 0x00000010
#define DMA_ISR_TCIF2 0x00000020
#define DMA_ISR_HTIF2 0x00000040
#define DMA_ISR_TEIF2 0x00000080
#define DMA_ISR_GIF3 0x00000100
#define DMA_ISR_TCIF3 0x00000200
#define DMA_ISR_HTIF3 0x00000400
#define DMA_ISR_TEIF3 0x00000800
#define DMA_ISR_GIF4 0x00001000
#define DMA_ISR_TCIF4 0x00002000
#define DMA_ISR_HTIF4 0x00004000
#define DMA_ISR_TEIF4 0x00008000
#define DMA_ISR_GIF5 0x00010000
#define DMA_ISR_TCIF5 0x00020000
#define DMA_ISR_HTIF5 0x00040000
#define DMA_ISR_TEIF5 0x00080000
#define DMA_ISR_GIF6 0x00100000
#define DMA_ISR_TCIF6 0x00200000
#define DMA_ISR_HTIF6 0x00400000
#define DMA_ISR_TEIF6 0x00800000
#define DMA_ISR_GIF7 0x01000000
#define DMA_ISR_TCIF7 0x02000000
#define DMA_ISR_HTIF7 0x04000000
#define DMA_ISR_TEIF7 0x08000000
#define DMA1_BASE (AHBPERIPH_BASE + 0x0000)
static struct DMA *const DMA1 = (struct DMA *)DMA1_BASE;
#define DMA1_Channel1_BASE (AHBPERIPH_BASE + 0x0008)
static struct DMA_Channel *const DMA1_Channel1 =
(struct DMA_Channel *)DMA1_Channel1_BASE;
/* System Control Block */
struct SCB
{
volatile uint32_t CPUID;
volatile uint32_t ICSR;
volatile uint32_t VTOR;
volatile uint32_t AIRCR;
volatile uint32_t SCR;
volatile uint32_t CCR;
volatile uint8_t SHP[12];
volatile uint32_t SHCSR;
volatile uint32_t CFSR;
volatile uint32_t HFSR;
volatile uint32_t DFSR;
volatile uint32_t MMFAR;
volatile uint32_t BFAR;
volatile uint32_t AFSR;
volatile uint32_t PFR[2];
volatile uint32_t DFR;
volatile uint32_t ADR;
volatile uint32_t MMFR[4];
volatile uint32_t ISAR[5];
uint32_t RESERVED0[5];
volatile uint32_t CPACR;
};
#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

414
mcu/sys-mkl27z.c Normal file
View File

@@ -0,0 +1,414 @@
/*
* sys.c - First pages for MKL27Z256.
*
* Copyright (C) 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*
*
* First two pages of Flash ROM is difficult to use because of
* predefined purposes. It's defined as a default vector page and
* a flash configuration page.
*
* We put something useful to those two pages, together with the
* data for predefined purposes.
*/
#include <stdint.h>
#include <stdlib.h>
#include "board.h"
#define ADDR_VECTORS (0x00000900)
#define ADDR_SCR_VTOR 0xe000ed08
static void __attribute__ ((naked,section(".fixed_function.reset")))
reset (void)
{
uint32_t r3 = ADDR_SCR_VTOR;
asm volatile ("str %2, [%0]\n\t" /* Set SCR->VTOR */
"ldr %0, [%2]\n\t" /* Stack address */
"msr MSP, %0\n\t" /* Exception handler stack. */
"ldr %0, [%2, #4]\n\t" /* The entry address */
"bx %0\n\t" /* Jump to the entry */
".align 2"
: "=r" (r3)
: "0" (r3), "r" (ADDR_VECTORS)
: "memory");
/* Never reach here. */
}
static uint32_t
stack_entry[] __attribute__ ((section(".first_page.first_words"),used)) = {
/* Since MSP are soon modified in RESET, we put 0 here. */
0,
(uint32_t)reset,
};
#include "mcu/clk_gpio_init-mkl27z.c"
static void
set_led (int on)
{
if (on)
GPIOB->PCOR = (1 << 0); /* PTB0: Clear: Light on */
else
GPIOB->PSOR = (1 << 0); /* PTB0: Set : Light off */
}
/*
* Here comes other SYS routines and data.
*/
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = STRING_DESCRIPTOR */
/* sys version: "3.0" */
'3', 0, '.', 0, '0', 0,
};
static const uint8_t board_name_string[] = BOARD_NAME;
const uint8_t __attribute__((section(".sys.board_info")))
*const sys_board_name = board_name_string;
const uint32_t __attribute__((section(".sys.board_info")))
sys_board_id = BOARD_ID;
typedef void (*handler)(void);
handler sys_vector[] __attribute__ ((section(".sys.vectors"))) = {
clock_init,
gpio_init,
(handler)set_led,
NULL,
};
static uint32_t
flash_config[] __attribute__ ((section(".flash_config"),used)) = {
0xffffffff, 0xffffffff, /* Comparison Key */
0xffffffff, /* Protection bytes */
0xffff3ffe, /* FSEC=0xfe, FOPT=0x3f */
/* FOPT=0x3f:
* BOOTSRC_SEL=00: Boot from flash
*/
/* FSEC=0xfe:
* unsecure
*/
};
/*
* Flash memory routine
*/
struct FTFA {
volatile uint8_t FSTAT;
volatile uint8_t FCNFG;
volatile uint8_t FSEC;
volatile uint8_t FOPT;
/* Note: addressing (3,2,1,0, 7,6,5,4, B,A,9,8) */
/* Use Bx macro. */
volatile uint8_t FCCO[12];
/* Note: addressing (3,2,1,0). Use Bx macro. */
volatile uint8_t FPROT[4];
};
static struct FTFA *const FTFA = (struct FTFA *)0x40020000;
#define FSTAT_CCIF 0x80
#define B3 0
#define B2 1
#define B1 2
#define B0 3
#define B7 4
#define B6 5
#define B5 6
#define B4 7
#define BB 8
#define BA 9
#define B9 10
#define B8 11
uint32_t __attribute__ ((naked,section(".fixed_function.flash_do_internal")))
flash_do_internal (void)
{
#ifdef ORIGINAL_IN_C
uint8_t r;
asm volatile ("cpsid i" : : : "memory");
FTFA->FSTAT |= FSTAT_CCIF;
while (((r = FTFA->FSTAT) & FSTAT_CCIF) == 0)
;
r &= ~FSTAT_CCIF;
asm volatile ("cpsie i" : : : "memory");
return (uint32_t)r;
#else
register unsigned int r0 asm ("r0");
register unsigned int r1 asm ("r1") = (unsigned int)FTFA;
register unsigned int r2 asm ("r2") = FSTAT_CCIF;
asm volatile ("cpsid i\n\t"
"ldrb %0, [%1]\n\t"
"orr %0, %2\n\t"
"strb %0, [%1]\n"
"0:\t"
"ldrb %0, [%1]\n\t"
"uxtb %0, %0\n\t"
"tst %0, %2\n\t"
"beq 0b\n\t"
"cpsie i\n\t"
"bic %0, %2\n\t"
"bx lr"
: "=r" (r0)
: "r" (r1), "r" (r2)
: "memory");
return r0;
#endif
}
/*
* Let execute flash command.
* Since the code should be on RAM, we copy the code onto stack
* and let it go.
*/
uint32_t __attribute__ ((naked,section(".fixed_function.flash_do")))
flash_do (void)
{
register unsigned int r0 asm ("r0");
register unsigned int r1 asm ("r1");
register unsigned int r2 asm ("r2");
register unsigned int r3 asm ("r3") = (unsigned int)flash_do_internal&~3;
/* Address of Thumb code &1 == 1, so, we clear the last bits. ------^ */
asm volatile ("sub sp, #32\n\t"
"mov %1, sp\n\t"
"mov %2, #0\n"
"0:\t"
"cmp %2, #32\n\t"
"beq 1f\n\t"
"ldr %0, [%3, %2]\n\t"
"str %0, [%1, %2]\n\t"
"add %2, #4\n\t"
"b 0b\n"
"1:\t"
"add %1, #1\n\t" /* Thumb code requires LSB=1. */
"mov %3, lr\n\t"
"blx %1\n\t"
"add sp, #32\n\t"
"bx %3"
: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
: "3" (r3));
}
#define FLASH_COMMAND_PROGRAM_LONGWORD 0x06
#define FLASH_COMMAND_ERASE_FLASH_SECTOR 0x09
int __attribute__ ((naked,section(".fixed_function.flash_erase_page")))
flash_erase_page (uint32_t addr)
{
#ifdef ORIGINAL_IN_C
FTFA->FCCO[B0] = FLASH_COMMAND_ERASE_FLASH_SECTOR;
FTFA->FCCO[B3] = (addr >> 0) & 0xff;
FTFA->FCCO[B2] = (addr >> 8) & 0xff;
FTFA->FCCO[B1] = (addr >> 16) & 0xff;
flash_do ();
#else
register unsigned int r0 asm ("r0") = addr;
register unsigned int r1 asm ("r1");
register unsigned int r2 asm ("r2") = FLASH_COMMAND_ERASE_FLASH_SECTOR;
register unsigned int r3 asm ("r3") = (unsigned int)FTFA;
asm volatile ("strb %2, [%3, #7]\n\t"
"strb %0, [%3, #4]\n\t"
"lsr %0, #8\n\t"
"strb %0, [%3, #5]\n\t"
"lsr %0, #8\n\t"
"strb %0, [%3, #6]\n\t"
"b flash_do"
: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
: "0" (r0), "2" (r2), "3" (r3));
#endif
}
int __attribute__ ((naked,section(".fixed_function.flash_program_word")))
flash_program_word (uint32_t addr, uint32_t word)
{
#ifdef ORIGINAL_IN_C
FTFA->FCCO[B0] = FLASH_COMMAND_PROGRAM_LONGWORD;
FTFA->FCCO[B3] = (addr >> 0) & 0xff;
FTFA->FCCO[B2] = (addr >> 8) & 0xff;
FTFA->FCCO[B1] = (addr >> 16) & 0xff;
FTFA->FCCO[B4] = (word >> 0) & 0xff;
FTFA->FCCO[B5] = (word >> 8) & 0xff;
FTFA->FCCO[B6] = (word >> 16) & 0xff;
FTFA->FCCO[B7] = (word >> 24) & 0xff;
flash_do ();
#else
register unsigned int r0 asm ("r0") = addr;
register unsigned int r1 asm ("r1") = word;
register unsigned int r2 asm ("r2") = FLASH_COMMAND_PROGRAM_LONGWORD;
register unsigned int r3 asm ("r3") = (unsigned int)FTFA;
asm volatile ("strb %2, [%3, #7]\n\t"
"strb %0, [%3, #4]\n\t"
"lsr %0, #8\n\t"
"strb %0, [%3, #5]\n\t"
"lsr %0, #8\n\t"
"strb %0, [%3, #6]\n\t"
"strb %1, [%3, #11]\n\t"
"lsr %1, #8\n\t"
"strb %1, [%3, #10]\n\t"
"lsr %1, #8\n\t"
"strb %1, [%3, #9]\n\t"
"lsr %1, #8\n\t"
"strb %1, [%3, #8]\n\t"
"b flash_do"
: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
: "0" (r0), "1" (r1), "2" (r2), "3" (r3));
#endif
}
/*
* CRC32 calculation routines.
*/
void __attribute__ ((naked,section(".fixed_function.crc32_init")))
crc32_init (unsigned int *p)
{
#ifdef ORIGINAL_IN_C
*p = 0xffffffff;
#else
register unsigned int r3 asm ("r3");
asm volatile ("mov %0, #1\n\t"
"neg %0, %0\n\t"
"str %0, [%1]\n\t"
"bx lr"
: "=r" (r3)
: "r" (p)
: "memory");
#endif
}
#ifdef ORIGINAL_IN_C
const unsigned int *const crc32_table= (const unsigned int *)0x00000500;
#endif
void __attribute__ ((naked,section(".fixed_function.crc32_u8")))
crc32_u8 (unsigned int *p, unsigned char v)
{
#ifdef ORIGINAL_IN_C
*p = crc32_table[(*p & 0xff) ^ v] ^ (*p >> 8);
#else
register unsigned int r2 asm ("r2");
register unsigned int r3 asm ("r3");
asm volatile ("ldrb %2, [%4]\n\t"
"eor %0, %2\n\t"
"mov %2, #0xa0\n\t" /* (0x0500 >> 3) */
"lsl %0, %0, #2\n\t"
"lsl %2, %2, #3\n\t"
"add %0, %0, %2\n\t"
"ldr %2, [%4]\n\t"
"ldr %1, [%0]\n\t"
"lsr %2, %2, #8\n\t"
"eor %2, %1\n\t"
"str %2, [%4]\n\t"
"bx lr"
: "=r" (v), "=r" (r2), "=r" (r3)
: "0" (v), "r" (p)
: "memory");
#endif
}
void __attribute__ ((naked,section(".fixed_function.crc32_u32")))
crc32_u32 (unsigned int *p, unsigned int u)
{
#ifdef ORIGINAL_IN_C
crc32_u8 (p, u & 0xff);
crc32_u8 (p, (u >> 8)& 0xff);
crc32_u8 (p, (u >> 16)& 0xff);
crc32_u8 (p, (u >> 24)& 0xff);
#else
register unsigned int r3 asm ("r3");
register unsigned int r4 asm ("r4");
register unsigned int r5 asm ("r5");
asm volatile ("push {%1, %2, %3, lr}\n\t"
"mov %2, %0\n\t"
"mov %3, %5\n\t"
"uxtb %0, %0\n\t"
"bl crc32_u8\n\t"
"lsr %0, %2, #8\n\t"
"mov %5, %3\n\t"
"uxtb %0, %0\n\t"
"bl crc32_u8\n\t"
"lsr %0, %2, #16\n\t"
"mov %5, %3\n\t"
"uxtb %0, %0\n\t"
"bl crc32_u8\n\t"
"mov %5, %3\n\t"
"lsr %0, %2, #24\n\t"
"bl crc32_u8\n\t"
"pop {%1, %2, %3, pc}"
: "=r" (u), "=r" (r3), "=r" (r4), "=r" (r5)
: "0" (u), "r" (p)
: "memory");
#endif
}
/*
* Table of CRC32, generated by gen_crc_table.py
*/
const unsigned int
crc32_table[256] __attribute__ ((section(".crc32_table"))) = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};

39
mcu/sys-mkl27z.h Normal file
View File

@@ -0,0 +1,39 @@
extern const uint8_t sys_version[8];
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
extern const uint32_t sys_board_id;
extern const char *const sys_board_name;
#endif
typedef void (*handler)(void);
extern handler sys_vector[16];
static inline void
set_led (int on)
{
void (*func) (int) = (void (*)(int))sys_vector[2];
return (*func) (on);
}
void crc32_init (unsigned int *);
void crc32_u8 (unsigned int *, unsigned char);
void crc32_u32 (unsigned int *, unsigned int);
int flash_erase_page (uint32_t addr);
int flash_program_word (uint32_t addr, uint32_t word);
#ifdef REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
/* Provide the function entries. */
static void __attribute__ ((used))
clock_init (void)
{
(*sys_vector[0]) ();
}
static void __attribute__ ((used))
gpio_init (void)
{
(*sys_vector[1]) ();
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* sys.c - system routines for the initial page for STM32F030 / STM32F103.
*
* Copyright (C) 2013, 2014, 2015 Flying Stone Technology
* Copyright (C) 2013, 2014, 2015, 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
@@ -17,41 +17,9 @@
#include <stdlib.h>
#include "board.h"
#include "clk_gpio_init.c"
#define STM32F0_USE_VECTOR_ON_RAM
#include "mcu/clk_gpio_init-stm32.c"
#define CORTEX_PRIORITY_BITS 4
#define CORTEX_PRIORITY_MASK(n) ((n) << (8 - CORTEX_PRIORITY_BITS))
#define USB_LP_CAN1_RX0_IRQn 20
#define STM32_USB_IRQ_PRIORITY 11
struct NVIC {
uint32_t ISER[8];
uint32_t unused1[24];
uint32_t ICER[8];
uint32_t unused2[24];
uint32_t ISPR[8];
uint32_t unused3[24];
uint32_t ICPR[8];
uint32_t unused4[24];
uint32_t IABR[8];
uint32_t unused5[56];
uint32_t IPR[60];
};
static struct NVIC *const NVICBase = ((struct NVIC *const)0xE000E100);
#define NVIC_ISER(n) (NVICBase->ISER[n >> 5])
#define NVIC_ICPR(n) (NVICBase->ICPR[n >> 5])
#define NVIC_IPR(n) (NVICBase->IPR[n >> 2])
static void
nvic_enable_vector (uint32_t n, uint32_t prio)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh)) | (prio << sh);
NVIC_ICPR (n) = 1 << (n & 0x1F);
NVIC_ISER (n) = 1 << (n & 0x1F);
}
static void
usb_cable_config (int enable)
@@ -118,13 +86,6 @@ usb_lld_sys_init (void)
usb_cable_config (1);
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
/*
* Note that we also have other IRQ(s):
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
* USBWakeUp_IRQn (suspend/resume)
*/
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
}
@@ -362,7 +323,7 @@ struct SCB
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
static struct SCB *const SCB = (struct SCB *)SCB_BASE;
#define SYSRESETREQ 0x04
static void
@@ -402,7 +363,7 @@ reset (void)
"1: .word 0x20000000"
: /* no output */ : /* no input */ : "memory");
#else
extern const unsigned long *FT0, *FT1, *FT2;
extern const uint32_t FT0[256], FT1[256], FT2[256];
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
"ldr r0, 1f\n\t" /* r0 = SCR */
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
@@ -450,8 +411,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
/* sys version: "2.1" */
'2', 0, '.', 0, '1', 0,
/* sys version: "3.0" */
'3', 0, '.', 0, '0', 0,
};
const uint32_t __attribute__((section(".sys.board_id")))

View File

@@ -16,8 +16,12 @@
#endif
extern const uint8_t sys_version[8];
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
extern const uint32_t sys_board_id;
extern const uint8_t sys_board_name[];
#else
# define SYS_BOARD_ID BOARD_ID
#endif
typedef void (*handler)(void);
extern handler vector[16];
@@ -113,22 +117,18 @@ nvic_system_reset (void)
(*vector[12]) ();
}
/*
* Users can override INLINE by 'attribute((used))' to have an
* implementation defined.
*/
#if !defined(INLINE)
#define INLINE __inline__
#endif
#ifdef REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
/* Provide the function entries. */
static INLINE void
static void __attribute__ ((used))
clock_init (void)
{
(*vector[13]) ();
}
static INLINE void
static void __attribute__ ((used))
gpio_init (void)
{
(*vector[14]) ();
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* sys.c - system routines for the initial page for STM32F103.
*
* Copyright (C) 2013, 2014, 2015 Flying Stone Technology
* Copyright (C) 2013, 2014, 2015, 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Copying and distribution of this file, with or without modification,
@@ -17,41 +17,8 @@
#include <stdlib.h>
#include "board.h"
#include "clk_gpio_init.c"
#include "mcu/clk_gpio_init-stm32.c"
#define CORTEX_PRIORITY_BITS 4
#define CORTEX_PRIORITY_MASK(n) ((n) << (8 - CORTEX_PRIORITY_BITS))
#define USB_LP_CAN1_RX0_IRQn 20
#define STM32_USB_IRQ_PRIORITY 11
struct NVIC {
uint32_t ISER[8];
uint32_t unused1[24];
uint32_t ICER[8];
uint32_t unused2[24];
uint32_t ISPR[8];
uint32_t unused3[24];
uint32_t ICPR[8];
uint32_t unused4[24];
uint32_t IABR[8];
uint32_t unused5[56];
uint32_t IPR[60];
};
static struct NVIC *const NVICBase = ((struct NVIC *const)0xE000E100);
#define NVIC_ISER(n) (NVICBase->ISER[n >> 5])
#define NVIC_ICPR(n) (NVICBase->ICPR[n >> 5])
#define NVIC_IPR(n) (NVICBase->IPR[n >> 2])
static void
nvic_enable_vector (uint32_t n, uint32_t prio)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh)) | (prio << sh);
NVIC_ICPR (n) = 1 << (n & 0x1F);
NVIC_ISER (n) = 1 << (n & 0x1F);
}
static void
usb_cable_config (int enable)
@@ -118,13 +85,6 @@ usb_lld_sys_init (void)
usb_cable_config (1);
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
nvic_enable_vector (USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
/*
* Note that we also have other IRQ(s):
* USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
* USBWakeUp_IRQn (suspend/resume)
*/
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0;
}
@@ -253,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;
@@ -309,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;
@@ -356,7 +324,7 @@ struct SCB
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
static struct SCB *const SCB = (struct SCB *)SCB_BASE;
#define SYSRESETREQ 0x04
static void
@@ -370,7 +338,7 @@ nvic_system_reset (void)
static void __attribute__ ((naked))
reset (void)
{
extern const unsigned long *FT0, *FT1, *FT2;
extern const uint32_t FT0[256], FT1[256], FT2[256];
/*
* This code may not be at the start of flash ROM, because of DFU.
@@ -423,8 +391,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2, /* bLength */
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
/* sys version: "2.1" */
'2', 0, '.', 0, '1', 0,
/* sys version: "3.0" */
'3', 0, '.', 0, '0', 0,
};
const uint32_t __attribute__((section(".sys.board_id")))
@@ -432,3 +400,149 @@ sys_board_id = BOARD_ID;
const uint8_t __attribute__((section(".sys.board_name")))
sys_board_name[] = BOARD_NAME;
/*
* aes-constant-ft.c - AES forward tables.
*
* We need something useful for the initial flash ROM page (4 Ki
* bytes), which cannot be modified after installation. Even after
* upgrade of the firmware, it stays intact.
*
* We decide to put 3/4 of AES forward tables to fill 3 Ki bytes, as
* its useful and it won't change.
*
* The code was taken from aes.c of PolarSSL version 0.14, and then,
* modified to add section names.
*
* Since this is just a data, it wouldn't be copyright-able, but the
* original auther would claim so. Thus, we put original copyright
* notice here. It is highly likely that there will be no such a
* thing for copyright. Nevertheless, we think that PolarSSL is good
* software to address here, and encourage people using it.
*
*/
#include <stdint.h>
/*
* Original copyright notice is below:
*/
/*
* FIPS-197 compliant AES implementation
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
*
* http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
/*
* Forward tables
*/
#define FT \
\
V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \
V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \
V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \
V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \
V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \
V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \
V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \
V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \
V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \
V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \
V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \
V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \
V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \
V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \
V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \
V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \
V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \
V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \
V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \
V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \
V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \
V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \
V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \
V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \
V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \
V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \
V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \
V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \
V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \
V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \
V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \
V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \
V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \
V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \
V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \
V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \
V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \
V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \
V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \
V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \
V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \
V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \
V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \
V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \
V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \
V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \
V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \
V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \
V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \
V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \
V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \
V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \
V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \
V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \
V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \
V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \
V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \
V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \
V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \
V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \
V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \
V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \
V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \
V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C)
#define V(a,b,c,d) 0x##a##b##c##d
const uint32_t FT0[256] __attribute__((section(".sys.0"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##b##c##d##a
const uint32_t FT1[256] __attribute__((section(".sys.1"))) = { FT };
#undef V
#define V(a,b,c,d) 0x##c##d##a##b
const uint32_t FT2[256] __attribute__((section(".sys.2"))) = { FT };
#undef V
#ifdef ORIGINAL_IMPLEMENTATION
#define V(a,b,c,d) 0x##d##a##b##c
const uint32_t FT3[256] = { FT };
#undef V
#endif

View File

@@ -12,8 +12,13 @@
#define BOARD_ID_NITROKEY_START 0xad1e7ebd
extern const uint8_t sys_version[8];
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
extern const uint32_t sys_board_id;
extern const uint8_t sys_board_name[];
# define SYS_BOARD_ID sys_board_id
#else
# define SYS_BOARD_ID BOARD_ID
#endif
typedef void (*handler)(void);
extern handler vector[16];
@@ -109,22 +114,18 @@ nvic_system_reset (void)
(*vector[12]) ();
}
/*
* Users can override INLINE by 'attribute((used))' to have an
* implementation defined.
*/
#if !defined(INLINE)
#define INLINE __inline__
#endif
#ifdef REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
/* Provide the function entries. */
static INLINE void
static void __attribute__ ((used))
clock_init (void)
{
(*vector[13]) ();
}
static INLINE void
static void __attribute__ ((used))
gpio_init (void)
{
(*vector[14]) ();
}
#endif

993
mcu/usb-mkl27z.c Normal file
View File

@@ -0,0 +1,993 @@
/*
* usb-mkl27z.c - USB driver for MKL27Z
*
* Copyright (C) 2016 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "usb_lld.h"
#define DATA0 0
#define DATA1 1
struct endpoint_ctl {
uint32_t rx_odd: 1;
uint32_t tx_odd: 1;
};
static struct endpoint_ctl ep[16];
struct USB_CONF {
const uint8_t PERID; /* Peripheral ID register */
uint8_t rsvd0[3]; /* */
const uint8_t IDCOMP; /* Peripheral ID Complement register */
uint8_t rsvd1[3]; /* */
const uint8_t REV; /* Peripheral Revision register */
uint8_t rsvd2[3]; /* */
volatile uint8_t ADDINFO; /* Peripheral Additional Info register */
};
static struct USB_CONF *const USB_CONF = (struct USB_CONF *)0x40072000;
struct USB_CTRL0 {
volatile uint8_t OTGCTL; /* OTG Control register */
};
static struct USB_CTRL0 *const USB_CTRL0 = (struct USB_CTRL0 *)0x4007201c;
struct USB_CTRL1 {
volatile uint8_t ISTAT; /* Interrupt Status register */
uint8_t rsvd5[3]; /* */
volatile uint8_t INTEN; /* Interrupt Enable register */
uint8_t rsvd6[3]; /* */
volatile uint8_t ERRSTAT; /* Error Interrupt Status register */
uint8_t rsvd7[3]; /* */
volatile uint8_t ERREN; /* Error Interrupt Enable register */
uint8_t rsvd8[3]; /* */
volatile uint8_t STAT; /* Status register */
uint8_t rsvd9[3]; /* */
volatile uint8_t CTL; /* Control register */
uint8_t rsvd10[3]; /* */
volatile uint8_t ADDR; /* Address register */
uint8_t rsvd11[3]; /* */
volatile uint8_t BDTPAGE1; /* BDT Page register 1 */
uint8_t rsvd12[3]; /* */
volatile uint8_t FRMNUML; /* Frame Number register Low */
uint8_t rsvd13[3]; /* */
volatile uint8_t FRMNUMH; /* Frame Number register High */
uint8_t rsvd14[11]; /* */
volatile uint8_t BDTPAGE2; /* BDT Page Register 2 */
uint8_t rsvd15[3]; /* */
volatile uint8_t BDTPAGE3; /* BDT Page Register 3 */
};
static struct USB_CTRL1 *const USB_CTRL1 = (struct USB_CTRL1 *)0x40072080;
/* Interrupt source bits */
#define USB_IS_STALL (1 << 7)
#define USB_IS_RESUME (1 << 5)
#define USB_IS_SLEEP (1 << 4)
#define USB_IS_TOKDNE (1 << 3)
#define USB_IS_SOFTOK (1 << 2)
#define USB_IS_ERROR (1 << 1)
#define USB_IS_USBRST (1 << 0)
struct USB_ENDPT {
volatile uint8_t EP; /* Endpoint Control register */
uint8_t rsvd17[3];
};
static struct USB_ENDPT *const USB_ENDPT = (struct USB_ENDPT *)0x400720c0;
struct USB_CTRL2 {
volatile uint8_t USBCTRL; /* USB Control register */
uint8_t rsvd33[3]; /* */
volatile uint8_t OBSERVE; /* USB OTG Observe register */
uint8_t rsvd34[3]; /* */
volatile uint8_t CONTROL; /* USB OTG Control register */
uint8_t rsvd35[3]; /* */
volatile uint8_t USBTRC0; /* USB Transceiver Control register 0 */
uint8_t rsvd36[7]; /* */
volatile uint8_t USBFRMADJUST; /* Frame Adjut Register */
};
static struct USB_CTRL2 *const USB_CTRL2 = (struct USB_CTRL2 *)0x40072100;
/* Buffer Descriptor */
struct BD {
volatile uint32_t ctrl;
volatile void *buf;
};
/*
uint32_t rsvd0 : 2;
volatile uint32_t STALL: 1;
volatile uint32_t DTS: 1;
volatile uint32_t NINC: 1;
volatile uint32_t KEEP: 1;
volatile uint32_t DATA01: 1;
volatile uint32_t OWN: 1;
uint32_t rsvd1: 8;
volatile uint32_t BC: 10;
uint32_t rsvd2: 6;
*/
#define TOK_PID(ctrl) ((ctrl >> 2) & 0x0f)
extern uint8_t __usb_bdt__;
static struct BD *const BD_table = (struct BD *)&__usb_bdt__;
static void
kl27z_usb_init (void)
{
int i;
memset (ep, 0, sizeof (ep));
memset (BD_table, 0, 16 * 2 * 2 * sizeof (struct BD));
/* D+ pull up */
USB_CTRL0->OTGCTL = 0x80;
USB_CTRL1->ERREN = 0xff;
USB_CTRL1->BDTPAGE1 = ((uint32_t)BD_table) >> 8;
USB_CTRL1->BDTPAGE2 = ((uint32_t)BD_table) >> 16;
USB_CTRL1->BDTPAGE3 = ((uint32_t)BD_table) >> 24;
/* Not suspended, Pull-down disabled. */
USB_CTRL2->USBCTRL = 0x00;
/* DP Pullup in non-OTG device mode. */
USB_CTRL2->CONTROL = 0x10;
/* Disable all endpoints. */
for (i = 0; i < 16; i++)
USB_ENDPT[i].EP = 0;
/*
* Enable USB FS communication module, clearing all ODD-bits
* for BDT.
*/
USB_CTRL1->CTL = 0x03;
/* ??? How we can ask re-enumeration? Is only hard RESET enough? */
}
static void
kl27z_set_daddr (uint8_t daddr)
{
USB_CTRL1->ADDR = daddr;
}
static void
kl27z_prepare_ep0_setup (struct usb_dev *dev)
{
/* Endpoint 0, TX=0. */
BD_table[ep[0].rx_odd].ctrl = 0x00080088; /* Len=8, OWN=1, DATA01=0, DTS=1 */
BD_table[ep[0].rx_odd].buf = &dev->dev_req;
BD_table[!ep[0].rx_odd].ctrl = 0x0000; /* OWN=0 */
BD_table[!ep[0].rx_odd].buf = NULL;
}
static void
kl27z_prepare_ep0_in (const void *buf, uint8_t len, int data01)
{
/* Endpoint 0, TX=1 *//* OWN=1, DTS=1 */
BD_table[2+ep[0].tx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6);
BD_table[2+ep[0].tx_odd].buf = (void *)buf;
}
static void
kl27z_prepare_ep0_out (void *buf, uint8_t len, int data01)
{
/* Endpoint 0, TX=0 *//* OWN=1, DTS=1 */
BD_table[ep[0].rx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6);
BD_table[ep[0].rx_odd].buf = buf;
}
static int
kl27z_ep_is_disabled (uint8_t n)
{
return (USB_ENDPT[n].EP == 0);
}
static int
kl27z_ep_is_stall (uint8_t n)
{
return (USB_ENDPT[n].EP & 0x02) >> 1;
}
static void
kl27z_ep_stall (uint8_t n)
{
USB_ENDPT[n].EP |= 0x02;
}
static void
kl27z_ep_clear_stall (uint8_t n)
{
USB_ENDPT[n].EP &= ~0x02;
}
static void
kl27z_ep_clear_dtog (int rx, uint8_t n)
{
uint32_t config;
if (!kl27z_ep_is_stall (n))
/* Just in case, when the endpoint is active */
kl27z_ep_stall (n);
if (rx)
{
config = BD_table[4*n+ep[n].rx_odd].ctrl;
BD_table[4*n+!ep[n].rx_odd].ctrl &= ~(1 << 6);
if ((config & 0x0080)) /* OWN already? */
{
/*
* How to update BDT entry which is owned by USBFS seems to
* be not clearly documented. It would be just OK to update
* it as long as the endpoint is stalled (BDT entry is
* actually not in use). We write 0 at first and then write
* value with OWN, to avoid possible failure.
*/
BD_table[4*n+ep[n].rx_odd].ctrl = 0;
BD_table[4*n+ep[n].rx_odd].ctrl = (config & ~(1 << 6));
}
}
else
{
config = BD_table[4*n+2+ep[n].tx_odd].ctrl;
BD_table[4*n+2+!ep[n].tx_odd].ctrl &= ~(1 << 6);
if ((config & 0x0080)) /* OWN already? */
{
BD_table[4*n+2+ep[n].tx_odd].ctrl = 0;
BD_table[4*n+2+ep[n].tx_odd].ctrl = (config & ~(1 << 6));
}
}
kl27z_ep_clear_stall (n);
}
#include "usb_lld_driver.h"
static int handle_transaction (struct usb_dev *dev, uint8_t stat);
void
usb_lld_stall (int n)
{
kl27z_ep_stall (n);
}
void
usb_lld_ctrl_error (struct usb_dev *dev)
{
dev->state = STALLED;
kl27z_ep_stall (ENDP0);
}
int
usb_lld_ctrl_ack (struct usb_dev *dev)
{
/* Zero length packet for ACK. */
dev->state = WAIT_STATUS_IN;
kl27z_prepare_ep0_in (&dev->dev_req, 0, DATA1);
return USB_EVENT_OK;
}
void
usb_lld_init (struct usb_dev *dev, uint8_t feature)
{
usb_lld_set_configuration (dev, 0);
dev->feature = feature;
dev->state = WAIT_SETUP;
kl27z_set_daddr (0);
kl27z_usb_init ();
/* Enable the endpoint 0. */
USB_ENDPT[0].EP = 0x0d;
/* Clear Interrupt Status Register, and enable interrupt for USB */
USB_CTRL1->ISTAT = 0xff; /* All clear */
USB_CTRL1->INTEN = USB_IS_STALL | USB_IS_TOKDNE
| USB_IS_ERROR | USB_IS_USBRST;
}
#define USB_MAKE_EV(event) (event<<24)
#define USB_MAKE_TXRX(ep_num,txrx,len) ((txrx? (1<<23):0)|(ep_num<<16)|len)
int
usb_lld_event_handler (struct usb_dev *dev)
{
uint8_t istat_value = USB_CTRL1->ISTAT;
uint8_t stat = USB_CTRL1->STAT;
if ((istat_value & USB_IS_USBRST))
{
USB_CTRL1->ISTAT = USB_IS_USBRST;
return USB_MAKE_EV (USB_EVENT_DEVICE_RESET);
}
else if ((istat_value & USB_IS_TOKDNE))
return handle_transaction (dev, stat);
else if ((istat_value & USB_IS_ERROR))
{ /* Clear Errors. */
USB_CTRL1->ERRSTAT = USB_CTRL1->ERRSTAT;
USB_CTRL1->ISTAT = USB_IS_ERROR;
}
else if ((istat_value & USB_IS_STALL))
{
/* Does STAT have ENDPOINT info in this case?: No, it doesn't. */
if (kl27z_ep_is_stall (0))
{ /* It's endpoint 0, recover from erorr. */
dev->state = WAIT_SETUP;
kl27z_ep_clear_stall (0);
kl27z_prepare_ep0_setup (dev);
}
USB_CTRL1->ISTAT = USB_IS_STALL;
}
return USB_EVENT_OK;
}
static void
handle_datastage_out (struct usb_dev *dev, uint8_t stat)
{
struct ctrl_data *data_p = &dev->ctrl_data;
int odd = (stat >> 2)&1;
int data01 = !((BD_table[odd].ctrl >> 6)&1);
uint32_t len = (BD_table[odd].ctrl >> 16)&0x3ff;
data_p->len -= len;
data_p->addr += len;
len = data_p->len;
if (len > USB_MAX_PACKET_SIZE)
len = USB_MAX_PACKET_SIZE;
if (data_p->len == 0)
{
/* No more data to receive, proceed to send acknowledge for IN. */
dev->state = WAIT_STATUS_IN;
kl27z_prepare_ep0_in (&dev->dev_req, 0, DATA1);
}
else
{
dev->state = OUT_DATA;
kl27z_prepare_ep0_out (data_p->addr, len, data01);
}
}
static void
handle_datastage_in (struct usb_dev *dev, uint8_t stat)
{
struct ctrl_data *data_p = &dev->ctrl_data;
int odd = (stat >> 2)&1;
int data01 = !((BD_table[2+odd].ctrl >> 6)&1);
uint32_t len = USB_MAX_PACKET_SIZE;
if ((data_p->len == 0) && (dev->state == LAST_IN_DATA))
{
if (data_p->require_zlp)
{
data_p->require_zlp = 0;
/* No more data to send. Send empty packet */
kl27z_prepare_ep0_in (&dev->dev_req, 0, data01);
}
else
{
/* No more data to send, proceed to receive OUT acknowledge. */
dev->state = WAIT_STATUS_OUT;
kl27z_prepare_ep0_out (&dev->dev_req, 0, DATA1);
}
return;
}
dev->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA;
if (len > data_p->len)
len = data_p->len;
kl27z_prepare_ep0_in (data_p->addr, len, data01);
data_p->len -= len;
data_p->addr += len;
}
typedef int (*HANDLER) (struct usb_dev *dev);
static int
std_none (struct usb_dev *dev)
{
(void)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;
if (arg->value != 0 || arg->len != 2 || (arg->index >> 8) != 0
|| USB_SETUP_SET (arg->type))
return -1;
if (rcp == DEVICE_RECIPIENT)
{
if (arg->index == 0)
{
/* Get Device Status */
uint8_t feature = dev->feature;
/* Remote Wakeup enabled */
if ((feature & (1 << 5)))
status_info |= 2;
else
status_info &= ~2;
/* Bus-powered */
if ((feature & (1 << 6)))
status_info |= 1;
else /* Self-powered */
status_info &= ~1;
return usb_lld_ctrl_send (dev, &status_info, 2);
}
}
else if (rcp == INTERFACE_RECIPIENT)
{
if (dev->configuration == 0)
return -1;
return USB_EVENT_GET_STATUS_INTERFACE;
}
else if (rcp == ENDPOINT_RECIPIENT)
{
uint8_t n = (arg->index & 0x0f);
if ((arg->index & 0x70) || n == ENDP0)
return -1;
if (kl27z_ep_is_disabled (n))
return -1;
status_info = kl27z_ep_is_stall (n);
return usb_lld_ctrl_send (dev, &status_info, 2);
}
return -1;
}
static int
std_clear_feature (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_GET (arg->type))
return -1;
if (rcp == DEVICE_RECIPIENT)
{
if (arg->len != 0 || arg->index != 0)
return -1;
if (arg->value == FEATURE_DEVICE_REMOTE_WAKEUP)
{
dev->feature &= ~(1 << 5);
return USB_EVENT_CLEAR_FEATURE_DEVICE;
}
}
else if (rcp == ENDPOINT_RECIPIENT)
{
uint8_t n = (arg->index & 0x0f);
if (dev->configuration == 0)
return -1;
if (arg->len != 0 || (arg->index >> 8) != 0
|| arg->value != FEATURE_ENDPOINT_HALT || n == ENDP0)
return -1;
if (kl27z_ep_is_disabled (n))
return -1;
kl27z_ep_clear_dtog ((arg->index & 0x80) == 0, n);
return USB_EVENT_CLEAR_FEATURE_ENDPOINT;
}
return -1;
}
static int
std_set_feature (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_GET (arg->type))
return -1;
if (rcp == DEVICE_RECIPIENT)
{
if (arg->len != 0 || arg->index != 0)
return -1;
if (arg->value == FEATURE_DEVICE_REMOTE_WAKEUP)
{
dev->feature |= 1 << 5;
return USB_EVENT_SET_FEATURE_DEVICE;
}
}
else if (rcp == ENDPOINT_RECIPIENT)
{
uint8_t n = (arg->index & 0x0f);
if (dev->configuration == 0)
return -1;
if (arg->len != 0 || (arg->index >> 8) != 0
|| arg->value != FEATURE_ENDPOINT_HALT || n == ENDP0)
return -1;
if (kl27z_ep_is_disabled (n))
return -1;
kl27z_ep_stall (n);
return USB_EVENT_SET_FEATURE_ENDPOINT;
}
return -1;
}
static int
std_set_address (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_GET (arg->type))
return -1;
if (rcp == DEVICE_RECIPIENT && arg->len == 0 && arg->value <= 127
&& arg->index == 0 && dev->configuration == 0)
return usb_lld_ctrl_ack (dev);
return -1;
}
static int
std_get_descriptor (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
if (USB_SETUP_SET (arg->type))
return -1;
return USB_EVENT_GET_DESCRIPTOR;
}
static int
std_get_configuration (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_SET (arg->type))
return -1;
if (arg->value != 0 || arg->index != 0 || arg->len != 1)
return -1;
if (rcp == DEVICE_RECIPIENT)
return usb_lld_ctrl_send (dev, &dev->configuration, 1);
return -1;
}
static int
std_set_configuration (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_GET (arg->type))
return -1;
if (rcp == DEVICE_RECIPIENT && arg->index == 0 && arg->len == 0)
return USB_EVENT_SET_CONFIGURATION;
return -1;
}
static int
std_get_interface (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_SET (arg->type))
return -1;
if (arg->value != 0 || (arg->index >> 8) != 0 || arg->len != 1)
return -1;
if (dev->configuration == 0)
return -1;
if (rcp == INTERFACE_RECIPIENT)
return USB_EVENT_GET_INTERFACE;
return -1;
}
static int
std_set_interface (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
if (USB_SETUP_GET (arg->type) || rcp != INTERFACE_RECIPIENT
|| arg->len != 0 || (arg->index >> 8) != 0
|| (arg->value >> 8) != 0 || dev->configuration == 0)
return -1;
return USB_EVENT_SET_INTERFACE;
}
static int
handle_setup0 (struct usb_dev *dev)
{
struct ctrl_data *data_p = &dev->ctrl_data;
int r = -1;
HANDLER handler;
data_p->addr = NULL;
data_p->len = 0;
data_p->require_zlp = 0;
if ((dev->dev_req.type & REQUEST_TYPE) == STANDARD_REQUEST)
{
switch (dev->dev_req.request)
{
case 0: handler = std_get_status; break;
case 1: handler = std_clear_feature; break;
case 3: handler = std_set_feature; break;
case 5: handler = std_set_address; break;
case 6: handler = std_get_descriptor; break;
case 8: handler = std_get_configuration; break;
case 9: handler = std_set_configuration; break;
case 10: handler = std_get_interface; break;
case 11: handler = std_set_interface; break;
default: handler = std_none; break;
}
if ((r = (*handler) (dev)) < 0)
{
usb_lld_ctrl_error (dev);
return USB_EVENT_OK;
}
else
return r;
}
else
return USB_EVENT_CTRL_REQUEST;
}
static int
handle_in0 (struct usb_dev *dev, uint8_t stat)
{
int r = 0;
if (dev->state == IN_DATA || dev->state == LAST_IN_DATA)
handle_datastage_in (dev, stat);
else if (dev->state == WAIT_STATUS_IN)
{ /* Control WRITE transfer done successfully. */
uint16_t value = dev->dev_req.value;
if ((dev->dev_req.request == SET_ADDRESS) &&
((dev->dev_req.type & (REQUEST_TYPE | RECIPIENT))
== (STANDARD_REQUEST | DEVICE_RECIPIENT)))
{
kl27z_set_daddr (value);
ep[0].rx_odd = 0;
r = USB_EVENT_DEVICE_ADDRESSED;
}
else
r = USB_EVENT_CTRL_WRITE_FINISH;
dev->state = WAIT_SETUP;
kl27z_prepare_ep0_setup (dev);
}
else
{
dev->state = STALLED;
kl27z_ep_stall (ENDP0);
}
return r;
}
static void
handle_out0 (struct usb_dev *dev, uint8_t stat)
{
if (dev->state == OUT_DATA)
/* It's normal control WRITE transfer. */
handle_datastage_out (dev, stat);
else if (dev->state == WAIT_STATUS_OUT)
{ /* Control READ transfer done successfully. */
dev->state = WAIT_SETUP;
kl27z_prepare_ep0_setup (dev);
}
else
{
/*
* dev->state == IN_DATA || dev->state == LAST_IN_DATA
* (Host aborts the transfer before finish)
* Or else, unexpected state.
* STALL the endpoint, until we receive the next SETUP token.
*/
dev->state = STALLED;
kl27z_ep_stall (ENDP0);
}
}
#define USB_TOKEN_ACK 0x02
#define USB_TOKEN_IN 0x09
#define USB_TOKEN_SETUP 0x0d
static int
handle_transaction (struct usb_dev *dev, uint8_t stat)
{
int odd = (stat >> 2)&1;
uint8_t ep_num = (stat >> 4);
int r;
if (ep_num == 0)
{
if ((stat & 0x08) == 0)
{
ep[0].rx_odd ^= 1;
if (TOK_PID (BD_table[odd].ctrl) == USB_TOKEN_SETUP)
{
r = handle_setup0 (dev);
USB_CTRL1->ISTAT = USB_IS_TOKDNE;
USB_CTRL1->CTL = 0x01; /* Clear TXSUSPENDTOKENBUSY. */
return USB_MAKE_EV (r);
}
else
{
handle_out0 (dev, stat);
USB_CTRL1->ISTAT = USB_IS_TOKDNE;
return USB_EVENT_OK;
}
}
else
{
ep[0].tx_odd ^= 1;
r = handle_in0 (dev, stat);
USB_CTRL1->ISTAT = USB_IS_TOKDNE;
return USB_MAKE_EV (r);
}
}
else
{
uint16_t len;
if ((stat & 0x08) == 0)
{
len = (BD_table[4*ep_num+odd].ctrl >> 16)&0x3ff;
ep[ep_num].rx_odd ^= 1;
USB_CTRL1->ISTAT = USB_IS_TOKDNE;
return USB_MAKE_TXRX (ep_num, 0, len);
}
else
{
/*
* IN transaction is usually in a sequence like:
*
* -----time------>
* host: IN ACK
* device: DATA0/1
*
* Although it is not described in the specification (it's
* ambiguous), it is actually possible for some host
* implementation to send back a NAK on erroneous case like
* a device sent oversized data.
*
* -----time------>
* host: IN NAK
* device: DATA0/1
*
* We do our best to distinguish successful tx and tx with
* failure.
*
*/
uint32_t dmaerr = (USB_CTRL1->ERRSTAT & (1 << 5));
int success = (dmaerr == 0);
len = (BD_table[4*ep_num+2+odd].ctrl >> 16)&0x3ff;
if (!success)
USB_CTRL1->ERRSTAT = dmaerr; /* Clear error. */
ep[ep_num].tx_odd ^= 1;
USB_CTRL1->ISTAT = USB_IS_TOKDNE;
return USB_MAKE_TXRX (ep_num, 1, len);
}
}
}
void
usb_lld_reset (struct usb_dev *dev, uint8_t feature)
{
usb_lld_set_configuration (dev, 0);
dev->feature = feature;
dev->state = WAIT_SETUP;
/* Reset USB */
USB_CTRL2->USBTRC0 = 0xc0;
USB_CTRL1->CTL = 0x00; /* Disable USB FS communication module */
kl27z_set_daddr (0);
kl27z_usb_init ();
/* Clear Interrupt Status Register, and enable interrupt for USB */
USB_CTRL1->ISTAT = 0xff; /* All clear */
USB_CTRL1->INTEN = USB_IS_STALL | USB_IS_TOKDNE
| USB_IS_ERROR | USB_IS_USBRST;
}
void
usb_lld_setup_endp (struct usb_dev *dev, int n, int rx_en, int tx_en)
{
if (n == 0)
{
/* Enable the endpoint 0. */
USB_ENDPT[0].EP = 0x0d;
kl27z_prepare_ep0_setup (dev);
}
else
{
/* Enable the endpoint. */
USB_ENDPT[n].EP = (rx_en << 3)|(tx_en << 2)|0x11;
/* Configure BDT entry so that it starts with DATA0. */
/* RX */
BD_table[4*n+ep[n].rx_odd].ctrl = 0x0000;
BD_table[4*n+ep[n].rx_odd].buf = NULL;
BD_table[4*n+!ep[n].rx_odd].ctrl = 0x0040;
BD_table[4*n+!ep[n].rx_odd].buf = NULL;
/* TX */
BD_table[4*n+2+ep[n].tx_odd].ctrl = 0x0000;
BD_table[4*n+2+ep[n].tx_odd].buf = NULL;
BD_table[4*n+2+!ep[n].tx_odd].ctrl = 0x0040;
BD_table[4*n+2+!ep[n].tx_odd].buf = NULL;
}
}
void
usb_lld_set_configuration (struct usb_dev *dev, uint8_t config)
{
dev->configuration = config;
}
uint8_t
usb_lld_current_configuration (struct usb_dev *dev)
{
return dev->configuration;
}
int
usb_lld_ctrl_recv (struct usb_dev *dev, void *p, size_t len)
{
struct ctrl_data *data_p = &dev->ctrl_data;
data_p->addr = (uint8_t *)p;
data_p->len = len;
if (len > USB_MAX_PACKET_SIZE)
len = USB_MAX_PACKET_SIZE;
kl27z_prepare_ep0_out (p, len, DATA1);
dev->state = OUT_DATA;
return USB_EVENT_OK;
}
/*
* BUF: Pointer to data memory. Data memory should not be allocated
* on stack when BUFLEN > USB_MAX_PACKET_SIZE.
*
* BUFLEN: size of the data.
*/
int
usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
{
struct ctrl_data *data_p = &dev->ctrl_data;
uint32_t len_asked = dev->dev_req.len;
uint32_t len;
data_p->addr = (void *)buf;
data_p->len = buflen;
/* Restrict the data length to be the one host asks for */
if (data_p->len > len_asked)
data_p->len = len_asked;
data_p->require_zlp = (data_p->len != 0
&& (data_p->len % USB_MAX_PACKET_SIZE) == 0);
if (data_p->len < USB_MAX_PACKET_SIZE)
{
len = data_p->len;
dev->state = LAST_IN_DATA;
}
else
{
len = USB_MAX_PACKET_SIZE;
dev->state = IN_DATA;
}
kl27z_prepare_ep0_in (data_p->addr, len, DATA1);
data_p->len -= len;
data_p->addr += len;
return USB_EVENT_OK;
}
void
usb_lld_rx_enable_buf (int n, void *buf, size_t len)
{
int data01 = !((BD_table[4*n+!ep[n].rx_odd].ctrl >> 6)&1);
BD_table[4*n+ep[n].rx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6);
BD_table[4*n+ep[n].rx_odd].buf = buf;
}
void
usb_lld_tx_enable_buf (int n, const void *buf, size_t len)
{
int data01 = !((BD_table[4*n+2+!ep[n].tx_odd].ctrl >> 6)&1);
BD_table[4*n+2+ep[n].tx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6);
BD_table[4*n+2+ep[n].tx_odd].buf = (void *)buf;
}

File diff suppressed because it is too large Load Diff

2180
mcu/usb-usbip.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,13 +6,31 @@ ifneq ($(USE_EVENTFLAG),)
CSRC += $(CHOPSTX)/eventflag.c
endif
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
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
@@ -24,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
@@ -46,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 $@
@@ -55,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)

7
sys.h Normal file
View File

@@ -0,0 +1,7 @@
#if defined(MCU_KINETIS_L)
#include "mcu/sys-mkl27z.h"
#elif defined(MCU_STM32F0)
#include "mcu/sys-stm32f0.h"
#else
#include "mcu/sys-stm32f103.h"
#endif

171
usb_lld.h Normal file
View File

@@ -0,0 +1,171 @@
#define STANDARD_ENDPOINT_DESC_SIZE 0x09
/* endpoints enumeration */
#define ENDP0 ((uint8_t)0)
#define ENDP1 ((uint8_t)1)
#define ENDP2 ((uint8_t)2)
#define ENDP3 ((uint8_t)3)
#define ENDP4 ((uint8_t)4)
#define ENDP5 ((uint8_t)5)
#define ENDP6 ((uint8_t)6)
#define ENDP7 ((uint8_t)7)
enum RECIPIENT_TYPE
{
DEVICE_RECIPIENT = 0, /* Recipient device */
INTERFACE_RECIPIENT, /* Recipient interface */
ENDPOINT_RECIPIENT, /* Recipient endpoint */
OTHER_RECIPIENT
};
enum DESCRIPTOR_TYPE
{
DEVICE_DESCRIPTOR = 1,
CONFIG_DESCRIPTOR,
STRING_DESCRIPTOR,
INTERFACE_DESCRIPTOR,
ENDPOINT_DESCRIPTOR
};
#define REQUEST_DIR 0x80 /* Mask to get request dir */
#define REQUEST_TYPE 0x60 /* Mask to get request type */
#define STANDARD_REQUEST 0x00 /* Standard request */
#define CLASS_REQUEST 0x20 /* Class request */
#define VENDOR_REQUEST 0x40 /* Vendor request */
#define RECIPIENT 0x1F /* Mask to get recipient */
#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
struct device_req {
uint8_t type;
uint8_t request;
uint16_t value;
uint16_t index;
uint16_t len;
};
struct ctrl_data {
uint8_t *addr;
uint16_t len;
uint8_t require_zlp;
};
struct usb_dev {
uint8_t configuration;
uint8_t feature;
uint8_t state;
struct device_req dev_req;
struct ctrl_data ctrl_data;
};
enum {
USB_EVENT_OK=0, /* Processed in lower layer. */
/* Device reset and suspend. */
USB_EVENT_DEVICE_RESET,
USB_EVENT_DEVICE_SUSPEND,
/* Device Requests (Control WRITE Transfer): Standard */
USB_EVENT_SET_CONFIGURATION,
USB_EVENT_SET_INTERFACE,
USB_EVENT_SET_FEATURE_DEVICE,
USB_EVENT_SET_FEATURE_ENDPOINT,
USB_EVENT_CLEAR_FEATURE_DEVICE,
USB_EVENT_CLEAR_FEATURE_ENDPOINT,
/* Device Requests (Control READ Transfer): Standard */
USB_EVENT_GET_STATUS_INTERFACE,
USB_EVENT_GET_DESCRIPTOR,
USB_EVENT_GET_INTERFACE,
/* Device Requests (Control READ/WRITE Transfer): Non-Standard */
USB_EVENT_CTRL_REQUEST,
USB_EVENT_CTRL_WRITE_FINISH,
/* Device addressed. */
USB_EVENT_DEVICE_ADDRESSED,
};
enum DEVICE_STATE {
UNCONNECTED,
ATTACHED,
POWERED,
SUSPENDED,
ADDRESSED,
CONFIGURED
};
void usb_lld_init (struct usb_dev *dev, uint8_t feature);
/*
* Return value is encoded integer:
* event-no: 8-bit, 0 if TX/RX
* tx/rx-flag: 1-bit, 0 if rx, 1 if tx
* endpoint no: 7-bit
* length: 16-bit
*/
#define USB_EVENT_TXRX(e) ((e >> 23) & 1)
#define USB_EVENT_LEN(e) (e & 0xffff)
#define USB_EVENT_ENDP(e) ((e >> 16) & 0x7f)
#define USB_EVENT_ID(e) ((e >> 24))
int usb_lld_event_handler (struct usb_dev *dev);
/*
* Control Endpoint ENDP0 does device requests handling.
* In response to an event of
* USB_EVENT_SET_CONFIGURATION
* USB_EVENT_SET_INTERFACE
* USB_EVENT_SET_FEATURE_DEVICE
* USB_EVENT_SET_FEATURE_ENDPOINT
* USB_EVENT_CLEAR_FEATURE_DEVICE
* USB_EVENT_CLEAR_FEATURE_ENDPOINT
* USB_EVENT_GET_STATUS_INTERFACE
* USB_EVENT_GET_DESCRIPTOR
* USB_EVENT_GET_INTERFACE
* USB_EVENT_CTRL_REQUEST
* a single action should be done, which is SEND, RECV, or,
* ACKNOWLEDGE (no data to be sent, or to be received).
* Otherwise, it's an error.
*/
int usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen);
int usb_lld_ctrl_recv (struct usb_dev *dev, void *p, size_t len);
int usb_lld_ctrl_ack (struct usb_dev *dev);
void usb_lld_ctrl_error (struct usb_dev *dev);
void usb_lld_reset (struct usb_dev *dev, uint8_t feature);
void usb_lld_set_configuration (struct usb_dev *dev, uint8_t config);
uint8_t usb_lld_current_configuration (struct usb_dev *dev);
void usb_lld_prepare_shutdown (void);
void usb_lld_shutdown (void);
#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 */
#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */
void usb_lld_tx_enable (int ep_num, size_t len);
void usb_lld_rx_enable (int ep_num);
void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
int ep_rx_addr, int ep_tx_addr,
int ep_rx_memory_size);
void usb_lld_stall_tx (int ep_num);
void usb_lld_stall_rx (int ep_num);
void usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len);
void usb_lld_write (uint8_t ep_num, const void *buf, size_t len);
void usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len);
void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n);
void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n);
#endif

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
};