Compare commits
162 Commits
release/0.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d25cee5040 | ||
|
|
e420168c82 | ||
|
|
7dc67d2210 | ||
|
|
49b0556a24 | ||
|
|
43bbdb44dc | ||
|
|
d4f4f80ad9 | ||
|
|
7ad7527e81 | ||
|
|
951afbad3a | ||
|
|
2b717c91da | ||
|
|
05732b445a | ||
|
|
1cbe0abdee | ||
|
|
802dbbd639 | ||
|
|
2764fc4ea2 | ||
|
|
f500ac03da | ||
|
|
808aa5b186 | ||
|
|
f781ac9e6a | ||
|
|
32d0b8200d | ||
|
|
05382581e8 | ||
|
|
aa97af66db | ||
|
|
e6a53c99c4 | ||
|
|
cb770e9ae3 | ||
|
|
aa63ac79bc | ||
|
|
74cff25b78 | ||
|
|
5cd4871a94 | ||
|
|
c0a84627b6 | ||
|
|
8dabbe6e1c | ||
|
|
0a68140530 | ||
|
|
ce3cd63144 | ||
|
|
199db97025 | ||
|
|
1533284ace | ||
|
|
0e9737eb61 | ||
|
|
265fb971c0 | ||
|
|
26d5bb0115 | ||
|
|
bf1ac08e6c | ||
|
|
530ddcfeda | ||
|
|
19b0590c1f | ||
|
|
72210e4250 | ||
|
|
61892c85b0 | ||
|
|
75e6b06dd5 | ||
|
|
dd190c8207 | ||
|
|
22039ee717 | ||
|
|
cb628fe317 | ||
|
|
f3cc662548 | ||
|
|
b58dd05c9d | ||
|
|
7b1c442d88 | ||
|
|
b4b9aace03 | ||
|
|
741aba1997 | ||
|
|
022666402c | ||
|
|
69677aecd4 | ||
|
|
bc35bc81cf | ||
|
|
499e575528 | ||
|
|
9f9aeae4bf | ||
|
|
ecd90b1b99 | ||
|
|
39e53ae747 | ||
|
|
9b9d40c16b | ||
|
|
1eff465303 | ||
|
|
de895e6b65 | ||
|
|
d4cca9f0dc | ||
|
|
de9eb6f1e7 | ||
|
|
2c14f21b20 | ||
|
|
9e527b0532 | ||
|
|
817167dbcc | ||
|
|
63974743b4 | ||
|
|
14c4256337 | ||
|
|
8c4ea854cb | ||
|
|
a610821458 | ||
|
|
3071929c62 | ||
|
|
14cb38e56f | ||
|
|
a362f32cdd | ||
|
|
e684e853c8 | ||
|
|
2b98dc3de8 | ||
|
|
44054415c8 | ||
|
|
66b4eb3058 | ||
|
|
b72154f47b | ||
|
|
378201a1c7 | ||
|
|
1a7bd3e202 | ||
|
|
b34b9b6440 | ||
|
|
d745c9fdb9 | ||
|
|
3552fc5615 | ||
|
|
621dff7cb3 | ||
|
|
83643c53ca | ||
|
|
040f389449 | ||
|
|
44273a70fc | ||
|
|
7257f30636 | ||
|
|
941a8f6fbd | ||
|
|
13926ac05a | ||
|
|
bbe09de209 | ||
|
|
f161928b0b | ||
|
|
035057db24 | ||
|
|
5ac8a1f251 | ||
|
|
168af852a5 | ||
|
|
e398fc9689 | ||
|
|
5a08752b9c | ||
|
|
b572e3f8e0 | ||
|
|
55b011a721 | ||
|
|
c191d86bf2 | ||
|
|
96d2a81331 | ||
|
|
fa7cecc0b4 | ||
|
|
a34937453c | ||
|
|
dd54b5ff20 | ||
|
|
c08044e22b | ||
|
|
5b7c5a9996 | ||
|
|
bc39f0e582 | ||
|
|
e671a539b0 | ||
|
|
2c9191c4b3 | ||
|
|
af5982507f | ||
|
|
a1b993c2e2 | ||
|
|
e73d14ca27 | ||
|
|
d8df82badf | ||
|
|
f51a54e4c6 | ||
|
|
5fe5ff36c4 | ||
|
|
a4f28ee176 | ||
|
|
87767f1be5 | ||
|
|
8b018df382 | ||
|
|
5d9802388c | ||
|
|
478dd2c784 | ||
|
|
6f7a591417 | ||
|
|
d142cbbea3 | ||
|
|
f011d643e9 | ||
|
|
1fbbf66e8e | ||
|
|
1f7d4a6aac | ||
|
|
526b8fec2a | ||
|
|
5419580519 | ||
|
|
78c825afe8 | ||
|
|
1bd14d8d40 | ||
|
|
80258ba7c7 | ||
|
|
ca1b22c3eb | ||
|
|
6c68c55301 | ||
|
|
d941299149 | ||
|
|
b2b0eb7418 | ||
|
|
7798e620a6 | ||
|
|
89eb54929e | ||
|
|
a96f84ff74 | ||
|
|
9d84537c13 | ||
|
|
d448d3c678 | ||
|
|
bc664fe943 | ||
|
|
08cca6b9f8 | ||
|
|
c9d59a3f3f | ||
|
|
09f27704f5 | ||
|
|
1f23bd4048 | ||
|
|
f5880ee5d5 | ||
|
|
c7e571eca0 | ||
|
|
0decd305b9 | ||
|
|
a2a29146a6 | ||
|
|
e7bd234a0d | ||
|
|
c71a24ddcb | ||
|
|
663cbabe7c | ||
|
|
41ac81a66b | ||
|
|
986518fba7 | ||
|
|
15a4403f24 | ||
|
|
40adf95c24 | ||
|
|
5a7381ece6 | ||
|
|
52626a3368 | ||
|
|
440188c373 | ||
|
|
a6541cbcc6 | ||
|
|
74c7b5bcb3 | ||
|
|
4d7e97028e | ||
|
|
d061e6f931 | ||
|
|
5f1c26ff17 | ||
|
|
78718e57df | ||
|
|
a756987d2a | ||
|
|
b6e3a1aba1 |
15
.gitlab-ci.yml
Normal file
15
.gitlab-ci.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
image: debian:stable
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get -y install texi2html
|
||||||
|
|
||||||
|
pages:
|
||||||
|
stage: deploy
|
||||||
|
script:
|
||||||
|
- mkdir -p html && (cd html && texi2html ../doc/chopstx.texi)
|
||||||
|
- mv html/ public
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- public
|
||||||
|
only:
|
||||||
|
- master
|
||||||
38
AUTHORS
38
AUTHORS
@@ -2,6 +2,10 @@ Aidan Thornton:
|
|||||||
Added Maple Mini support.
|
Added Maple Mini support.
|
||||||
board/board-maple-mini.h
|
board/board-maple-mini.h
|
||||||
|
|
||||||
|
Jeremy Drake:
|
||||||
|
Modified STM32F103 support.
|
||||||
|
mcu/sys-stm32f103.c
|
||||||
|
|
||||||
Kaz Kojima:
|
Kaz Kojima:
|
||||||
Added STM32 Primer2 support.
|
Added STM32 Primer2 support.
|
||||||
board/board-stm32-primer2.h
|
board/board-stm32-primer2.h
|
||||||
@@ -22,17 +26,35 @@ Mateusz Zalega:
|
|||||||
board/board-nitrokey-start.h
|
board/board-nitrokey-start.h
|
||||||
|
|
||||||
NIIBE Yutaka:
|
NIIBE Yutaka:
|
||||||
Write the library:
|
Wrote the library:
|
||||||
chopstx.c, eventflag.c, entry.c,
|
chopstx.c, entry.c, eventflag.c,
|
||||||
clk_gpio_init-kl.c, clk_gpio_init-stm32.c
|
|
||||||
chopstx.h, eventflag.h
|
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
|
chopstx.svg, chopstx.png
|
||||||
Write examples:
|
Wrote examples:
|
||||||
example-led, example-cdc, example-fsm-55
|
example-led, example-cdc, example-fsm-55, example-fs-bb48,
|
||||||
Write board:
|
example-usb-serial
|
||||||
|
Wrote board/*:
|
||||||
board-fst-01.h, board-fst-01-00.h,
|
board-fst-01.h, board-fst-01-00.h,
|
||||||
board-olimex-stm32-h103.h, board-stm8s-discovery.h
|
board-olimex-stm32-h103.h, board-stm8s-discovery.h
|
||||||
board-cq-starm.h, board-stbee-mini.h, board-stbee.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
|
||||||
|
contrib/usart-stm32f103.c
|
||||||
|
|
||||||
|
Paul Fertser:
|
||||||
|
Added Blue Pill support.
|
||||||
|
board/board-blue-pill.h
|
||||||
|
|
||||||
|
Szczepan Zalega:
|
||||||
|
Modified Nitrokey-Start support.
|
||||||
|
board/board-nitrokey-start.h
|
||||||
|
|||||||
507
ChangeLog
507
ChangeLog
@@ -1,3 +1,510 @@
|
|||||||
|
2018-09-29 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.10.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.10.
|
||||||
|
|
||||||
|
2018-09-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* contrib/ackbtn-stm32f103.c: New.
|
||||||
|
* rules.mk [USE_ACKBTN] (CSRC): Add ack-button support.
|
||||||
|
|
||||||
|
2018-09-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
Fix for chopstx_intr_done. No spurious interrupts.
|
||||||
|
* contrib/adc-mkl27z.c (adc_wait_completion): Fix.
|
||||||
|
* contrib/adc-stm32f103.c (adc_wait_completion): Likewise.
|
||||||
|
* contrib/usart-stm32f103.c (usart_main): Likewise.
|
||||||
|
* example-cdc-gnu-linux/usb-cdc.c (tty_main): Likewise.
|
||||||
|
* example-cdc/usb-cdc.c (tty_main): Likewise.
|
||||||
|
* example-fraucheky/main.c (usb_main): Likewise.
|
||||||
|
* example-fs-bb48/touch.c (touch_get): Likewise.
|
||||||
|
* example-fs-bb48/usb-cdc.c (tty_main): Likewise.
|
||||||
|
* example-primer2/primer2-ts.c (adc3_conversion): Likewise.
|
||||||
|
* example-usb-serial/usb-cdc.c (cdc_main): Likewise.
|
||||||
|
|
||||||
|
2018-09-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx.h (chopstx_intr_done): New function.
|
||||||
|
* chopstx.c (chopstx_intr_done): New function.
|
||||||
|
(chopstx_poll): Don't call chx_clr_intr.
|
||||||
|
Ensure data memory barrier for interrupt handling.
|
||||||
|
|
||||||
|
* chopstx-cortex-m.c (chx_dmb): New static function.
|
||||||
|
* chopstx-gnu-linux.c (chx_dmb): Ditto.
|
||||||
|
|
||||||
|
2018-09-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/stm32.h (struct GPIO, struct FLASH): Moved from...
|
||||||
|
* mcu/clk_gpio_init-stm32.c: ... here.
|
||||||
|
(AFIO_MAPR_SWJ_CFG_JTAGDISABLE): Move to ...
|
||||||
|
* mcu/stm32f103.h: ... here.
|
||||||
|
* mcu/sys-stm32f103.c: Don't include "mcu/cortex-m.h".
|
||||||
|
|
||||||
|
* board/board-fst-01sz.h: New.
|
||||||
|
* mcu/sys-stm32f103.h (BOARD_ID_FST_01SZ): New.
|
||||||
|
* contrib/adc-stm32f103.c (get_adc_config): Add BOARD_ID_FST_01SZ.
|
||||||
|
|
||||||
|
2018-08-20 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/usb-stm32f103.c (usb_lld_ctrl_send): Fix for ZLP.
|
||||||
|
* mcu/usb-usbip.c (usb_lld_ctrl_send): Likewise.
|
||||||
|
* mcu/usb-mkl27z.c (usb_lld_ctrl_send): Likewise.
|
||||||
|
|
||||||
|
2018-05-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.9.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.9.
|
||||||
|
|
||||||
|
2018-05-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* board/board-blue-pill.h (GPIO_USB_SET_TO_ENABLE): Remove.
|
||||||
|
|
||||||
|
* doc/chopstx.texi (Compile-time macro): New chapter.
|
||||||
|
|
||||||
|
* mcu/sys-stm32f103.c (usb_lld_sys_init): Use MHZ.
|
||||||
|
(flash_protect): Fix for GD32F103.
|
||||||
|
|
||||||
|
2018-04-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* board/board-blue-pill-g.h: New. Define STM32_ADCPRE and
|
||||||
|
STM32_USBPRE for 96MHz clock.
|
||||||
|
* mcu/stm32.h (STM32_USBPRE_DIV2): New for GD32F103.
|
||||||
|
* mcu/clk_gpio_init-stm32.c: Allow constants, which are defined by
|
||||||
|
board.h (STM32_ADCPRE and STM32_USBPRE).
|
||||||
|
* mcu/chx-stm32f103.c: Use STM32_ADCPRE and STM32_USBPRE.
|
||||||
|
|
||||||
|
* mcu/usb-stm32f103.c (usb_lld_init): BTABLE setting at
|
||||||
|
initialization.
|
||||||
|
(usb_lld_reset): Not at each reset.
|
||||||
|
|
||||||
|
* contrib/adc-stm32f103.c [MCU_STM32F1_GD32F1]: Use continuous
|
||||||
|
sampling with no DELIBARATELY_DO_IT_WRONG_START_STOP.
|
||||||
|
(adc_init): Wait after ADC_CR2_ADON.
|
||||||
|
(adc_start): Likewise. Enabling by ADC_CR2_ADON after all other
|
||||||
|
registers configuration.
|
||||||
|
|
||||||
|
2018-01-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.8.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.8.
|
||||||
|
|
||||||
|
2018-01-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/stm32f103.h: Include stm32.h and cortex-m.h.
|
||||||
|
|
||||||
|
2018-01-09 Anthony Romano <romanoanthony061@gmail.com>
|
||||||
|
|
||||||
|
* contrib/adc-stm32f103.c: Support IN8 config.
|
||||||
|
|
||||||
|
2017-12-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.7.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.7.
|
||||||
|
|
||||||
|
2017-12-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* contrib/usart-stm32f103.c: New.
|
||||||
|
* example-usb-serial: New example.
|
||||||
|
|
||||||
|
2017-12-16 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx.c (chx_timer_expired): Bug fix of wake up.
|
||||||
|
(chx_mutex_unlock): Avoid non-deterministic thing.
|
||||||
|
|
||||||
|
2017-12-14 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* board/board-st-nucleo-f103.h: Update.
|
||||||
|
|
||||||
|
* mcu/sys-stm32f103.h (BOARD_ID_FST_01G): New.
|
||||||
|
|
||||||
|
* contrib/adc-stm32f103.c (get_adc_config): Add a case for
|
||||||
|
BOARD_ID_FST_01G and BOARD_ID_ST_NUCLEO_F103.
|
||||||
|
|
||||||
|
2017-11-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.6.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.6.
|
||||||
|
* doc/chopstx-api.texi: Regenerated.
|
||||||
|
|
||||||
|
2017-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-fsm-55: Update using stack-def.h.
|
||||||
|
|
||||||
|
2017-11-20 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-led: Update using stack-def.h.
|
||||||
|
|
||||||
|
* chopstx-cortex-m.c [__ARM_ARCH_6M__] (chx_sched): Fix.
|
||||||
|
|
||||||
|
2017-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-fsm-55/hh.c (main): Just return.
|
||||||
|
|
||||||
|
2017-11-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/chx-stm32f103.c (configure_clock): Change prescaler on
|
||||||
|
sleep.
|
||||||
|
|
||||||
|
* mcu/clk_gpio_init-stm32.c (clock_init): Don't turn on CRC
|
||||||
|
module.
|
||||||
|
|
||||||
|
* mcu/clk_gpio_init-stm32.c (STM32_*): Move to...
|
||||||
|
* mcu/stm32.h (STM32_*): ... this header file.
|
||||||
|
|
||||||
|
* mcu/stm32f103.h, mcu/clk_gpio_init-stm32.c (RCC): Move to...
|
||||||
|
* mcu/stm32.h (RCC): ... this header file.
|
||||||
|
|
||||||
|
* example-fsm-55: Update for new sleep API.
|
||||||
|
|
||||||
|
* rules.mk (CSRC): Add mcu/chx-$(CHIP).c.
|
||||||
|
|
||||||
|
* chopstx-cortex-m.c (idle, chx_sleep_mode): Remove.
|
||||||
|
(chx_sched, preempt): Call chx_idle.
|
||||||
|
* mcu/chx-mkl27z.c, mcu/chx-stm32f0.c, mcu/chx-stm32f103.c: New.
|
||||||
|
* mcu/stm32.h: New.
|
||||||
|
|
||||||
|
* chopstx-gnu-linux.c (chx_sleep_mode): Move to...
|
||||||
|
* mcu/chx-gnu-linux.c: Here.
|
||||||
|
|
||||||
|
* mcu/stm32f103.h (DBGMCU): New.
|
||||||
|
|
||||||
|
* mcu/cortex-m.h: New.
|
||||||
|
* mcu/sys-stm32f0.c, mcu/sys-stm32f103.c: Use mcu/cortex-m.h.
|
||||||
|
|
||||||
|
* chopstx.c (chopstx_conf_idle): Call chx_sleep_mode before
|
||||||
|
changing chx_allow_sleep.
|
||||||
|
|
||||||
|
* board/board-blue-pill.h, board/board-cq-starm.h,
|
||||||
|
board/board-fst-01-00.h, board/board-fst-01.h,
|
||||||
|
board/board-fst-01g.h, board/board-maple-mini.h,
|
||||||
|
board/board-nitrokey-start.h, board/board-olimex-stm32-h103.h,
|
||||||
|
board/board-st-dongle.h, board/board-st-nucleo-f103.h,
|
||||||
|
board/board-stbee-mini.h, board/board-stbee.h,
|
||||||
|
board/board-stm32-primer2.h: Add MCU_STM32F1.
|
||||||
|
|
||||||
|
2017-11-16 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx.h (chopstx_poll): API change.
|
||||||
|
* chopstx.c (chopstx_poll): Use const pointer.
|
||||||
|
|
||||||
|
* chopstx-cortex-m.c (idle): Support WFE.
|
||||||
|
[!MCU_STM32F0] (chx_sleep_mode): Clock feed by HSI.
|
||||||
|
|
||||||
|
2017-11-15 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx.c (chopstx_conf_idle): Call chx_sleep_mode.
|
||||||
|
* chopstx-cortex-m.c (chx_sleep_mode): New.
|
||||||
|
* chopstx-gnu-linux.c (chx_sleep_mode): New.
|
||||||
|
|
||||||
|
2017-11-15 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-fsm-55/hh.c (main): Add call to chopstx_conf_idle.
|
||||||
|
* example-fsm-55/Makefile (DEFS): Remove USE_WFI_FOR_IDLE.
|
||||||
|
|
||||||
|
* chopstx.c (chx_init): Initialize sleep lock.
|
||||||
|
(chopstx_conf_idle): New.
|
||||||
|
* chopstx-cortex-m.c (idle): Support sleep.
|
||||||
|
|
||||||
|
* mcu/usb-stm32f103.c (usb_lld_event_handler): Fix suspend/resume.
|
||||||
|
|
||||||
|
2017-11-14 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* usb_lld.h (DEVICE_STATE): Add prefix USB_DEVICE_STATE_.
|
||||||
|
(USB_DEVICE_STATE_DEFAULT): New.
|
||||||
|
|
||||||
|
* mcu/usb-stm32f103.c (usb_lld_init): Suspend/resume init.
|
||||||
|
(usb_lld_event_handler): Add suspend/resume support.
|
||||||
|
|
||||||
|
* example-cdc/usb-cdc.c: Follow the change of usb_lld.h.
|
||||||
|
* example-cdc-gnu-linux/usb-cdc.c: Ditto.
|
||||||
|
* example-fs-bb48/usb-cdc.c: Ditto.
|
||||||
|
* example-fraucheky/main.c: Ditto.
|
||||||
|
* example-fraucheky/Makefile (USE_SYS): Add for debug.
|
||||||
|
|
||||||
|
2017-11-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/usb-stm32f103.c (usb_lld_init): Set up interrupt on errors.
|
||||||
|
|
||||||
|
* usb_lld.h (USB_EVENT_DEVICE_WAKEUP): New.
|
||||||
|
(INTR_REQ_USB): Define here.
|
||||||
|
* mcu/usb-usbip.c, example-cdc/usb-cdc.c,
|
||||||
|
example-fraucheky/main.c, example-fs-bb48/usb-cdc.c: Change
|
||||||
|
for INTR_REQ_USB.
|
||||||
|
|
||||||
|
2017-11-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx-cortex-m.c (svc): Replace stack top to TP.
|
||||||
|
(chx_sched): Return ->v correctly.
|
||||||
|
|
||||||
|
* chopstx.c (chx_timer_expired): Fix timeout.
|
||||||
|
|
||||||
|
2017-10-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/sys-stm32f103.h (nonreturn_handler0, nonreturn_handler1): New.
|
||||||
|
|
||||||
|
2017-10-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/usb-usbip.c (usbip_run_server): Shutdown support.
|
||||||
|
(usb_lld_shutdown): Shutdown glace-fully.
|
||||||
|
|
||||||
|
2017-10-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.5.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.5.
|
||||||
|
* doc/chopstx-api.texi: Regenerated.
|
||||||
|
|
||||||
|
2017-10-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-cdc-gnu-linux/sample.c (main): Support debug option.
|
||||||
|
|
||||||
|
* mcu/sys-gnu-linux.h (debug): New.
|
||||||
|
* mcu/sys-gnu-linux.c: Use debug.
|
||||||
|
* mcu/usb-usbip.c: Use debug.
|
||||||
|
|
||||||
|
* example-cdc/sample.ld (.process_stack, .main_stack): Add NOLOAD.
|
||||||
|
|
||||||
|
2017-09-29 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/sys-stm32f103.c (flash_program_halfword, flash_erase_page)
|
||||||
|
(flash_write, flash_erase_all_and_exec): Use uintptr_t.
|
||||||
|
|
||||||
|
2017-09-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/sys-gnu-linux.c: Flash emulation implemented.
|
||||||
|
|
||||||
|
2017-09-05 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* example-cdc: Use stack-def.h.
|
||||||
|
* example-cdc/stack-def.h: New.
|
||||||
|
|
||||||
|
2017-09-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* mcu/sys-stm32f103.h (nvic_system_reset): Add noreturn attribute.
|
||||||
|
|
||||||
|
* sys.h: Add mcu/sys-gnu-linux.h.
|
||||||
|
|
||||||
|
* mcu/sys-gnu-linux.c: New.
|
||||||
|
* mcu/sys-gnu-linux.h: New.
|
||||||
|
|
||||||
|
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>
|
2016-05-31 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
* VERSION: 0.12.
|
* VERSION: 0.12.
|
||||||
|
|||||||
163
NEWS
163
NEWS
@@ -1,6 +1,169 @@
|
|||||||
NEWS - Noteworthy changes
|
NEWS - Noteworthy changes
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.10
|
||||||
|
|
||||||
|
Released 2018-09-29
|
||||||
|
|
||||||
|
** Function chopstx_intr_wait is not deprecated, now.
|
||||||
|
Once, it was said that it's deprecated, but it's active again
|
||||||
|
to match the new function of chopstx_intr_done.
|
||||||
|
|
||||||
|
** API change: chopstx_poll, chopstx_intr_wait, chopstx_intr_done
|
||||||
|
To avoid spurious interrupt, we introduce new function
|
||||||
|
chopstx_intr_done, which should be called after interrupt handling.
|
||||||
|
|
||||||
|
** New driver: Acknowledge button for FST-01SZ
|
||||||
|
The use case is waiting user's acknowledge. We use EXTI interrupt
|
||||||
|
feature of STM32.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.9
|
||||||
|
|
||||||
|
Released 2018-05-09
|
||||||
|
|
||||||
|
** GD32F103 support
|
||||||
|
GD32F103 is an alternative implementation of STM32F103 by Giga Device,
|
||||||
|
which can run at 96MHz.
|
||||||
|
|
||||||
|
** Minor USB driver fix for STM32F103/GD32F103
|
||||||
|
BTABLE setting should be done at initialization, not at USB RESET.
|
||||||
|
|
||||||
|
** Minor SYS driver fix for GD32F103
|
||||||
|
flash_protect should check FLASH_CR_OPTWRE.
|
||||||
|
|
||||||
|
** Minor ADC driver change for GD32F103
|
||||||
|
ADC on GD32F103 is another implementation and its behavior is somewhat
|
||||||
|
different. It requires waits after enabling. So, we use continuous
|
||||||
|
sampling, instead of start and stop for each sample. Still, we
|
||||||
|
observe enough noise (> 4.7 bit/byte) for each ADC sampling.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.8
|
||||||
|
|
||||||
|
Released 2018-01-19
|
||||||
|
|
||||||
|
** Minor driver API fix
|
||||||
|
In version 1.6, part of mcu/stm32f103.h was moved into mcu/cortex-m.h
|
||||||
|
and mcu/stm32.h. Now, mcu/stm32f103.h automatically includes
|
||||||
|
mcu/cortex-m.h and mcu/stm32.h, so that it doesn't break existing
|
||||||
|
applications.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.7
|
||||||
|
|
||||||
|
Released 2017-12-19
|
||||||
|
|
||||||
|
** Fix: timer wakeup
|
||||||
|
Timer expiration had a bug. When it is waken up, the wake up doesn't
|
||||||
|
handle as a timer expiration when there are multiple threads on same
|
||||||
|
timing of expire. It confuses as if it were forced wakeup.
|
||||||
|
|
||||||
|
** New driver: USART for STM32.
|
||||||
|
USART driver for STM32 is added.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.6
|
||||||
|
|
||||||
|
Released 2017-11-24
|
||||||
|
|
||||||
|
** Fix cancellation
|
||||||
|
In Chopstx 1.4 and 1.5, cancellation doesn't work for real MCU. This
|
||||||
|
is due to the change of chx_sched interface, introduced for GNU/Linux
|
||||||
|
emulation. This bug is fixed.
|
||||||
|
|
||||||
|
** New feature: sleep mode
|
||||||
|
New function chopstx_conf_idle is added to support sleep. Note that
|
||||||
|
use of sleep by this feature requires careful preparation. For
|
||||||
|
example, enabling sleep, a board with no RESET pin cannot be debugged
|
||||||
|
by JTAG/SWD. Setting of DBGMCU_CR (0xE0042004) is required beforehand
|
||||||
|
(hardware default is zero).
|
||||||
|
|
||||||
|
** API change: chopstx_poll
|
||||||
|
This is a kind of clarification. The third argument is now an array
|
||||||
|
of constant pointers. We don't touch the array itself, just use it.
|
||||||
|
This allows having the array in read-only memory and can contribute
|
||||||
|
less use of RAM.
|
||||||
|
|
||||||
|
** USB API changes
|
||||||
|
INTR_REQ_USB is now defined by usb_lld.h. Enumeration type of
|
||||||
|
DEVICE_STATE now has USB_DEVICE_STATE_ prefix.
|
||||||
|
|
||||||
|
** USB driver change
|
||||||
|
USB suspend and wakeup events are supported for STM32F103.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.5
|
||||||
|
|
||||||
|
Released 2017-10-10
|
||||||
|
|
||||||
|
** Stack size definition by stack-def.h
|
||||||
|
Stack size of each thread was used to be defined in ldscript.
|
||||||
|
While emulation on GNU/Linux doesn't use ldscript, it is better
|
||||||
|
to put those definitions in independent header file. Please see
|
||||||
|
example-cdc/stack-def.h and example-cdc/sample.ld.
|
||||||
|
|
||||||
|
** More support for emulation on GNU/Linux
|
||||||
|
We have SYS driver for emulation on GNU/Linux. It has flash ROM
|
||||||
|
emulation.
|
||||||
|
|
||||||
|
|
||||||
|
* 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
|
* Major changes in Chopstx 0.12
|
||||||
|
|
||||||
Released 2016-05-31
|
Released 2016-05-31
|
||||||
|
|||||||
36
README
36
README
@@ -1,21 +1,34 @@
|
|||||||
Chopstx - Threads and only Threads
|
Chopstx - Threads and only Threads
|
||||||
Version 0.12
|
Version 1.10
|
||||||
2016-05-31
|
2018-09-29
|
||||||
Niibe Yutaka
|
Niibe Yutaka
|
||||||
Flying Stone Technology
|
Flying Stone Technology
|
||||||
|
|
||||||
What's Chopstx?
|
What's Chopstx?
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Chopstx is an RT thread library for STM32F103 (ARM Cortex-M3),
|
Chopstx is an RT thread library for STM32F103 and GD32F103 (ARM
|
||||||
STM32F030 (ARM Cortex-M0), and MKL27Z (ARM Cortex-M0plus).
|
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,
|
While most RTOSes come with many features, drivers, and protocol
|
||||||
Chopstx just offers a simple RT thread library.
|
stacks, Chopstx just offers a simple RT thread library.
|
||||||
|
|
||||||
With Chopstx, interrupt handling is also done by a thread. This
|
With Chopstx, interrupt handling is also done by a thread. This
|
||||||
enables coherent code for ease of maintenance.
|
enables coherent code for ease of maintenance.
|
||||||
|
|
||||||
|
While threads are important, we don't need more threads than
|
||||||
|
necessary. Chopstx provides a feature of poll, so that we can
|
||||||
|
minimize use of threads.
|
||||||
|
|
||||||
|
|
||||||
|
Note that this library is _not_ related to the hand game:
|
||||||
|
|
||||||
|
https://en.wikipedia.org/wiki/Chopsticks_(hand_game)
|
||||||
|
|
||||||
|
Thanks to Yao Wei and Enrico Zini for giving me an opportunity
|
||||||
|
visiting the wiki page above, when my children were playing the game.
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
@@ -29,13 +42,15 @@ Example code
|
|||||||
============
|
============
|
||||||
|
|
||||||
We have some examples in this distribution; Useful ones are LED
|
We have some examples in this distribution; Useful ones are LED
|
||||||
blinker and USB CDC-ACM function. For STM32F103, you can build it
|
blinker and USB CDC-ACM device. For STM32F103, you can build it USB
|
||||||
USB CDC-ACM demo by:
|
CDC-ACM demo by:
|
||||||
|
|
||||||
$ cd example-cdc
|
$ cd example-cdc
|
||||||
$ ln -sf ../board/board-olimex-stm32-h103.h board.h
|
$ ln -sf ../board/board-olimex-stm32-h103.h board.h
|
||||||
$ make
|
$ make
|
||||||
|
|
||||||
|
If you want to try GD32F103, Add -DMHZ=96 to DEFS in Makefile.
|
||||||
|
|
||||||
For a specific board named FSM-55, an example of LED matrix dynamic
|
For a specific board named FSM-55, an example of LED matrix dynamic
|
||||||
driver is provided. See the directory: example-fsm-55.
|
driver is provided. See the directory: example-fsm-55.
|
||||||
|
|
||||||
@@ -45,8 +60,9 @@ For STM32 Primer2, see the directory: example-primer2.
|
|||||||
Future Works
|
Future Works
|
||||||
============
|
============
|
||||||
|
|
||||||
Convenience function to determine the bottom of thread stack, thread
|
Convenience function to determine the bottom of thread stack,
|
||||||
local storage would be next things to be done.
|
configuration of thread size by compiler's output would be next things
|
||||||
|
to be done.
|
||||||
|
|
||||||
Experimental SMP port for Cortex-A7 is under development. For SMP,
|
Experimental SMP port for Cortex-A7 is under development. For SMP,
|
||||||
more careful considerations for shared access to objects of struct
|
more careful considerations for shared access to objects of struct
|
||||||
|
|||||||
42
board/board-blue-pill-g.h
Normal file
42
board/board-blue-pill-g.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#define BOARD_NAME "Blue Pill GD32F103"
|
||||||
|
/* http://wiki.stm32duino.com/index.php?title=Blue_Pill */
|
||||||
|
/* echo -n "Blue Pill GD32F103" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
|
||||||
|
#define BOARD_ID 0xed415594
|
||||||
|
|
||||||
|
#define MCU_STM32F1_GD32F1 1
|
||||||
|
#define STM32_USBPRE STM32_USBPRE_DIV2
|
||||||
|
#define STM32_ADCPRE STM32_ADCPRE_DIV8
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
#define STM32_PLLMUL_VALUE 12
|
||||||
|
#define STM32_HSECLK 8000000
|
||||||
|
|
||||||
|
#define GPIO_LED_BASE GPIOC_BASE
|
||||||
|
#define GPIO_LED_CLEAR_TO_EMIT 13
|
||||||
|
#define GPIO_USB_BASE GPIOA_BASE
|
||||||
|
#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)
|
||||||
|
*
|
||||||
|
* Port C setup.
|
||||||
|
* 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)
|
||||||
38
board/board-blue-pill.h
Normal file
38
board/board-blue-pill.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#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 MCU_STM32F1 1
|
||||||
|
#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
|
||||||
|
#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)
|
||||||
|
*
|
||||||
|
* Port C setup.
|
||||||
|
* 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)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "CQ STARM"
|
#define BOARD_NAME "CQ STARM"
|
||||||
#define BOARD_ID 0xc5480875
|
#define BOARD_ID 0xc5480875
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "FST-01-00"
|
#define BOARD_NAME "FST-01-00"
|
||||||
#define BOARD_ID 0x613870a9
|
#define BOARD_ID 0x613870a9
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define BOARD_ID 0x696886af
|
#define BOARD_ID 0x696886af
|
||||||
/* echo -n "FST-01" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
|
/* echo -n "FST-01" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
@@ -70,6 +71,7 @@
|
|||||||
* Those will be removed soon, once such an driver will be improved
|
* Those will be removed soon, once such an driver will be improved
|
||||||
* in new style.
|
* in new style.
|
||||||
*/
|
*/
|
||||||
|
#if defined(PINPAD_CIR_SUPPORT)
|
||||||
/* For pin-cir settings of Gnuk */
|
/* For pin-cir settings of Gnuk */
|
||||||
#define TIMx TIM2
|
#define TIMx TIM2
|
||||||
#define INTR_REQ_TIM TIM2_IRQ
|
#define INTR_REQ_TIM TIM2_IRQ
|
||||||
@@ -82,3 +84,4 @@
|
|||||||
#define ENABLE_RCC_APB1
|
#define ENABLE_RCC_APB1
|
||||||
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM2EN
|
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM2EN
|
||||||
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM2RST
|
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM2RST
|
||||||
|
#endif
|
||||||
|
|||||||
86
board/board-fst-01g.h
Normal file
86
board/board-fst-01g.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#define BOARD_NAME "FST-01G"
|
||||||
|
#define BOARD_ID 0x8801277f
|
||||||
|
/* echo -n "FST-01G" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
|
||||||
|
|
||||||
|
#define MCU_STM32F1 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.
|
||||||
|
*/
|
||||||
|
#if defined(PINPAD_CIR_SUPPORT)
|
||||||
|
#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
|
||||||
|
#endif
|
||||||
43
board/board-fst-01sz.h
Normal file
43
board/board-fst-01sz.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#define BOARD_NAME "FST-01SZ"
|
||||||
|
#define BOARD_ID 0x7e6fb084
|
||||||
|
/* echo -n "FST-01SZ" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
|
||||||
|
|
||||||
|
#define MCU_STM32F1_GD32F1 1
|
||||||
|
#define STM32_USBPRE STM32_USBPRE_DIV2
|
||||||
|
#define STM32_ADCPRE STM32_ADCPRE_DIV8
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
#define STM32_PLLMUL_VALUE 8
|
||||||
|
#define STM32_HSECLK 12000000
|
||||||
|
|
||||||
|
#define GPIO_LED_BASE GPIOA_BASE
|
||||||
|
#define GPIO_LED_SET_TO_EMIT 8
|
||||||
|
#define GPIO_USB_BASE GPIOA_BASE
|
||||||
|
#undef GPIO_OTHER_BASE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port A setup.
|
||||||
|
* PA0 - input with pull-up: AN0 for NeuG
|
||||||
|
* PA1 - input with pull-up: AN1 for NeuG
|
||||||
|
* PA3 - input with pull-up: Hall effect sensor output
|
||||||
|
* PA8 - Push pull output 10MHz 0 default (LED 1:ON 0:OFF)
|
||||||
|
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||||
|
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||||
|
* ------------------------ Default
|
||||||
|
* PAx - input with pull-up.
|
||||||
|
*/
|
||||||
|
#define VAL_GPIO_LED_ODR 0xFFFFE6FF
|
||||||
|
#define VAL_GPIO_LED_CRL 0x88888888 /* PA7...PA0 */
|
||||||
|
#define VAL_GPIO_LED_CRH 0x88811881 /* PA15...PA8 */
|
||||||
|
|
||||||
|
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPAEN
|
||||||
|
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPARST
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Board specific information other than clock and GPIO initial
|
||||||
|
* setting should not be in board-*.h, but each driver should include
|
||||||
|
* such specific information by itself.
|
||||||
|
*/
|
||||||
4
board/board-gnu-linux.h
Normal file
4
board/board-gnu-linux.h
Normal 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
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "Maple Mini"
|
#define BOARD_NAME "Maple Mini"
|
||||||
#define BOARD_ID 0x7a445272
|
#define BOARD_ID 0x7a445272
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "NITROKEY-START"
|
#define BOARD_NAME "NITROKEY-START"
|
||||||
#define BOARD_ID 0xad1e7ebd
|
#define BOARD_ID 0xad1e7ebd
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
* PA4 - floating input
|
* PA4 - floating input
|
||||||
* PA5 - floating input
|
* PA5 - floating input
|
||||||
* PA6 - 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)
|
* PA8 - floating input (smartcard, SCDSA)
|
||||||
* PA9 - floating input
|
* PA9 - floating input
|
||||||
* PA10 - floating input
|
* PA10 - floating input
|
||||||
@@ -37,13 +38,13 @@
|
|||||||
* PA14 - input with pull-up.
|
* PA14 - input with pull-up.
|
||||||
* PA15 - Push pull output (USB 1:ON 0:OFF)
|
* 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_CRL 0x34444488 /* PA7...PA0 */
|
||||||
#define VAL_GPIO_USB_CRH 0x38811444 /* PA15...PA8 */
|
#define VAL_GPIO_USB_CRH 0x38811444 /* PA15...PA8 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Port B setup.
|
* Port B setup.
|
||||||
* PB0 - Push pull output (LED2 1:ON 0:OFF)
|
* PB0 - Push pull output (Green LED2 1:ON 0:OFF)
|
||||||
* ------------------------ Default
|
* ------------------------ Default
|
||||||
* PBx - input with pull-up.
|
* PBx - input with pull-up.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "Olimex STM32-H103"
|
#define BOARD_NAME "Olimex STM32-H103"
|
||||||
#define BOARD_ID 0xf92bb594
|
#define BOARD_ID 0xf92bb594
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
@@ -30,11 +31,3 @@
|
|||||||
|
|
||||||
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPCEN
|
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPCEN
|
||||||
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPCRST
|
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPCRST
|
||||||
|
|
||||||
/* NeuG settings for ADC2. */
|
|
||||||
#define NEUG_ADC_SETTING2_SMPR1 ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5) \
|
|
||||||
| ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5)
|
|
||||||
#define NEUG_ADC_SETTING2_SMPR2 0
|
|
||||||
#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) \
|
|
||||||
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11)
|
|
||||||
#define NEUG_ADC_SETTING2_NUM_CHANNELS 2
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/* echo -n "ST Dongle" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
|
/* echo -n "ST Dongle" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
|
||||||
#define BOARD_ID 0x2cd4e471
|
#define BOARD_ID 0x2cd4e471
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* GND BLACK --> 20 GND
|
* GND BLACK --> 20 GND
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
@@ -25,21 +26,40 @@
|
|||||||
#define GPIO_LED_BASE GPIOA_BASE
|
#define GPIO_LED_BASE GPIOA_BASE
|
||||||
#define GPIO_LED_SET_TO_EMIT 5
|
#define GPIO_LED_SET_TO_EMIT 5
|
||||||
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
|
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
|
||||||
#undef GPIO_OTHER_BASE
|
#define GPIO_OTHER_BASE GPIOB_BASE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Port A setup.
|
* Port A setup.
|
||||||
* PA0 - input with pull-up. AN0
|
* PA0 - Input with pull-up USART2-CTS
|
||||||
* PA1 - input with pull-up. AN1
|
* PA1 - Alternate function push pull output 2MHz USART2-RTS
|
||||||
* PA5 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
* PA2 - Alternate function push pull output 2MHz USART2-TX
|
||||||
|
* PA3 - Input with pull-up USART2-RX
|
||||||
|
* PA4 - Alternate function push pull output 2MHz USART2-CK
|
||||||
|
* PA5 - Push pull output 2MHz (LED 1:ON 0:OFF)
|
||||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||||
* ------------------------ Default
|
* ------------------------ Default
|
||||||
* PAx - input with pull-up
|
* PAx - input with pull-up
|
||||||
*/
|
*/
|
||||||
#define VAL_GPIO_LED_ODR 0xFFFFE7FF
|
#define VAL_GPIO_LED_ODR 0xFFFFE7FF
|
||||||
#define VAL_GPIO_LED_CRL 0x88388888 /* PA7...PA0 */
|
#define VAL_GPIO_LED_CRL 0x882A8AA8 /* PA7...PA0 */
|
||||||
#define VAL_GPIO_LED_CRH 0x88811888 /* PA15...PA8 */
|
#define VAL_GPIO_LED_CRH 0x88811888 /* PA15...PA8 */
|
||||||
|
|
||||||
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPAEN
|
/*
|
||||||
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPARST
|
* Port B setup.
|
||||||
|
* PB0 - input with pull-up: AN8 for NeuG
|
||||||
|
* PB1 - input with pull-up: AN9 for NeuG
|
||||||
|
* PB10 - Alternate function push pull output 2MHz USART3-TX
|
||||||
|
* PB11 - Input with pull-up USART3-RX
|
||||||
|
* PB12 - Alternate function push pull output 2MHz USART3-CK
|
||||||
|
* PB13 - Input with pull-up USART3-CTS
|
||||||
|
* PB14 - Alternate function push pull output 2MHz USART3-RTS
|
||||||
|
* ------------------------ Default
|
||||||
|
* PBx - input with pull-up.
|
||||||
|
*/
|
||||||
|
#define VAL_GPIO_OTHER_ODR 0xFFFFFFFF
|
||||||
|
#define VAL_GPIO_OTHER_CRL 0x88888888 /* PB7...PB0 */
|
||||||
|
#define VAL_GPIO_OTHER_CRH 0x8A8A8A88 /* PB15...PB8 */
|
||||||
|
|
||||||
|
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN)
|
||||||
|
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "STBee Mini"
|
#define BOARD_NAME "STBee Mini"
|
||||||
#define BOARD_ID 0x1f341961
|
#define BOARD_ID 0x1f341961
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#define BOARD_NAME "STBee"
|
#define BOARD_NAME "STBee"
|
||||||
#define BOARD_ID 0x945c37e8
|
#define BOARD_ID 0x945c37e8
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
|
/* High-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
#define STM32_PLLMUL_VALUE 6
|
#define STM32_PLLMUL_VALUE 6
|
||||||
#define STM32_HSECLK 12000000
|
#define STM32_HSECLK 12000000
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#define BOARD_NAME "STM32 Primer2"
|
#define BOARD_NAME "STM32 Primer2"
|
||||||
#define BOARD_ID 0x21e5798d
|
#define BOARD_ID 0x21e5798d
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
|
/* High-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
#define STM32_PLLMUL_VALUE 6
|
#define STM32_PLLMUL_VALUE 6
|
||||||
#define STM32_HSECLK 12000000
|
#define STM32_HSECLK 12000000
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#define BOARD_NAME "STM8S Discovery"
|
#define BOARD_NAME "STM8S Discovery"
|
||||||
#define BOARD_ID 0x2f0976bb
|
#define BOARD_ID 0x2f0976bb
|
||||||
|
|
||||||
|
#define MCU_STM32F1 1
|
||||||
#define STM32F10X_MD /* Medium-density device */
|
#define STM32F10X_MD /* Medium-density device */
|
||||||
|
|
||||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
#define VAL_GPIO_OTHER_CRH 0x88888888 /* PB15...PB8 */
|
#define VAL_GPIO_OTHER_CRH 0x88888888 /* PB15...PB8 */
|
||||||
|
|
||||||
|
|
||||||
/* For pin-cir settings of Gnuk */
|
#if defined(PINPAD_CIR_SUPPORT)
|
||||||
#define TIMx TIM3
|
#define TIMx TIM3
|
||||||
#define INTR_REQ_TIM TIM3_IRQ
|
#define INTR_REQ_TIM TIM3_IRQ
|
||||||
#define AFIO_EXTICR_INDEX 1
|
#define AFIO_EXTICR_INDEX 1
|
||||||
@@ -57,3 +58,4 @@
|
|||||||
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM3RST
|
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM3RST
|
||||||
#define AFIO_MAPR_SOMETHING AFIO_MAPR_TIM3_REMAP_PARTIALREMAP
|
#define AFIO_MAPR_SOMETHING AFIO_MAPR_TIM3_REMAP_PARTIALREMAP
|
||||||
/* Remap (PB4, PB5) -> (TIM3_CH1, TIM3_CH2) */
|
/* Remap (PB4, PB5) -> (TIM3_CH1, TIM3_CH2) */
|
||||||
|
#endif
|
||||||
|
|||||||
699
chopstx-cortex-m.c
Normal file
699
chopstx-cortex-m.c
Normal file
@@ -0,0 +1,699 @@
|
|||||||
|
/*
|
||||||
|
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
|
||||||
|
* for Cortex-M0/M3
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Data Memory Barrier. */
|
||||||
|
static void
|
||||||
|
chx_dmb (void)
|
||||||
|
{
|
||||||
|
asm volatile ("dmb" : : : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 (timer expiration, lock aquirement).
|
||||||
|
* -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"
|
||||||
|
: "=r" (tp) : "0" (yield): "memory");
|
||||||
|
#else
|
||||||
|
register uint32_t arg_yield asm ("r1");
|
||||||
|
|
||||||
|
/* Build stack data as if it were an exception entry. */
|
||||||
|
/*
|
||||||
|
* r0: TP scratch
|
||||||
|
* r1: 0 scratch
|
||||||
|
* r2: 0 scratch
|
||||||
|
* r3: 0 scratch
|
||||||
|
* r12: 0 scratch
|
||||||
|
* lr as-is
|
||||||
|
* pc: return address (= .L_CONTEXT_SWITCH_FINISH)
|
||||||
|
* psr: INITIAL_XPSR scratch
|
||||||
|
*/
|
||||||
|
asm ("mov r1, lr\n\t"
|
||||||
|
"ldr r2, =.L_CONTEXT_SWITCH_FINISH\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"
|
||||||
|
"mov r1, r0\n\t"
|
||||||
|
"ldr r2, =running\n\t"
|
||||||
|
"ldr r0, [r2]\n\t"
|
||||||
|
"push {r0, r3}"
|
||||||
|
: "=r" (tp), "=r" (arg_yield)
|
||||||
|
: "0" (yield)
|
||||||
|
: "r2", "r3", "memory");
|
||||||
|
|
||||||
|
/* Save registers onto CHX_THREAD struct. */
|
||||||
|
asm ("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"
|
||||||
|
: /* no output */
|
||||||
|
: "r" (tp)
|
||||||
|
: "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, =chx_idle\n\t" /* PC = idle */
|
||||||
|
/**/
|
||||||
|
/* Unmask interrupts. */
|
||||||
|
"cpsie i\n\t"
|
||||||
|
"bx r0\n"
|
||||||
|
|
||||||
|
/* Normal context switch */
|
||||||
|
"0:\n\t"
|
||||||
|
"add r0, #20\n\t"
|
||||||
|
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||||
|
"ldm r0!, {r1, r2, r3}\n\t"
|
||||||
|
"mov r8, r1\n\t"
|
||||||
|
"mov r9, r2\n\t"
|
||||||
|
"mov r10, r3\n\t"
|
||||||
|
"ldm r0!, {r1, r2}\n\t"
|
||||||
|
"mov r11, r1\n\t"
|
||||||
|
"mov sp, r2\n\t"
|
||||||
|
"sub r0, #45\n\t"
|
||||||
|
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
||||||
|
"cmp r1, #247\n\t"
|
||||||
|
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
|
||||||
|
/**/
|
||||||
|
/* Unmask interrupts. */
|
||||||
|
"cpsie i\n"
|
||||||
|
/**/
|
||||||
|
"1:\n\t"
|
||||||
|
/*
|
||||||
|
0: r0
|
||||||
|
4: r1
|
||||||
|
8: r2
|
||||||
|
12: r3
|
||||||
|
16: r12
|
||||||
|
20: lr
|
||||||
|
24: pc
|
||||||
|
28: psr
|
||||||
|
32: possibly exists for alignment
|
||||||
|
[28 or 32] <-- pc
|
||||||
|
*/
|
||||||
|
"ldr r0, [sp, #28]\n\t"
|
||||||
|
"lsl r1, r0, #23\n\t"
|
||||||
|
"bcc 2f\n\t"
|
||||||
|
/**/
|
||||||
|
"ldr r2, [sp, #24]\n\t"
|
||||||
|
"mov r1, #1\n\t"
|
||||||
|
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||||
|
"str r2, [sp, #32]\n\t"
|
||||||
|
"msr APSR_nzcvq, r0\n\t"
|
||||||
|
/**/
|
||||||
|
"ldr r0, [sp, #20]\n\t"
|
||||||
|
"mov lr, r0\n\t"
|
||||||
|
"ldr r0, [sp, #16]\n\t"
|
||||||
|
"mov r12, r0\n\t"
|
||||||
|
"pop {r0, r1, r2, r3}\n\t"
|
||||||
|
"add sp, #16\n\t"
|
||||||
|
"pop {pc}\n"
|
||||||
|
"2:\n\t"
|
||||||
|
"ldr r2, [sp, #24]\n\t"
|
||||||
|
"mov r1, #1\n\t"
|
||||||
|
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||||
|
"str r2, [sp, #28]\n\t"
|
||||||
|
"msr APSR_nzcvq, r0\n\t"
|
||||||
|
/**/
|
||||||
|
"ldr r0, [sp, #20]\n\t"
|
||||||
|
"mov lr, r0\n\t"
|
||||||
|
"ldr r0, [sp, #16]\n\t"
|
||||||
|
"mov r12, r0\n\t"
|
||||||
|
"pop {r0, r1, r2, r3}\n\t"
|
||||||
|
"add sp, #12\n\t"
|
||||||
|
"pop {pc}\n\t"
|
||||||
|
".L_CONTEXT_SWITCH_FINISH:"
|
||||||
|
: "=r" (tp) /* Return value in R0 */
|
||||||
|
: "0" (tp)
|
||||||
|
: "memory");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
asm volatile ("bx lr"
|
||||||
|
: "=r" (tp)
|
||||||
|
: "0" (tp->v)
|
||||||
|
: "memory");
|
||||||
|
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, =chx_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]\n\t"
|
||||||
|
"str r0, [r6]"
|
||||||
|
: "=r" (tp), "=r" (orig_r0)
|
||||||
|
: /* no input */
|
||||||
|
: "r2", "r3", "r4", "r5", "r6", "memory");
|
||||||
|
|
||||||
|
if (orig_r0) /* yield */
|
||||||
|
{
|
||||||
|
if (tp->flag_sched_rr)
|
||||||
|
chx_timer_dequeue (tp);
|
||||||
|
chx_ready_enqueue (tp);
|
||||||
|
running = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp = chx_ready_pop ();
|
||||||
|
if (tp && tp->flag_sched_rr)
|
||||||
|
{
|
||||||
|
chx_spin_lock (&q_timer.lock);
|
||||||
|
chx_timer_insert (tp, PREEMPTION_USEC);
|
||||||
|
chx_spin_unlock (&q_timer.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
asm volatile (
|
||||||
|
"b .L_CONTEXT_SWITCH"
|
||||||
|
: /* no output */ : "r" (tp) : "memory");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
12
chopstx-cortex-m.h
Normal file
12
chopstx-cortex-m.h
Normal 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;
|
||||||
351
chopstx-gnu-linux.c
Normal file
351
chopstx-gnu-linux.c
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
||||||
|
* for GNU/Linux emulation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017, 2018 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>
|
||||||
|
|
||||||
|
/* Data Memory Barrier. */
|
||||||
|
static void
|
||||||
|
chx_dmb (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
10
chopstx-gnu-linux.h
Normal 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;
|
||||||
23
chopstx.h
23
chopstx.h
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* chopstx.h - Threads and only threads.
|
* chopstx.h - Threads and only threads.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013, 2016 Flying Stone Technology
|
* Copyright (C) 2013, 2016, 2017 Flying Stone Technology
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Chopstx, a thread library for embedded.
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
@@ -30,7 +30,7 @@ struct chx_qh {
|
|||||||
struct chx_pq *next, *prev;
|
struct chx_pq *next, *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uint32_t chopstx_t;
|
typedef uintptr_t chopstx_t;
|
||||||
typedef uint8_t chopstx_prio_t;
|
typedef uint8_t chopstx_prio_t;
|
||||||
|
|
||||||
extern chopstx_t chopstx_main;
|
extern chopstx_t chopstx_main;
|
||||||
@@ -39,7 +39,7 @@ extern chopstx_t chopstx_main;
|
|||||||
/* NOTE: This signature is different to PTHREAD's one. */
|
/* NOTE: This signature is different to PTHREAD's one. */
|
||||||
chopstx_t
|
chopstx_t
|
||||||
chopstx_create (uint32_t flags_and_prio,
|
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 *);
|
void *(thread_entry) (void *), void *);
|
||||||
#define CHOPSTX_PRIO_BITS 8
|
#define CHOPSTX_PRIO_BITS 8
|
||||||
#define CHOPSTX_DETACHED 0x10000
|
#define CHOPSTX_DETACHED 0x10000
|
||||||
@@ -83,7 +83,7 @@ void chopstx_cond_broadcast (chopstx_cond_t *cond);
|
|||||||
* Library provides default implementation as weak reference.
|
* Library provides default implementation as weak reference.
|
||||||
* User can replace it.
|
* User can replace it.
|
||||||
*/
|
*/
|
||||||
void chx_fatal (uint32_t err_code) __attribute__((__weak__, __noreturn__));
|
void chx_fatal (uint32_t err_code) __attribute__((__noreturn__));
|
||||||
|
|
||||||
int chopstx_join (chopstx_t, void **);
|
int chopstx_join (chopstx_t, void **);
|
||||||
void chopstx_exit (void *retval) __attribute__((__noreturn__));
|
void chopstx_exit (void *retval) __attribute__((__noreturn__));
|
||||||
@@ -113,7 +113,7 @@ typedef struct chx_cleanup {
|
|||||||
void chopstx_cleanup_push (chopstx_cleanup_t *clp);
|
void chopstx_cleanup_push (chopstx_cleanup_t *clp);
|
||||||
void chopstx_cleanup_pop (int execute);
|
void chopstx_cleanup_pop (int execute);
|
||||||
|
|
||||||
void chopstx_setpriority (chopstx_prio_t);
|
chopstx_prio_t chopstx_setpriority (chopstx_prio_t);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CHOPSTX_POLL_COND = 0,
|
CHOPSTX_POLL_COND = 0,
|
||||||
@@ -121,6 +121,11 @@ enum {
|
|||||||
CHOPSTX_POLL_JOIN,
|
CHOPSTX_POLL_JOIN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct chx_poll_head {
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t ready;
|
||||||
|
};
|
||||||
|
|
||||||
struct chx_poll_cond {
|
struct chx_poll_cond {
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
uint16_t ready;
|
uint16_t ready;
|
||||||
@@ -150,9 +155,13 @@ typedef struct chx_intr chopstx_intr_t;
|
|||||||
|
|
||||||
void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num);
|
void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num);
|
||||||
|
|
||||||
void chopstx_intr_wait (chopstx_intr_t *intr); /* DEPRECATED */
|
void chopstx_intr_wait (chopstx_intr_t *intr);
|
||||||
|
void chopstx_intr_done (chopstx_intr_t *intr);
|
||||||
|
|
||||||
|
|
||||||
int chopstx_poll (uint32_t *usec_p, int n, ...);
|
int chopstx_poll (uint32_t *usec_p, int n,
|
||||||
|
struct chx_poll_head *const pd_array[]);
|
||||||
|
|
||||||
|
int chopstx_conf_idle (int enable_sleep);
|
||||||
|
|
||||||
#define CHOPSTX_THREAD_SIZE 64
|
#define CHOPSTX_THREAD_SIZE 64
|
||||||
|
|||||||
88
contrib/ackbtn-stm32f103.c
Normal file
88
contrib/ackbtn-stm32f103.c
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* ackbtn-stm32f103.c - Acknowledge button support for STM32F103
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 g10 Code GmbH
|
||||||
|
* 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 <string.h>
|
||||||
|
#include <chopstx.h>
|
||||||
|
#include <mcu/stm32f103.h>
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "sys.h"
|
||||||
|
|
||||||
|
static uint32_t pin_config;
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_init (chopstx_intr_t *intr)
|
||||||
|
{
|
||||||
|
uint8_t irq_num;
|
||||||
|
uint32_t afio_exticr_index;
|
||||||
|
uint32_t afio_exticr_extiX_pY;
|
||||||
|
int rising_edge;
|
||||||
|
|
||||||
|
switch (SYS_BOARD_ID)
|
||||||
|
{
|
||||||
|
case BOARD_ID_FST_01SZ:
|
||||||
|
default:
|
||||||
|
/* PA3 is connected to a hall sensor DRV5032FA */
|
||||||
|
afio_exticr_index = 0;
|
||||||
|
afio_exticr_extiX_pY = AFIO_EXTICR1_EXTI3_PA;
|
||||||
|
irq_num = EXTI3_IRQ;
|
||||||
|
pin_config = 0x0008; /* EXTI_PR_PR3 == EXTI_IMR_MR3 == EXTI_RTSR_TR3 */
|
||||||
|
rising_edge = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chopstx_claim_irq (intr, irq_num);
|
||||||
|
|
||||||
|
/* Configure EXTI line */
|
||||||
|
if (afio_exticr_extiX_pY)
|
||||||
|
AFIO->EXTICR[afio_exticr_index] |= afio_exticr_extiX_pY;
|
||||||
|
|
||||||
|
/* Interrupt is masked, now */
|
||||||
|
EXTI->IMR &= ~pin_config;
|
||||||
|
|
||||||
|
/* Configure which edge is detected */
|
||||||
|
if (rising_edge)
|
||||||
|
EXTI->RTSR |= pin_config;
|
||||||
|
else
|
||||||
|
EXTI->FTSR |= pin_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_enable (void)
|
||||||
|
{
|
||||||
|
EXTI->PR |= pin_config; /* Clear pending interrupt */
|
||||||
|
EXTI->IMR |= pin_config; /* Enable interrupt clearing the mask */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_disable (void)
|
||||||
|
{
|
||||||
|
EXTI->IMR &= ~pin_config; /* Disable interrupt having the mask */
|
||||||
|
EXTI->PR |= pin_config; /* Clear pending interrupt */
|
||||||
|
}
|
||||||
3
contrib/ackbtn.h
Normal file
3
contrib/ackbtn.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
void ackbtn_init (chopstx_intr_t *intr);
|
||||||
|
void ackbtn_enable (void);
|
||||||
|
void ackbtn_disable (void);
|
||||||
77
contrib/adc-gnu-linux.c
Normal file
77
contrib/adc-gnu-linux.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ struct DMAMUX {
|
|||||||
volatile uint32_t CHCFG2;
|
volatile uint32_t CHCFG2;
|
||||||
volatile uint32_t CHCFG3;
|
volatile uint32_t CHCFG3;
|
||||||
};
|
};
|
||||||
static struct DMAMUX *const DMAMUX = (struct DMAMUX *const)0x40021000;
|
static struct DMAMUX *const DMAMUX = (struct DMAMUX *)0x40021000;
|
||||||
|
|
||||||
#define INTR_REQ_DMA0 0
|
#define INTR_REQ_DMA0 0
|
||||||
|
|
||||||
@@ -50,8 +50,8 @@ struct DMA {
|
|||||||
volatile uint32_t DSR_BCR;
|
volatile uint32_t DSR_BCR;
|
||||||
volatile uint32_t DCR;
|
volatile uint32_t DCR;
|
||||||
};
|
};
|
||||||
static struct DMA *const DMA0 = (struct DMA *const)0x40008100;
|
static struct DMA *const DMA0 = (struct DMA *)0x40008100;
|
||||||
static struct DMA *const DMA1 = (struct DMA *const)0x40008110;
|
static struct DMA *const DMA1 = (struct DMA *)0x40008110;
|
||||||
|
|
||||||
|
|
||||||
/* We don't use ADC interrupt. Just for reference. */
|
/* We don't use ADC interrupt. Just for reference. */
|
||||||
@@ -92,7 +92,7 @@ struct ADC {
|
|||||||
volatile uint32_t CLM1;
|
volatile uint32_t CLM1;
|
||||||
volatile uint32_t CLM0;
|
volatile uint32_t CLM0;
|
||||||
};
|
};
|
||||||
static struct ADC *const ADC0 = (struct ADC *const)0x4003B000;
|
static struct ADC *const ADC0 = (struct ADC *)0x4003B000;
|
||||||
|
|
||||||
/* SC1 */
|
/* SC1 */
|
||||||
#define ADC_SC1_DIFF (1 << 5)
|
#define ADC_SC1_DIFF (1 << 5)
|
||||||
@@ -295,18 +295,20 @@ adc_stop (void)
|
|||||||
int
|
int
|
||||||
adc_wait_completion (void)
|
adc_wait_completion (void)
|
||||||
{
|
{
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
/* Wait DMA completion */
|
/* Wait DMA completion */
|
||||||
chopstx_poll (NULL, 1, &adc_intr);
|
chopstx_intr_wait (&adc_intr);
|
||||||
|
|
||||||
DMA0->DSR_BCR = (1 << 24);
|
DMA0->DSR_BCR = (1 << 24);
|
||||||
DMA1->DSR_BCR = (1 << 24);
|
DMA1->DSR_BCR = (1 << 24);
|
||||||
|
|
||||||
adc_stop_conversion ();
|
adc_stop_conversion ();
|
||||||
|
|
||||||
|
chopstx_intr_done (&adc_intr);
|
||||||
|
|
||||||
for (i = 0; i < adc.count; i++)
|
for (i = 0; i < adc.count; i++)
|
||||||
*adc.p++ = (uint8_t)adc.buf[i];
|
*adc.p++ = (uint8_t)adc.buf[i];
|
||||||
|
|
||||||
@@ -3,26 +3,30 @@
|
|||||||
* In this ADC driver, there are NeuG specific parts.
|
* In this ADC driver, there are NeuG specific parts.
|
||||||
* You need to modify to use this as generic ADC driver.
|
* You need to modify to use this as generic ADC driver.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011, 2012, 2013, 2015, 2016
|
* Copyright (C) 2011, 2012, 2013, 2015, 2016, 2017, 2018
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of NeuG, a True Random Number Generator
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
* implementation based on quantization error of ADC (for STM32F103).
|
|
||||||
*
|
*
|
||||||
* NeuG is free software: you can redistribute it and/or modify it
|
* Chopstx is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by
|
* under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* NeuG is distributed in the hope that it will be useful, but WITHOUT
|
* Chopstx is distributed in the hope that it will be useful, but
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* License for more details.
|
* General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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 <stdint.h>
|
||||||
@@ -30,6 +34,8 @@
|
|||||||
#include <chopstx.h>
|
#include <chopstx.h>
|
||||||
#include <mcu/stm32f103.h>
|
#include <mcu/stm32f103.h>
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
|
#include "board.h"
|
||||||
|
#include "sys.h"
|
||||||
|
|
||||||
#define STM32_ADC_ADC1_DMA_PRIORITY 2
|
#define STM32_ADC_ADC1_DMA_PRIORITY 2
|
||||||
|
|
||||||
@@ -42,6 +48,7 @@
|
|||||||
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0)
|
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0)
|
||||||
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3)
|
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3)
|
||||||
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6)
|
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6)
|
||||||
|
#define ADC_SMPR2_SMP_AN8(n) ((n) << 24)
|
||||||
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27)
|
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27)
|
||||||
|
|
||||||
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
|
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
|
||||||
@@ -56,6 +63,7 @@
|
|||||||
#define ADC_CHANNEL_IN0 0
|
#define ADC_CHANNEL_IN0 0
|
||||||
#define ADC_CHANNEL_IN1 1
|
#define ADC_CHANNEL_IN1 1
|
||||||
#define ADC_CHANNEL_IN2 2
|
#define ADC_CHANNEL_IN2 2
|
||||||
|
#define ADC_CHANNEL_IN8 8
|
||||||
#define ADC_CHANNEL_IN9 9
|
#define ADC_CHANNEL_IN9 9
|
||||||
#define ADC_CHANNEL_IN10 10
|
#define ADC_CHANNEL_IN10 10
|
||||||
#define ADC_CHANNEL_IN11 11
|
#define ADC_CHANNEL_IN11 11
|
||||||
@@ -63,7 +71,9 @@
|
|||||||
#define ADC_CHANNEL_VREFINT 17
|
#define ADC_CHANNEL_VREFINT 17
|
||||||
|
|
||||||
#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
|
#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
|
||||||
|
#ifndef MCU_STM32F1_GD32F1
|
||||||
#define DELIBARATELY_DO_IT_WRONG_START_STOP
|
#define DELIBARATELY_DO_IT_WRONG_START_STOP
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
|
#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
|
||||||
#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
|
#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
|
||||||
@@ -108,6 +118,8 @@ adc_init (void)
|
|||||||
|
|
||||||
ADC1->CR1 = 0;
|
ADC1->CR1 = 0;
|
||||||
ADC1->CR2 = ADC_CR2_ADON;
|
ADC1->CR2 = ADC_CR2_ADON;
|
||||||
|
chopstx_usec_wait (1000);
|
||||||
|
|
||||||
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
|
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
|
||||||
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
|
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
|
||||||
;
|
;
|
||||||
@@ -118,6 +130,8 @@ adc_init (void)
|
|||||||
|
|
||||||
ADC2->CR1 = 0;
|
ADC2->CR1 = 0;
|
||||||
ADC2->CR2 = ADC_CR2_ADON;
|
ADC2->CR2 = ADC_CR2_ADON;
|
||||||
|
chopstx_usec_wait (1000);
|
||||||
|
|
||||||
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
|
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
|
||||||
while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
|
while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
|
||||||
;
|
;
|
||||||
@@ -131,15 +145,13 @@ adc_init (void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "board.h"
|
|
||||||
#include "sys.h"
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_adc_config (uint32_t config[4])
|
get_adc_config (uint32_t config[4])
|
||||||
{
|
{
|
||||||
config[2] = ADC_SQR1_NUM_CH(2);
|
config[2] = ADC_SQR1_NUM_CH(2);
|
||||||
switch (SYS_BOARD_ID)
|
switch (SYS_BOARD_ID)
|
||||||
{
|
{
|
||||||
|
case BOARD_ID_FST_01G:
|
||||||
case BOARD_ID_FST_01:
|
case BOARD_ID_FST_01:
|
||||||
config[0] = 0;
|
config[0] = 0;
|
||||||
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
|
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
|
||||||
@@ -165,14 +177,22 @@ get_adc_config (uint32_t config[4])
|
|||||||
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2);
|
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BOARD_ID_ST_NUCLEO_F103:
|
||||||
|
config[0] = 0;
|
||||||
|
config[1] = ADC_SMPR2_SMP_AN8(ADC_SAMPLE_1P5)
|
||||||
|
| ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5);
|
||||||
|
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN8)
|
||||||
|
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9);
|
||||||
|
break;
|
||||||
|
|
||||||
case BOARD_ID_CQ_STARM:
|
case BOARD_ID_CQ_STARM:
|
||||||
case BOARD_ID_FST_01_00:
|
case BOARD_ID_FST_01_00:
|
||||||
case BOARD_ID_MAPLE_MINI:
|
case BOARD_ID_MAPLE_MINI:
|
||||||
case BOARD_ID_STM32_PRIMER2:
|
case BOARD_ID_STM32_PRIMER2:
|
||||||
case BOARD_ID_STM8S_DISCOVERY:
|
case BOARD_ID_STM8S_DISCOVERY:
|
||||||
case BOARD_ID_ST_DONGLE:
|
case BOARD_ID_ST_DONGLE:
|
||||||
case BOARD_ID_ST_NUCLEO_F103:
|
|
||||||
case BOARD_ID_NITROKEY_START:
|
case BOARD_ID_NITROKEY_START:
|
||||||
|
case BOARD_ID_FST_01SZ:
|
||||||
default:
|
default:
|
||||||
config[0] = 0;
|
config[0] = 0;
|
||||||
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
|
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
|
||||||
@@ -198,24 +218,26 @@ adc_start (void)
|
|||||||
|
|
||||||
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
|
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->SMPR1 = NEUG_ADC_SETTING1_SMPR1;
|
||||||
ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
|
ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
|
||||||
ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
|
ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
|
||||||
ADC1->SQR2 = 0;
|
ADC1->SQR2 = 0;
|
||||||
ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
|
ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
|
||||||
|
ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
|
||||||
ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
|
|
||||||
| ADC_CR1_SCAN);
|
| ADC_CR1_SCAN);
|
||||||
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);
|
||||||
|
chopstx_usec_wait (1000);
|
||||||
|
|
||||||
ADC2->SMPR1 = config[0];
|
ADC2->SMPR1 = config[0];
|
||||||
ADC2->SMPR2 = config[1];
|
ADC2->SMPR2 = config[1];
|
||||||
ADC2->SQR1 = config[2];
|
ADC2->SQR1 = config[2];
|
||||||
ADC2->SQR2 = 0;
|
ADC2->SQR2 = 0;
|
||||||
ADC2->SQR3 = config[3];
|
ADC2->SQR3 = config[3];
|
||||||
|
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;
|
||||||
|
chopstx_usec_wait (1000);
|
||||||
|
|
||||||
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
|
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
|
||||||
/*
|
/*
|
||||||
@@ -297,7 +319,7 @@ adc_wait_completion (void)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
chopstx_poll (NULL, 1, &adc_intr);
|
chopstx_intr_wait (&adc_intr);
|
||||||
flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause. */
|
flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause. */
|
||||||
/*
|
/*
|
||||||
* Clear interrupt cause of channel 1.
|
* Clear interrupt cause of channel 1.
|
||||||
@@ -306,6 +328,7 @@ adc_wait_completion (void)
|
|||||||
* and TEIF.
|
* and TEIF.
|
||||||
*/
|
*/
|
||||||
DMA1->IFCR = (flags & ~1);
|
DMA1->IFCR = (flags & ~1);
|
||||||
|
chopstx_intr_done (&adc_intr);
|
||||||
|
|
||||||
if ((flags & STM32_DMA_ISR_TEIF) != 0) /* DMA errors */
|
if ((flags & STM32_DMA_ISR_TEIF) != 0) /* DMA errors */
|
||||||
{
|
{
|
||||||
630
contrib/usart-stm32f103.c
Normal file
630
contrib/usart-stm32f103.c
Normal file
@@ -0,0 +1,630 @@
|
|||||||
|
/*
|
||||||
|
* usart-stm32.c - USART driver for STM32F103 (USART2 and USART3)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 g10 Code GmbH
|
||||||
|
* 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/stm32.h>
|
||||||
|
#include <contrib/usart.h>
|
||||||
|
|
||||||
|
struct USART {
|
||||||
|
volatile uint32_t SR;
|
||||||
|
volatile uint32_t DR;
|
||||||
|
volatile uint32_t BRR;
|
||||||
|
volatile uint32_t CR1;
|
||||||
|
volatile uint32_t CR2;
|
||||||
|
volatile uint32_t CR3;
|
||||||
|
volatile uint32_t GTPR;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define USART2_BASE (APB1PERIPH_BASE + 0x4400)
|
||||||
|
#define USART3_BASE (APB1PERIPH_BASE + 0x4800)
|
||||||
|
static struct USART *const USART2 = (struct USART *)USART2_BASE;
|
||||||
|
static struct USART *const USART3 = (struct USART *)USART3_BASE;
|
||||||
|
|
||||||
|
#define USART_SR_CTS (1 << 9)
|
||||||
|
#define USART_SR_LBD (1 << 8)
|
||||||
|
#define USART_SR_TXE (1 << 7)
|
||||||
|
#define USART_SR_TC (1 << 6)
|
||||||
|
#define USART_SR_RXNE (1 << 5)
|
||||||
|
#define USART_SR_IDLE (1 << 4)
|
||||||
|
#define USART_SR_ORE (1 << 3)
|
||||||
|
#define USART_SR_NE (1 << 2)
|
||||||
|
#define USART_SR_FE (1 << 1)
|
||||||
|
#define USART_SR_PE (1 << 0)
|
||||||
|
|
||||||
|
|
||||||
|
#define USART_CR1_UE (1 << 13)
|
||||||
|
#define USART_CR1_M (1 << 12)
|
||||||
|
#define USART_CR1_WAKE (1 << 11)
|
||||||
|
#define USART_CR1_PCE (1 << 10)
|
||||||
|
#define USART_CR1_PS (1 << 9)
|
||||||
|
#define USART_CR1_PEIE (1 << 8)
|
||||||
|
#define USART_CR1_TXEIE (1 << 7)
|
||||||
|
#define USART_CR1_TCIE (1 << 6)
|
||||||
|
#define USART_CR1_RXNEIE (1 << 5)
|
||||||
|
#define USART_CR1_IDLEIE (1 << 4)
|
||||||
|
#define USART_CR1_TE (1 << 3)
|
||||||
|
#define USART_CR1_RE (1 << 2)
|
||||||
|
#define USART_CR1_RWU (1 << 1)
|
||||||
|
#define USART_CR1_SBK (1 << 0)
|
||||||
|
|
||||||
|
|
||||||
|
static struct USART *
|
||||||
|
get_usart_dev (uint8_t dev_no)
|
||||||
|
{
|
||||||
|
if (dev_no == 2)
|
||||||
|
return USART2;
|
||||||
|
else if (dev_no == 3)
|
||||||
|
return USART3;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We assume 36MHz f_PCLK */
|
||||||
|
struct brr_setting {
|
||||||
|
uint8_t baud_spec;
|
||||||
|
uint16_t brr_value;
|
||||||
|
};
|
||||||
|
#define NUM_BAUD (int)(sizeof (brr_table) / sizeof (struct brr_setting))
|
||||||
|
|
||||||
|
static const struct brr_setting brr_table[] = {
|
||||||
|
{ B600, (3750 << 4)},
|
||||||
|
{ B1200, (1875 << 4)},
|
||||||
|
{ B2400, ( 937 << 4)|8},
|
||||||
|
{ B9600, ( 234 << 4)|6},
|
||||||
|
{ B19200, ( 117 << 4)|3},
|
||||||
|
{ B57600, ( 39 << 4)|1},
|
||||||
|
{ B115200, ( 19 << 4)|8},
|
||||||
|
{ B230400, ( 9 << 4)|12},
|
||||||
|
{ B460800, ( 4 << 4)|14},
|
||||||
|
{ B921600, ( 2 << 4)|7},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *usart_main (void *arg);
|
||||||
|
|
||||||
|
static struct usart_stat usart2_stat;
|
||||||
|
static struct usart_stat usart3_stat;
|
||||||
|
|
||||||
|
int
|
||||||
|
usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||||
|
{
|
||||||
|
struct USART *USARTx = get_usart_dev (dev_no);
|
||||||
|
uint8_t baud_spec = (config_bits & MASK_BAUD);
|
||||||
|
int i;
|
||||||
|
uint32_t cr1_config = (USART_CR1_UE | USART_CR1_RXNEIE
|
||||||
|
| USART_CR1_TE | USART_CR1_RE);
|
||||||
|
/* TXEIE will be enabled when putting char */
|
||||||
|
/* No CTSIE, PEIE, TCIE, IDLEIE, LBDIE */
|
||||||
|
if (USARTx == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Disable USART before configure. */
|
||||||
|
USARTx->CR1 &= ~USART_CR1_UE;
|
||||||
|
|
||||||
|
if (((config_bits & MASK_CS) == CS7 && (config_bits & PARENB))
|
||||||
|
|| ((config_bits & MASK_CS) == CS8 && (config_bits & PARENB) == 0))
|
||||||
|
cr1_config &= ~USART_CR1_M;
|
||||||
|
else if ((config_bits & MASK_CS) == CS8)
|
||||||
|
cr1_config |= USART_CR1_M;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((config_bits & PARENB) == 0)
|
||||||
|
cr1_config &= ~USART_CR1_PCE;
|
||||||
|
else
|
||||||
|
cr1_config |= USART_CR1_PCE;
|
||||||
|
|
||||||
|
if ((config_bits & PARODD) == 0)
|
||||||
|
cr1_config &= ~USART_CR1_PS;
|
||||||
|
else
|
||||||
|
cr1_config |= USART_CR1_PS;
|
||||||
|
|
||||||
|
if ((config_bits & MASK_STOP) == STOP0B5)
|
||||||
|
USARTx->CR2 = (0x1 << 12);
|
||||||
|
else if ((config_bits & MASK_STOP) == STOP1B)
|
||||||
|
USARTx->CR2 = (0x0 << 12);
|
||||||
|
else if ((config_bits & MASK_STOP) == STOP1B5)
|
||||||
|
USARTx->CR2 = (0x3 << 12);
|
||||||
|
else /* if ((config_bits & MASK_STOP) == STOP2B) */
|
||||||
|
USARTx->CR2 = (0x2 << 12);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_BAUD; i++)
|
||||||
|
if (brr_table[i].baud_spec == baud_spec)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i >= NUM_BAUD)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
USARTx->BRR = brr_table[i].brr_value;
|
||||||
|
|
||||||
|
if ((config_bits & MASK_FLOW))
|
||||||
|
USARTx->CR3 = (1 << 9) | (1 << 8);
|
||||||
|
else
|
||||||
|
USARTx->CR3 = 0;
|
||||||
|
|
||||||
|
USARTx->CR1 = cr1_config;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int (*ss_notify_callback) (uint8_t dev_no, uint16_t notify_bits);
|
||||||
|
|
||||||
|
void
|
||||||
|
usart_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
|
||||||
|
int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||||
|
{
|
||||||
|
ss_notify_callback = cb;
|
||||||
|
usart2_stat.dev_no = 2;
|
||||||
|
usart3_stat.dev_no = 3;
|
||||||
|
|
||||||
|
/* Enable USART2 and USART3 clocks, and strobe reset. */
|
||||||
|
RCC->APB1ENR |= ((1 << 18) | (1 << 17));
|
||||||
|
RCC->APB1RSTR = ((1 << 18) | (1 << 17));
|
||||||
|
RCC->APB1RSTR = 0;
|
||||||
|
|
||||||
|
usart_config (2, B115200 | CS8 | STOP1B);
|
||||||
|
usart_config (3, B115200 | CS8 | STOP1B);
|
||||||
|
chopstx_create (prio, stack_addr, stack_size, usart_main, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ring buffer
|
||||||
|
*/
|
||||||
|
#define MAX_RB_BUF 1024
|
||||||
|
|
||||||
|
struct rb {
|
||||||
|
uint8_t *buf;
|
||||||
|
chopstx_mutex_t m;
|
||||||
|
chopstx_cond_t data_available;
|
||||||
|
chopstx_cond_t space_available;
|
||||||
|
uint32_t head :10;
|
||||||
|
uint32_t tail :10;
|
||||||
|
uint32_t size :10;
|
||||||
|
uint32_t full : 1;
|
||||||
|
uint32_t empty : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: size = 1024 can still work, regardless of the limit of 10-bit.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rb_init (struct rb *rb, uint8_t *p, uint16_t size)
|
||||||
|
{
|
||||||
|
rb->buf = p;
|
||||||
|
rb->size = size;
|
||||||
|
chopstx_mutex_init (&rb->m);
|
||||||
|
chopstx_cond_init (&rb->data_available);
|
||||||
|
chopstx_cond_init (&rb->space_available);
|
||||||
|
rb->head = rb->tail = 0;
|
||||||
|
rb->full = 0;
|
||||||
|
rb->empty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_add (struct rb *rb, uint8_t v)
|
||||||
|
{
|
||||||
|
rb->buf[rb->tail++] = v;
|
||||||
|
if (rb->tail == rb->size)
|
||||||
|
rb->tail = 0;
|
||||||
|
if (rb->tail == rb->head)
|
||||||
|
rb->full = 1;
|
||||||
|
rb->empty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
rb_del (struct rb *rb)
|
||||||
|
{
|
||||||
|
uint32_t v = rb->buf[rb->head++];
|
||||||
|
|
||||||
|
if (rb->head == rb->size)
|
||||||
|
rb->head = 0;
|
||||||
|
if (rb->head == rb->tail)
|
||||||
|
rb->empty = 1;
|
||||||
|
rb->full = 0;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Application: consumer
|
||||||
|
* Hardware: generator
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
rb_ll_put (struct rb *rb, uint8_t v)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
chopstx_mutex_lock (&rb->m);
|
||||||
|
if (rb->full)
|
||||||
|
r = -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r = 0;
|
||||||
|
rb_add (rb, v);
|
||||||
|
chopstx_cond_signal (&rb->data_available);
|
||||||
|
}
|
||||||
|
chopstx_mutex_unlock (&rb->m);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Application: generator
|
||||||
|
* Hardware: consumer
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
rb_ll_get (struct rb *rb)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
chopstx_mutex_lock (&rb->m);
|
||||||
|
if (rb->empty)
|
||||||
|
r = -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r = rb_del (rb);
|
||||||
|
chopstx_cond_signal (&rb->space_available);
|
||||||
|
}
|
||||||
|
chopstx_mutex_unlock (&rb->m);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_ll_flush (struct rb *rb)
|
||||||
|
{
|
||||||
|
chopstx_mutex_lock (&rb->m);
|
||||||
|
while (!rb->empty)
|
||||||
|
rb_del (rb);
|
||||||
|
chopstx_cond_signal (&rb->space_available);
|
||||||
|
chopstx_mutex_unlock (&rb->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Application: consumer
|
||||||
|
* Hardware: generator
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
rb_read (struct rb *rb, uint8_t *buf, uint16_t buflen)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
chopstx_mutex_lock (&rb->m);
|
||||||
|
while (rb->empty)
|
||||||
|
chopstx_cond_wait (&rb->data_available, &rb->m);
|
||||||
|
|
||||||
|
while (i < buflen)
|
||||||
|
{
|
||||||
|
buf[i++] = rb_del (rb);
|
||||||
|
if (rb->empty)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chopstx_cond_signal (&rb->space_available);
|
||||||
|
chopstx_mutex_unlock (&rb->m);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Application: generator
|
||||||
|
* Hardware: consumer
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rb_write (struct rb *rb, uint8_t *buf, uint16_t buflen)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
chopstx_mutex_lock (&rb->m);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
while (rb->full)
|
||||||
|
chopstx_cond_wait (&rb->space_available, &rb->m);
|
||||||
|
|
||||||
|
while (i < buflen)
|
||||||
|
{
|
||||||
|
rb_add (rb, buf[i++]);
|
||||||
|
if (rb->full)
|
||||||
|
{
|
||||||
|
chopstx_cond_signal (&rb->data_available);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i < buflen);
|
||||||
|
|
||||||
|
if (i)
|
||||||
|
chopstx_cond_signal (&rb->data_available);
|
||||||
|
chopstx_mutex_unlock (&rb->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rb_empty_check (void *arg)
|
||||||
|
{
|
||||||
|
struct rb *rb = arg;
|
||||||
|
return rb->empty == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_get_prepare_poll (struct rb *rb, chopstx_poll_cond_t *poll_desc)
|
||||||
|
{
|
||||||
|
poll_desc->type = CHOPSTX_POLL_COND;
|
||||||
|
poll_desc->ready = 0;
|
||||||
|
poll_desc->cond = &rb->data_available;
|
||||||
|
poll_desc->mutex = &rb->m;
|
||||||
|
poll_desc->check = rb_empty_check;
|
||||||
|
poll_desc->arg = rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INTR_REQ_USART2 38
|
||||||
|
#define INTR_REQ_USART3 39
|
||||||
|
|
||||||
|
static uint8_t buf_usart2_rb_a2h[256];
|
||||||
|
static uint8_t buf_usart2_rb_h2a[512];
|
||||||
|
static uint8_t buf_usart3_rb_a2h[256];
|
||||||
|
static uint8_t buf_usart3_rb_h2a[512];
|
||||||
|
|
||||||
|
static struct chx_intr usart2_intr;
|
||||||
|
static struct chx_intr usart3_intr;
|
||||||
|
|
||||||
|
static struct rb usart2_rb_a2h;
|
||||||
|
static struct rb usart2_rb_h2a;
|
||||||
|
static struct rb usart3_rb_a2h;
|
||||||
|
static struct rb usart3_rb_h2a;
|
||||||
|
|
||||||
|
static chopstx_poll_cond_t usart2_app_write_event;
|
||||||
|
static chopstx_poll_cond_t usart3_app_write_event;
|
||||||
|
|
||||||
|
static struct chx_poll_head *usart_poll[4];
|
||||||
|
|
||||||
|
/* Global variables so that it can be easier to debug. */
|
||||||
|
static int usart2_tx_ready;
|
||||||
|
static int usart3_tx_ready;
|
||||||
|
|
||||||
|
#define UART_STATE_BITMAP_RX_CARRIER (1 << 0)
|
||||||
|
#define UART_STATE_BITMAP_TX_CARRIER (1 << 1)
|
||||||
|
#define UART_STATE_BITMAP_BREAK (1 << 2)
|
||||||
|
#define UART_STATE_BITMAP_RINGSIGNAL (1 << 3)
|
||||||
|
#define UART_STATE_BITMAP_FRAMING (1 << 4)
|
||||||
|
#define UART_STATE_BITMAP_PARITY (1 << 5)
|
||||||
|
#define UART_STATE_BITMAP_OVERRUN (1 << 6)
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat)
|
||||||
|
{
|
||||||
|
int tx_ready = 0;
|
||||||
|
uint32_t r = USARTx->SR;
|
||||||
|
int notify_bits = 0;
|
||||||
|
|
||||||
|
if ((r & USART_SR_TXE))
|
||||||
|
{
|
||||||
|
tx_ready = 1;
|
||||||
|
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r & USART_SR_RXNE))
|
||||||
|
{
|
||||||
|
uint32_t data = USARTx->DR;
|
||||||
|
|
||||||
|
/* DR register should be accessed even if data is not used.
|
||||||
|
* Its read-access has side effect of clearing error flags.
|
||||||
|
*/
|
||||||
|
asm volatile ("" : : "r" (data) : "memory");
|
||||||
|
|
||||||
|
if ((r & USART_SR_NE))
|
||||||
|
stat->err_rx_noise++;
|
||||||
|
else if ((r & USART_SR_FE))
|
||||||
|
{
|
||||||
|
/* NOTE: Noway to distinguish framing error and break */
|
||||||
|
|
||||||
|
stat->rx_break++;
|
||||||
|
notify_bits |= UART_STATE_BITMAP_BREAK;
|
||||||
|
}
|
||||||
|
else if ((r & USART_SR_PE))
|
||||||
|
{
|
||||||
|
stat->err_rx_parity++;
|
||||||
|
notify_bits |= UART_STATE_BITMAP_PARITY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((r & USART_SR_ORE))
|
||||||
|
{
|
||||||
|
stat->err_rx_overrun++;
|
||||||
|
notify_bits |= UART_STATE_BITMAP_OVERRUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: if CS is 7-bit, mask it, or else parity bit in upper layer */
|
||||||
|
if (rb_ll_put (rb2a, (data & 0xff)) < 0)
|
||||||
|
stat->err_rx_overflow++;
|
||||||
|
else
|
||||||
|
stat->rx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((r & USART_SR_ORE))
|
||||||
|
{ /* Clear ORE */
|
||||||
|
uint32_t data = USARTx->DR;
|
||||||
|
asm volatile ("" : : "r" (data) : "memory");
|
||||||
|
stat->err_rx_overrun++;
|
||||||
|
notify_bits |= UART_STATE_BITMAP_OVERRUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify_bits)
|
||||||
|
{
|
||||||
|
if ((*ss_notify_callback) (stat->dev_no, notify_bits))
|
||||||
|
stat->err_notify_overflow++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_tx_ready (struct USART *USARTx, struct rb *rb2h,
|
||||||
|
struct usart_stat *stat)
|
||||||
|
{
|
||||||
|
int tx_ready = 1;
|
||||||
|
int c = rb_ll_get (rb2h);
|
||||||
|
|
||||||
|
if (c >= 0)
|
||||||
|
{
|
||||||
|
uint32_t r;
|
||||||
|
|
||||||
|
USARTx->DR = (c & 0xff);
|
||||||
|
stat->tx++;
|
||||||
|
r = USARTx->SR;
|
||||||
|
if ((r & USART_SR_TXE) == 0)
|
||||||
|
{
|
||||||
|
tx_ready = 0;
|
||||||
|
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
usart_main (void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
usart2_tx_ready = 1;
|
||||||
|
usart3_tx_ready = 1;
|
||||||
|
|
||||||
|
chopstx_claim_irq (&usart2_intr, INTR_REQ_USART2);
|
||||||
|
chopstx_claim_irq (&usart3_intr, INTR_REQ_USART3);
|
||||||
|
|
||||||
|
rb_init (&usart2_rb_a2h, buf_usart2_rb_a2h, sizeof buf_usart2_rb_a2h);
|
||||||
|
rb_init (&usart2_rb_h2a, buf_usart2_rb_h2a, sizeof buf_usart2_rb_h2a);
|
||||||
|
rb_init (&usart3_rb_a2h, buf_usart3_rb_a2h, sizeof buf_usart3_rb_a2h);
|
||||||
|
rb_init (&usart3_rb_h2a, buf_usart3_rb_h2a, sizeof buf_usart3_rb_h2a);
|
||||||
|
|
||||||
|
rb_get_prepare_poll (&usart2_rb_a2h, &usart2_app_write_event);
|
||||||
|
rb_get_prepare_poll (&usart3_rb_a2h, &usart3_app_write_event);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
usart_poll[n++] = (struct chx_poll_head *)&usart2_intr;
|
||||||
|
usart_poll[n++] = (struct chx_poll_head *)&usart3_intr;
|
||||||
|
if (usart2_tx_ready)
|
||||||
|
usart_poll[n++] = (struct chx_poll_head *)&usart2_app_write_event;
|
||||||
|
else
|
||||||
|
usart2_app_write_event.ready = 0;
|
||||||
|
if (usart3_tx_ready)
|
||||||
|
usart_poll[n++] = (struct chx_poll_head *)&usart3_app_write_event;
|
||||||
|
else
|
||||||
|
usart3_app_write_event.ready = 0;
|
||||||
|
|
||||||
|
chopstx_poll (NULL, n, usart_poll);
|
||||||
|
|
||||||
|
if (usart2_intr.ready)
|
||||||
|
{
|
||||||
|
usart2_tx_ready = handle_intr (USART2, &usart2_rb_h2a, &usart2_stat);
|
||||||
|
chopstx_intr_done (&usart2_intr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usart3_intr.ready)
|
||||||
|
{
|
||||||
|
usart3_tx_ready = handle_intr (USART3, &usart3_rb_h2a, &usart3_stat);
|
||||||
|
chopstx_intr_done (&usart3_intr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usart2_tx_ready && usart2_app_write_event.ready)
|
||||||
|
usart2_tx_ready = handle_tx_ready (USART2,
|
||||||
|
&usart2_rb_a2h, &usart2_stat);
|
||||||
|
|
||||||
|
if (usart3_tx_ready && usart3_app_write_event.ready)
|
||||||
|
usart3_tx_ready = handle_tx_ready (USART3,
|
||||||
|
&usart3_rb_a2h, &usart3_stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
usart_read (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||||
|
{
|
||||||
|
struct rb *rb;
|
||||||
|
|
||||||
|
if (dev_no == 2)
|
||||||
|
rb = &usart2_rb_h2a;
|
||||||
|
else if (dev_no == 3)
|
||||||
|
rb = &usart3_rb_h2a;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (buf == NULL && buflen == 0)
|
||||||
|
{
|
||||||
|
rb_ll_flush (rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return rb_read (rb, (uint8_t *)buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
usart_write (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||||
|
{
|
||||||
|
struct rb *rb;
|
||||||
|
|
||||||
|
if (dev_no == 2)
|
||||||
|
rb = &usart2_rb_a2h;
|
||||||
|
else if (dev_no == 3)
|
||||||
|
rb = &usart3_rb_a2h;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (buf == NULL && buflen == 0)
|
||||||
|
rb_ll_flush (rb);
|
||||||
|
else
|
||||||
|
rb_write (rb, (uint8_t *)buf, buflen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct usart_stat *
|
||||||
|
usart_stat (uint8_t dev_no)
|
||||||
|
{
|
||||||
|
if (dev_no == 2)
|
||||||
|
return &usart2_stat;
|
||||||
|
else if (dev_no == 3)
|
||||||
|
return &usart3_stat;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
usart_send_break (uint8_t dev_no)
|
||||||
|
{
|
||||||
|
struct USART *USARTx = get_usart_dev (dev_no);
|
||||||
|
if (USARTx == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((USARTx->CR1 & 0x01))
|
||||||
|
return 1; /* Busy sending break, which was requested before. */
|
||||||
|
|
||||||
|
USARTx->CR1 |= 0x01;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
66
contrib/usart.h
Normal file
66
contrib/usart.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#define B0 0 /* POSIX to hang up */
|
||||||
|
|
||||||
|
/* POSIX supports B75 to B300 */
|
||||||
|
#define B600 16
|
||||||
|
#define B1200 17
|
||||||
|
#define B2400 19
|
||||||
|
#define B9600 21
|
||||||
|
#define B19200 22
|
||||||
|
#define B57600 24
|
||||||
|
#define B115200 25
|
||||||
|
#define B230400 26
|
||||||
|
#define B460800 27
|
||||||
|
#define B921600 28
|
||||||
|
#define MASK_BAUD 0x3f
|
||||||
|
|
||||||
|
/* POSIX supports 5, 6. USB suppots 16 */
|
||||||
|
#define CS7 (2 << 6)
|
||||||
|
#define CS8 (3 << 6)
|
||||||
|
#define MASK_CS (0x7 << 6)
|
||||||
|
|
||||||
|
#define STOP0B5 (0 << 9) /* USART Hardware only */
|
||||||
|
#define STOP1B (1 << 9) /* USB, POSIX */
|
||||||
|
#define STOP1B5 (2 << 9) /* USB */
|
||||||
|
#define STOP2B (3 << 9) /* USB, POSIX */
|
||||||
|
#define MASK_STOP (0x3 << 9)
|
||||||
|
|
||||||
|
#define PARENB (1 << 11)
|
||||||
|
#define PARODD (2 << 11)
|
||||||
|
#define MASK_PAR (0x7 << 11)
|
||||||
|
/* USB 0: none, 1: odd, 2: even, 3: mark, 4: space */
|
||||||
|
|
||||||
|
#define CRTSCTS (1 << 14)
|
||||||
|
#define MASK_FLOW (0x1 << 14)
|
||||||
|
|
||||||
|
/*
|
||||||
|
BAUD_BITS 6
|
||||||
|
CS_BITS 3
|
||||||
|
STOP_BITS 2
|
||||||
|
PAR_BITS 3
|
||||||
|
*/
|
||||||
|
/* USB: SET_CONTROL_LINE_STATE
|
||||||
|
DTR RTS */
|
||||||
|
/* USB: SERIAL_STATE
|
||||||
|
DSR DCD RI */
|
||||||
|
|
||||||
|
struct usart_stat {
|
||||||
|
uint8_t dev_no;
|
||||||
|
|
||||||
|
uint32_t tx;
|
||||||
|
uint32_t rx;
|
||||||
|
uint32_t rx_break;
|
||||||
|
uint32_t err_notify_overflow;
|
||||||
|
uint32_t err_rx_overflow; /* software side */
|
||||||
|
uint32_t err_rx_overrun; /* hardware side */
|
||||||
|
uint32_t err_rx_noise;
|
||||||
|
uint32_t err_rx_parity;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void usart_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
|
||||||
|
int (*ss_notify_callback) (uint8_t dev_no, uint16_t notify_bits));
|
||||||
|
int usart_config (uint8_t dev_no, uint32_t config_bits);
|
||||||
|
int usart_read (uint8_t dev_no, char *buf, uint16_t buflen);
|
||||||
|
int usart_write (uint8_t dev_no, char *buf, uint16_t buflen);
|
||||||
|
const struct usart_stat *usart_stat (uint8_t dev_no);
|
||||||
|
int usart_send_break (uint8_t dev_no);
|
||||||
@@ -9,7 +9,7 @@ stop further execution of code. It never returns.
|
|||||||
|
|
||||||
@subheading chopstx_create
|
@subheading chopstx_create
|
||||||
@anchor{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})
|
@deftypefun {chopstx_t} {chopstx_create} (uint32_t @var{flags_and_prio}, uintptr_t @var{stack_addr}, size_t @var{stack_size}, voidfunc @var{thread_entry}, void * @var{arg})
|
||||||
@var{flags_and_prio}: Flags and priority
|
@var{flags_and_prio}: Flags and priority
|
||||||
|
|
||||||
@var{stack_addr}: Stack address
|
@var{stack_addr}: Stack address
|
||||||
@@ -107,6 +107,14 @@ Claim interrupt @var{intr} with @var{irq_num}
|
|||||||
Wait for the interrupt @var{intr} to be occured.
|
Wait for the interrupt @var{intr} to be occured.
|
||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
|
@subheading chopstx_intr_done
|
||||||
|
@anchor{chopstx_intr_done}
|
||||||
|
@deftypefun {void} {chopstx_intr_done} (chopstx_intr_t * @var{intr})
|
||||||
|
@var{intr}: Pointer to INTR structure
|
||||||
|
|
||||||
|
Finish for the interrupt @var{intr} occurred.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
@subheading chopstx_cleanup_push
|
@subheading chopstx_cleanup_push
|
||||||
@anchor{chopstx_cleanup_push}
|
@anchor{chopstx_cleanup_push}
|
||||||
@deftypefun {void} {chopstx_cleanup_push} (struct chx_cleanup * @var{clp})
|
@deftypefun {void} {chopstx_cleanup_push} (struct chx_cleanup * @var{clp})
|
||||||
@@ -176,20 +184,23 @@ Returns old state which is 0 when it was enabled.
|
|||||||
|
|
||||||
@subheading chopstx_poll
|
@subheading chopstx_poll
|
||||||
@anchor{chopstx_poll}
|
@anchor{chopstx_poll}
|
||||||
@deftypefun {int} {chopstx_poll} (uint32_t * @var{usec_p}, int @var{n}, @var{...})
|
@deftypefun {int} {chopstx_poll} (uint32_t * @var{usec_p}, int @var{n}, struct chx_poll_head *const [] @var{pd_array})
|
||||||
@var{usec_p}: Pointer to usec for timeout. Forever if NULL.
|
@var{usec_p}: Pointer to usec for timeout. Forever if NULL.
|
||||||
|
|
||||||
@var{n}: Number of poll descriptors
|
@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.
|
Returns number of active descriptors.
|
||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
@subheading chopstx_setpriority
|
@subheading chopstx_setpriority
|
||||||
@anchor{chopstx_setpriority}
|
@anchor{chopstx_setpriority}
|
||||||
@deftypefun {void} {chopstx_setpriority} (chopstx_prio_t @var{prio})
|
@deftypefun {chopstx_prio_t} {chopstx_setpriority} (chopstx_prio_t @var{prio_new})
|
||||||
@var{prio}: priority
|
|
||||||
|
|
||||||
Change the schedule priority with @var{prio}.
|
Change the schedule priority with @var{prio}.
|
||||||
|
Returns the old priority.
|
||||||
|
|
||||||
In general, it is not recommended to use this function because
|
In general, it is not recommended to use this function because
|
||||||
dynamically changing schedule priorities complicates the system.
|
dynamically changing schedule priorities complicates the system.
|
||||||
@@ -198,3 +209,23 @@ which starts its execution with priority of CHX_PRIO_MAIN_INIT, and
|
|||||||
let it change its priority after initialization of other threads.
|
let it change its priority after initialization of other threads.
|
||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
|
@subheading chx_sleep_mode
|
||||||
|
@anchor{chx_sleep_mode}
|
||||||
|
@deftypefun {extern void} {chx_sleep_mode} (int @var{enable_sleep})
|
||||||
|
@var{enable_sleep}: Enable sleep on idle or not
|
||||||
|
|
||||||
|
If @var{enable_sleep} is > 0, allow sleep for the idle thread.
|
||||||
|
|
||||||
|
Behavior of @var{enable_sleep} >= 1 depends on MCU.
|
||||||
|
|
||||||
|
For STM32F0, 1 for Sleep (CPU clock OFF only), 2 for Stop (Wakeup
|
||||||
|
by EXTI, voltage regulator on), 3 for Stop (Wakeup by EXTI, voltage
|
||||||
|
regulator low-power), 4 for Standby (Wakeup by RESET, voltage
|
||||||
|
regulator off).
|
||||||
|
|
||||||
|
For STM32F103, 1 for normal sleep, and 2 for sleep with lower 8MHz
|
||||||
|
clock.
|
||||||
|
|
||||||
|
Return previous value of @var{enable_sleep}.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
\input texinfo @c -*-texinfo-*-
|
\input texinfo @c -*-texinfo-*-
|
||||||
@c %**start of header
|
@c %**start of header
|
||||||
@setfilename chopstx.info
|
@setfilename chopstx.info
|
||||||
@set VERSION 0.12
|
@set VERSION 1.10
|
||||||
@settitle Chopstx Reference Manual
|
@settitle Chopstx Reference Manual
|
||||||
@c Unify some of the indices.
|
@c Unify some of the indices.
|
||||||
@syncodeindex tp fn
|
@syncodeindex tp fn
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
This manual is for Chopstx (version @value{VERSION}).
|
This manual is for Chopstx (version @value{VERSION}).
|
||||||
|
|
||||||
@noindent
|
@noindent
|
||||||
Copyright @copyright{} 2013, 2015, 2016 Flying Stone Technology @*
|
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018 Flying Stone Technology @*
|
||||||
|
|
||||||
@quotation
|
@quotation
|
||||||
Permission is granted to copy, distribute and/or modify this document
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
@@ -59,6 +59,10 @@ section entitled ``Copying''.
|
|||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Introduction:: What is Chopstx.
|
* Introduction:: What is Chopstx.
|
||||||
|
* Threads and only Threads:: Threads and only Threads.
|
||||||
|
* Poll or Pole:: Poll or Pole.
|
||||||
|
* Note (Use of sleep mode):: Use it carefully.
|
||||||
|
* Compile-time macro:: Macro to be defined.
|
||||||
* API:: API.
|
* API:: API.
|
||||||
|
|
||||||
Appendix
|
Appendix
|
||||||
@@ -83,15 +87,91 @@ Indexes
|
|||||||
@node Introduction
|
@node Introduction
|
||||||
@chapter Introduction
|
@chapter Introduction
|
||||||
|
|
||||||
Chopstx is an RT thread library for ARM Cortex-M0 and Cortex-M3.
|
Chopstx is an RT thread library for ARM Cortex-M0, Cortex-M0plus,
|
||||||
Specifically, it is used for STM32F030, STM32F103, and KL27Z.
|
Cortex-M3 and GNU/Linux emulation. Specifically, it is used for
|
||||||
|
STM32F030, MKL27Z, STM32F103, GD32F103 and as a command on GNU/Linux.
|
||||||
|
|
||||||
While most RTOSes come with many features, drivers, and stacks,
|
While most RTOSes come with many features, drivers, and stacks,
|
||||||
Chopstx just offers a RT thread library.
|
Chopstx just offers an RT thread library.
|
||||||
|
|
||||||
With Chopstx, interrupt handling is also done by a thread. This
|
With Chopstx, interrupt handling is also done by a thread. This
|
||||||
enables coherent code for ease of maintenance.
|
enables coherent code for ease of maintenance.
|
||||||
|
|
||||||
|
While threads are important, we don't need more threads than
|
||||||
|
necessary. Chopstx provides a feature of poll, so that we can
|
||||||
|
minimize use of threads.
|
||||||
|
|
||||||
|
|
||||||
|
@node Threads and only Threads
|
||||||
|
@chapter Threads and only Threads
|
||||||
|
|
||||||
|
Chopstx doesn't use the feature of (prioritized) nested vector
|
||||||
|
interrupt mechanism at all. All interrupts are equally handled by a
|
||||||
|
single entry of chx_handle_intr which just wakes up corresponding
|
||||||
|
thread. This is the feature of Chopstx.
|
||||||
|
|
||||||
|
Nested vector interrupt machanism would be useful for interrupt-driven
|
||||||
|
programming style for specific application targets, or, some other
|
||||||
|
programing style like the one with spl of Unix. Some engineers
|
||||||
|
(especially, hardware side) still seem to believe that it is a good
|
||||||
|
feature to have. But from the view point of programming and
|
||||||
|
maintenance of software, this is one of the most difficult part with
|
||||||
|
little benefit, if any.
|
||||||
|
|
||||||
|
With traditional interrupt handling, a demarcation of what should be
|
||||||
|
done by interrupt handler, bottom half, and thead is crucial for
|
||||||
|
applications' performance. And because the demarcation should be done
|
||||||
|
at an early stage of an application development, it has a tendency,
|
||||||
|
many parts are getting demanding higher priority. Amount of code for
|
||||||
|
higher priority interrupt hander is getting bigger and bigger, while
|
||||||
|
losing performance.
|
||||||
|
|
||||||
|
On the other hand, ``Threads (and only Threads)'' programming style
|
||||||
|
gives us best flexibility and it can make an application more
|
||||||
|
predictable, deterministic and easy to maintain.
|
||||||
|
|
||||||
|
There are some applications, like square wave generator, which are not
|
||||||
|
suited to this programming style; Another programming style can
|
||||||
|
support more performance (frequency). In general, such an example is
|
||||||
|
best suited by hardware (not software).
|
||||||
|
|
||||||
|
|
||||||
|
@node Poll or Pole
|
||||||
|
@chapter Poll or Pole
|
||||||
|
Chopstx provides the @code{chopstx_poll} function to wait on multiple events.
|
||||||
|
|
||||||
|
Using @code{chopstx_poll}, we can write an application by event-driven
|
||||||
|
programming style, with minimum number of threads, avoiding
|
||||||
|
complicated dependency between threads.
|
||||||
|
|
||||||
|
|
||||||
|
@node Note (Use of sleep mode)
|
||||||
|
@chapter Note (Use of sleep mode)
|
||||||
|
|
||||||
|
Calling the chopstx_conf_idle function (> 0) to allow the idle thread
|
||||||
|
going to sleep. MCU will be in sleep mode when no threads are
|
||||||
|
running. By setting relevant bits of system registers, MCU will be
|
||||||
|
able to be into stop or stand-by mode, which is MCU dependent.
|
||||||
|
|
||||||
|
If you use this sleep feature, please consider and implement your
|
||||||
|
program carefully. Enabling sleep, it may result a bricked board; A
|
||||||
|
board with no RESET pin cannot be debugged by JTAG/SWD.
|
||||||
|
|
||||||
|
|
||||||
|
@node Compile-time macro
|
||||||
|
@chapter Compile-time macro
|
||||||
|
|
||||||
|
Compiling Chopstx, a macro MHZ should be supplied.
|
||||||
|
|
||||||
|
For example, when using the makefile rule of chopstx/rules.mk, please
|
||||||
|
define the make variable DEFS with -DMHZ=72 before inclusion of the rule file.
|
||||||
|
|
||||||
|
@subheading MHZ
|
||||||
|
@anchor{MHZ}
|
||||||
|
@defmac {MHZ}
|
||||||
|
Running CPU clock in MHz. Used for chopstx_usec_wait.
|
||||||
|
@end defmac
|
||||||
|
|
||||||
|
|
||||||
@node API
|
@node API
|
||||||
@chapter API
|
@chapter API
|
||||||
|
|||||||
33
entry.c
33
entry.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* entry.c - Entry routine when reset and interrupt vectors.
|
* entry.c - Entry routine when reset and interrupt vectors.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013, 2014, 2015, 2016
|
* Copyright (C) 2013, 2014, 2015, 2016, 2017
|
||||||
* Flying Stone Technology
|
* Flying Stone Technology
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -32,6 +32,21 @@
|
|||||||
#include <chopstx.h>
|
#include <chopstx.h>
|
||||||
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
|
#ifdef GNU_LINUX_EMULATION
|
||||||
|
int emulated_main (int, const char **);
|
||||||
|
void chx_init (struct chx_thread *);
|
||||||
|
void chx_systick_init (void);
|
||||||
|
extern struct chx_thread main_thread;
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
chx_init (&main_thread);
|
||||||
|
chx_systick_init ();
|
||||||
|
emulated_main (argc, argv);
|
||||||
|
}
|
||||||
|
#else
|
||||||
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
|
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
|
||||||
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
|
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
@@ -203,10 +218,10 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
|||||||
chx_handle_intr /* DMA1 CH6 */, chx_handle_intr /* DMA1 CH7 */,
|
chx_handle_intr /* DMA1 CH6 */, chx_handle_intr /* DMA1 CH7 */,
|
||||||
chx_handle_intr /* ADC1_2 */, chx_handle_intr /* USB HP */,
|
chx_handle_intr /* ADC1_2 */, chx_handle_intr /* USB HP */,
|
||||||
/* 0x90 */
|
/* 0x90 */
|
||||||
chx_handle_intr /* USB LP */, chx_handle_intr /* CAN */,
|
chx_handle_intr /* USB LP */, chx_handle_intr /* CAN RX1 */,
|
||||||
/* ... and more. EXT9_5, TIMx, I2C, SPI, USART, EXT15_10 */
|
chx_handle_intr /* CAN SCE */, chx_handle_intr /* EXT9_5 */,
|
||||||
chx_handle_intr, chx_handle_intr,
|
/* 0xa0 */
|
||||||
/* 0xA0 */
|
/* ... and more. TIMx, I2C, SPI, USART... */
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
/* 0xc0 */
|
/* 0xc0 */
|
||||||
@@ -214,14 +229,16 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
|||||||
/* STM32F0 doesn't have more. */
|
/* STM32F0 doesn't have more. */
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
/* 0xe0 */
|
||||||
|
chx_handle_intr /* EXT15_10 */, chx_handle_intr /* RTCAlarm */,
|
||||||
|
chx_handle_intr /* USBWakeup */, chx_handle_intr,
|
||||||
#endif
|
#endif
|
||||||
#if !defined(STM32F10X_MD)
|
#if !defined(STM32F10X_MD)
|
||||||
/* High-density chips have more; RTCAlarm, USBWakeup, ... , DMA2_Channel4_5 */
|
/* High-density chips have more; ... DMA2_Channel4_5 */
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||||
chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -111,9 +111,10 @@ eventmask_t
|
|||||||
eventflag_wait_timeout (struct eventflag *ev, uint32_t usec)
|
eventflag_wait_timeout (struct eventflag *ev, uint32_t usec)
|
||||||
{
|
{
|
||||||
chopstx_poll_cond_t poll_desc;
|
chopstx_poll_cond_t poll_desc;
|
||||||
|
struct chx_poll_head *pd_array[1] = { (struct chx_poll_head *)&poll_desc };
|
||||||
|
|
||||||
eventflag_prepare_poll (ev, &poll_desc);
|
eventflag_prepare_poll (ev, &poll_desc);
|
||||||
chopstx_poll (&usec, 1, &poll_desc);
|
chopstx_poll (&usec, 1, pd_array);
|
||||||
return eventflag_get (ev);
|
return eventflag_get (ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
43
example-cdc-gnu-linux/Makefile
Normal file
43
example-cdc-gnu-linux/Makefile
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Makefile for example application of Chopstx
|
||||||
|
|
||||||
|
PROJECT = sample
|
||||||
|
|
||||||
|
### This is for GNU/Linux
|
||||||
|
|
||||||
|
CHOPSTX = ..
|
||||||
|
LDSCRIPT=
|
||||||
|
CSRC = sample.c usb-cdc.c command.c
|
||||||
|
|
||||||
|
CHIP=gnu-linux
|
||||||
|
USE_SYS = yes
|
||||||
|
USE_USB = yes
|
||||||
|
USE_ADC = yes
|
||||||
|
EMULATION=yes
|
||||||
|
|
||||||
|
###################################
|
||||||
|
CROSS =
|
||||||
|
CC = $(CROSS)gcc
|
||||||
|
LD = $(CROSS)gcc
|
||||||
|
OBJCOPY = $(CROSS)objcopy
|
||||||
|
|
||||||
|
MCU = none
|
||||||
|
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||||
|
DEFS = -DGNU_LINUX_EMULATION -DUSE_SYS_BOARD_ID
|
||||||
|
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
|
||||||
|
|
||||||
|
build/flash.data: Makefile
|
||||||
|
@echo 'Generating 8192-byte flash.data'
|
||||||
|
@/bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff' >$@
|
||||||
|
@for i in $(shell seq 1023); do /bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff' >>$@; done
|
||||||
|
|
||||||
|
|
||||||
41
example-cdc-gnu-linux/README
Normal file
41
example-cdc-gnu-linux/README
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
(0) Build and generate initial flash data
|
||||||
|
|
||||||
|
$ make
|
||||||
|
$ make build/flash.data
|
||||||
|
|
||||||
|
|
||||||
|
(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
|
||||||
|
|
||||||
1
example-cdc-gnu-linux/board.h
Symbolic link
1
example-cdc-gnu-linux/board.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../board/board-gnu-linux.h
|
||||||
579
example-cdc-gnu-linux/command.c
Normal file
579
example-cdc-gnu-linux/command.c
Normal file
@@ -0,0 +1,579 @@
|
|||||||
|
#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 =
|
||||||
|
"mdb ADDR [COUNT]; memory display byte\r\n"
|
||||||
|
"mwh ADDR VALUE [COUNT]; memory write halfword\r\n"
|
||||||
|
"fes ADDR [COUNT]; flash erase sector\r\n"
|
||||||
|
"fwh ADDR VALUE [COUNT]; flash write halfword\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 '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOUCH_SUPPORT
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
compose_hex_ptr (char *s, uintptr_t v)
|
||||||
|
{
|
||||||
|
s[0] = hexchar (v >> 60);
|
||||||
|
s[1] = hexchar (v >> 56);
|
||||||
|
s[2] = hexchar (v >> 52);
|
||||||
|
s[3] = hexchar (v >> 48);
|
||||||
|
s[4] = hexchar (v >> 44);
|
||||||
|
s[5] = hexchar (v >> 40);
|
||||||
|
s[6] = hexchar (v >> 36);
|
||||||
|
s[7] = hexchar (v >> 32);
|
||||||
|
s[8] = hexchar (v >> 28);
|
||||||
|
s[9] = hexchar (v >> 24);
|
||||||
|
s[10] = hexchar (v >> 20);
|
||||||
|
s[11] = hexchar (v >> 16);
|
||||||
|
s[12] = hexchar (v >> 12);
|
||||||
|
s[13] = hexchar (v >> 8);
|
||||||
|
s[14] = hexchar (v >> 4);
|
||||||
|
s[15] = hexchar (v);
|
||||||
|
return s+16;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 char *
|
||||||
|
compose_hex_byte (char *s, uint8_t v)
|
||||||
|
{
|
||||||
|
s[0] = hexchar (v >> 4);
|
||||||
|
s[1] = hexchar (v);
|
||||||
|
return s+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_hex (struct tty *tty, const char *s, uintptr_t *v_p)
|
||||||
|
{
|
||||||
|
uintptr_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TOUCH_SUPPORT
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_mdb (struct tty *tty, const char *line)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uintptr_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, "mdb error\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
uint8_t v;
|
||||||
|
char output[68];
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = compose_hex_ptr (output, addr);
|
||||||
|
*s++ = ':';
|
||||||
|
*s++ = ' ';
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
v = *(uint8_t *)addr;
|
||||||
|
s = compose_hex_byte (s, v);
|
||||||
|
i++;
|
||||||
|
addr += 1;
|
||||||
|
if (i >= count || (i % 16) == 0)
|
||||||
|
break;
|
||||||
|
*s++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
*s++ = '\r';
|
||||||
|
*s++ = '\n';
|
||||||
|
tty_send (tty, output, s - output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_mwh (struct tty *tty, const char *line)
|
||||||
|
{
|
||||||
|
(void)tty;
|
||||||
|
(void)line;
|
||||||
|
put_line (tty, "mwh not yet supported\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_fes (struct tty *tty, const char *line)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uintptr_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_fwh (struct tty *tty, const char *line)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uintptr_t addr = 0;
|
||||||
|
uintptr_t d;
|
||||||
|
uint16_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, &d);
|
||||||
|
value = (uint16_t)d;
|
||||||
|
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_halfword (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[] = {
|
||||||
|
#ifdef TOUCH_SUPPORT
|
||||||
|
{ "button", cmd_button },
|
||||||
|
{ "touch", cmd_touch },
|
||||||
|
#endif
|
||||||
|
{ "mdb", cmd_mdb },
|
||||||
|
{ "mwh", cmd_mwh },
|
||||||
|
{ "fes", cmd_fes },
|
||||||
|
{ "fwh", cmd_fwh },
|
||||||
|
#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));
|
||||||
|
}
|
||||||
|
}
|
||||||
2
example-cdc-gnu-linux/command.h
Normal file
2
example-cdc-gnu-linux/command.h
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
void cmd_dispatch (struct tty *tty, const char *line);
|
||||||
|
char * compose_hex_ptr (char *s, uintptr_t v);
|
||||||
2
example-cdc-gnu-linux/config.h
Normal file
2
example-cdc-gnu-linux/config.h
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#undef CRC32_SUPPORT
|
||||||
|
#define ADC_SUPPORT
|
||||||
197
example-cdc-gnu-linux/sample.c
Normal file
197
example-cdc-gnu-linux/sample.c
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
#include <chopstx.h>
|
||||||
|
|
||||||
|
#include "sys.h"
|
||||||
|
|
||||||
|
#include "usb_lld.h"
|
||||||
|
#include "tty.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
uintptr_t addr;
|
||||||
|
|
||||||
|
if (argc >= 2 && !strncmp (argv[1], "--debug=", 8))
|
||||||
|
debug = strtol (&argv[1][8], NULL, 10);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
addr = flash_init ("flash.data");
|
||||||
|
flash_unlock ();
|
||||||
|
|
||||||
|
u = 1;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
puts("send hello");
|
||||||
|
if (tty_send (tty, s, 32) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s[0] = hexchar (count >> 4);
|
||||||
|
s[1] = hexchar (count & 0x0f);
|
||||||
|
s[2] = ':';
|
||||||
|
s[3] = ' ';
|
||||||
|
compose_hex_ptr (s+4, addr);
|
||||||
|
s[20] = '\r';
|
||||||
|
s[21] = '\n';
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (tty_send (tty, s, 22) < 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;
|
||||||
|
}
|
||||||
9
example-cdc-gnu-linux/tty.h
Normal file
9
example-cdc-gnu-linux/tty.h
Normal 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-cdc-gnu-linux/usb-cdc.c
Normal file
952
example-cdc-gnu-linux/usb-cdc.c
Normal file
@@ -0,0 +1,952 @@
|
|||||||
|
#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 = USB_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 = USB_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 = USB_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 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 = USB_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);
|
||||||
|
chopstx_intr_done (&usb_intr);
|
||||||
|
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 = USB_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 == USB_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 != USB_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;
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ CHIP=stm32f103
|
|||||||
|
|
||||||
USE_SYS = yes
|
USE_SYS = yes
|
||||||
USE_USB = yes
|
USE_USB = yes
|
||||||
|
ENABLE_OUTPUT_HEX=yes
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
CROSS = arm-none-eabi-
|
CROSS = arm-none-eabi-
|
||||||
@@ -19,7 +20,7 @@ OBJCOPY = $(CROSS)objcopy
|
|||||||
|
|
||||||
MCU = cortex-m3
|
MCU = cortex-m3
|
||||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||||
DEFS = -DUSE_SYS3 -DFREE_STANDING
|
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=72
|
||||||
OPT = -O3 -Os -g
|
OPT = -O3 -Os -g
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
|
|||||||
@@ -61,14 +61,14 @@ blk (void *arg)
|
|||||||
#define PRIO_PWM 3
|
#define PRIO_PWM 3
|
||||||
#define PRIO_BLK 2
|
#define PRIO_BLK 2
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
#define STACK_MAIN
|
||||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
#define STACK_PROCESS_1
|
||||||
|
#define STACK_PROCESS_2
|
||||||
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
#include "stack-def.h"
|
||||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
#define STACK_ADDR_PWM ((uint32_t)process1_base)
|
||||||
|
#define STACK_SIZE_PWM (sizeof process1_base)
|
||||||
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
#define STACK_ADDR_BLK ((uint32_t)process2_base)
|
||||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
#define STACK_SIZE_BLK (sizeof process2_base)
|
||||||
|
|
||||||
|
|
||||||
static char hexchar (uint8_t x)
|
static char hexchar (uint8_t x)
|
||||||
@@ -98,8 +98,8 @@ main (int argc, const char *argv[])
|
|||||||
|
|
||||||
m = 10;
|
m = 10;
|
||||||
|
|
||||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
|
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||||
|
|
||||||
chopstx_usec_wait (200*1000);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ main (int argc, const char *argv[])
|
|||||||
m = 50;
|
m = 50;
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
uint8_t s[LINEBUFSIZE];
|
char s[LINEBUFSIZE];
|
||||||
|
|
||||||
u = 1;
|
u = 1;
|
||||||
tty_wait_connection (tty);
|
tty_wait_connection (tty);
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ST32F103 memory setup.
|
* ST32F103 memory setup.
|
||||||
*/
|
*/
|
||||||
__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
|
MEMORY
|
||||||
{
|
{
|
||||||
@@ -78,34 +73,21 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
_textdata = _etext;
|
_textdata = _etext;
|
||||||
|
|
||||||
.process_stack :
|
.process_stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
__process3_stack_base__ = .;
|
*(.process_stack.3)
|
||||||
. += __process3_stack_size__;
|
*(.process_stack.2)
|
||||||
|
*(.process_stack.1)
|
||||||
|
*(.process_stack.0)
|
||||||
. = ALIGN(8);
|
. = 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
|
} > ram
|
||||||
|
|
||||||
.main_stack :
|
.main_stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
__main_stack_base__ = .;
|
*(.main_stack)
|
||||||
. += __main_stack_size__;
|
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
__main_stack_end__ = .;
|
|
||||||
} > ram
|
} > ram
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
|
|||||||
24
example-cdc/stack-def.h
Normal file
24
example-cdc/stack-def.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#if defined(STACK_MAIN)
|
||||||
|
/* Idle+Exception handlers */
|
||||||
|
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
|
||||||
|
char main_base[0x0100] __attribute__ ((section(".main_stack")));
|
||||||
|
|
||||||
|
/* Main program */
|
||||||
|
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
|
||||||
|
char process0_base[0x0400] __attribute__ ((section(".process_stack.0")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* First thread program */
|
||||||
|
#if defined(STACK_PROCESS_1)
|
||||||
|
char process1_base[0x0200] __attribute__ ((section(".process_stack.1")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Second thread program */
|
||||||
|
#if defined(STACK_PROCESS_2)
|
||||||
|
char process2_base[0x0200] __attribute__ ((section(".process_stack.2")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Third thread program */
|
||||||
|
#if defined(STACK_PROCESS_3)
|
||||||
|
char process3_base[0x0200] __attribute__ ((section(".process_stack.3")));
|
||||||
|
#endif
|
||||||
@@ -5,5 +5,5 @@ struct tty;
|
|||||||
struct tty *tty_open (void);
|
struct tty *tty_open (void);
|
||||||
void tty_wait_configured (struct tty *tty);
|
void tty_wait_configured (struct tty *tty);
|
||||||
void tty_wait_connection (struct tty *tty);
|
void tty_wait_connection (struct tty *tty);
|
||||||
int tty_send (struct tty *tty, uint8_t *buf, int count);
|
int tty_send (struct tty *tty, const char *buf, int count);
|
||||||
int tty_recv (struct tty *tty, uint8_t *buf, uint32_t *timeout);
|
int tty_recv (struct tty *tty, char *buf, uint32_t *timeout);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ static const struct line_coding line_coding0 = {
|
|||||||
*
|
*
|
||||||
* In that case, add argument to TTY_OPEN function and
|
* In that case, add argument to TTY_OPEN function and
|
||||||
* modify TTY_GET function to get the TTY structure. Functions which
|
* modify TTY_GET function to get the TTY structure. Functions which
|
||||||
* directy accesses TTY0 (usb_cb_device_reset and usb_cb_handle_event)
|
* directy accesses TTY0 (usb_device_reset and usb_set_configuration)
|
||||||
* should be modified, too.
|
* should be modified, too.
|
||||||
*
|
*
|
||||||
* Modification of TTY_MAIN thread will be also needed to echo back
|
* Modification of TTY_MAIN thread will be also needed to echo back
|
||||||
@@ -234,10 +234,10 @@ static const uint8_t vcom_string3[28] = {
|
|||||||
#define NUM_INTERFACES 2
|
#define NUM_INTERFACES 2
|
||||||
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_device_reset (void)
|
usb_device_reset (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
usb_lld_reset (VCOM_FEATURE_BUS_POWERED);
|
usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
|
||||||
|
|
||||||
/* Initialize Endpoint 0 */
|
/* Initialize Endpoint 0 */
|
||||||
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
|
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
|
||||||
@@ -248,7 +248,7 @@ usb_cb_device_reset (void)
|
|||||||
tty0.flag_connected = 0;
|
tty0.flag_connected = 0;
|
||||||
tty0.flag_send_ready = 1;
|
tty0.flag_send_ready = 1;
|
||||||
tty0.flag_input_avail = 0;
|
tty0.flag_input_avail = 0;
|
||||||
tty0.device_state = ATTACHED;
|
tty0.device_state = USB_DEVICE_STATE_ATTACHED;
|
||||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
}
|
}
|
||||||
@@ -256,13 +256,15 @@ usb_cb_device_reset (void)
|
|||||||
|
|
||||||
#define CDC_CTRL_DTR 0x0001
|
#define CDC_CTRL_DTR 0x0001
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
|
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) && arg->index == 0
|
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
|
||||||
&& USB_SETUP_SET (req) && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
&& USB_SETUP_SET (arg->type)
|
||||||
|
&& arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (arg->index, 0);
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
@@ -272,63 +274,74 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
|
|||||||
chopstx_cond_signal (&t->cnd);
|
chopstx_cond_signal (&t->cnd);
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
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
|
static int
|
||||||
vcom_port_data_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
|
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))
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (arg->index, 0);
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
|
if (arg->request == USB_CDC_REQ_GET_LINE_CODING)
|
||||||
return usb_lld_reply_request (&t->line_coding,
|
return usb_lld_ctrl_send (dev, &t->line_coding,
|
||||||
sizeof (struct line_coding), arg);
|
sizeof (struct line_coding));
|
||||||
}
|
}
|
||||||
else /* USB_SETUP_SET (req) */
|
else /* USB_SETUP_SET (req) */
|
||||||
{
|
{
|
||||||
if (req_no == USB_CDC_REQ_SET_LINE_CODING
|
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
|
||||||
&& arg->len == sizeof (struct line_coding))
|
&& arg->len == sizeof (struct line_coding))
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (arg->index, 0);
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
usb_lld_set_data_to_recv (&t->line_coding,
|
return usb_lld_ctrl_recv (dev, &t->line_coding,
|
||||||
sizeof (struct line_coding));
|
sizeof (struct line_coding));
|
||||||
return USB_SUCCESS;
|
|
||||||
}
|
}
|
||||||
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||||
return USB_SUCCESS;
|
return usb_lld_ctrl_ack (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
|
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) && arg->index == 0)
|
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
|
||||||
return vcom_port_data_setup (req, req_no, arg);
|
return vcom_port_data_setup (dev);
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
|
usb_get_descriptor (struct usb_dev *dev)
|
||||||
struct req_args *arg)
|
|
||||||
{
|
{
|
||||||
|
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)
|
if (rcp != DEVICE_RECIPIENT)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
if (desc_type == DEVICE_DESCRIPTOR)
|
if (desc_type == DEVICE_DESCRIPTOR)
|
||||||
return usb_lld_reply_request (vcom_device_desc, sizeof (vcom_device_desc),
|
return usb_lld_ctrl_send (dev,
|
||||||
arg);
|
vcom_device_desc, sizeof (vcom_device_desc));
|
||||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||||
return usb_lld_reply_request (vcom_config_desc, sizeof (vcom_config_desc),
|
return usb_lld_ctrl_send (dev,
|
||||||
arg);
|
vcom_config_desc, sizeof (vcom_config_desc));
|
||||||
else if (desc_type == STRING_DESCRIPTOR)
|
else if (desc_type == STRING_DESCRIPTOR)
|
||||||
{
|
{
|
||||||
const uint8_t *str;
|
const uint8_t *str;
|
||||||
@@ -353,13 +366,13 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
|
|||||||
size = sizeof (vcom_string3);
|
size = sizeof (vcom_string3);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return usb_lld_reply_request (str, size, arg);
|
return usb_lld_ctrl_send (dev, str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -388,83 +401,87 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_handle_event (uint8_t event_type, uint16_t value)
|
usb_set_configuration (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t current_conf;
|
uint8_t current_conf;
|
||||||
|
|
||||||
switch (event_type)
|
current_conf = usb_lld_current_configuration (dev);
|
||||||
{
|
|
||||||
case USB_EVENT_ADDRESS:
|
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
|
||||||
tty0.device_state = ADDRESSED;
|
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
|
||||||
return USB_SUCCESS;
|
|
||||||
case USB_EVENT_CONFIG:
|
|
||||||
current_conf = usb_lld_current_configuration ();
|
|
||||||
if (current_conf == 0)
|
if (current_conf == 0)
|
||||||
{
|
{
|
||||||
if (value != 1)
|
if (dev->dev_req.value != 1)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
usb_lld_set_configuration (1);
|
usb_lld_set_configuration (dev, 1);
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
for (i = 0; i < NUM_INTERFACES; i++)
|
||||||
vcom_setup_endpoints_for_interface (i, 0);
|
vcom_setup_endpoints_for_interface (i, 0);
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
tty0.device_state = CONFIGURED;
|
tty0.device_state = USB_DEVICE_STATE_CONFIGURED;
|
||||||
|
chopstx_cond_signal (&tty0.cnd);
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
}
|
}
|
||||||
else if (current_conf != value)
|
else if (current_conf != dev->dev_req.value)
|
||||||
{
|
{
|
||||||
if (value != 0)
|
if (dev->dev_req.value != 0)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
usb_lld_set_configuration (0);
|
usb_lld_set_configuration (dev, 0);
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
for (i = 0; i < NUM_INTERFACES; i++)
|
||||||
vcom_setup_endpoints_for_interface (i, 1);
|
vcom_setup_endpoints_for_interface (i, 1);
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
tty0.device_state = ADDRESSED;
|
tty0.device_state = USB_DEVICE_STATE_ADDRESSED;
|
||||||
|
chopstx_cond_signal (&tty0.cnd);
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
}
|
}
|
||||||
/* Do nothing when current_conf == value */
|
|
||||||
return USB_SUCCESS;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
usb_lld_ctrl_ack (dev);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_interface (uint8_t cmd, struct req_args *arg)
|
usb_set_interface (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
const uint8_t zero = 0;
|
uint16_t interface = dev->dev_req.index;
|
||||||
uint16_t interface = arg->index;
|
uint16_t alt = dev->dev_req.value;
|
||||||
uint16_t alt = arg->value;
|
|
||||||
|
|
||||||
if (interface >= NUM_INTERFACES)
|
if (interface >= NUM_INTERFACES)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
switch (cmd)
|
|
||||||
{
|
|
||||||
case USB_SET_INTERFACE:
|
|
||||||
if (alt != 0)
|
if (alt != 0)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vcom_setup_endpoints_for_interface (interface, 0);
|
vcom_setup_endpoints_for_interface (interface, 0);
|
||||||
return USB_SUCCESS;
|
usb_lld_ctrl_ack (dev);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case USB_GET_INTERFACE:
|
static int
|
||||||
return usb_lld_reply_request (&zero, 1, arg);
|
usb_get_interface (struct usb_dev *dev)
|
||||||
|
{
|
||||||
|
const uint8_t zero = 0;
|
||||||
|
uint16_t interface = dev->dev_req.index;
|
||||||
|
|
||||||
default:
|
if (interface >= NUM_INTERFACES)
|
||||||
case USB_QUERY_INTERFACE:
|
return -1;
|
||||||
return USB_SUCCESS;
|
|
||||||
}
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -515,8 +532,8 @@ tty_echo_char (struct tty *t, int c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_tx_done (uint8_t ep_num, uint32_t len)
|
usb_tx_done (uint8_t ep_num, uint16_t len)
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (-1, ep_num);
|
struct tty *t = tty_get (-1, ep_num);
|
||||||
|
|
||||||
@@ -598,19 +615,18 @@ tty_input_char (struct tty *t, int c)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_rx_ready (uint8_t ep_num)
|
usb_rx_ready (uint8_t ep_num, uint16_t len)
|
||||||
{
|
{
|
||||||
uint8_t recv_buf[64];
|
uint8_t recv_buf[64];
|
||||||
struct tty *t = tty_get (-1, ep_num);
|
struct tty *t = tty_get (-1, ep_num);
|
||||||
|
|
||||||
if (ep_num == ENDP3)
|
if (ep_num == ENDP3)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i;
|
||||||
|
|
||||||
r = usb_lld_rx_data_len (ENDP3);
|
usb_lld_rxcpy (recv_buf, ep_num, 0, len);
|
||||||
usb_lld_rxcpy (recv_buf, ep_num, 0, r);
|
for (i = 0; i < len; i++)
|
||||||
for (i = 0; i < r; i++)
|
|
||||||
if (tty_input_char (t, recv_buf[i]))
|
if (tty_input_char (t, recv_buf[i]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -623,12 +639,12 @@ usb_cb_rx_ready (uint8_t ep_num)
|
|||||||
|
|
||||||
static void *tty_main (void *arg);
|
static void *tty_main (void *arg);
|
||||||
|
|
||||||
#define INTR_REQ_USB 20
|
|
||||||
#define PRIO_TTY 4
|
#define PRIO_TTY 4
|
||||||
|
|
||||||
extern uint8_t __process3_stack_base__, __process3_stack_size__;
|
#define STACK_PROCESS_3
|
||||||
const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__;
|
#include "stack-def.h"
|
||||||
const size_t __stacksize_tty = (size_t)&__process3_stack_size__;
|
#define STACK_ADDR_TTY ((uint32_t)process3_base)
|
||||||
|
#define STACK_SIZE_TTY (sizeof process3_base)
|
||||||
|
|
||||||
struct tty *
|
struct tty *
|
||||||
tty_open (void)
|
tty_open (void)
|
||||||
@@ -640,10 +656,10 @@ tty_open (void)
|
|||||||
tty0.flag_connected = 0;
|
tty0.flag_connected = 0;
|
||||||
tty0.flag_send_ready = 1;
|
tty0.flag_send_ready = 1;
|
||||||
tty0.flag_input_avail = 0;
|
tty0.flag_input_avail = 0;
|
||||||
tty0.device_state = UNCONNECTED;
|
tty0.device_state = USB_DEVICE_STATE_UNCONNECTED;
|
||||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||||
|
|
||||||
chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0);
|
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
|
||||||
return &tty0;
|
return &tty0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,6 +668,8 @@ static void *
|
|||||||
tty_main (void *arg)
|
tty_main (void *arg)
|
||||||
{
|
{
|
||||||
struct tty *t = arg;
|
struct tty *t = arg;
|
||||||
|
struct usb_dev dev;
|
||||||
|
int e;
|
||||||
|
|
||||||
#if defined(OLDER_SYS_H)
|
#if defined(OLDER_SYS_H)
|
||||||
/*
|
/*
|
||||||
@@ -660,9 +678,9 @@ tty_main (void *arg)
|
|||||||
*
|
*
|
||||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||||
* invocation of usb_interrupt_handler won't occur.
|
* invocation of usb_lld_event_handler won't occur.
|
||||||
*
|
*
|
||||||
* Calling usb_interrupt_handler is no harm even if there were no
|
* Calling usb_lld_event_handler is no harm even if there were no
|
||||||
* interrupts, thus, we call it unconditionally here, just in case
|
* interrupts, thus, we call it unconditionally here, just in case
|
||||||
* if there is a request.
|
* if there is a request.
|
||||||
*
|
*
|
||||||
@@ -671,22 +689,118 @@ tty_main (void *arg)
|
|||||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
usb_lld_init (VCOM_FEATURE_BUS_POWERED);
|
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||||
usb_interrupt_handler ();
|
goto event_handle;
|
||||||
#else
|
#else
|
||||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||||
usb_lld_init (VCOM_FEATURE_BUS_POWERED);
|
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
chopstx_poll (NULL, 1, &usb_intr);
|
chopstx_intr_wait (&usb_intr);
|
||||||
if (usb_intr.ready)
|
if (usb_intr.ready)
|
||||||
usb_interrupt_handler ();
|
{
|
||||||
|
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);
|
||||||
|
chopstx_intr_done (&usb_intr);
|
||||||
|
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 = USB_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);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
if (t->device_state == CONFIGURED && t->flag_connected
|
if (t->device_state == USB_DEVICE_STATE_CONFIGURED && t->flag_connected
|
||||||
&& t->flag_send_ready)
|
&& t->flag_send_ready)
|
||||||
{
|
{
|
||||||
uint8_t line[32];
|
uint8_t line[32];
|
||||||
@@ -710,7 +824,7 @@ void
|
|||||||
tty_wait_configured (struct tty *t)
|
tty_wait_configured (struct tty *t)
|
||||||
{
|
{
|
||||||
chopstx_mutex_lock (&t->mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
while (t->device_state != CONFIGURED)
|
while (t->device_state != USB_DEVICE_STATE_CONFIGURED)
|
||||||
chopstx_cond_wait (&t->cnd, &t->mtx);
|
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
}
|
}
|
||||||
@@ -743,10 +857,10 @@ check_tx (struct tty *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
tty_send (struct tty *t, uint8_t *buf, int len)
|
tty_send (struct tty *t, const char *buf, int len)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint8_t *p;
|
const char *p;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
@@ -801,7 +915,7 @@ check_rx (void *arg)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
tty_recv (struct tty *t, uint8_t *buf, uint32_t *timeout)
|
tty_recv (struct tty *t, char *buf, uint32_t *timeout)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
chopstx_poll_cond_t poll_desc;
|
chopstx_poll_cond_t poll_desc;
|
||||||
@@ -815,7 +929,10 @@ tty_recv (struct tty *t, uint8_t *buf, uint32_t *timeout)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
chopstx_poll (timeout, 1, &poll_desc);
|
struct chx_poll_head *pd_array[1] = {
|
||||||
|
(struct chx_poll_head *)&poll_desc
|
||||||
|
};
|
||||||
|
chopstx_poll (timeout, 1, pd_array);
|
||||||
chopstx_mutex_lock (&t->mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
r = check_rx (t);
|
r = check_rx (t);
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
|
|||||||
43
example-fraucheky/EXAMPLE-README
Normal file
43
example-fraucheky/EXAMPLE-README
Normal 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.
|
||||||
62
example-fraucheky/INDEX.HTM
Normal file
62
example-fraucheky/INDEX.HTM
Normal 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>
|
||||||
45
example-fraucheky/Makefile
Normal file
45
example-fraucheky/Makefile
Normal 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 = yes
|
||||||
|
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
1
example-fraucheky/board.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../board/board-gnu-linux.h
|
||||||
2
example-fraucheky/config.h.in
Normal file
2
example-fraucheky/config.h.in
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@FRAUCHEKY_DEFINE@
|
||||||
|
@FRAUCHEKY_MSC_DEFINE@
|
||||||
137
example-fraucheky/configure
vendored
Executable file
137
example-fraucheky/configure
vendored
Executable 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
|
||||||
318
example-fraucheky/main.c
Normal file
318
example-fraucheky/main.c
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
#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 = USB_DEVICE_STATE_UNCONNECTED;
|
||||||
|
|
||||||
|
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_init (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);
|
||||||
|
|
||||||
|
/* Notify upper layer. */
|
||||||
|
chopstx_mutex_lock (&usb_mtx);
|
||||||
|
bDeviceState = USB_DEVICE_STATE_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 = USB_DEVICE_STATE_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 = USB_DEVICE_STATE_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 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);
|
||||||
|
chopstx_intr_done (&interrupt);
|
||||||
|
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 = USB_DEVICE_STATE_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 = USB_DEVICE_STATE_UNCONNECTED;
|
||||||
|
usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB,
|
||||||
|
usb_main, NULL);
|
||||||
|
fraucheky_init ();
|
||||||
|
while (bDeviceState != USB_DEVICE_STATE_CONFIGURED)
|
||||||
|
chopstx_usec_wait (250*1000);
|
||||||
|
fraucheky_main ();
|
||||||
|
chopstx_cancel (usb_thd);
|
||||||
|
chopstx_join (usb_thd, NULL);
|
||||||
|
usb_lld_shutdown ();
|
||||||
|
bDeviceState = USB_DEVICE_STATE_UNCONNECTED;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ PROJECT = sample
|
|||||||
|
|
||||||
CHOPSTX = ..
|
CHOPSTX = ..
|
||||||
LDSCRIPT= sample.ld
|
LDSCRIPT= sample.ld
|
||||||
CSRC = sample.c usb-cdc.c command.c
|
CSRC = sample.c usb-cdc.c command.c touch.c
|
||||||
CHIP=mkl27z
|
CHIP=mkl27z
|
||||||
|
|
||||||
USE_SYS = yes
|
USE_SYS = yes
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct command_table
|
|||||||
static void
|
static void
|
||||||
put_line (struct tty *tty, const char *line)
|
put_line (struct tty *tty, const char *line)
|
||||||
{
|
{
|
||||||
tty_send (tty, (uint8_t *)line, strlen (line));
|
tty_send (tty, line, strlen (line));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *help_string =
|
static const char *help_string =
|
||||||
@@ -51,7 +51,6 @@ static char hexchar (uint8_t x)
|
|||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DECIMAL_OUTPUT
|
|
||||||
static char *
|
static char *
|
||||||
compose_decimal (char *s, int value)
|
compose_decimal (char *s, int value)
|
||||||
{
|
{
|
||||||
@@ -87,7 +86,7 @@ compose_decimal (char *s, int value)
|
|||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
compose_hex (char *s, uint32_t v)
|
compose_hex (char *s, uint32_t v)
|
||||||
@@ -143,6 +142,68 @@ get_hex (struct tty *tty, const char *s, uint32_t *v_p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
static void
|
||||||
cmd_mdw (struct tty *tty, const char *line)
|
cmd_mdw (struct tty *tty, const char *line)
|
||||||
{
|
{
|
||||||
@@ -203,7 +264,7 @@ cmd_mdw (struct tty *tty, const char *line)
|
|||||||
|
|
||||||
*s++ = '\r';
|
*s++ = '\r';
|
||||||
*s++ = '\n';
|
*s++ = '\n';
|
||||||
tty_send (tty, (uint8_t *)output, s - output);
|
tty_send (tty, output, s - output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +387,7 @@ cmd_crc32 (struct tty *tty, const char *line)
|
|||||||
s = compose_hex (string, v);
|
s = compose_hex (string, v);
|
||||||
*s++ = '\r';
|
*s++ = '\r';
|
||||||
*s++ = '\n';
|
*s++ = '\n';
|
||||||
tty_send (tty, (uint8_t *)string, sizeof (string));
|
tty_send (tty, string, sizeof (string));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -369,7 +430,7 @@ cmd_adc (struct tty *tty, const char *line)
|
|||||||
{
|
{
|
||||||
*s++ = '\r';
|
*s++ = '\r';
|
||||||
*s++ = '\n';
|
*s++ = '\n';
|
||||||
tty_send (tty, (uint8_t *)output, s - output);
|
tty_send (tty, output, s - output);
|
||||||
s = output;
|
s = output;
|
||||||
if (i >= 64)
|
if (i >= 64)
|
||||||
break;
|
break;
|
||||||
@@ -393,14 +454,14 @@ cmd_sysinfo (struct tty *tty, const char *line)
|
|||||||
*s++ = sys_version[6];
|
*s++ = sys_version[6];
|
||||||
*s++ = '\r';
|
*s++ = '\r';
|
||||||
*s++ = '\n';
|
*s++ = '\n';
|
||||||
tty_send (tty, (uint8_t *)output, s - output);
|
tty_send (tty, output, s - output);
|
||||||
|
|
||||||
memcpy (output, "Board ID: ", 10);
|
memcpy (output, "Board ID: ", 10);
|
||||||
s = output + 10;
|
s = output + 10;
|
||||||
s = compose_hex (s, sys_board_id);
|
s = compose_hex (s, sys_board_id);
|
||||||
*s++ = '\r';
|
*s++ = '\r';
|
||||||
*s++ = '\n';
|
*s++ = '\n';
|
||||||
tty_send (tty, (uint8_t *)output, s - output);
|
tty_send (tty, output, s - output);
|
||||||
|
|
||||||
memcpy (output, "Board name: ", 12);
|
memcpy (output, "Board name: ", 12);
|
||||||
s = output + 12;
|
s = output + 12;
|
||||||
@@ -412,7 +473,7 @@ cmd_sysinfo (struct tty *tty, const char *line)
|
|||||||
|
|
||||||
*s++ = '\r';
|
*s++ = '\r';
|
||||||
*s++ = '\n';
|
*s++ = '\n';
|
||||||
tty_send (tty, (uint8_t *)output, s - output);
|
tty_send (tty, output, s - output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -425,6 +486,8 @@ cmd_help (struct tty *tty, const char *line)
|
|||||||
|
|
||||||
|
|
||||||
struct command_table command_table[] = {
|
struct command_table command_table[] = {
|
||||||
|
{ "button", cmd_button },
|
||||||
|
{ "touch", cmd_touch },
|
||||||
{ "mdw", cmd_mdw },
|
{ "mdw", cmd_mdw },
|
||||||
{ "mww", cmd_mww },
|
{ "mww", cmd_mww },
|
||||||
{ "fes", cmd_fes },
|
{ "fes", cmd_fes },
|
||||||
@@ -470,10 +533,10 @@ cmd_dispatch (struct tty *tty, const char *line)
|
|||||||
(*command_table[i].handler) (tty, p);
|
(*command_table[i].handler) (tty, p);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint8_t crlf[] = { '\r', '\n' };
|
char crlf[] = { '\r', '\n' };
|
||||||
|
|
||||||
put_line (tty, "No such command: ");
|
put_line (tty, "No such command: ");
|
||||||
tty_send (tty, (const uint8_t *)line, n);
|
tty_send (tty, line, n);
|
||||||
tty_send (tty, crlf, sizeof (crlf));
|
tty_send (tty, crlf, sizeof (crlf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const unsigned int *const crc32_table= (const unsigned int *const)0x00000480;
|
const unsigned int *const crc32_table= (const unsigned int *)0x00000480;
|
||||||
|
|
||||||
void
|
void
|
||||||
crc32_init (unsigned int *p)
|
crc32_init (unsigned int *p)
|
||||||
|
|||||||
@@ -7,27 +7,7 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
#include <sys.h>
|
||||||
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 GPIO *const GPIOB = (struct GPIO *const)0x400FF040;
|
|
||||||
static struct GPIO *const GPIOD = (struct GPIO *const)0x400FF0C0;
|
|
||||||
static struct GPIO *const GPIOE = (struct GPIO *const)0x400FF100;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
static chopstx_mutex_t mtx;
|
static chopstx_mutex_t mtx;
|
||||||
static chopstx_cond_t cnd0;
|
static chopstx_cond_t cnd0;
|
||||||
@@ -95,14 +75,14 @@ blk (void *arg)
|
|||||||
#define PRIO_PWM 3
|
#define PRIO_PWM 3
|
||||||
#define PRIO_BLK 2
|
#define PRIO_BLK 2
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||||
|
|
||||||
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
|
||||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
|
||||||
|
|
||||||
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
|
||||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
|
||||||
|
|
||||||
|
|
||||||
static char hexchar (uint8_t x)
|
static char hexchar (uint8_t x)
|
||||||
@@ -117,6 +97,8 @@ static char hexchar (uint8_t x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern void touch_init (void);
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, const char *argv[])
|
main (int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
@@ -132,8 +114,8 @@ main (int argc, const char *argv[])
|
|||||||
|
|
||||||
m = 10;
|
m = 10;
|
||||||
|
|
||||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
|
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||||
|
|
||||||
chopstx_usec_wait (200*1000);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
@@ -144,6 +126,8 @@ main (int argc, const char *argv[])
|
|||||||
|
|
||||||
u = 1;
|
u = 1;
|
||||||
|
|
||||||
|
touch_init ();
|
||||||
|
|
||||||
tty = tty_open ();
|
tty = tty_open ();
|
||||||
tty_wait_configured (tty);
|
tty_wait_configured (tty);
|
||||||
|
|
||||||
@@ -151,7 +135,7 @@ main (int argc, const char *argv[])
|
|||||||
m = 50;
|
m = 50;
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
uint8_t s[LINEBUFSIZE];
|
char s[LINEBUFSIZE];
|
||||||
|
|
||||||
connection_loop:
|
connection_loop:
|
||||||
u = 1;
|
u = 1;
|
||||||
@@ -175,7 +159,7 @@ main (int argc, const char *argv[])
|
|||||||
uint32_t usec;
|
uint32_t usec;
|
||||||
|
|
||||||
/* Prompt */
|
/* Prompt */
|
||||||
if (tty_send (tty, (uint8_t *)"> ", 2) < 0)
|
if (tty_send (tty, "> ", 2) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
usec = 3000000; /* 3.0 seconds */
|
usec = 3000000; /* 3.0 seconds */
|
||||||
|
|||||||
99
example-fs-bb48/touch.c
Normal file
99
example-fs-bb48/touch.c
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#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. */
|
||||||
|
|
||||||
|
chopstx_intr_done (&tpm1_intr);
|
||||||
|
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 ();
|
||||||
|
}
|
||||||
@@ -5,5 +5,5 @@ struct tty;
|
|||||||
struct tty *tty_open (void);
|
struct tty *tty_open (void);
|
||||||
void tty_wait_configured (struct tty *tty);
|
void tty_wait_configured (struct tty *tty);
|
||||||
void tty_wait_connection (struct tty *tty);
|
void tty_wait_connection (struct tty *tty);
|
||||||
int tty_send (struct tty *tty, const uint8_t *buf, int count);
|
int tty_send (struct tty *tty, const char *buf, int count);
|
||||||
int tty_recv (struct tty *tty, uint8_t *buf, uint32_t *timeout);
|
int tty_recv (struct tty *tty, char *buf, uint32_t *timeout);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static const struct line_coding line_coding0 = {
|
|||||||
*
|
*
|
||||||
* In that case, add argument to TTY_OPEN function and
|
* In that case, add argument to TTY_OPEN function and
|
||||||
* modify TTY_GET function to get the TTY structure. Functions which
|
* modify TTY_GET function to get the TTY structure. Functions which
|
||||||
* directy accesses TTY0 (usb_cb_device_reset and usb_cb_handle_event)
|
* directy accesses TTY0 (usb_device_reset and usb_set_configuration)
|
||||||
* should be modified, too.
|
* should be modified, too.
|
||||||
*
|
*
|
||||||
* Modification of TTY_MAIN thread will be also needed to echo back
|
* Modification of TTY_MAIN thread will be also needed to echo back
|
||||||
@@ -231,13 +231,13 @@ static const uint8_t vcom_string3[28] = {
|
|||||||
#define NUM_INTERFACES 2
|
#define NUM_INTERFACES 2
|
||||||
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_device_reset (void)
|
usb_device_reset (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
usb_lld_reset (VCOM_FEATURE_BUS_POWERED);
|
usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
|
||||||
|
|
||||||
/* Initialize Endpoint 0 */
|
/* Initialize Endpoint 0 */
|
||||||
usb_lld_setup_endp (ENDP0, 1, 1);
|
usb_lld_setup_endp (dev, ENDP0, 1, 1);
|
||||||
|
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
tty0.inputline_len = 0;
|
tty0.inputline_len = 0;
|
||||||
@@ -245,7 +245,7 @@ usb_cb_device_reset (void)
|
|||||||
tty0.flag_connected = 0;
|
tty0.flag_connected = 0;
|
||||||
tty0.flag_send_ready = 1;
|
tty0.flag_send_ready = 1;
|
||||||
tty0.flag_input_avail = 0;
|
tty0.flag_input_avail = 0;
|
||||||
tty0.device_state = ATTACHED;
|
tty0.device_state = USB_DEVICE_STATE_ATTACHED;
|
||||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
}
|
}
|
||||||
@@ -253,13 +253,15 @@ usb_cb_device_reset (void)
|
|||||||
|
|
||||||
#define CDC_CTRL_DTR 0x0001
|
#define CDC_CTRL_DTR 0x0001
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
|
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) && arg->index == 0
|
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
|
||||||
&& USB_SETUP_SET (req) && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
&& USB_SETUP_SET (arg->type)
|
||||||
|
&& arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (arg->index, 0);
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
@@ -272,60 +274,65 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vcom_port_data_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
|
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))
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (arg->index, 0);
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
|
if (arg->request == USB_CDC_REQ_GET_LINE_CODING)
|
||||||
return usb_lld_reply_request (&t->line_coding,
|
return usb_lld_ctrl_send (dev, &t->line_coding,
|
||||||
sizeof (struct line_coding), arg);
|
sizeof (struct line_coding));
|
||||||
}
|
}
|
||||||
else /* USB_SETUP_SET (req) */
|
else /* USB_SETUP_SET (req) */
|
||||||
{
|
{
|
||||||
if (req_no == USB_CDC_REQ_SET_LINE_CODING
|
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
|
||||||
&& arg->len == sizeof (struct line_coding))
|
&& arg->len == sizeof (struct line_coding))
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (arg->index, 0);
|
struct tty *t = tty_get (arg->index, 0);
|
||||||
|
|
||||||
usb_lld_set_data_to_recv (&t->line_coding,
|
return usb_lld_ctrl_recv (dev, &t->line_coding,
|
||||||
sizeof (struct line_coding));
|
sizeof (struct line_coding));
|
||||||
return USB_SUCCESS;
|
|
||||||
}
|
}
|
||||||
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||||
return USB_SUCCESS;
|
return usb_lld_ctrl_ack (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
|
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) && arg->index == 0)
|
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
|
||||||
return vcom_port_data_setup (req, req_no, arg);
|
return vcom_port_data_setup (dev);
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
|
usb_get_descriptor (struct usb_dev *dev)
|
||||||
struct req_args *arg)
|
|
||||||
{
|
{
|
||||||
|
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)
|
if (rcp != DEVICE_RECIPIENT)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
if (desc_type == DEVICE_DESCRIPTOR)
|
if (desc_type == DEVICE_DESCRIPTOR)
|
||||||
return usb_lld_reply_request (vcom_device_desc, sizeof (vcom_device_desc),
|
return usb_lld_ctrl_send (dev,
|
||||||
arg);
|
vcom_device_desc, sizeof (vcom_device_desc));
|
||||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||||
return usb_lld_reply_request (vcom_config_desc, sizeof (vcom_config_desc),
|
return usb_lld_ctrl_send (dev,
|
||||||
arg);
|
vcom_config_desc, sizeof (vcom_config_desc));
|
||||||
else if (desc_type == STRING_DESCRIPTOR)
|
else if (desc_type == STRING_DESCRIPTOR)
|
||||||
{
|
{
|
||||||
const uint8_t *str;
|
const uint8_t *str;
|
||||||
@@ -350,22 +357,23 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
|
|||||||
size = sizeof (vcom_string3);
|
size = sizeof (vcom_string3);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return usb_lld_reply_request (str, size, arg);
|
return usb_lld_ctrl_send (dev, str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
|
vcom_setup_endpoints_for_interface (struct usb_dev *dev,
|
||||||
|
uint16_t interface, int stop)
|
||||||
{
|
{
|
||||||
if (interface == 0)
|
if (interface == 0)
|
||||||
{
|
{
|
||||||
if (!stop)
|
if (!stop)
|
||||||
usb_lld_setup_endp (ENDP2, 0, 1);
|
usb_lld_setup_endp (dev, ENDP2, 0, 1);
|
||||||
else
|
else
|
||||||
usb_lld_stall (ENDP2);
|
usb_lld_stall (ENDP2);
|
||||||
}
|
}
|
||||||
@@ -373,8 +381,8 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
|
|||||||
{
|
{
|
||||||
if (!stop)
|
if (!stop)
|
||||||
{
|
{
|
||||||
usb_lld_setup_endp (ENDP1, 0, 1);
|
usb_lld_setup_endp (dev, ENDP1, 0, 1);
|
||||||
usb_lld_setup_endp (ENDP3, 1, 0);
|
usb_lld_setup_endp (dev, ENDP3, 1, 0);
|
||||||
/* Start with no data receiving (ENDP3 not enabled)*/
|
/* Start with no data receiving (ENDP3 not enabled)*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -385,83 +393,85 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_handle_event (uint8_t event_type, uint16_t value)
|
usb_set_configuration (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t current_conf;
|
uint8_t current_conf;
|
||||||
|
|
||||||
switch (event_type)
|
current_conf = usb_lld_current_configuration (dev);
|
||||||
{
|
|
||||||
case USB_EVENT_ADDRESS:
|
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
|
||||||
tty0.device_state = ADDRESSED;
|
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
|
||||||
return USB_SUCCESS;
|
|
||||||
case USB_EVENT_CONFIG:
|
|
||||||
current_conf = usb_lld_current_configuration ();
|
|
||||||
if (current_conf == 0)
|
if (current_conf == 0)
|
||||||
{
|
{
|
||||||
if (value != 1)
|
if (dev->dev_req.value != 1)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
usb_lld_set_configuration (1);
|
usb_lld_set_configuration (dev, 1);
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
for (i = 0; i < NUM_INTERFACES; i++)
|
||||||
vcom_setup_endpoints_for_interface (i, 0);
|
vcom_setup_endpoints_for_interface (dev, i, 0);
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
tty0.device_state = CONFIGURED;
|
tty0.device_state = USB_DEVICE_STATE_CONFIGURED;
|
||||||
|
chopstx_cond_signal (&tty0.cnd);
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
}
|
}
|
||||||
else if (current_conf != value)
|
else if (current_conf != dev->dev_req.value)
|
||||||
{
|
{
|
||||||
if (value != 0)
|
if (dev->dev_req.value != 0)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
usb_lld_set_configuration (0);
|
usb_lld_set_configuration (dev, 0);
|
||||||
for (i = 0; i < NUM_INTERFACES; i++)
|
for (i = 0; i < NUM_INTERFACES; i++)
|
||||||
vcom_setup_endpoints_for_interface (i, 1);
|
vcom_setup_endpoints_for_interface (dev, i, 1);
|
||||||
chopstx_mutex_lock (&tty0.mtx);
|
chopstx_mutex_lock (&tty0.mtx);
|
||||||
tty0.device_state = ADDRESSED;
|
tty0.device_state = USB_DEVICE_STATE_ADDRESSED;
|
||||||
|
chopstx_cond_signal (&tty0.cnd);
|
||||||
chopstx_mutex_unlock (&tty0.mtx);
|
chopstx_mutex_unlock (&tty0.mtx);
|
||||||
}
|
}
|
||||||
/* Do nothing when current_conf == value */
|
|
||||||
return USB_SUCCESS;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return USB_UNSUPPORT;
|
return usb_lld_ctrl_ack (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static int
|
||||||
usb_cb_interface (uint8_t cmd, struct req_args *arg)
|
usb_set_interface (struct usb_dev *dev)
|
||||||
{
|
{
|
||||||
const uint8_t zero = 0;
|
uint16_t interface = dev->dev_req.index;
|
||||||
uint16_t interface = arg->index;
|
uint16_t alt = dev->dev_req.value;
|
||||||
uint16_t alt = arg->value;
|
|
||||||
|
|
||||||
if (interface >= NUM_INTERFACES)
|
if (interface >= NUM_INTERFACES)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
|
|
||||||
switch (cmd)
|
|
||||||
{
|
|
||||||
case USB_SET_INTERFACE:
|
|
||||||
if (alt != 0)
|
if (alt != 0)
|
||||||
return USB_UNSUPPORT;
|
return -1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vcom_setup_endpoints_for_interface (interface, 0);
|
vcom_setup_endpoints_for_interface (dev, interface, 0);
|
||||||
return USB_SUCCESS;
|
return usb_lld_ctrl_ack (dev);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case USB_GET_INTERFACE:
|
static int
|
||||||
return usb_lld_reply_request (&zero, 1, arg);
|
usb_get_interface (struct usb_dev *dev)
|
||||||
|
{
|
||||||
|
const uint8_t zero = 0;
|
||||||
|
uint16_t interface = dev->dev_req.index;
|
||||||
|
|
||||||
default:
|
if (interface >= NUM_INTERFACES)
|
||||||
case USB_QUERY_INTERFACE:
|
return -1;
|
||||||
return USB_SUCCESS;
|
|
||||||
}
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -511,8 +521,8 @@ tty_echo_char (struct tty *t, int c)
|
|||||||
put_char_to_ringbuffer (t, c);
|
put_char_to_ringbuffer (t, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_tx_done (uint8_t ep_num, uint32_t len)
|
usb_tx_done (uint8_t ep_num, uint16_t len)
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (-1, ep_num);
|
struct tty *t = tty_get (-1, ep_num);
|
||||||
|
|
||||||
@@ -594,17 +604,16 @@ tty_input_char (struct tty *t, int c)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
usb_cb_rx_ready (uint8_t ep_num)
|
usb_rx_ready (uint8_t ep_num, uint16_t len)
|
||||||
{
|
{
|
||||||
struct tty *t = tty_get (-1, ep_num);
|
struct tty *t = tty_get (-1, ep_num);
|
||||||
|
|
||||||
if (ep_num == ENDP3)
|
if (ep_num == ENDP3)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i;
|
||||||
|
|
||||||
r = usb_lld_rx_data_len (ENDP3);
|
for (i = 0; i < len; i++)
|
||||||
for (i = 0; i < r; i++)
|
|
||||||
if (tty_input_char (t, t->recv_buf0[i]))
|
if (tty_input_char (t, t->recv_buf0[i]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -617,12 +626,11 @@ usb_cb_rx_ready (uint8_t ep_num)
|
|||||||
|
|
||||||
static void *tty_main (void *arg);
|
static void *tty_main (void *arg);
|
||||||
|
|
||||||
#define INTR_REQ_USB 24
|
|
||||||
#define PRIO_TTY 4
|
#define PRIO_TTY 4
|
||||||
|
|
||||||
extern uint8_t __process3_stack_base__, __process3_stack_size__;
|
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
|
||||||
const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__;
|
#define STACK_ADDR_TTY ((uint32_t)__process3_stack_base__)
|
||||||
const size_t __stacksize_tty = (size_t)&__process3_stack_size__;
|
#define STACK_SIZE_TTY ((uint32_t)__process3_stack_size__)
|
||||||
|
|
||||||
struct tty *
|
struct tty *
|
||||||
tty_open (void)
|
tty_open (void)
|
||||||
@@ -634,10 +642,10 @@ tty_open (void)
|
|||||||
tty0.flag_connected = 0;
|
tty0.flag_connected = 0;
|
||||||
tty0.flag_send_ready = 1;
|
tty0.flag_send_ready = 1;
|
||||||
tty0.flag_input_avail = 0;
|
tty0.flag_input_avail = 0;
|
||||||
tty0.device_state = UNCONNECTED;
|
tty0.device_state = USB_DEVICE_STATE_UNCONNECTED;
|
||||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||||
|
|
||||||
chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0);
|
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
|
||||||
return &tty0;
|
return &tty0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,6 +654,8 @@ static void *
|
|||||||
tty_main (void *arg)
|
tty_main (void *arg)
|
||||||
{
|
{
|
||||||
struct tty *t = arg;
|
struct tty *t = arg;
|
||||||
|
struct usb_dev dev;
|
||||||
|
int e;
|
||||||
|
|
||||||
#if defined(OLDER_SYS_H)
|
#if defined(OLDER_SYS_H)
|
||||||
/*
|
/*
|
||||||
@@ -654,9 +664,9 @@ tty_main (void *arg)
|
|||||||
*
|
*
|
||||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||||
* invocation of usb_interrupt_handler won't occur.
|
* invocation of usb_lld_event_handler won't occur.
|
||||||
*
|
*
|
||||||
* Calling usb_interrupt_handler is no harm even if there were no
|
* Calling usb_lld_event_handler is no harm even if there were no
|
||||||
* interrupts, thus, we call it unconditionally here, just in case
|
* interrupts, thus, we call it unconditionally here, just in case
|
||||||
* if there is a request.
|
* if there is a request.
|
||||||
*
|
*
|
||||||
@@ -665,22 +675,121 @@ tty_main (void *arg)
|
|||||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
usb_lld_init (VCOM_FEATURE_BUS_POWERED);
|
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||||
usb_interrupt_handler ();
|
goto event_handle;
|
||||||
#else
|
#else
|
||||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||||
usb_lld_init (VCOM_FEATURE_BUS_POWERED);
|
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
chopstx_poll (NULL, 1, &usb_intr);
|
struct chx_poll_head *pd_array[1] = {
|
||||||
|
(struct chx_poll_head *)&usb_intr
|
||||||
|
};
|
||||||
|
chopstx_poll (NULL, 1, pd_array);
|
||||||
if (usb_intr.ready)
|
if (usb_intr.ready)
|
||||||
usb_interrupt_handler ();
|
{
|
||||||
|
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);
|
||||||
|
chopstx_intr_done (&usb_intr);
|
||||||
|
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 = USB_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);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
if (t->device_state == CONFIGURED && t->flag_connected
|
if (t->device_state == USB_DEVICE_STATE_CONFIGURED && t->flag_connected
|
||||||
&& t->flag_send_ready)
|
&& t->flag_send_ready)
|
||||||
{
|
{
|
||||||
uint8_t line[32];
|
uint8_t line[32];
|
||||||
@@ -704,7 +813,7 @@ void
|
|||||||
tty_wait_configured (struct tty *t)
|
tty_wait_configured (struct tty *t)
|
||||||
{
|
{
|
||||||
chopstx_mutex_lock (&t->mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
while (t->device_state != CONFIGURED)
|
while (t->device_state != USB_DEVICE_STATE_CONFIGURED)
|
||||||
chopstx_cond_wait (&t->cnd, &t->mtx);
|
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
}
|
}
|
||||||
@@ -720,8 +829,7 @@ tty_wait_connection (struct tty *t)
|
|||||||
t->flag_input_avail = 0;
|
t->flag_input_avail = 0;
|
||||||
t->send_head = t->send_tail = 0;
|
t->send_head = t->send_tail = 0;
|
||||||
t->inputline_len = 0;
|
t->inputline_len = 0;
|
||||||
/* Accept input for line */
|
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64); /* Accept input for line */
|
||||||
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64);
|
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,10 +846,10 @@ check_tx (struct tty *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
tty_send (struct tty *t, const uint8_t *buf, int len)
|
tty_send (struct tty *t, const char *buf, int len)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
const uint8_t *p;
|
const char *p;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
@@ -800,7 +908,7 @@ check_rx (void *arg)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
tty_recv (struct tty *t, uint8_t *buf, uint32_t *timeout)
|
tty_recv (struct tty *t, char *buf, uint32_t *timeout)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
chopstx_poll_cond_t poll_desc;
|
chopstx_poll_cond_t poll_desc;
|
||||||
@@ -814,7 +922,10 @@ tty_recv (struct tty *t, uint8_t *buf, uint32_t *timeout)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
chopstx_poll (timeout, 1, &poll_desc);
|
struct chx_poll_head *pd_array[1] = {
|
||||||
|
(struct chx_poll_head *)&poll_desc
|
||||||
|
};
|
||||||
|
chopstx_poll (timeout, 1, pd_array);
|
||||||
chopstx_mutex_lock (&t->mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
r = check_rx (t);
|
r = check_rx (t);
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ LDSCRIPT= hacker-emblem.ld
|
|||||||
|
|
||||||
CSRC = reset.c hh.c
|
CSRC = reset.c hh.c
|
||||||
|
|
||||||
|
CHIP=stm32f0
|
||||||
|
|
||||||
# Hacker Emblem and "Happy Hacking!" demonstration
|
# Hacker Emblem and "Happy Hacking!" demonstration
|
||||||
# CSRC = reset.c hh.c
|
# CSRC = reset.c hh.c
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@ OBJCOPY = $(CROSS)objcopy
|
|||||||
MCU = cortex-m0 # -save-temps
|
MCU = cortex-m0 # -save-temps
|
||||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||||
DEFS = -DMAKE_ENTRY_PUBLIC \
|
DEFS = -DMAKE_ENTRY_PUBLIC \
|
||||||
-DFREE_STANDING -DMHZ=48 -DUSE_WFI_FOR_IDLE
|
-DFREE_STANDING -DMHZ=48
|
||||||
OPT = -O3 -Os -g
|
OPT = -O3 -Os -g
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
static uint8_t main_finished;
|
static uint8_t main_finished;
|
||||||
|
|
||||||
#define PERIPH_BASE 0x40000000
|
#define PERIPH_BASE 0x40000000
|
||||||
#define APBPERIPH_BASE PERIPH_BASE
|
#define APB1PERIPH_BASE PERIPH_BASE
|
||||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||||
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
||||||
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
||||||
@@ -34,8 +34,8 @@ struct GPIO {
|
|||||||
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
|
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
|
||||||
#define GPIOF ((struct GPIO *) GPIOF_BASE)
|
#define GPIOF ((struct GPIO *) GPIOF_BASE)
|
||||||
|
|
||||||
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
|
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
|
||||||
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
|
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
|
||||||
|
|
||||||
static chopstx_mutex_t mtx;
|
static chopstx_mutex_t mtx;
|
||||||
static chopstx_cond_t cnd0, cnd1;
|
static chopstx_cond_t cnd0, cnd1;
|
||||||
@@ -163,17 +163,19 @@ button (void *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define STACK_MAIN
|
||||||
|
#define STACK_PROCESS_1
|
||||||
|
#define STACK_PROCESS_2
|
||||||
|
#include "stack-def.h"
|
||||||
|
|
||||||
#define PRIO_LED 3
|
#define PRIO_LED 3
|
||||||
#define PRIO_BUTTON 2
|
#define PRIO_BUTTON 2
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
#define STACK_ADDR_LED ((uint32_t)process1_base)
|
||||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
#define STACK_SIZE_LED (sizeof process1_base)
|
||||||
|
|
||||||
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
|
#define STACK_ADDR_BUTTON ((uint32_t)process2_base)
|
||||||
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
|
#define STACK_SIZE_BUTTON (sizeof process2_base)
|
||||||
|
|
||||||
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
|
|
||||||
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
|
|
||||||
|
|
||||||
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
|
#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))
|
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
|
||||||
@@ -365,8 +367,6 @@ text_display (uint8_t kind)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void setup_scr_sleepdeep (void);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, const char *argv[])
|
main (int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
@@ -378,14 +378,16 @@ main (int argc, const char *argv[])
|
|||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
|
chopstx_conf_idle (1);
|
||||||
|
|
||||||
chopstx_mutex_init (&mtx);
|
chopstx_mutex_init (&mtx);
|
||||||
chopstx_cond_init (&cnd0);
|
chopstx_cond_init (&cnd0);
|
||||||
chopstx_cond_init (&cnd1);
|
chopstx_cond_init (&cnd1);
|
||||||
|
|
||||||
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
|
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
|
||||||
__stacksize_led, led, NULL);
|
STACK_SIZE_LED, led, NULL);
|
||||||
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
|
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
|
||||||
__stacksize_button, button, NULL);
|
STACK_SIZE_BUTTON, button, NULL);
|
||||||
|
|
||||||
chopstx_usec_wait (200*1000);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
@@ -418,56 +420,6 @@ main (int argc, const char *argv[])
|
|||||||
chopstx_join (button_thd, NULL);
|
chopstx_join (button_thd, NULL);
|
||||||
chopstx_join (led_thd, NULL);
|
chopstx_join (led_thd, NULL);
|
||||||
|
|
||||||
setup_scr_sleepdeep ();
|
chopstx_conf_idle (4);
|
||||||
for (;;)
|
|
||||||
asm volatile ("wfi" : : : "memory");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 SCB_SCR_SLEEPDEEP (1 << 2)
|
|
||||||
|
|
||||||
struct PWR
|
|
||||||
{
|
|
||||||
volatile uint32_t CR;
|
|
||||||
volatile uint32_t CSR;
|
|
||||||
};
|
|
||||||
#define PWR_CR_PDDS 0x0002
|
|
||||||
#define PWR_CR_CWUF 0x0004
|
|
||||||
|
|
||||||
#define PWR_BASE (APBPERIPH_BASE + 0x00007000)
|
|
||||||
#define PWR ((struct PWR *) PWR_BASE)
|
|
||||||
|
|
||||||
static void setup_scr_sleepdeep (void)
|
|
||||||
{
|
|
||||||
PWR->CR |= PWR_CR_CWUF;
|
|
||||||
PWR->CR |= PWR_CR_PDDS;
|
|
||||||
SCB->SCR |= SCB_SCR_SLEEPDEEP;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ST32F0 memory setup.
|
* ST32F0 memory setup.
|
||||||
*/
|
*/
|
||||||
__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 */
|
|
||||||
__process3_stack_size__ = 0x0100; /* third thread program */
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash : org = 0x08000000, len = 16k
|
flash : org = 0x08000000, len = 16k
|
||||||
@@ -61,34 +55,15 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
_textdata = _etext;
|
_textdata = _etext;
|
||||||
|
|
||||||
.process_stack :
|
.stacks (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
__process3_stack_base__ = .;
|
*(.main_stack)
|
||||||
. += __process3_stack_size__;
|
*(.process_stack.0)
|
||||||
|
*(.process_stack.1)
|
||||||
|
*(.process_stack.2)
|
||||||
|
*(.process_stack.3)
|
||||||
. = ALIGN(8);
|
. = 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
|
} > ram
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
static uint8_t main_finished;
|
static uint8_t main_finished;
|
||||||
|
|
||||||
#define PERIPH_BASE 0x40000000
|
#define PERIPH_BASE 0x40000000
|
||||||
#define APBPERIPH_BASE PERIPH_BASE
|
#define APB1PERIPH_BASE PERIPH_BASE
|
||||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||||
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
||||||
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
||||||
@@ -34,8 +34,8 @@ struct GPIO {
|
|||||||
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
|
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
|
||||||
#define GPIOF ((struct GPIO *) GPIOF_BASE)
|
#define GPIOF ((struct GPIO *) GPIOF_BASE)
|
||||||
|
|
||||||
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
|
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
|
||||||
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
|
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
|
||||||
|
|
||||||
static chopstx_mutex_t mtx;
|
static chopstx_mutex_t mtx;
|
||||||
static chopstx_cond_t cnd0, cnd1;
|
static chopstx_cond_t cnd0, cnd1;
|
||||||
@@ -166,14 +166,16 @@ button (void *arg)
|
|||||||
#define PRIO_LED 3
|
#define PRIO_LED 3
|
||||||
#define PRIO_BUTTON 2
|
#define PRIO_BUTTON 2
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
#define STACK_MAIN
|
||||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
#define STACK_PROCESS_1
|
||||||
|
#define STACK_PROCESS_2
|
||||||
|
#include "stack-def.h"
|
||||||
|
|
||||||
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
|
#define STACK_ADDR_LED ((uint32_t)process1_base)
|
||||||
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
|
#define STACK_SIZE_LED (sizeof process1_base)
|
||||||
|
|
||||||
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
|
#define STACK_ADDR_BUTTON ((uint32_t)process2_base)
|
||||||
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
|
#define STACK_SIZE_BUTTON (sizeof process2_base)
|
||||||
|
|
||||||
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
|
#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))
|
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
|
||||||
@@ -355,8 +357,6 @@ text_display (uint8_t kind)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void setup_scr_sleepdeep (void);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, const char *argv[])
|
main (int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
@@ -366,14 +366,16 @@ main (int argc, const char *argv[])
|
|||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
|
chopstx_conf_idle (1);
|
||||||
|
|
||||||
chopstx_mutex_init (&mtx);
|
chopstx_mutex_init (&mtx);
|
||||||
chopstx_cond_init (&cnd0);
|
chopstx_cond_init (&cnd0);
|
||||||
chopstx_cond_init (&cnd1);
|
chopstx_cond_init (&cnd1);
|
||||||
|
|
||||||
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
|
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
|
||||||
__stacksize_led, led, NULL);
|
STACK_SIZE_LED, led, NULL);
|
||||||
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
|
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
|
||||||
__stacksize_button, button, NULL);
|
STACK_SIZE_BUTTON, button, NULL);
|
||||||
|
|
||||||
chopstx_usec_wait (200*1000);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
@@ -406,56 +408,6 @@ main (int argc, const char *argv[])
|
|||||||
chopstx_join (button_thd, NULL);
|
chopstx_join (button_thd, NULL);
|
||||||
chopstx_join (led_thd, NULL);
|
chopstx_join (led_thd, NULL);
|
||||||
|
|
||||||
setup_scr_sleepdeep ();
|
chopstx_conf_idle (4);
|
||||||
for (;;)
|
|
||||||
asm volatile ("wfi" : : : "memory");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 SCB_SCR_SLEEPDEEP (1 << 2)
|
|
||||||
|
|
||||||
struct PWR
|
|
||||||
{
|
|
||||||
volatile uint32_t CR;
|
|
||||||
volatile uint32_t CSR;
|
|
||||||
};
|
|
||||||
#define PWR_CR_PDDS 0x0002
|
|
||||||
#define PWR_CR_CWUF 0x0004
|
|
||||||
|
|
||||||
#define PWR_BASE (APBPERIPH_BASE + 0x00007000)
|
|
||||||
#define PWR ((struct PWR *) PWR_BASE)
|
|
||||||
|
|
||||||
static void setup_scr_sleepdeep (void)
|
|
||||||
{
|
|
||||||
PWR->CR |= PWR_CR_CWUF;
|
|
||||||
PWR->CR |= PWR_CR_PDDS;
|
|
||||||
SCB->SCR |= SCB_SCR_SLEEPDEEP;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
#define PERIPH_BASE 0x40000000
|
#define PERIPH_BASE 0x40000000
|
||||||
#define APBPERIPH_BASE PERIPH_BASE
|
#define APB1PERIPH_BASE PERIPH_BASE
|
||||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||||
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
||||||
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
||||||
@@ -35,8 +35,8 @@ struct GPIO {
|
|||||||
|
|
||||||
#define GPIO_SPEAKER_PIN 1
|
#define GPIO_SPEAKER_PIN 1
|
||||||
|
|
||||||
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
|
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
|
||||||
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
|
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
|
||||||
|
|
||||||
static chopstx_mutex_t mtx;
|
static chopstx_mutex_t mtx;
|
||||||
static chopstx_cond_t cnd;
|
static chopstx_cond_t cnd;
|
||||||
@@ -86,12 +86,16 @@ led_enable_column (uint8_t col)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define STACK_MAIN
|
||||||
|
#define STACK_PROCESS_1
|
||||||
|
#define STACK_PROCESS_2
|
||||||
|
#define STACK_PROCESS_3
|
||||||
|
#include "stack-def.h"
|
||||||
|
|
||||||
#define PRIO_LED 3
|
#define PRIO_LED 3
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
#define STACK_ADDR_LED ((uint32_t)process1_base)
|
||||||
|
#define STACK_SIZE_LED (sizeof process1_base)
|
||||||
const uint32_t stackaddr_led = (uint32_t)&__process1_stack_base__;
|
|
||||||
const size_t stacksize_led = (size_t)&__process1_stack_size__;
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
led (void *arg)
|
led (void *arg)
|
||||||
@@ -119,10 +123,9 @@ led (void *arg)
|
|||||||
|
|
||||||
|
|
||||||
#define PRIO_SPK 4
|
#define PRIO_SPK 4
|
||||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
|
||||||
|
|
||||||
const uint32_t stackaddr_spk = (uint32_t)&__process2_stack_base__;
|
#define STACK_ADDR_SPK ((uint32_t)process2_base)
|
||||||
const size_t stacksize_spk = (size_t)&__process2_stack_size__;
|
#define STACK_SIZE_SPK (sizeof process2_base)
|
||||||
|
|
||||||
static chopstx_mutex_t spk_mtx;
|
static chopstx_mutex_t spk_mtx;
|
||||||
static chopstx_cond_t spk_cnd;
|
static chopstx_cond_t spk_cnd;
|
||||||
@@ -193,10 +196,9 @@ spk (void *arg)
|
|||||||
|
|
||||||
|
|
||||||
#define PRIO_MUSIC 2
|
#define PRIO_MUSIC 2
|
||||||
extern uint8_t __process3_stack_base__, __process3_stack_size__;
|
|
||||||
|
|
||||||
const uint32_t stackaddr_music = (uint32_t)&__process3_stack_base__;
|
#define STACK_ADDR_MUSIC ((uint32_t)process3_base)
|
||||||
const size_t stacksize_music = (size_t)&__process3_stack_size__;
|
#define STACK_SIZE_MUSIC (sizeof process3_base)
|
||||||
|
|
||||||
#define C 0
|
#define C 0
|
||||||
#define D 1
|
#define D 1
|
||||||
@@ -254,7 +256,7 @@ music (void *arg)
|
|||||||
chopstx_cond_init (&spk_cnd);
|
chopstx_cond_init (&spk_cnd);
|
||||||
chopstx_cond_init (&spk_cnd_no_tone);
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
@@ -350,8 +352,8 @@ main (int argc, const char *argv[])
|
|||||||
chopstx_mutex_init (&mtx);
|
chopstx_mutex_init (&mtx);
|
||||||
chopstx_cond_init (&cnd);
|
chopstx_cond_init (&cnd);
|
||||||
|
|
||||||
chopstx_create (PRIO_LED, stackaddr_led, stacksize_led, led, NULL);
|
chopstx_create (PRIO_LED, STACK_ADDR_LED, STACK_SIZE_LED, led, NULL);
|
||||||
chopstx_create (PRIO_MUSIC, stackaddr_music, stacksize_music, music, NULL);
|
chopstx_create (PRIO_MUSIC, STACK_ADDR_MUSIC, STACK_SIZE_MUSIC, music, NULL);
|
||||||
|
|
||||||
chopstx_usec_wait (200*1000);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
|
|||||||
54
example-fsm-55/stack-def.h
Normal file
54
example-fsm-55/stack-def.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#define MAIN_SIZE 0x0080 /* Idle+Exception handlers */
|
||||||
|
#define SIZE_0 0x0100 /* Main program */
|
||||||
|
#define SIZE_1 0x0100 /* first thread program */
|
||||||
|
#define SIZE_2 0x0100 /* second thread program */
|
||||||
|
#define SIZE_3 0x0100 /* third thread program */
|
||||||
|
|
||||||
|
#if defined(STACK_MAIN)
|
||||||
|
/*
|
||||||
|
* The terminology of "main" is confusing in ARM architecture.
|
||||||
|
* Here, "main_base" is for exception handlers.
|
||||||
|
*/
|
||||||
|
/* Idle+Exception handlers */
|
||||||
|
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
|
||||||
|
char main_base[MAIN_SIZE] __attribute__ ((section(".main_stack")));
|
||||||
|
|
||||||
|
/* Main program */
|
||||||
|
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
|
||||||
|
char process0_base[SIZE_0] __attribute__ ((section(".process_stack.0")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* First thread program */
|
||||||
|
#if defined(STACK_PROCESS_1)
|
||||||
|
char process1_base[SIZE_1] __attribute__ ((section(".process_stack.1")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Second thread program */
|
||||||
|
#if defined(STACK_PROCESS_2)
|
||||||
|
char process2_base[SIZE_2] __attribute__ ((section(".process_stack.2")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Third thread program */
|
||||||
|
#if defined(STACK_PROCESS_3)
|
||||||
|
char process3_base[SIZE_3] __attribute__ ((section(".process_stack.3")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fourth thread program */
|
||||||
|
#if defined(STACK_PROCESS_4)
|
||||||
|
char process4_base[SIZE_4] __attribute__ ((section(".process_stack.4")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fifth thread program */
|
||||||
|
#if defined(STACK_PROCESS_5)
|
||||||
|
char process5_base[SIZE_5] __attribute__ ((section(".process_stack.5")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sixth thread program */
|
||||||
|
#if defined(STACK_PROCESS_6)
|
||||||
|
char process6_base[SIZE_6] __attribute__ ((section(".process_stack.6")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Seventh thread program */
|
||||||
|
#if defined(STACK_PROCESS_7)
|
||||||
|
char process7_base[SIZE_7] __attribute__ ((section(".process_stack.7")));
|
||||||
|
#endif
|
||||||
@@ -10,7 +10,7 @@ LDSCRIPT= sample.ld
|
|||||||
### LDSCRIPT= sample.ld.m3
|
### LDSCRIPT= sample.ld.m3
|
||||||
CSRC = sample.c
|
CSRC = sample.c
|
||||||
|
|
||||||
CHIP=stm32f030
|
CHIP=stm32f0
|
||||||
USE_SYS = yes
|
USE_SYS = yes
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
|
|||||||
@@ -72,14 +72,17 @@ blk (void *arg)
|
|||||||
#define PRIO_BLK 2
|
#define PRIO_BLK 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
#define STACK_MAIN
|
||||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
#define STACK_PROCESS_1
|
||||||
|
#define STACK_PROCESS_2
|
||||||
|
#include "stack-def.h"
|
||||||
|
|
||||||
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
|
||||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
|
||||||
|
|
||||||
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
#define STACK_ADDR_PWM ((uint32_t)process1_base)
|
||||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
#define STACK_SIZE_PWM (sizeof process1_base)
|
||||||
|
|
||||||
|
#define STACK_ADDR_BLK ((uint32_t)process2_base)
|
||||||
|
#define STACK_SIZE_BLK (sizeof process2_base)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -94,8 +97,8 @@ main (int argc, const char *argv[])
|
|||||||
|
|
||||||
m = 10;
|
m = 10;
|
||||||
|
|
||||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
|
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||||
|
|
||||||
chopstx_usec_wait (200*1000);
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ST32F0 memory setup.
|
* ST32F0 memory setup.
|
||||||
*/
|
*/
|
||||||
__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 */
|
|
||||||
__process3_stack_size__ = 0x0100; /* third thread program */
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash0 : org = 0x08000000, len = 4k
|
flash0 : org = 0x08000000, len = 4k
|
||||||
@@ -87,34 +81,15 @@ SECTIONS
|
|||||||
KEEP(*(.bss.startup.*))
|
KEEP(*(.bss.startup.*))
|
||||||
} > ram
|
} > ram
|
||||||
|
|
||||||
.process_stack :
|
.stacks (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
__process3_stack_base__ = .;
|
*(.main_stack)
|
||||||
. += __process3_stack_size__;
|
*(.process_stack.0)
|
||||||
|
*(.process_stack.1)
|
||||||
|
*(.process_stack.2)
|
||||||
|
*(.process_stack.3)
|
||||||
. = ALIGN(8);
|
. = 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
|
} > ram
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* ST32F103 memory setup.
|
* ST32F103 memory setup.
|
||||||
*/
|
*/
|
||||||
__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 */
|
|
||||||
__process3_stack_size__ = 0x0100; /* third thread program */
|
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash0 : org = 0x08000000, len = 4k
|
flash0 : org = 0x08000000, len = 4k
|
||||||
@@ -78,34 +72,14 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
_textdata = _etext;
|
_textdata = _etext;
|
||||||
|
|
||||||
.process_stack :
|
.stacks (NOLOAD) :
|
||||||
{
|
{
|
||||||
|
*(.main_stack)
|
||||||
|
*(.process_stack.0)
|
||||||
|
*(.process_stack.1)
|
||||||
|
*(.process_stack.2)
|
||||||
|
*(.process_stack.3)
|
||||||
. = ALIGN(8);
|
. = 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
|
} > ram
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
|
|||||||
53
example-led/stack-def.h
Normal file
53
example-led/stack-def.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#define MAIN_SIZE 0x0080 /* Idle+Exception handlers */
|
||||||
|
#define SIZE_0 0x0100 /* Main program */
|
||||||
|
#define SIZE_1 0x0100 /* first thread program */
|
||||||
|
#define SIZE_2 0x0100 /* second thread program */
|
||||||
|
|
||||||
|
#if defined(STACK_MAIN)
|
||||||
|
/*
|
||||||
|
* The terminology of "main" is confusing in ARM architecture.
|
||||||
|
* Here, "main_base" is for exception handlers.
|
||||||
|
*/
|
||||||
|
/* Idle+Exception handlers */
|
||||||
|
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
|
||||||
|
char main_base[MAIN_SIZE] __attribute__ ((section(".main_stack")));
|
||||||
|
|
||||||
|
/* Main program */
|
||||||
|
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
|
||||||
|
char process0_base[SIZE_0] __attribute__ ((section(".process_stack.0")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* First thread program */
|
||||||
|
#if defined(STACK_PROCESS_1)
|
||||||
|
char process1_base[SIZE_1] __attribute__ ((section(".process_stack.1")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Second thread program */
|
||||||
|
#if defined(STACK_PROCESS_2)
|
||||||
|
char process2_base[SIZE_2] __attribute__ ((section(".process_stack.2")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Third thread program */
|
||||||
|
#if defined(STACK_PROCESS_3)
|
||||||
|
char process3_base[SIZE_3] __attribute__ ((section(".process_stack.3")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fourth thread program */
|
||||||
|
#if defined(STACK_PROCESS_4)
|
||||||
|
char process4_base[SIZE_4] __attribute__ ((section(".process_stack.4")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fifth thread program */
|
||||||
|
#if defined(STACK_PROCESS_5)
|
||||||
|
char process5_base[SIZE_5] __attribute__ ((section(".process_stack.5")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sixth thread program */
|
||||||
|
#if defined(STACK_PROCESS_6)
|
||||||
|
char process6_base[SIZE_6] __attribute__ ((section(".process_stack.6")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Seventh thread program */
|
||||||
|
#if defined(STACK_PROCESS_7)
|
||||||
|
char process7_base[SIZE_7] __attribute__ ((section(".process_stack.7")));
|
||||||
|
#endif
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
#define PERIPH_BASE 0x40000000
|
#define PERIPH_BASE 0x40000000
|
||||||
#define APBPERIPH_BASE PERIPH_BASE
|
#define APB1PERIPH_BASE PERIPH_BASE
|
||||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||||
|
|
||||||
struct GPIO {
|
struct GPIO {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
#define PERIPH_BASE 0x40000000
|
#define PERIPH_BASE 0x40000000
|
||||||
#define APBPERIPH_BASE PERIPH_BASE
|
#define APB1PERIPH_BASE PERIPH_BASE
|
||||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||||
|
|
||||||
struct GPIO {
|
struct GPIO {
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ void adc3_conversion (uint32_t *result)
|
|||||||
/* Stop conversion. */
|
/* Stop conversion. */
|
||||||
ADC3->CR2 &= ~ADC_CR2_JSWSTART;
|
ADC3->CR2 &= ~ADC_CR2_JSWSTART;
|
||||||
|
|
||||||
|
#if USE_ADC3_INTR
|
||||||
|
chopstx_intr_done (&adc3_intr);
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
example-usb-serial/Makefile
Normal file
37
example-usb-serial/Makefile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Makefile for example application of Chopstx
|
||||||
|
|
||||||
|
PROJECT = sample
|
||||||
|
|
||||||
|
CHOPSTX = ..
|
||||||
|
LDSCRIPT= sample.ld
|
||||||
|
CSRC = sample.c usb-cdc.c
|
||||||
|
|
||||||
|
CHIP=stm32f103
|
||||||
|
|
||||||
|
USE_SYS = yes
|
||||||
|
USE_USB = yes
|
||||||
|
USE_USART = yes
|
||||||
|
|
||||||
|
###################################
|
||||||
|
CROSS = arm-none-eabi-
|
||||||
|
CC = $(CROSS)gcc
|
||||||
|
LD = $(CROSS)gcc
|
||||||
|
OBJCOPY = $(CROSS)objcopy
|
||||||
|
|
||||||
|
MCU = cortex-m3
|
||||||
|
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||||
|
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=72
|
||||||
|
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
|
||||||
|
|
||||||
|
sys.c: board.h
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f board.h
|
||||||
22
example-usb-serial/README
Normal file
22
example-usb-serial/README
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
This is an application example using ST Nucleo F103 board.
|
||||||
|
|
||||||
|
SB62 and SB63 should be soldered.
|
||||||
|
ST-Link/V2 is disconnected (SB13 and SB14).
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
|
||||||
|
Using the USB CDC-ACM for serial communication is a kind of wrong,
|
||||||
|
because it's designed for modem; No way to control CTSRTS.
|
||||||
|
|
||||||
|
TIOCGICOUNT
|
||||||
|
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
* Use of DMA for serial communication
|
||||||
|
* RS-232 support: GPIO with DTR (out), DCD (in), DSR (in), RI (in)
|
||||||
|
* serial config setting of CTSRTS?
|
||||||
|
By vendor specific control?
|
||||||
|
* stats report control
|
||||||
|
By vendor specific control?
|
||||||
|
* Half-duplex support
|
||||||
|
* Support of other communication mode: smartcard, IrDA, etc.
|
||||||
1
example-usb-serial/board.h
Symbolic link
1
example-usb-serial/board.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../board/board-st-nucleo-f103.h
|
||||||
17
example-usb-serial/cdc.h
Normal file
17
example-usb-serial/cdc.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#define BUFSIZE 64
|
||||||
|
|
||||||
|
struct cdc;
|
||||||
|
|
||||||
|
void
|
||||||
|
cdc_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
|
||||||
|
void (*sendbrk_callback) (uint8_t dev_no, uint16_t duration),
|
||||||
|
void (*config_callback) (uint8_t dev_no,
|
||||||
|
uint32_t bitrate, uint8_t format,
|
||||||
|
uint8_t paritytype, uint8_t databits));
|
||||||
|
void cdc_wait_configured (void);
|
||||||
|
|
||||||
|
struct cdc *cdc_open (uint8_t num);
|
||||||
|
void cdc_wait_connection (struct cdc *);
|
||||||
|
int cdc_send (struct cdc *s, const char *buf, int count);
|
||||||
|
int cdc_recv (struct cdc *s, char *buf, uint32_t *timeout);
|
||||||
|
int cdc_ss_notify (struct cdc *s, uint16_t state_bits);
|
||||||
257
example-usb-serial/sample.c
Normal file
257
example-usb-serial/sample.c
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <chopstx.h>
|
||||||
|
#include <contrib/usart.h>
|
||||||
|
|
||||||
|
#include <usb_lld.h>
|
||||||
|
#include "cdc.h"
|
||||||
|
|
||||||
|
/* For set_led */
|
||||||
|
#include "board.h"
|
||||||
|
#include "sys.h"
|
||||||
|
|
||||||
|
static void *
|
||||||
|
blk (void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
set_led (0);
|
||||||
|
chopstx_usec_wait (200*1000);
|
||||||
|
set_led (1);
|
||||||
|
chopstx_usec_wait (200*1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRIO_USART 4
|
||||||
|
#define PRIO_CDC2USART 3
|
||||||
|
#define PRIO_USART2CDC 3
|
||||||
|
#define PRIO_CDC 2
|
||||||
|
|
||||||
|
#define STACK_MAIN
|
||||||
|
#define STACK_PROCESS_1
|
||||||
|
#define STACK_PROCESS_2
|
||||||
|
#define STACK_PROCESS_3
|
||||||
|
#define STACK_PROCESS_4
|
||||||
|
#define STACK_PROCESS_5
|
||||||
|
#define STACK_PROCESS_6
|
||||||
|
#include "stack-def.h"
|
||||||
|
#define STACK_ADDR_CDC ((uintptr_t)process1_base)
|
||||||
|
#define STACK_SIZE_CDC (sizeof process1_base)
|
||||||
|
|
||||||
|
#define STACK_ADDR_USART ((uint32_t)process2_base)
|
||||||
|
#define STACK_SIZE_USART (sizeof process2_base)
|
||||||
|
|
||||||
|
#define STACK_ADDR_CDC2USART0 ((uint32_t)process3_base)
|
||||||
|
#define STACK_SIZE_CDC2USART0 (sizeof process3_base)
|
||||||
|
|
||||||
|
#define STACK_ADDR_USART2CDC0 ((uint32_t)process4_base)
|
||||||
|
#define STACK_SIZE_USART2CDC0 (sizeof process4_base)
|
||||||
|
|
||||||
|
#define STACK_ADDR_CDC2USART1 ((uint32_t)process5_base)
|
||||||
|
#define STACK_SIZE_CDC2USART1 (sizeof process5_base)
|
||||||
|
|
||||||
|
#define STACK_ADDR_USART2CDC1 ((uint32_t)process6_base)
|
||||||
|
#define STACK_SIZE_USART2CDC1 (sizeof process6_base)
|
||||||
|
|
||||||
|
|
||||||
|
struct cdc_usart {
|
||||||
|
uint8_t dev_no;
|
||||||
|
struct cdc *cdc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *
|
||||||
|
usart_to_cdc_loop (void *arg)
|
||||||
|
{
|
||||||
|
struct cdc_usart *cdc_usart = arg;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char s[BUFSIZE];
|
||||||
|
|
||||||
|
cdc_wait_connection (cdc_usart->cdc);
|
||||||
|
|
||||||
|
/* Flush USART buffers */
|
||||||
|
usart_read (cdc_usart->dev_no, NULL, 0);
|
||||||
|
usart_write (cdc_usart->dev_no, NULL, 0);
|
||||||
|
|
||||||
|
chopstx_usec_wait (100*1000);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int size = usart_read (cdc_usart->dev_no, s, BUFSIZE);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
if (cdc_send (cdc_usart->cdc, s, size) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
cdc_to_usart_loop (void *arg)
|
||||||
|
{
|
||||||
|
struct cdc_usart *cdc_usart = arg;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char s[BUFSIZE];
|
||||||
|
|
||||||
|
cdc_wait_connection (cdc_usart->cdc);
|
||||||
|
|
||||||
|
/* Flush USART buffers */
|
||||||
|
usart_read (cdc_usart->dev_no, NULL, 0);
|
||||||
|
usart_write (cdc_usart->dev_no, NULL, 0);
|
||||||
|
|
||||||
|
chopstx_usec_wait (50*1000);
|
||||||
|
|
||||||
|
/* Send ZLP at the beginning. */
|
||||||
|
cdc_send (cdc_usart->cdc, s, 0);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
uint32_t usec = 3000000; /* 3.0 seconds */
|
||||||
|
|
||||||
|
size = cdc_recv (cdc_usart->cdc, s, &usec);
|
||||||
|
if (size < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
usart_write (cdc_usart->dev_no, s, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cdc_usart cdc_usart0;
|
||||||
|
static struct cdc_usart cdc_usart1;
|
||||||
|
|
||||||
|
static int
|
||||||
|
ss_notify (uint8_t dev_no, uint16_t state_bits)
|
||||||
|
{
|
||||||
|
struct cdc *s;
|
||||||
|
|
||||||
|
if (dev_no == cdc_usart0.dev_no)
|
||||||
|
s = cdc_usart0.cdc;
|
||||||
|
else if (dev_no == cdc_usart1.dev_no)
|
||||||
|
s = cdc_usart1.cdc;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return cdc_ss_notify (s, state_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_break (uint8_t dev_no, uint16_t duration)
|
||||||
|
{
|
||||||
|
(void)duration; /* Not supported by USART. */
|
||||||
|
usart_send_break (dev_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_usart_config (uint8_t dev_no, uint32_t bitrate, uint8_t format,
|
||||||
|
uint8_t paritytype, uint8_t databits)
|
||||||
|
{
|
||||||
|
/* Check supported config(s) */
|
||||||
|
uint32_t config_bits;
|
||||||
|
|
||||||
|
if (bitrate == 9600)
|
||||||
|
config_bits = B9600;
|
||||||
|
else if (bitrate == 19200)
|
||||||
|
config_bits = B19200;
|
||||||
|
else if (bitrate == 57600)
|
||||||
|
config_bits = B57600;
|
||||||
|
else if (bitrate == 115200)
|
||||||
|
config_bits = B115200;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bitrate = 115200;
|
||||||
|
config_bits = B115200;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == 0)
|
||||||
|
config_bits |= STOP1B;
|
||||||
|
else if (format == 1)
|
||||||
|
config_bits |= STOP1B5;
|
||||||
|
else if (format == 2)
|
||||||
|
config_bits |= STOP2B;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format = 0;
|
||||||
|
config_bits |= STOP1B;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paritytype == 0)
|
||||||
|
config_bits |= 0;
|
||||||
|
else if (paritytype == 1)
|
||||||
|
config_bits |= (PARENB | PARODD);
|
||||||
|
else if (paritytype == 2)
|
||||||
|
config_bits |= PARENB;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
paritytype = 0;
|
||||||
|
config_bits |= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (databits == 7)
|
||||||
|
config_bits |= CS7;
|
||||||
|
else if (databits == 7)
|
||||||
|
config_bits |= CS8;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
databits = 8;
|
||||||
|
config_bits |= CS8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (databits == 7 && paritytype == 0)
|
||||||
|
{
|
||||||
|
databits = 8;
|
||||||
|
config_bits &= ~MASK_CS;
|
||||||
|
config_bits |= CS8;
|
||||||
|
}
|
||||||
|
|
||||||
|
usart_config (dev_no, config_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
chopstx_usec_wait (200*1000);
|
||||||
|
|
||||||
|
cdc_init (PRIO_CDC, STACK_ADDR_CDC, STACK_SIZE_CDC,
|
||||||
|
send_break, setup_usart_config);
|
||||||
|
cdc_wait_configured ();
|
||||||
|
|
||||||
|
usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify);
|
||||||
|
|
||||||
|
cdc_usart0.cdc = cdc_open (0);
|
||||||
|
cdc_usart0.dev_no = 2;
|
||||||
|
cdc_usart1.cdc = cdc_open (1);
|
||||||
|
cdc_usart1.dev_no = 3;
|
||||||
|
|
||||||
|
chopstx_create (PRIO_USART2CDC, STACK_ADDR_USART2CDC0,
|
||||||
|
STACK_SIZE_USART2CDC0, usart_to_cdc_loop, &cdc_usart0);
|
||||||
|
chopstx_create (PRIO_USART2CDC, STACK_ADDR_USART2CDC1,
|
||||||
|
STACK_SIZE_USART2CDC1, usart_to_cdc_loop, &cdc_usart1);
|
||||||
|
chopstx_create (PRIO_CDC2USART, STACK_ADDR_CDC2USART0,
|
||||||
|
STACK_SIZE_CDC2USART0, cdc_to_usart_loop, &cdc_usart0);
|
||||||
|
chopstx_create (PRIO_CDC2USART, STACK_ADDR_CDC2USART1,
|
||||||
|
STACK_SIZE_CDC2USART1, cdc_to_usart_loop, &cdc_usart1);
|
||||||
|
|
||||||
|
blk (NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
127
example-usb-serial/sample.ld
Normal file
127
example-usb-serial/sample.ld
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* ST32F103 memory setup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
flash0 : org = 0x08000000, len = 4k
|
||||||
|
flash : org = 0x08000000+0x1000, len = 60k
|
||||||
|
ram : org = 0x20000000, len = 20k
|
||||||
|
}
|
||||||
|
|
||||||
|
__ram_start__ = ORIGIN(ram);
|
||||||
|
__ram_size__ = 20k;
|
||||||
|
__ram_end__ = __ram_start__ + __ram_size__;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0;
|
||||||
|
|
||||||
|
.sys : ALIGN(4) SUBALIGN(4)
|
||||||
|
{
|
||||||
|
_sys = .;
|
||||||
|
KEEP(*(.vectors))
|
||||||
|
. = ALIGN(16);
|
||||||
|
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.*)
|
||||||
|
. = ALIGN(1024);
|
||||||
|
*(.sys.0)
|
||||||
|
*(.sys.1)
|
||||||
|
*(.sys.2)
|
||||||
|
} > flash0
|
||||||
|
|
||||||
|
_text = .;
|
||||||
|
|
||||||
|
.startup : ALIGN(128) SUBALIGN(128)
|
||||||
|
{
|
||||||
|
KEEP(*(.startup.vectors))
|
||||||
|
. = ALIGN (16);
|
||||||
|
} > flash =0xffffffff
|
||||||
|
|
||||||
|
.text : ALIGN(16) SUBALIGN(16)
|
||||||
|
{
|
||||||
|
*(.text.startup.*)
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata.*)
|
||||||
|
*(.glue_7t)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.gcc*)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} > flash
|
||||||
|
|
||||||
|
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
|
||||||
|
|
||||||
|
.ARM.exidx : {
|
||||||
|
PROVIDE(__exidx_start = .);
|
||||||
|
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||||
|
PROVIDE(__exidx_end = .);
|
||||||
|
} > flash
|
||||||
|
|
||||||
|
.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 (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
*(.process_stack.6)
|
||||||
|
*(.process_stack.5)
|
||||||
|
*(.process_stack.4)
|
||||||
|
*(.process_stack.3)
|
||||||
|
*(.process_stack.2)
|
||||||
|
*(.process_stack.1)
|
||||||
|
*(.process_stack.0)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} > ram
|
||||||
|
|
||||||
|
.main_stack (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
*(.main_stack)
|
||||||
|
. = ALIGN(8);
|
||||||
|
} > ram
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_data = .);
|
||||||
|
*(.data)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.data.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.ramtext)
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_edata = .);
|
||||||
|
} > ram AT > flash
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_bss_start = .);
|
||||||
|
*(.bss)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.bss.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_bss_end = .);
|
||||||
|
} > ram
|
||||||
|
|
||||||
|
PROVIDE(end = .);
|
||||||
|
_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
__heap_base__ = _end;
|
||||||
|
__heap_end__ = __ram_end__;
|
||||||
39
example-usb-serial/stack-def.h
Normal file
39
example-usb-serial/stack-def.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#if defined(STACK_MAIN)
|
||||||
|
/* Idle+Exception handlers */
|
||||||
|
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
|
||||||
|
char main_base[0x0080] __attribute__ ((section(".main_stack")));
|
||||||
|
|
||||||
|
/* Main program */
|
||||||
|
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
|
||||||
|
char process0_base[0x0400] __attribute__ ((section(".process_stack.0")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* First thread program */
|
||||||
|
#if defined(STACK_PROCESS_1)
|
||||||
|
char process1_base[0x0200] __attribute__ ((section(".process_stack.1")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Second thread program */
|
||||||
|
#if defined(STACK_PROCESS_2)
|
||||||
|
char process2_base[0x0200] __attribute__ ((section(".process_stack.2")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Third thread program */
|
||||||
|
#if defined(STACK_PROCESS_3)
|
||||||
|
char process3_base[0x0200] __attribute__ ((section(".process_stack.3")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fourth thread program */
|
||||||
|
#if defined(STACK_PROCESS_4)
|
||||||
|
char process4_base[0x0200] __attribute__ ((section(".process_stack.4")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fifth thread program */
|
||||||
|
#if defined(STACK_PROCESS_5)
|
||||||
|
char process5_base[0x0200] __attribute__ ((section(".process_stack.5")));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sixth thread program */
|
||||||
|
#if defined(STACK_PROCESS_6)
|
||||||
|
char process6_base[0x0200] __attribute__ ((section(".process_stack.6")));
|
||||||
|
#endif
|
||||||
1034
example-usb-serial/usb-cdc.c
Normal file
1034
example-usb-serial/usb-cdc.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,7 @@ In the development of Gnuk, we developed:
|
|||||||
|
|
||||||
It is now maintained as example-cdc/sys.c.
|
It is now maintained as example-cdc/sys.c.
|
||||||
|
|
||||||
There is another version in example-led/sys.c, which also support
|
There is another version in example-led/sys.c, which also supports
|
||||||
STM32F030, as well as STM32F103. But, it wouldn't be useful for
|
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
|
STM32F030. In fact, the file example-fsm-55/sys.c has name sys.c
|
||||||
but it doesn't include any system routines.
|
but it doesn't include any system routines.
|
||||||
@@ -74,7 +74,7 @@ Later on, we add another point.
|
|||||||
(3) It is good if the executable of Gnuk could be shared among
|
(3) It is good if the executable of Gnuk could be shared among
|
||||||
different boards.
|
different boards.
|
||||||
|
|
||||||
For (1) and (2), we decided put some useful routines and data which is
|
For (1) and (2), we decided put some useful routines and data which are
|
||||||
not need to be changed.
|
not need to be changed.
|
||||||
|
|
||||||
Now, the first 4KiB of flash ROM consists of:
|
Now, the first 4KiB of flash ROM consists of:
|
||||||
@@ -84,7 +84,7 @@ Now, the first 4KiB of flash ROM consists of:
|
|||||||
|
|
||||||
SYS consists of:
|
SYS consists of:
|
||||||
|
|
||||||
Internal: reset entry, end of RAM
|
Internal: reset entry, address of the end of RAM
|
||||||
Data: board identification
|
Data: board identification
|
||||||
Routines: board specific
|
Routines: board specific
|
||||||
board independent
|
board independent
|
||||||
@@ -94,7 +94,7 @@ and here is the list of all.
|
|||||||
* Internal routines
|
* Internal routines
|
||||||
|
|
||||||
reset entry
|
reset entry
|
||||||
end of RAM
|
address of the end of RAM
|
||||||
|
|
||||||
* Board identification
|
* Board identification
|
||||||
|
|
||||||
|
|||||||
5
mcu/chx-gnu-linux.c
Normal file
5
mcu/chx-gnu-linux.c
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
void
|
||||||
|
chx_sleep_mode (int enable_sleep)
|
||||||
|
{
|
||||||
|
(void)enable_sleep;
|
||||||
|
}
|
||||||
23
mcu/chx-mkl27z.c
Normal file
23
mcu/chx-mkl27z.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
extern int chx_allow_sleep;
|
||||||
|
|
||||||
|
void
|
||||||
|
chx_sleep_mode (int enable_sleep)
|
||||||
|
{
|
||||||
|
(void)enable_sleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((naked))
|
||||||
|
chx_idle (void)
|
||||||
|
{
|
||||||
|
int sleep_enabled;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep));
|
||||||
|
if (sleep_enabled)
|
||||||
|
{
|
||||||
|
asm volatile ("wfi" : : : "memory");
|
||||||
|
/* NOTE: it never comes here. Don't add lines after this. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
mcu/chx-stm32f0.c
Normal file
42
mcu/chx-stm32f0.c
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <mcu/cortex-m.h>
|
||||||
|
#define MCU_STM32F0
|
||||||
|
#include <mcu/stm32.h>
|
||||||
|
|
||||||
|
extern int chx_allow_sleep;
|
||||||
|
|
||||||
|
void
|
||||||
|
chx_sleep_mode (int how)
|
||||||
|
{
|
||||||
|
PWR->CR |= PWR_CR_CWUF;
|
||||||
|
PWR->CR &= ~(PWR_CR_PDDS|PWR_CR_LPDS);
|
||||||
|
|
||||||
|
if (how == 0 || how == 1 /* Sleep only (not deepsleep) */)
|
||||||
|
SCB->SCR &= ~SCB_SCR_SLEEPDEEP;
|
||||||
|
else
|
||||||
|
{ /* Deepsleep */
|
||||||
|
/* how == 2: deepsleep but regulator ON */
|
||||||
|
if (how == 3)
|
||||||
|
PWR->CR |= PWR_CR_LPDS; /* regulator low-power mode */
|
||||||
|
else if (how == 4)
|
||||||
|
PWR->CR |= PWR_CR_PDDS; /* Power down: All OFF */
|
||||||
|
|
||||||
|
SCB->SCR |= SCB_SCR_SLEEPDEEP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((naked))
|
||||||
|
chx_idle (void)
|
||||||
|
{
|
||||||
|
int sleep_enabled;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep));
|
||||||
|
if (sleep_enabled)
|
||||||
|
{
|
||||||
|
asm volatile ("wfi" : : : "memory");
|
||||||
|
/* NOTE: it never comes here. Don't add lines after this. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
92
mcu/chx-stm32f103.c
Normal file
92
mcu/chx-stm32f103.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <mcu/stm32f103.h>
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
extern int chx_allow_sleep;
|
||||||
|
|
||||||
|
#define STM32_PLLSRC STM32_PLLSRC_HSE
|
||||||
|
#define STM32_PLLMUL ((STM32_PLLMUL_VALUE - 2) << 18)
|
||||||
|
#ifndef STM32_ADCPRE
|
||||||
|
#define STM32_ADCPRE STM32_ADCPRE_DIV6
|
||||||
|
#endif
|
||||||
|
#ifndef STM32_USBPRE
|
||||||
|
#define STM32_USBPRE STM32_USBPRE_DIV1P5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
configure_clock (int high)
|
||||||
|
{
|
||||||
|
uint32_t cfg_sw;
|
||||||
|
uint32_t cfg;
|
||||||
|
|
||||||
|
if (high)
|
||||||
|
{
|
||||||
|
cfg = STM32_MCO_NOCLOCK | STM32_USBPRE
|
||||||
|
| STM32_PLLMUL | STM32_PLLXTPRE | STM32_PLLSRC
|
||||||
|
| STM32_ADCPRE | STM32_PPRE2_DIV1
|
||||||
|
| STM32_PPRE1_DIV2 | STM32_HPRE_DIV1;
|
||||||
|
|
||||||
|
cfg_sw = RCC_CFGR_SW_PLL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cfg = STM32_MCO_NOCLOCK | STM32_USBPRE
|
||||||
|
| STM32_PLLMUL | STM32_PLLXTPRE | STM32_PLLSRC
|
||||||
|
| STM32_ADCPRE_DIV8 | STM32_PPRE2_DIV16
|
||||||
|
| STM32_PPRE1_DIV16 | STM32_HPRE_DIV8;
|
||||||
|
|
||||||
|
cfg_sw = RCC_CFGR_SW_HSI;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCC->CFGR = cfg | cfg_sw;
|
||||||
|
while ((RCC->CFGR & RCC_CFGR_SWS) != (cfg_sw << 2))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When HOW=0 or HOW=1, SYSCLK is PLL (72MHz).
|
||||||
|
* When HOW=2, SYSCLK will be 1MHz with HSI (8MHz) on sleep.
|
||||||
|
*
|
||||||
|
* With lower clock, it can achieve lower power consumption.
|
||||||
|
*
|
||||||
|
* Implementation note: Deepsleep is only useful with RTC, Watch Dog,
|
||||||
|
* or WKUP pin. We can't use deepsleep for USB, it never wakes up.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
chx_sleep_mode (int how)
|
||||||
|
{
|
||||||
|
if (how == 0 || how == 1)
|
||||||
|
configure_clock (1);
|
||||||
|
|
||||||
|
/* how == 2: Defer setting to 8MHz clock to the idle function */
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((naked))
|
||||||
|
chx_idle (void)
|
||||||
|
{
|
||||||
|
int sleep_enabled;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep));
|
||||||
|
if (sleep_enabled)
|
||||||
|
{
|
||||||
|
asm volatile ("cpsid i" : : : "memory");
|
||||||
|
if (sleep_enabled == 1)
|
||||||
|
{
|
||||||
|
/* Allow JTAG/SWD access on sleep. */
|
||||||
|
DBGMCU->CR |= DBG_SLEEP;
|
||||||
|
}
|
||||||
|
else if (sleep_enabled == 2)
|
||||||
|
{
|
||||||
|
DBGMCU->CR &= ~DBG_SLEEP; /* Disable HCLK on sleep */
|
||||||
|
configure_clock (0);
|
||||||
|
}
|
||||||
|
asm volatile ("cpsie i" : : : "memory");
|
||||||
|
|
||||||
|
asm volatile ("wfi" : : : "memory");
|
||||||
|
/* NOTE: it never comes here. Don't add lines after this. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* clk_gpio_init-kl.c - Clock and GPIO initialization for Kinetis L.
|
* clk_gpio_init-mkl27z.c - Clock and GPIO initialization for Kinetis L.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Flying Stone Technology
|
* Copyright (C) 2016 Flying Stone Technology
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
@@ -38,7 +38,7 @@ struct MCG {
|
|||||||
uint8_t reserved2[15]; /* */
|
uint8_t reserved2[15]; /* */
|
||||||
volatile uint8_t MC; /* MCG Miscellaneous Control Register */
|
volatile uint8_t MC; /* MCG Miscellaneous Control Register */
|
||||||
};
|
};
|
||||||
static struct MCG *const MCG = (struct MCG *const)0x40064000;
|
static struct MCG *const MCG = (struct MCG *)0x40064000;
|
||||||
|
|
||||||
struct USB_CLK_RECOVER {
|
struct USB_CLK_RECOVER {
|
||||||
volatile uint8_t CTRL; /* USB Clock */
|
volatile uint8_t CTRL; /* USB Clock */
|
||||||
@@ -51,7 +51,7 @@ struct USB_CLK_RECOVER {
|
|||||||
/* interrupt status */
|
/* interrupt status */
|
||||||
};
|
};
|
||||||
static struct USB_CLK_RECOVER *const USB_CLK_RECOVER =
|
static struct USB_CLK_RECOVER *const USB_CLK_RECOVER =
|
||||||
(struct USB_CLK_RECOVER *const)0x40072140;
|
(struct USB_CLK_RECOVER *)0x40072140;
|
||||||
|
|
||||||
static void __attribute__((used))
|
static void __attribute__((used))
|
||||||
clock_init (void)
|
clock_init (void)
|
||||||
@@ -66,10 +66,12 @@ clock_init (void)
|
|||||||
while ((MCG->S & 0x0c) != 0)
|
while ((MCG->S & 0x0c) != 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
SIM->SOPT2 = 0x00040060; /* USBSRC=IRC48, CLOKOUTSEL=LPO, RTC-clock */
|
/* TPMSRC=IRC48M, USBSRC=IRC48M, CLOKOUTSEL=LPO, RTC-clock */
|
||||||
|
SIM->SOPT2 = 0x01040060;
|
||||||
|
|
||||||
SIM->SCGC4 = (1 << 18); /* Enable USB FS clock */
|
SIM->SCGC4 = (1 << 18); /* Enable USB FS clock */
|
||||||
SIM->SCGC5 = (1 << 10); /* Enable Port B clock */
|
SIM->SCGC5 = (1 << 10); /* Enable Port B clock */
|
||||||
|
SIM->SCGC6 = (1 << 25)|1; /* Enable TPM1 clock */
|
||||||
SIM->COPC = 0; /* COP disabled */
|
SIM->COPC = 0; /* COP disabled */
|
||||||
|
|
||||||
/* Crystal-less USB setup. */
|
/* Crystal-less USB setup. */
|
||||||
@@ -78,44 +80,6 @@ clock_init (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
static struct PORT *const PORTB = (struct PORT *const)0x4004A000;
|
|
||||||
static struct PORT *const PORTD = (struct PORT *const)0x4004C000;
|
|
||||||
static struct PORT *const PORTE = (struct PORT *const)0x4004D000;
|
|
||||||
|
|
||||||
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 GPIO *const GPIOB = (struct GPIO *const)0x400FF040;
|
|
||||||
static struct GPIO *const GPIOD = (struct GPIO *const)0x400FF0C0;
|
|
||||||
static struct GPIO *const GPIOE = (struct GPIO *const)0x400FF100;
|
|
||||||
|
|
||||||
|
|
||||||
static void __attribute__((used))
|
static void __attribute__((used))
|
||||||
gpio_init (void)
|
gpio_init (void)
|
||||||
{
|
{
|
||||||
@@ -124,14 +88,14 @@ gpio_init (void)
|
|||||||
| (0<<4) /* PassiveFilterEnable=0 */
|
| (0<<4) /* PassiveFilterEnable=0 */
|
||||||
| (1<<2) /* SlewRateEnable = slow */
|
| (1<<2) /* SlewRateEnable = slow */
|
||||||
| (0<<1) /* pull enable = 0 */
|
| (0<<1) /* pull enable = 0 */
|
||||||
| (0<<0) /* puddselect= 0 */
|
| (0<<0) /* pull up select= 0 */
|
||||||
;
|
;
|
||||||
PORTB->PCR1 = (1<<8) /* GPIO */
|
PORTB->PCR1 = (1<<8) /* GPIO */
|
||||||
| (0<<6) /* DriveStrengthEnable=0 */
|
| (0<<6) /* DriveStrengthEnable=0 */
|
||||||
| (0<<4) /* PassiveFilterEnable=0 */
|
| (0<<4) /* PassiveFilterEnable=0 */
|
||||||
| (1<<2) /* SlewRateEnable = slow */
|
| (1<<2) /* SlewRateEnable = slow */
|
||||||
| (0<<1) /* pull enable = 0 */
|
| (0<<1) /* pull enable = 0 */
|
||||||
| (0<<0) /* puddselect= 0 */
|
| (0<<0) /* pull up select= 0 */
|
||||||
;
|
;
|
||||||
|
|
||||||
GPIOB->PDDR = (1 << 1) | (1 << 0); /* PTB0, PTB1 : Output */
|
GPIOB->PDDR = (1 << 1) | (1 << 0); /* PTB0, PTB1 : Output */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* clk_gpio_init-stm32.c - Clock and GPIO initialization for STM32.
|
* clk_gpio_init-stm32.c - Clock and GPIO initialization for STM32.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Flying Stone Technology
|
* Copyright (C) 2015, 2018 Flying Stone Technology
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Chopstx, a thread library for embedded.
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
@@ -26,28 +26,11 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define STM32_SW_HSI (0 << 0)
|
#if defined(MCU_STM32F0)
|
||||||
#define STM32_SW_PLL (2 << 0)
|
#include <mcu/stm32.h>
|
||||||
#define STM32_PLLSRC_HSI (0 << 16)
|
#else
|
||||||
#define STM32_PLLSRC_HSE (1 << 16)
|
#include <mcu/stm32f103.h>
|
||||||
|
#endif
|
||||||
#define STM32_PLLXTPRE_DIV1 (0 << 17)
|
|
||||||
#define STM32_PLLXTPRE_DIV2 (1 << 17)
|
|
||||||
|
|
||||||
#define STM32_HPRE_DIV1 (0 << 4)
|
|
||||||
|
|
||||||
#define STM32_PPRE1_DIV1 (0 << 8)
|
|
||||||
#define STM32_PPRE1_DIV2 (4 << 8)
|
|
||||||
|
|
||||||
#define STM32_PPRE2_DIV1 (0 << 11)
|
|
||||||
#define STM32_PPRE2_DIV2 (4 << 11)
|
|
||||||
|
|
||||||
#define STM32_ADCPRE_DIV4 (1 << 14)
|
|
||||||
#define STM32_ADCPRE_DIV6 (2 << 14)
|
|
||||||
|
|
||||||
#define STM32_USBPRE_DIV1P5 (0 << 22)
|
|
||||||
|
|
||||||
#define STM32_MCO_NOCLOCK (0 << 24)
|
|
||||||
|
|
||||||
#if defined(MCU_STM32F0)
|
#if defined(MCU_STM32F0)
|
||||||
#define STM32_PPRE1 STM32_PPRE1_DIV1
|
#define STM32_PPRE1 STM32_PPRE1_DIV1
|
||||||
@@ -64,9 +47,13 @@
|
|||||||
#define STM32_SW STM32_SW_PLL
|
#define STM32_SW STM32_SW_PLL
|
||||||
#define STM32_HPRE STM32_HPRE_DIV1
|
#define STM32_HPRE STM32_HPRE_DIV1
|
||||||
#define STM32_PPRE2 STM32_PPRE2_DIV1
|
#define STM32_PPRE2 STM32_PPRE2_DIV1
|
||||||
|
#ifndef STM32_ADCPRE
|
||||||
#define STM32_ADCPRE STM32_ADCPRE_DIV6
|
#define STM32_ADCPRE STM32_ADCPRE_DIV6
|
||||||
|
#endif
|
||||||
#define STM32_MCOSEL STM32_MCO_NOCLOCK
|
#define STM32_MCOSEL STM32_MCO_NOCLOCK
|
||||||
|
#ifndef STM32_USBPRE
|
||||||
#define STM32_USBPRE STM32_USBPRE_DIV1P5
|
#define STM32_USBPRE STM32_USBPRE_DIV1P5
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STM32_PLLMUL ((STM32_PLLMUL_VALUE - 2) << 18)
|
#define STM32_PLLMUL ((STM32_PLLMUL_VALUE - 2) << 18)
|
||||||
#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
|
#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
|
||||||
@@ -74,113 +61,6 @@
|
|||||||
#define STM32_HCLK (STM32_SYSCLK / 1)
|
#define STM32_HCLK (STM32_SYSCLK / 1)
|
||||||
|
|
||||||
|
|
||||||
#define PERIPH_BASE 0x40000000
|
|
||||||
#define APBPERIPH_BASE PERIPH_BASE
|
|
||||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
|
||||||
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
|
||||||
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
|
||||||
|
|
||||||
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;
|
|
||||||
#if defined(MCU_STM32F0)
|
|
||||||
volatile uint32_t AHBRSTR;
|
|
||||||
volatile uint32_t CFGR2;
|
|
||||||
volatile uint32_t CFGR3;
|
|
||||||
volatile uint32_t CR2;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
|
|
||||||
static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
|
|
||||||
|
|
||||||
#define RCC_APB1ENR_USBEN 0x00800000
|
|
||||||
#define RCC_APB1RSTR_USBRST 0x00800000
|
|
||||||
|
|
||||||
#define RCC_CR_HSION 0x00000001
|
|
||||||
#define RCC_CR_HSIRDY 0x00000002
|
|
||||||
#define RCC_CR_HSITRIM 0x000000F8
|
|
||||||
#define RCC_CR_HSEON 0x00010000
|
|
||||||
#define RCC_CR_HSERDY 0x00020000
|
|
||||||
#define RCC_CR_PLLON 0x01000000
|
|
||||||
#define RCC_CR_PLLRDY 0x02000000
|
|
||||||
|
|
||||||
#define RCC_CFGR_SWS 0x0000000C
|
|
||||||
#define RCC_CFGR_SWS_HSI 0x00000000
|
|
||||||
|
|
||||||
#define RCC_AHBENR_CRCEN 0x0040
|
|
||||||
|
|
||||||
#if defined(MCU_STM32F0)
|
|
||||||
#define RCC_AHBRSTR_IOPARST 0x00020000
|
|
||||||
#define RCC_AHBRSTR_IOPBRST 0x00040000
|
|
||||||
#define RCC_AHBRSTR_IOPCRST 0x00080000
|
|
||||||
#define RCC_AHBRSTR_IOPDRST 0x00100000
|
|
||||||
#define RCC_AHBRSTR_IOPFRST 0x00400000
|
|
||||||
|
|
||||||
#define RCC_AHBENR_IOPAEN 0x00020000
|
|
||||||
#define RCC_AHBENR_IOPBEN 0x00040000
|
|
||||||
#define RCC_AHBENR_IOPCEN 0x00080000
|
|
||||||
#define RCC_AHBENR_IOPDEN 0x00100000
|
|
||||||
#define RCC_AHBENR_IOPFEN 0x00400000
|
|
||||||
|
|
||||||
#define RCC_APB2RSTR_SYSCFGRST 0x00000001
|
|
||||||
#define RCC_APB2ENR_SYSCFGEN 0x00000001
|
|
||||||
#else
|
|
||||||
#define RCC_APB2RSTR_AFIORST 0x00000001
|
|
||||||
#define RCC_APB2RSTR_IOPARST 0x00000004
|
|
||||||
#define RCC_APB2RSTR_IOPBRST 0x00000008
|
|
||||||
#define RCC_APB2RSTR_IOPCRST 0x00000010
|
|
||||||
#define RCC_APB2RSTR_IOPDRST 0x00000020
|
|
||||||
#define RCC_APB2RSTR_IOPERST 0x00000040
|
|
||||||
#define RCC_APB2RSTR_IOPFRST 0x00000080
|
|
||||||
#define RCC_APB2RSTR_IOPGRST 0x00000100
|
|
||||||
|
|
||||||
#define RCC_APB2ENR_AFIOEN 0x00000001
|
|
||||||
#define RCC_APB2ENR_IOPAEN 0x00000004
|
|
||||||
#define RCC_APB2ENR_IOPBEN 0x00000008
|
|
||||||
#define RCC_APB2ENR_IOPCEN 0x00000010
|
|
||||||
#define RCC_APB2ENR_IOPDEN 0x00000020
|
|
||||||
#define RCC_APB2ENR_IOPEEN 0x00000040
|
|
||||||
#define RCC_APB2ENR_IOPFEN 0x00000080
|
|
||||||
#define RCC_APB2ENR_IOPGEN 0x00000100
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MCU_STM32F0)
|
|
||||||
struct SYSCFG {
|
|
||||||
volatile uint32_t CFGR1;
|
|
||||||
uint32_t dummy0;
|
|
||||||
volatile uint32_t EXTICR[4];
|
|
||||||
volatile uint32_t CFGR2;
|
|
||||||
};
|
|
||||||
#define SYSCFG_CFGR1_MEM_MODE 0x03
|
|
||||||
|
|
||||||
#define SYSCFG_BASE (APBPERIPH_BASE + 0x00010000)
|
|
||||||
static struct SYSCFG *const SYSCFG = ((struct SYSCFG *const) SYSCFG_BASE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct FLASH {
|
|
||||||
volatile uint32_t ACR;
|
|
||||||
volatile uint32_t KEYR;
|
|
||||||
volatile uint32_t OPTKEYR;
|
|
||||||
volatile uint32_t SR;
|
|
||||||
volatile uint32_t CR;
|
|
||||||
volatile uint32_t AR;
|
|
||||||
volatile uint32_t RESERVED;
|
|
||||||
volatile uint32_t OBR;
|
|
||||||
volatile uint32_t WRPR;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FLASH_R_BASE (AHBPERIPH_BASE + 0x2000)
|
|
||||||
static struct FLASH *const FLASH = ((struct FLASH *const) FLASH_R_BASE);
|
|
||||||
|
|
||||||
static void __attribute__((used))
|
static void __attribute__((used))
|
||||||
clock_init (void)
|
clock_init (void)
|
||||||
{
|
{
|
||||||
@@ -218,9 +98,6 @@ clock_init (void)
|
|||||||
/* Flash setup */
|
/* Flash setup */
|
||||||
FLASH->ACR = STM32_FLASHBITS;
|
FLASH->ACR = STM32_FLASHBITS;
|
||||||
|
|
||||||
/* CRC */
|
|
||||||
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
|
||||||
|
|
||||||
/* Switching on the configured clock source. */
|
/* Switching on the configured clock source. */
|
||||||
RCC->CFGR |= STM32_SW;
|
RCC->CFGR |= STM32_SW;
|
||||||
while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2))
|
while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2))
|
||||||
@@ -239,81 +116,12 @@ clock_init (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(MCU_STM32F0)
|
static struct GPIO *const GPIO_LED = (struct GPIO *)GPIO_LED_BASE;
|
||||||
struct GPIO {
|
|
||||||
volatile uint32_t MODER;
|
|
||||||
volatile uint16_t OTYPER;
|
|
||||||
uint16_t dummy0;
|
|
||||||
volatile uint32_t OSPEEDR;
|
|
||||||
volatile uint32_t PUPDR;
|
|
||||||
volatile uint16_t IDR;
|
|
||||||
uint16_t dummy1;
|
|
||||||
volatile uint16_t ODR;
|
|
||||||
uint16_t dummy2;
|
|
||||||
volatile uint16_t BSRR;
|
|
||||||
uint16_t dummy3;
|
|
||||||
volatile uint32_t LCKR;
|
|
||||||
volatile uint32_t AFR[2];
|
|
||||||
volatile uint16_t BRR;
|
|
||||||
uint16_t dummy4;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GPIOA_BASE (AHB2PERIPH_BASE + 0x0000)
|
|
||||||
#define GPIOA ((struct GPIO *) GPIOA_BASE)
|
|
||||||
#define GPIOB_BASE (AHB2PERIPH_BASE + 0x0400)
|
|
||||||
#define GPIOB ((struct GPIO *) GPIOB_BASE)
|
|
||||||
#define GPIOC_BASE (AHB2PERIPH_BASE + 0x0800)
|
|
||||||
#define GPIOC ((struct GPIO *) GPIOC_BASE)
|
|
||||||
#define GPIOD_BASE (AHB2PERIPH_BASE + 0x0C00)
|
|
||||||
#define GPIOD ((struct GPIO *) GPIOD_BASE)
|
|
||||||
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
|
|
||||||
#define GPIOF ((struct GPIO *) GPIOF_BASE)
|
|
||||||
#else
|
|
||||||
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 *const)AFIO_BASE;
|
|
||||||
|
|
||||||
#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
|
|
||||||
#define AFIO_MAPR_SWJ_CFG_DISABLE 0x04000000
|
|
||||||
#define AFIO_MAPR_SWJ_CFG_JTAGDISABLE 0x02000000
|
|
||||||
|
|
||||||
|
|
||||||
struct GPIO {
|
|
||||||
volatile uint32_t CRL;
|
|
||||||
volatile uint32_t CRH;
|
|
||||||
volatile uint32_t IDR;
|
|
||||||
volatile uint32_t ODR;
|
|
||||||
volatile uint32_t BSRR;
|
|
||||||
volatile uint32_t BRR;
|
|
||||||
volatile uint32_t LCKR;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
|
|
||||||
#define GPIOA ((struct GPIO *) GPIOA_BASE)
|
|
||||||
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
|
|
||||||
#define GPIOB ((struct GPIO *) GPIOB_BASE)
|
|
||||||
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
|
|
||||||
#define GPIOC ((struct GPIO *) GPIOC_BASE)
|
|
||||||
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
|
|
||||||
#define GPIOD ((struct GPIO *) GPIOD_BASE)
|
|
||||||
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
|
|
||||||
#define GPIOE ((struct GPIO *) GPIOE_BASE)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
|
|
||||||
#ifdef GPIO_USB_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
|
#endif
|
||||||
#ifdef GPIO_OTHER_BASE
|
#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
|
#endif
|
||||||
|
|
||||||
static void __attribute__((used))
|
static void __attribute__((used))
|
||||||
@@ -347,7 +155,7 @@ gpio_init (void)
|
|||||||
AFIO->MAPR |= AFIO_MAPR_SOMETHING;
|
AFIO->MAPR |= AFIO_MAPR_SOMETHING;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* LED is mandatory. If it's on an independent port, we configure it. */
|
/* LED is mandatory. We configure it always. */
|
||||||
GPIO_LED->ODR = VAL_GPIO_LED_ODR;
|
GPIO_LED->ODR = VAL_GPIO_LED_ODR;
|
||||||
GPIO_LED->CRH = VAL_GPIO_LED_CRH;
|
GPIO_LED->CRH = VAL_GPIO_LED_CRH;
|
||||||
GPIO_LED->CRL = VAL_GPIO_LED_CRL;
|
GPIO_LED->CRL = VAL_GPIO_LED_CRL;
|
||||||
|
|||||||
29
mcu/cortex-m.h
Normal file
29
mcu/cortex-m.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/* 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 MMAR;
|
||||||
|
volatile uint32_t BFAR;
|
||||||
|
volatile uint32_t AFSR;
|
||||||
|
volatile uint32_t PFR[2];
|
||||||
|
volatile uint32_t DFR;
|
||||||
|
volatile uint32_t AFR;
|
||||||
|
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 *)SCB_BASE;
|
||||||
|
#define SCB_SCR_SLEEPDEEP (1 << 2)
|
||||||
|
#define SCB_AIRCR_SYSRESETREQ 0x04
|
||||||
41
mcu/mkl27z.h
41
mcu/mkl27z.h
@@ -28,4 +28,43 @@ struct SIM {
|
|||||||
volatile uint32_t COPC; /* COP Control Register */
|
volatile uint32_t COPC; /* COP Control Register */
|
||||||
volatile uint32_t SRVCOP; /* Service COP */
|
volatile uint32_t SRVCOP; /* Service COP */
|
||||||
};
|
};
|
||||||
static struct SIM *const SIM = (struct SIM *const)0x40047000;
|
|
||||||
|
/* 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;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user