Compare commits
103 Commits
b6c90e3df4
...
a8e9074faf
| Author | SHA1 | Date | |
|---|---|---|---|
| a8e9074faf | |||
|
|
e12a7e0bb3 | ||
|
|
fdbe91600d | ||
|
|
daca396027 | ||
|
|
a6b96fe434 | ||
|
|
c5a83cb9a5 | ||
|
|
8f20122e54 | ||
|
|
c31a91947d | ||
|
|
71cc5a8f32 | ||
|
|
73d6c13d15 | ||
|
|
d43fbb140a | ||
|
|
9b822282f0 | ||
|
|
91ddc8fd02 | ||
|
|
0698bc4c9e | ||
|
|
7dda49eb40 | ||
|
|
cc49f4ef23 | ||
|
|
a0732c125a | ||
|
|
6be482413c | ||
|
|
9253777f5f | ||
|
|
63f47cede3 | ||
|
|
4c0c15588e | ||
|
|
e58e134b42 | ||
|
|
4cd47453ae | ||
|
|
89523f22bf | ||
|
|
0e5994506a | ||
|
|
bdbc84ba18 | ||
|
|
c73258138c | ||
|
|
2180ed24be | ||
|
|
b70de1b98d | ||
|
|
355482550b | ||
|
|
858a9f5d01 | ||
|
|
c7b83fd51c | ||
|
|
8e55209f33 | ||
|
|
4bde2ae1fc | ||
|
|
d4ba52b0d1 | ||
|
|
b483dc460d | ||
|
|
9ff47d75b5 | ||
|
|
d66481d67c | ||
|
|
b539f27475 | ||
|
|
128cd508b6 | ||
|
|
4f46af7557 | ||
|
|
0de43691ab | ||
|
|
79305c3de4 | ||
|
|
c1ea549995 | ||
|
|
fee2cae8c4 | ||
|
|
3317fb39ab | ||
|
|
de4ab0d3c9 | ||
|
|
be43aa3051 | ||
|
|
e7e6f5b184 | ||
|
|
74e52fd7f9 | ||
|
|
fe1ca5f055 | ||
|
|
3199ac7aae | ||
|
|
d22ffb2d07 | ||
|
|
c818ec89a4 | ||
|
|
2d2d544c5d | ||
|
|
97811f2e1c | ||
|
|
2db324e93d | ||
|
|
886343d40d | ||
|
|
f6c29ab274 | ||
|
|
8afabfa301 | ||
|
|
1d2aacd0a4 | ||
|
|
359082f80a | ||
|
|
1f159888a0 | ||
|
|
f37d83e55d | ||
|
|
b20f66b5e4 | ||
|
|
5d344acad9 | ||
|
|
06eef36868 | ||
|
|
ca06df793a | ||
|
|
92de60e5f2 | ||
|
|
61c0edcc96 | ||
|
|
7b129cd50f | ||
|
|
f237314ebf | ||
|
|
52efc84f5c | ||
|
|
5a326eee54 | ||
|
|
054950bc9a | ||
|
|
e5e46b5de5 | ||
|
|
8b9d2c007a | ||
|
|
5a6910a45b | ||
|
|
f8880aafec | ||
|
|
681a0055e4 | ||
|
|
69a7960876 | ||
|
|
7f77e5a13d | ||
|
|
bf585aba18 | ||
|
|
bf7afa7348 | ||
|
|
7f4eae6c56 | ||
|
|
8c045a6b8d | ||
|
|
ac026cc501 | ||
|
|
8d7106d992 | ||
|
|
2c0b1eee03 | ||
|
|
83817af2d7 | ||
|
|
339da2901c | ||
|
|
06130d071b | ||
|
|
02ca3a6cd5 | ||
|
|
aeea3c31f8 | ||
|
|
91dbfaf6b7 | ||
|
|
304441d393 | ||
|
|
4780da5b5b | ||
|
|
a4aa99f772 | ||
|
|
3315435579 | ||
|
|
bd330d81c3 | ||
|
|
078c8db5d7 | ||
|
|
53e4d1a371 | ||
|
|
2b18685cbf |
6
AUTHORS
6
AUTHORS
@@ -2,6 +2,10 @@ Aidan Thornton:
|
||||
Added Maple Mini support.
|
||||
board/board-maple-mini.h
|
||||
|
||||
Evangelos Rigas:
|
||||
Added Gnukey-DS support.
|
||||
board/board-gnukey-ds.h
|
||||
|
||||
Jeremy Drake:
|
||||
Modified STM32F103 support.
|
||||
mcu/sys-stm32f103.c
|
||||
@@ -34,7 +38,7 @@ NIIBE Yutaka:
|
||||
eventflag.c, eventflag.h
|
||||
Wrote the drivers mcu/*:
|
||||
chx-gnu-linux.c, chx-mkl27z.c, chx-stm32f0.c, chx-stm32f103.c,
|
||||
clk_gpio_init-mkl27z.c, clk_gpio_init-stm32.c,
|
||||
clk_gpio_init-mkl27z.c, clk_gpio_init-stm32f.c,
|
||||
cortex-m.h, mkl27z.h, stm32.h, stm32f103.h,
|
||||
sys-gnu-linux.c,sys-gnu-linux.h,
|
||||
sys-mkl27z.c, sys-mkl27z.h,
|
||||
|
||||
320
ChangeLog
320
ChangeLog
@@ -1,3 +1,323 @@
|
||||
2022-04-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.21.
|
||||
* doc/chopstx.texi (VERSION): 1.21.
|
||||
|
||||
2022-04-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport the changes from master.
|
||||
* chopstx.c (struct chx_pq): Use struct qh.
|
||||
(struct chx_px): Use struct qh.
|
||||
(struct chx_thread): Use struct qh.
|
||||
(FOR_QUEUE): Remove.
|
||||
(ll_dequeue): Follow the changes of above.
|
||||
(ll_prio_push): Use struct qh for the loop.
|
||||
(ll_prio_enqueue): Likewise.
|
||||
(chx_set_timer): Use struct qh for the first argument.
|
||||
(chx_timer_insert, chx_timer_dequeue): Use struct qh for the loop.
|
||||
(chx_timer_expired): Likewise.
|
||||
(chx_init, chopstx_create, chx_proxy_init): Use the address at q.
|
||||
(chx_exit): Use struct qh for the loop.
|
||||
(chx_mutex_unlock): Fix the calculation of the priority.
|
||||
* chopstx-cortex-m.c (chx_handle_intr): Not use FOR_QUEUE macro.
|
||||
* chopstx-gnu-linux.c (chx_handle_intr): Not use FOR_QUEUE macro.
|
||||
|
||||
2022-04-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport the changes from master.
|
||||
* chopstx.h (struct chx_qh): Change the type for next and prev.
|
||||
* chopstx.c (FOR_QUEUE): New macro.
|
||||
(ll_empty): Follow the change of struct chx_qh.
|
||||
(ll_insert): Change the type of the first argument.
|
||||
(ll_pop): Follow the change of struct chx_qh.
|
||||
(ll_prio_push): Use FOR_QUEUE macro. Follow the change of
|
||||
ll_insert.
|
||||
(ll_prio_enqueue, chx_timer_insert): Likewise.
|
||||
(chx_timer_dequeue, chx_init, chx_exit): Likewise.
|
||||
(chopstx_mutex_init, chopstx_cond_init): Likewise.
|
||||
* chopstx-cortex-m.c (chx_handle_intr): Use FOR_QUEUE macro.
|
||||
* chopstx-gnu-linux.c (chx_handle_intr): Use FOR_QUEUE macro.
|
||||
|
||||
2021-10-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.20.
|
||||
* doc/chopstx.texi (VERSION): 1.20.
|
||||
|
||||
2021-10-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport from master.
|
||||
* mcu/usb-usbip.c (URB_DATA_SIZE): Tweak the value.
|
||||
|
||||
2021-02-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.19.
|
||||
* doc/chopstx.texi (VERSION): 1.19.
|
||||
|
||||
2021-02-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport from master.
|
||||
* contrib/ackbtn-gnu-linux.c: New.
|
||||
* mcu/usb-usbip.c (usbip_run_server): Add start-up message.
|
||||
* contrib/adc-gnu-linux.c (adc_start_conversion): Use getrandom.
|
||||
|
||||
2021-02-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport from 2.1.
|
||||
* chopstx-gnu-linux.c (chopstx_create_arch): Clear TP.
|
||||
* example-cdc-gnu-linux/usb-cdc.c (tty_recv): Cancel the input.
|
||||
* example-cdc-gnu-linux/sample.c (main): Handle timeout by canceling
|
||||
input.
|
||||
|
||||
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.18.
|
||||
* doc/chopstx.texi (VERSION): 1.18.
|
||||
|
||||
2019-12-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_poll): Call CHECK for condition
|
||||
valiable after woken up.
|
||||
|
||||
2019-12-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-gnu-linux.c (chx_thread_start): Fix return value.
|
||||
|
||||
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (chx_set_running): New.
|
||||
(chx_init_arch): Use chx_set_running.
|
||||
(preempt, svc): Remove set to running, not needed.
|
||||
|
||||
* chopstx-gnu-linux.c (chx_set_running): New.
|
||||
(chx_init_arch, chx_request_preemption, chx_sched): Use
|
||||
chx_set_running and chx_running.
|
||||
(chx_sched): Bug fix of return value handling.
|
||||
|
||||
2019-11-20 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.17.
|
||||
* doc/chopstx.texi (VERSION): 1.17.
|
||||
|
||||
* chopstx-gnu-linux.c (chx_running): New.
|
||||
(chx_init_arch): Set RUNNING.
|
||||
|
||||
2019-11-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (chx_running): New.
|
||||
(chx_init_arch): Set RUNNING.
|
||||
|
||||
* chopstx.c (chx_init): Don't set RUNNING here.
|
||||
(chx_timer_expired): Use chx_running.
|
||||
(chx_systick_init, chx_exit, chx_mutex_unlock, chopstx_create)
|
||||
(chopstx_mutex_lock, chopstx_mutex_unlock, chopstx_cleanup_push)
|
||||
(chopstx_cleanup_pop, chopstx_exit, chopstx_cancel)
|
||||
(chopstx_testcancel, chopstx_setcancelstate, chx_proxy_init)
|
||||
(chopstx_poll, chopstx_setpriority): Likewise.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-gnu-linux.c (chx_systick_init_arch): Rename.
|
||||
(chx_interrupt_controller_init): Rename.
|
||||
* chopstx-cortex-m.c (chx_systick_init_arch): Rename.
|
||||
(chx_interrupt_controller_init): Rename.
|
||||
* chopstx.c (chx_systick_init): Use chx_systick_init_arch.
|
||||
(chx_init): Use chx_interrupt_controller_init.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_ready_pop): Check flag_sched_rr here.
|
||||
* chopstx-cortex-m.c (chx_sched) [__ARM_ARCH_6M__]: Use
|
||||
new interface of chx_ready_pop.
|
||||
(preempt,svc): Likewise.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (ticks_to_usec): New.
|
||||
* chopstx-gnu-linux.c (ticks_to_usec): New.
|
||||
* chopstx.c (chx_snooze): Use ticks_to_usec.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* rules.mk (CSRC): Change the rule of entry*.c.
|
||||
* entry.c: It's only for Cortex-M, now.
|
||||
* entry-gnu-linux.c: New file.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* entry.c: Use chopstx-cortex-m.h.
|
||||
* chopstx.h (CHOPSTX_THREAD_SIZE): Move the definition to ...
|
||||
* chopstx-cortex-m.h (CHOPSTX_THREAD_SIZE): ... here.
|
||||
|
||||
2019-10-07 Jeremy Drake <jeremy@drastrom.science>
|
||||
|
||||
* mcu/usb-st-common.c (usb_lld_init): Move BTABLE initialization
|
||||
after clearing ISTR register.
|
||||
|
||||
2019-09-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
When it was exactly 64-byte, two ZLPs were sent wrongly.
|
||||
* mcu/usb-st-common.c (usb_lld_ctrl_send): Fix for 64-byte.
|
||||
* mcu/usb-usbip.c (usb_lld_ctrl_send): Likewise.
|
||||
* mcu/usb-mkl27z.c (usb_lld_ctrl_send): Likewise.
|
||||
|
||||
2019-05-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.16.
|
||||
* doc/chopstx.texi (VERSION): 1.16.
|
||||
|
||||
2019-05-22 Evangelos Rigas <erigas@rnd2.org>
|
||||
|
||||
* board/board-gnukey-ds.h: New.
|
||||
|
||||
2019-05-14 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.15.
|
||||
* doc/chopstx.texi (VERSION): 1.15.
|
||||
|
||||
2019-05-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* board/board-maple-mini.h: Assert USB D+ pull-up.
|
||||
* board/board-olimex-stm32-h103.h: Likewise.
|
||||
* board/board-stbee.h:Likewise.
|
||||
* board/board-stm32-primer2.h: Likewise.
|
||||
|
||||
* mcu/usb-stm32f103.c: Don't use usb_lld_sys_init and
|
||||
usb_lld_sys_shutdown in SYS.
|
||||
* mcu/usb-stm32l4.c: Ditto.
|
||||
|
||||
2019-05-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_claim_irq): Check INTR before the call.
|
||||
|
||||
* chopstx-cortex-m.c (chx_disable_intr): Have return value.
|
||||
* chopstx-gnu-linux.c (chx_disable_intr): Likewise.
|
||||
|
||||
2019-05-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/sys-stm32f103.c: SYS version 4.0.
|
||||
* mcu/sys-gnu-linux.c: Likewise.
|
||||
* mcu/sys-mkl27z.c: Likewise.
|
||||
* mcu/sys-stm32l4.c: Likewise.
|
||||
* mcu/sys-stm32f0.c: Likewise.
|
||||
|
||||
2019-05-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/sys-stm32f103.c (usb_lld_sys_shutdown, usb_lld_sys_init):
|
||||
Only cable config.
|
||||
|
||||
* mcu/sys-stm32l4.c (usb_lld_sys_shutdown, usb_lld_sys_init):
|
||||
Likewise.
|
||||
|
||||
* mcu/usb-st-common.c (usb_lld_init): Call chip specific routine.
|
||||
(usb_lld_shutdown): Likewise.
|
||||
|
||||
* mcu/usb-stm32l4.c (usb_lld_init_chip_specific)
|
||||
(usb_lld_shutdown_chip_specific): New.
|
||||
|
||||
* mcu/usb-stm32f103.c (usb_lld_init_chip_specific)
|
||||
(usb_lld_shutdown_chip_specific): New.
|
||||
|
||||
* rules.mk (DEFS): Add -DUSE_SYS when USE_SYS.
|
||||
|
||||
2019-04-25 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart.h (BSCARD1, BSCARD2...): New.
|
||||
(BSCARD): Remove.
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config_baud): Rename
|
||||
from usart_config_brr, changing API.
|
||||
* contrib/usart-stm32l4.c (usart_config_baud): Likewise.
|
||||
|
||||
2019-04-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/sys-stm32l4.c: New.
|
||||
* mcu/chx-stm32l4.c: New. Not support suspend yet.
|
||||
* mcu/stm32l.h: New.
|
||||
* mcu/clk_gpio_init-stm32l.c: New.
|
||||
|
||||
2019-04-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/usb-stm32l4.c: New.
|
||||
* mcu/usb-st-common.c: Factor out from usb-stm32f103.c.
|
||||
|
||||
2019-04-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32l4.c: New.
|
||||
* contrib/usart-common.c: Factor out from usart-stm32f103.c.
|
||||
|
||||
* entry.c [__ARM_ARCH_7EM__] (entry): Fix for Cortex-M4.
|
||||
|
||||
2019-04-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c: Support Cortex-M4 (not touching FPU).
|
||||
|
||||
2019-04-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/clk_gpio_init-stm32f.c: Rename from clk_gpio_init-stm32.c.
|
||||
|
||||
* entry.c: Use STM32F10X_HD.
|
||||
* board/board-stbee.h (STM32F10X_HD): Add.
|
||||
* board/board-stm32-primer2.h (STM32F10X_HD): Add.
|
||||
|
||||
2019-04-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_block_sendrecv): Support
|
||||
busy-wait when timeout_block_p == 0.
|
||||
|
||||
2019-04-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_block_sendrecv): New.
|
||||
(usart_init0): New.
|
||||
|
||||
2019-03-30 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config_brr): New.
|
||||
(usart_config_re): New internal function.
|
||||
(handle_intr, handle_tx_ready): Use TC for smartcard.
|
||||
(usart_wait_write_completion): New internal function.
|
||||
(usart_write): Support half-duplex smartcard mode.
|
||||
|
||||
2019-03-29 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_read_ext): New.
|
||||
(usart_read_prepare_poll): New.
|
||||
|
||||
2019-03-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.14.
|
||||
* doc/chopstx.texi (VERSION): 1.14.
|
||||
|
||||
2019-03-01 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config): Fix SCEN setting
|
||||
procedure.
|
||||
|
||||
2019-03-01 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config): Support parity error
|
||||
interrupt setting.
|
||||
(usart_init): Don't call usart_config here.
|
||||
* example-usb-serial/sample.c: It's application calling
|
||||
usart_config.
|
||||
|
||||
2019-02-28 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart.h (BSCARD): New.
|
||||
* contrib/usart-stm32f103.c (BSCARD): Baudrate for smartcard.
|
||||
(usart_config_clken): New.
|
||||
(usart_config): Fix for MODE_SMARTCARD.
|
||||
|
||||
* board/board-st-nucleo-f103.h: Define pins for smartcard
|
||||
interface.
|
||||
|
||||
2019-02-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart.h (MODE_SMARTCARD, MODE_IRDA, MODE_IRDA_LP)
|
||||
(MASK_MODE): New.
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config): Add support for
|
||||
those modes.
|
||||
|
||||
2018-12-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.13.
|
||||
|
||||
@@ -5,7 +5,7 @@ include following exception to GNU GPL.
|
||||
--------------------
|
||||
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
|
||||
GPL normally required by section 4, provided you inform the recipients
|
||||
of GNU GPL by a written offer.
|
||||
--------------------
|
||||
|
||||
|
||||
119
NEWS
119
NEWS
@@ -1,6 +1,125 @@
|
||||
NEWS - Noteworthy changes
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.21
|
||||
|
||||
Released 2022-04-22
|
||||
|
||||
** Fix of struct chx_qh and struct chx_thread/pq/px.
|
||||
|
||||
Good compiler complains/warns for possible different size of
|
||||
structures. To avoid this, access to the objects are fixed.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.20
|
||||
|
||||
Released 2021-10-12
|
||||
|
||||
** Fix of USB driver for GNU/Linux emulation
|
||||
|
||||
Fix the value of URB_DATA_SIZE, so that Gnuk can work with PC/SC.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.19
|
||||
|
||||
Released 2021-02-18
|
||||
|
||||
** Acknowledge button support for GNU/Linux emulation
|
||||
User is asked acknowledge by RET with standard input.
|
||||
|
||||
** USB driver for GNU/Linux emulation
|
||||
It shows start-up message now.
|
||||
|
||||
** ADC driver for GNU/Linux emulation
|
||||
It uses getrandom(2), output is not deterministic any more.
|
||||
|
||||
** Bug fix for GNU/Linux emulation
|
||||
When creating a thread, allocated memory for struct chx_thread was not
|
||||
initialized by chopstx_create_arch, assuming getcontext does it well.
|
||||
To make sure (getcontext would not update the area for FPU registers,
|
||||
when not used), it's now initialized by zeros.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.18
|
||||
|
||||
Released 2019-12-30
|
||||
|
||||
** Fix of chopstx_poll
|
||||
When waiting for a condition variable, we supply CHECK method with a
|
||||
descriptor. Since a condition variable may be fired for multiple
|
||||
reasons, old implementation of chopstx_poll may return with wrong
|
||||
information saying a condition of CHECK were met but actually not. It
|
||||
should not return when condition is not satisfied and it should not
|
||||
give wrong information to application. Fixed by calling the CHECK
|
||||
method again when woken up, and don't return when no condition meet.
|
||||
|
||||
** Bug fix for GNU/Linux emulation
|
||||
When woken up, return value of chx_sched was wrong. Because of this,
|
||||
timeout handling had problem. Termination value of a thread was
|
||||
wrong.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.17
|
||||
|
||||
Released 2019-11-20
|
||||
|
||||
** USB drivers bug fix for STM32 and ZLP handling for 64-byte packet.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.16
|
||||
|
||||
Released 2019-05-22
|
||||
|
||||
** New board support: Gnukey-DS
|
||||
It is contributed by Evangelos Rigas.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.15
|
||||
|
||||
Released 2019-05-14
|
||||
|
||||
** SYS version 4.0
|
||||
USB initialization/finalization API has been changed. SYS routines
|
||||
only handle USB cable configuration when supported by a board.
|
||||
|
||||
** USB driver change
|
||||
Enabling/disabling USB module is done by USB driver. It's
|
||||
responsibility of board configuration to enable external transistor
|
||||
for pull-up D+-line by board/*.h. For all boards, USB driver doesn't
|
||||
use usb_lld_sys_init or usb_lld_sys_shutdown (those routines only can
|
||||
be used for USB self powered system, which Chopstx does not support
|
||||
yet).
|
||||
|
||||
** Board configuration change
|
||||
For USB driver change, board-maple-mini.h, board-olimex-stm32-h103.h,
|
||||
board-stbee.h, and board-stm32-primer2.h were changed. Pull-up is
|
||||
enabled at the time of gpio_init.
|
||||
|
||||
** Cortex-M4 support
|
||||
Cortex-M4 support has been added. Not supporting use of FPU or DSP,
|
||||
yet. Note that it's not intend to be used by Gnuk.
|
||||
|
||||
** STM32L432 support
|
||||
USART and USB drivers are added.
|
||||
|
||||
** New board support: ST Nucleo-32 L432
|
||||
ST Nucleo-32 L432 is a small board with ST-Link/V2-1.
|
||||
|
||||
** Minor implementation change: chopstx_claim_irq
|
||||
If the interrupt is disabled (possibly by chx_intr) when
|
||||
chopstx_claim_irq is called, INTR->ready is set to 1. This allows
|
||||
calling chopstx_claim_irq after hardware initialization which may
|
||||
cause an interrupt before the call of chopstx_claim_irq.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.14
|
||||
|
||||
Released 2019-03-02
|
||||
|
||||
** Enhancement of driver: USART for STM32
|
||||
Now, it supports smartcard communication.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.13
|
||||
|
||||
Released 2018-12-19
|
||||
|
||||
19
README
19
README
@@ -1,6 +1,6 @@
|
||||
Chopstx - Threads and only Threads
|
||||
Version 1.12
|
||||
2018-11-12
|
||||
Version 1.21
|
||||
2021-04-22
|
||||
Niibe Yutaka
|
||||
Flying Stone Technology
|
||||
|
||||
@@ -8,8 +8,8 @@ What's Chopstx?
|
||||
===============
|
||||
|
||||
Chopstx is an RT thread library for STM32F103 and GD32F103 (ARM
|
||||
Cortex-M3), STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus), and
|
||||
emulation on GNU/Linux.
|
||||
Cortex-M3), STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus),
|
||||
STM32L432 (ARM Cortex-M4), and emulation on GNU/Linux.
|
||||
|
||||
While most RTOSes come with many features, drivers, and protocol
|
||||
stacks, Chopstx just offers a simple RT thread library.
|
||||
@@ -19,7 +19,7 @@ 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.
|
||||
handle multiple events by a single thread.
|
||||
|
||||
|
||||
Note that this library is _not_ related to the hand game:
|
||||
@@ -60,11 +60,6 @@ For STM32 Primer2, see the directory: example-primer2.
|
||||
Future Works
|
||||
============
|
||||
|
||||
Convenience function to determine the bottom of thread stack,
|
||||
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,
|
||||
more careful considerations for shared access to objects of struct
|
||||
chx_pq is needed. So, modifications required will not be small.
|
||||
RISC-V port (for GD32VF103) is available in 2.x. Please have a look
|
||||
at the master branch, and test it if possible.
|
||||
--
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* PA0 - input with pull-up. AN0
|
||||
* PA1 - input with pull-up. AN1
|
||||
* PA8 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
||||
* PA10 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PA10 - Push pull output 50MHz (USB 1:ON 0:OFF) default 1
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* ------------------------ Default
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* 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 (USB 1:ON 0:OFF)
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF) default 1
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* ------------------------ Default
|
||||
|
||||
39
board/board-gnukey-ds.h
Normal file
39
board/board-gnukey-ds.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#define BOARD_NAME "Gnukey DS"
|
||||
#define BOARD_ID 0x67ee65a3
|
||||
/* echo -n "Gnukey DS" | 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 9 // 8MHz * 9 = 72 MHz
|
||||
#define STM32_HSECLK 8000000
|
||||
|
||||
#define GPIO_LED_BASE GPIOA_BASE
|
||||
#define GPIO_LED_SET_TO_EMIT 3
|
||||
#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
|
||||
* PA2 - input with pull-up: Hall effect sensor output
|
||||
* PA3 - 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 0xFFFFE7F7 /* 0/1 Pull Down/Up */
|
||||
#define VAL_GPIO_LED_CRL 0x88881888 /* PA7...PA0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88811888 /* 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.
|
||||
*/
|
||||
@@ -30,11 +30,11 @@
|
||||
/*
|
||||
* Port B setup.
|
||||
* PB1 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
||||
* PB9 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PB9 - Push pull output 50MHz (USB 0:ON 1:OFF) default 0
|
||||
* ------------------------ Default
|
||||
* PBx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFDFF
|
||||
#define VAL_GPIO_LED_CRL 0x88888838 /* PB7...PB0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88888838 /* PB15...PB8 */
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
* PA10 - floating input
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* PA15 - Push pull output (USB_EN 1:ON 0:OFF)
|
||||
* PA15 - Push pull output (USB_EN 1:ON 0:OFF) default 1
|
||||
* ------------------------ Default
|
||||
* PA8 - input with pull-up.
|
||||
* PA9 - floating input.
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
* PC1 - input with pull-up. AN11 for NeuG
|
||||
* PC6 - input without pull-up/down
|
||||
* PC7 - input without pull-up/down
|
||||
* PC11 - Open-drain output 50MHz (USB disconnect).
|
||||
* PC11 - Open-drain output 50MHz (USB 0:ON 1:OFF) default 0
|
||||
* PC12 - Push Pull output 50MHz (LED).
|
||||
* ------------------------ Default
|
||||
* PCx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFF7FF
|
||||
#define VAL_GPIO_LED_CRL 0x44888888 /* PC7...PC0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88837888 /* PC15...PC8 */
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* PA9 - Push pull output 50MHz (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)
|
||||
* PA15 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PA15 - Push pull output 50MHz (USB 1:ON 0:OFF) default 1
|
||||
* ------------------------ Default
|
||||
* PAx - input with pull-up
|
||||
*/
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
*
|
||||
* At CN10, connect USB cable
|
||||
* Vbus RED --> 10 NC ----------> CN7 (6 E5V)
|
||||
* D+ GREEN --> 12 PA11 ---[1K5]--> CN6 (4 3V3)
|
||||
* D- WHITE --> 14 PA12
|
||||
* D+ GREEN --> 12 PA12 ---[1K5]--> CN6 (4 3V3)
|
||||
* D- WHITE --> 14 PA11
|
||||
* 16 PB12 (USART3-CK) ---> smartcard CK
|
||||
* 18
|
||||
* GND BLACK --> 20 GND
|
||||
*/
|
||||
|
||||
@@ -49,17 +51,26 @@
|
||||
* 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
|
||||
* ---
|
||||
* ---
|
||||
* PB4 - Input with pull-up: Card insertion detect: 0 when detected
|
||||
* ---
|
||||
* PB6 - Output push pull 2MHz: Vcc for card: default 0
|
||||
* ---
|
||||
* PB8 - Output push pull 2MHz: Vpp for card: default 0
|
||||
* PB9 - Output push pull 2MHz: RST for card: default 0
|
||||
* PB10 - Alternate function open-drain output 50MHz USART3-TX
|
||||
* PB11 - Input with pull-up USART3-RX
|
||||
* PB12 - Alternate function push pull output 2MHz USART3-CK
|
||||
* PB12 - Alternate function push pull output 50MHz USART3-CK
|
||||
* PB13 - Input with pull-up USART3-CTS
|
||||
* PB14 - Alternate function push pull output 2MHz USART3-RTS
|
||||
* PB14 - Alternate function push pull output 50MHz 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 VAL_GPIO_OTHER_ODR 0xFFFFFCBF
|
||||
#define VAL_GPIO_OTHER_CRL 0x82888888 /* PB7...PB0 */
|
||||
#define VAL_GPIO_OTHER_CRH 0x8B8B8F22 /* PB15...PB8 */
|
||||
|
||||
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN)
|
||||
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST)
|
||||
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN)
|
||||
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | RCC_APB2RSTR_AFIORST)
|
||||
|
||||
75
board/board-st-nucleo-l432.h
Normal file
75
board/board-st-nucleo-l432.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#define BOARD_NAME "ST Nucleo L432"
|
||||
#define BOARD_ID 0x3a8d5116
|
||||
|
||||
/*
|
||||
* When using USB, please add USB cable to ST Nucleo L432.
|
||||
*
|
||||
* At CN4, connect USB cable, only when ST Link is not connected
|
||||
* Vbus RED --> 4
|
||||
*
|
||||
* At CN3, connect USB cable
|
||||
* D- WHITE --> 13 PA11
|
||||
* D+ GREEN --> 5 PA12
|
||||
* GND BLACK --> 4 GND
|
||||
*
|
||||
* Smartcard VCC: PA3
|
||||
* Smartcard GND: GND --+
|
||||
* Smartcard RST: PA1 |
|
||||
* Smartcard VPP: PA4 |
|
||||
* Smartcard CLK: PA8 |
|
||||
* Smartcard I/O: PA9 |
|
||||
* GND --+
|
||||
* Smartcard DETECT: PA0
|
||||
*/
|
||||
|
||||
#define MCU_STM32L4 1
|
||||
|
||||
#define GPIO_LED_BASE GPIOB_BASE
|
||||
#define GPIO_LED_SET_TO_EMIT 3
|
||||
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
|
||||
#define GPIO_OTHER_BASE GPIOA_BASE
|
||||
|
||||
/*
|
||||
* Port A setup.
|
||||
*
|
||||
* MODER: 10 10 - 10 10 - 10 11 - 10 10 11 11 - 11 01 - 01 10 - 01 00
|
||||
*
|
||||
* PA0 - Input with pull-up: Card insertion detect: 0 when detected
|
||||
* PA1 - Output push-pull default 0: Card RST
|
||||
* PA2 - USART2-TX (AF7): output push-pull
|
||||
* PA3 - Output push-pull default 0: Card Vcc
|
||||
* PA4 - Output push-pull default 0: Card Vpp
|
||||
* PA8 - USART1-CK (AF7): output push-pull: Card CLK
|
||||
* PA9 - USART1-TX (AF7): output(input) Open-drain pull-up: Card I/O
|
||||
* PA11 - USBDM (AF10): input/output
|
||||
* PA12 - USBDP (AF10): input/output
|
||||
* PA13 - SWDIO (AF0)
|
||||
* PA14 - SWDCLK (AF0)
|
||||
* PA15 - USART2-RX (AF3): input with pull-up
|
||||
* ------------------------ Default
|
||||
* PAx - analog input
|
||||
*/
|
||||
#define VAL_GPIO_OTHER_MODER 0xAABAFD64
|
||||
#define VAL_GPIO_OTHER_OTYPER 0x00000200
|
||||
#define VAL_GPIO_OTHER_OSPEEDR 0xFFFFFFFF
|
||||
#define VAL_GPIO_OTHER_PUPDR 0x40040001
|
||||
#define VAL_GPIO_OTHER_AFRL 0x00000700
|
||||
#define VAL_GPIO_OTHER_AFRH 0x300AA077
|
||||
|
||||
/*
|
||||
* Port B setup.
|
||||
*
|
||||
* MODER: 11 11 - 11 11 - 11 11 - 11 11 11 11 - 11 11 - 01 11 - 11 11
|
||||
*
|
||||
* PB3 - ON (LED 1:ON 0:OFF)
|
||||
* ------------------------ Default
|
||||
* PBx - analog input
|
||||
*/
|
||||
#define VAL_GPIO_LED_MODER 0xFFFFFF7F
|
||||
#define VAL_GPIO_LED_OTYPER 0x00000000
|
||||
#define VAL_GPIO_LED_OSPEEDR 0x00000000
|
||||
#define VAL_GPIO_LED_PUPDR 0x00000000
|
||||
#define VAL_GPIO_LED_AFRL 0x00000000
|
||||
#define VAL_GPIO_LED_AFRH 0x00000000
|
||||
|
||||
#define RCC_AHB2_GPIO (RCC_AHB2_GPIOA | RCC_AHB2_GPIOB)
|
||||
@@ -52,7 +52,7 @@
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* PA13 - Open Drain output (LED1 0:ON 1:OFF)
|
||||
* PA14 - Push pull output (USB ENABLE 0:DISABLE 1:ENABLE)
|
||||
* PA14 - Push pull output (USB 1:ON 0:OFF) default 1
|
||||
* PA15 - Open Drain output (LED2 0:ON 1:OFF)
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFE77F
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define BOARD_ID 0x945c37e8
|
||||
|
||||
#define MCU_STM32F1 1
|
||||
/* High-density device */
|
||||
#define STM32F10X_HD /* High-density device */
|
||||
|
||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||
#define STM32_PLLMUL_VALUE 6
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
/*
|
||||
* Port D setup.
|
||||
* PD3 - Push pull output (USB_DISC 1:USB-DISABLE 0:USB-ENABLE) 2MHz
|
||||
* PD3 - Push pull output (USB 1:OFF 0:ON) 2MHz default 0
|
||||
* PD4 - Open Drain output 2MHz (LED1).
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFF7
|
||||
#define VAL_GPIO_LED_CRL 0x88862888 /* PD7...PD0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88888888 /* PD15...PD8 */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define BOARD_ID 0x21e5798d
|
||||
|
||||
#define MCU_STM32F1 1
|
||||
/* High-density device */
|
||||
#define STM32F10X_HD /* High-density device */
|
||||
|
||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||
#define STM32_PLLMUL_VALUE 6
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
/*
|
||||
* Port D setup.
|
||||
* PD3 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PD3 - Push pull output 50MHz (USB 0:ON 1:OFF) default 0
|
||||
* ------------------------ Default
|
||||
* PDx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFFFF7
|
||||
#define VAL_GPIO_USB_CRL 0x88883888 /* PD7...PD0 */
|
||||
#define VAL_GPIO_USB_CRH 0x88888888 /* PD15...PD8 */
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
|
||||
* for Cortex-M0/M3
|
||||
* for Cortex-M0/M3/M4
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -24,10 +24,25 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
static struct chx_thread *running;
|
||||
|
||||
static struct chx_thread *
|
||||
chx_running (void)
|
||||
{
|
||||
return running;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_running (struct chx_thread *r)
|
||||
{
|
||||
running = r;
|
||||
}
|
||||
|
||||
|
||||
/* Data Memory Barrier. */
|
||||
static void
|
||||
chx_dmb (void)
|
||||
@@ -84,7 +99,7 @@ struct chx_stack_regs {
|
||||
#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__)
|
||||
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
|
||||
|
||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
|
||||
@@ -106,30 +121,34 @@ struct chx_stack_regs {
|
||||
* 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;
|
||||
struct SYST {
|
||||
volatile uint32_t CSR;
|
||||
volatile uint32_t RVR;
|
||||
volatile uint32_t CVR;
|
||||
const uint32_t CALIB;
|
||||
};
|
||||
static struct SYST *const SYST = (struct SYST *)0xE000E010;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
chx_systick_init_arch (void)
|
||||
{
|
||||
*SYST_RVR = 0;
|
||||
*SYST_CVR = 0;
|
||||
*SYST_CSR = 7;
|
||||
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;
|
||||
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;
|
||||
return SYST->CVR;
|
||||
}
|
||||
|
||||
static uint32_t usec_to_ticks (uint32_t usec)
|
||||
@@ -137,6 +156,12 @@ static uint32_t usec_to_ticks (uint32_t usec)
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ticks_to_usec (uint32_t ticks)
|
||||
{
|
||||
return ticks / MHZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt Handling
|
||||
*/
|
||||
@@ -175,10 +200,13 @@ chx_clr_intr (uint8_t irq_num)
|
||||
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
int already_disabled = !!(NVIC_ICER (irq_num) & (1 << (irq_num & 0x1f)));
|
||||
|
||||
NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
return already_disabled;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -198,7 +226,7 @@ static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
|
||||
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
chx_interrupt_controller_init (void)
|
||||
{
|
||||
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
|
||||
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
|
||||
@@ -239,7 +267,7 @@ chx_cpu_sched_unlock (void)
|
||||
void
|
||||
chx_handle_intr (void)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
register uint32_t irq_num;
|
||||
|
||||
asm volatile ("mrs %0, IPSR\n\t"
|
||||
@@ -248,7 +276,10 @@ chx_handle_intr (void)
|
||||
|
||||
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)
|
||||
for (q = q_intr.q.next; q != &q_intr.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
@@ -258,6 +289,7 @@ chx_handle_intr (void)
|
||||
chx_request_preemption (px->master->prio);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
@@ -265,6 +297,7 @@ static void
|
||||
chx_init_arch (struct chx_thread *tp)
|
||||
{
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
chx_set_running (tp);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -302,7 +335,7 @@ chx_sched (uint32_t yield)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
asm volatile (
|
||||
"svc #0"
|
||||
: "=r" (tp) : "0" (yield): "memory");
|
||||
@@ -359,12 +392,6 @@ chx_sched (uint32_t yield)
|
||||
}
|
||||
|
||||
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. */
|
||||
@@ -555,19 +582,12 @@ preempt (void)
|
||||
}
|
||||
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"
|
||||
@@ -644,7 +664,7 @@ preempt (void)
|
||||
: /* no output */ : "r" (tp) : "memory");
|
||||
}
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
/*
|
||||
* System call: switch to another thread.
|
||||
* There are two cases:
|
||||
@@ -681,16 +701,9 @@ svc (void)
|
||||
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"
|
||||
|
||||
@@ -10,3 +10,5 @@ struct tcontext {
|
||||
};
|
||||
|
||||
typedef struct tcontext tcontext_t;
|
||||
|
||||
#define CHOPSTX_THREAD_SIZE 64
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
||||
* for GNU/Linux emulation
|
||||
*
|
||||
* Copyright (C) 2017, 2018 Flying Stone Technology
|
||||
* Copyright (C) 2017, 2018, 2019, 2021 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -23,7 +23,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -32,6 +32,21 @@
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static struct chx_thread *running;
|
||||
|
||||
static struct chx_thread *
|
||||
chx_running (void)
|
||||
{
|
||||
return running;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_running (struct chx_thread *r)
|
||||
{
|
||||
running = r;
|
||||
}
|
||||
|
||||
|
||||
/* Data Memory Barrier. */
|
||||
static void
|
||||
chx_dmb (void)
|
||||
@@ -42,7 +57,7 @@ chx_dmb (void)
|
||||
static sigset_t ss_cur;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
chx_systick_init_arch (void)
|
||||
{
|
||||
const struct itimerval it = { {0, 0}, {0, 0} };
|
||||
|
||||
@@ -76,6 +91,11 @@ usec_to_ticks (uint32_t usec)
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ticks_to_usec (uint32_t ticks)
|
||||
{
|
||||
return ticks / MHZ;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_enable_intr (uint8_t irq_num)
|
||||
@@ -89,10 +109,13 @@ chx_clr_intr (uint8_t irq_num)
|
||||
(void)irq_num;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
int already_disabled = sigismember (&ss_cur, irq_num);
|
||||
|
||||
sigaddset (&ss_cur, irq_num);
|
||||
return already_disabled;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -102,7 +125,7 @@ chx_set_intr_prio (uint8_t n)
|
||||
}
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
chx_interrupt_controller_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -131,11 +154,13 @@ idle (void)
|
||||
void
|
||||
chx_handle_intr (uint32_t irq_num)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
|
||||
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)
|
||||
for (q = q_intr.q.next; q != &q_intr.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
@@ -146,6 +171,7 @@ chx_handle_intr (uint32_t irq_num)
|
||||
chx_request_preemption (px->master->prio);
|
||||
return;
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
@@ -197,19 +223,22 @@ chx_init_arch (struct chx_thread *tp)
|
||||
makecontext (&idle_tc, idle, 0);
|
||||
|
||||
getcontext (&tp->tc);
|
||||
|
||||
chx_set_running (tp);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_request_preemption (uint16_t prio)
|
||||
{
|
||||
struct chx_thread *tp, *tp_prev;
|
||||
ucontext_t *tcp;
|
||||
struct chx_thread *tp_prev;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
|
||||
if (running && (uint16_t)running->prio >= prio)
|
||||
if (tp && (uint16_t)tp->prio >= prio)
|
||||
return;
|
||||
|
||||
/* Change the context to another thread with higher priority. */
|
||||
tp = tp_prev = running;
|
||||
tp_prev = tp;
|
||||
if (tp)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
@@ -222,23 +251,15 @@ chx_request_preemption (uint16_t prio)
|
||||
}
|
||||
else
|
||||
chx_ready_push (tp);
|
||||
running = NULL;
|
||||
}
|
||||
|
||||
tp = running = chx_ready_pop ();
|
||||
tp = 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;
|
||||
|
||||
chx_set_running (tp);
|
||||
if (tp_prev)
|
||||
{
|
||||
/*
|
||||
@@ -283,10 +304,9 @@ static uintptr_t
|
||||
chx_sched (uint32_t yield)
|
||||
{
|
||||
struct chx_thread *tp, *tp_prev;
|
||||
uintptr_t v;
|
||||
ucontext_t *tcp;
|
||||
|
||||
tp = tp_prev = running;
|
||||
tp = tp_prev = chx_running ();
|
||||
if (yield)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
@@ -294,35 +314,28 @@ chx_sched (uint32_t yield)
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
|
||||
running = tp = chx_ready_pop ();
|
||||
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;
|
||||
}
|
||||
|
||||
chx_set_running (tp);
|
||||
swapcontext (&tp_prev->tc, tcp);
|
||||
chx_cpu_sched_unlock ();
|
||||
return v;
|
||||
|
||||
tp = chx_running ();
|
||||
return tp->v;
|
||||
}
|
||||
|
||||
static void __attribute__((__noreturn__))
|
||||
chx_thread_start (voidfunc thread_entry, void *arg)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
chx_cpu_sched_unlock ();
|
||||
thread_entry (arg);
|
||||
chopstx_exit (0);
|
||||
ret = thread_entry (arg);
|
||||
chopstx_exit (ret);
|
||||
}
|
||||
|
||||
static struct chx_thread *
|
||||
@@ -339,6 +352,7 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
|
||||
* signal blocked. The sigmask will be cleared in chx_thread_start.
|
||||
*/
|
||||
chx_cpu_sched_lock ();
|
||||
memset (tp, 0, sizeof (struct chx_thread));
|
||||
getcontext (&tp->tc);
|
||||
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
|
||||
tp->tc.uc_stack.ss_size = stack_size;
|
||||
|
||||
231
chopstx.c
231
chopstx.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* chopstx.c - Threads and only threads.
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -23,7 +23,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -83,14 +83,14 @@ chx_fatal (uint32_t err_code)
|
||||
int chx_allow_sleep;
|
||||
static struct chx_spinlock chx_enable_sleep_lock;
|
||||
|
||||
/* RUNNING: the current thread. */
|
||||
struct chx_thread *running;
|
||||
|
||||
struct chx_queue {
|
||||
struct chx_qh q;
|
||||
struct chx_spinlock lock;
|
||||
};
|
||||
|
||||
/* Forward declaration. */
|
||||
struct chx_pq;
|
||||
|
||||
/* READY: priority queue. */
|
||||
static struct chx_queue q_ready;
|
||||
|
||||
@@ -129,7 +129,7 @@ static void chx_spin_unlock (struct chx_spinlock *lk)
|
||||
|
||||
/**************/
|
||||
struct chx_pq {
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh q;
|
||||
uint32_t : 4;
|
||||
uint32_t : 5;
|
||||
uint32_t : 6;
|
||||
@@ -141,7 +141,7 @@ struct chx_pq {
|
||||
};
|
||||
|
||||
struct chx_px { /* inherits PQ */
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh q;
|
||||
uint32_t : 4;
|
||||
uint32_t : 5;
|
||||
uint32_t : 6;
|
||||
@@ -157,7 +157,7 @@ struct chx_px { /* inherits PQ */
|
||||
};
|
||||
|
||||
struct chx_thread { /* inherits PQ */
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh q;
|
||||
uint32_t state : 4;
|
||||
uint32_t flag_detached : 1;
|
||||
uint32_t flag_got_cancel : 1;
|
||||
@@ -183,63 +183,69 @@ struct chx_thread { /* inherits PQ */
|
||||
static int
|
||||
ll_empty (struct chx_qh *q)
|
||||
{
|
||||
return q == (struct chx_qh *)q->next;
|
||||
return q == q->next;
|
||||
}
|
||||
|
||||
static struct chx_pq *
|
||||
ll_dequeue (struct chx_pq *pq)
|
||||
{
|
||||
pq->next->prev = pq->prev;
|
||||
pq->prev->next = pq->next;
|
||||
pq->prev = pq->next = pq;
|
||||
pq->q.next->prev = pq->q.prev;
|
||||
pq->q.prev->next = pq->q.next;
|
||||
pq->q.prev = pq->q.next = &pq->q;
|
||||
return pq;
|
||||
}
|
||||
|
||||
static void
|
||||
ll_insert (struct chx_pq *pq0, struct chx_qh *q)
|
||||
ll_insert (struct chx_qh *q0, struct chx_qh *q)
|
||||
{
|
||||
struct chx_pq *pq = (struct chx_pq *)q;
|
||||
|
||||
pq0->next = (struct chx_pq *)pq;
|
||||
pq0->prev = pq->prev;
|
||||
pq->prev->next = (struct chx_pq *)pq0;
|
||||
pq->prev = pq0;
|
||||
q0->next = q;
|
||||
q0->prev = q->prev;
|
||||
q->prev->next = q0;
|
||||
q->prev = q0;
|
||||
}
|
||||
|
||||
|
||||
static struct chx_pq *
|
||||
ll_pop (struct chx_qh *q)
|
||||
{
|
||||
if (q == (struct chx_qh *)q->next)
|
||||
if (q == q->next)
|
||||
return NULL;
|
||||
|
||||
return ll_dequeue (q->next);
|
||||
return ll_dequeue ((struct chx_pq *)q->next);
|
||||
}
|
||||
|
||||
static void
|
||||
ll_prio_push (struct chx_pq *pq0, struct chx_qh *q0)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
|
||||
for (q = q0->next; q != q0; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
for (p = q0->next; p != (struct chx_pq *)q0; p = p->next)
|
||||
if (p->prio <= pq0->prio)
|
||||
break;
|
||||
}
|
||||
|
||||
pq0->parent = q0;
|
||||
ll_insert (pq0, (struct chx_qh *)p);
|
||||
ll_insert (&pq0->q, q);
|
||||
}
|
||||
|
||||
static void
|
||||
ll_prio_enqueue (struct chx_pq *pq0, struct chx_qh *q0)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
|
||||
for (q = q0->next; q != q0; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
for (p = q0->next; p != (struct chx_pq *)q0; p = p->next)
|
||||
if (p->prio < pq0->prio)
|
||||
break;
|
||||
}
|
||||
|
||||
pq0->parent = q0;
|
||||
ll_insert (pq0, (struct chx_qh *)p);
|
||||
ll_insert (&pq0->q, q);
|
||||
}
|
||||
|
||||
|
||||
@@ -271,6 +277,12 @@ chx_ready_pop (void)
|
||||
tp->state = THREAD_RUNNING;
|
||||
chx_spin_unlock (&q_ready.lock);
|
||||
|
||||
if (tp && tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
@@ -305,29 +317,35 @@ chx_ready_enqueue (struct chx_thread *tp)
|
||||
#endif
|
||||
|
||||
static void
|
||||
chx_set_timer (struct chx_thread *tp, uint32_t ticks)
|
||||
chx_set_timer (struct chx_qh *q, uint32_t ticks)
|
||||
{
|
||||
if (tp == (struct chx_thread *)&q_timer.q)
|
||||
if (q == &q_timer.q)
|
||||
chx_systick_reload (ticks);
|
||||
else
|
||||
{
|
||||
struct chx_thread *tp = (struct chx_thread *)q;
|
||||
|
||||
tp->v = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
static struct chx_thread *
|
||||
chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
uint32_t ticks = usec_to_ticks (usec);
|
||||
uint32_t next_ticks = chx_systick_get ();
|
||||
|
||||
for (p = q_timer.q.next; p != (struct chx_pq *)&q_timer.q; p = p->next)
|
||||
for (q = q_timer.q.next; q != &q_timer.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
if (ticks < next_ticks)
|
||||
{
|
||||
tp->parent = &q_timer.q;
|
||||
ll_insert ((struct chx_pq *)tp, (struct chx_qh *)p);
|
||||
chx_set_timer ((struct chx_thread *)tp->prev, ticks);
|
||||
chx_set_timer (tp, (next_ticks - ticks));
|
||||
ll_insert (&tp->q, q);
|
||||
chx_set_timer (tp->q.prev, ticks);
|
||||
chx_set_timer (&tp->q, (next_ticks - ticks));
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -337,12 +355,12 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
}
|
||||
}
|
||||
|
||||
if (p == (struct chx_pq *)&q_timer.q)
|
||||
if (q == &q_timer.q)
|
||||
{
|
||||
tp->parent = &q_timer.q;
|
||||
ll_insert ((struct chx_pq *)tp, (struct chx_qh *)p);
|
||||
chx_set_timer ((struct chx_thread *)tp->prev, ticks);
|
||||
chx_set_timer (tp, 1); /* Non-zero for the last entry. */
|
||||
ll_insert (&tp->q, q);
|
||||
chx_set_timer (tp->q.prev, ticks);
|
||||
chx_set_timer (&tp->q, 1); /* Non-zero for the last entry. */
|
||||
}
|
||||
|
||||
return tp;
|
||||
@@ -352,25 +370,30 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
static uint32_t
|
||||
chx_timer_dequeue (struct chx_thread *tp)
|
||||
{
|
||||
struct chx_thread *tp_prev;
|
||||
struct chx_qh *q_prev;
|
||||
uint32_t ticks_remained;
|
||||
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
ticks_remained = chx_systick_get ();
|
||||
tp_prev = (struct chx_thread *)tp->prev;
|
||||
if (tp_prev == (struct chx_thread *)&q_timer.q)
|
||||
q_prev = tp->q.prev;
|
||||
if (q_prev == &q_timer.q)
|
||||
{
|
||||
if (tp->next == (struct chx_pq *)&q_timer.q)
|
||||
if (tp->q.next == &q_timer.q)
|
||||
chx_systick_reload (0); /* Cancel timer. */
|
||||
else
|
||||
chx_systick_reload (ticks_remained + tp->v); /* Update timer. */
|
||||
}
|
||||
else
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_thread *tp_prev = (struct chx_thread *)q_prev;
|
||||
struct chx_qh *q;
|
||||
|
||||
for (q = q_timer.q.next; q != &q_timer.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
for (p = q_timer.q.next; p != (struct chx_pq *)tp; p = p->next)
|
||||
ticks_remained += p->v;
|
||||
}
|
||||
|
||||
tp_prev->v += tp->v;
|
||||
}
|
||||
@@ -385,6 +408,7 @@ void
|
||||
chx_timer_expired (void)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
struct chx_thread *running = chx_running ();
|
||||
uint16_t prio = 0; /* Use uint16_t here. */
|
||||
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
@@ -402,15 +426,17 @@ chx_timer_expired (void)
|
||||
|
||||
if (!ll_empty (&q_timer.q))
|
||||
{
|
||||
struct chx_thread *tp_next;
|
||||
struct chx_qh *q, *q_next;
|
||||
|
||||
for (tp = (struct chx_thread *)q_timer.q.next;
|
||||
tp != (struct chx_thread *)&q_timer.q && next_tick == 0;
|
||||
tp = tp_next)
|
||||
for (q = q_timer.q.next;
|
||||
q != &q_timer.q && next_tick == 0;
|
||||
q = q_next)
|
||||
{
|
||||
tp = (struct chx_thread *)q;
|
||||
|
||||
next_tick = tp->v;
|
||||
tp->v = (uintptr_t)0;
|
||||
tp_next = (struct chx_thread *)tp->next;
|
||||
q_next = tp->q.next;
|
||||
ll_dequeue ((struct chx_pq *)tp);
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp == running)
|
||||
@@ -421,7 +447,7 @@ chx_timer_expired (void)
|
||||
}
|
||||
|
||||
if (!ll_empty (&q_timer.q))
|
||||
chx_set_timer ((struct chx_thread *)&q_timer.q, next_tick);
|
||||
chx_set_timer (&q_timer.q, next_tick);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,10 +459,12 @@ chx_timer_expired (void)
|
||||
void
|
||||
chx_systick_init (void)
|
||||
{
|
||||
chx_systick_reset ();
|
||||
chx_systick_init_arch ();
|
||||
|
||||
if ((CHX_FLAGS_MAIN & CHOPSTX_SCHED_RR))
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
chx_timer_insert (running, PREEMPTION_USEC);
|
||||
@@ -450,19 +478,19 @@ chopstx_t chopstx_main;
|
||||
void
|
||||
chx_init (struct chx_thread *tp)
|
||||
{
|
||||
chx_prio_init ();
|
||||
chx_interrupt_controller_init ();
|
||||
chx_init_arch (tp);
|
||||
chx_spin_init (&chx_enable_sleep_lock);
|
||||
|
||||
q_ready.q.next = q_ready.q.prev = (struct chx_pq *)&q_ready.q;
|
||||
q_ready.q.next = q_ready.q.prev = &q_ready.q;
|
||||
chx_spin_init (&q_ready.lock);
|
||||
q_timer.q.next = q_timer.q.prev = (struct chx_pq *)&q_timer.q;
|
||||
q_timer.q.next = q_timer.q.prev = &q_timer.q;
|
||||
chx_spin_init (&q_timer.lock);
|
||||
q_join.q.next = q_join.q.prev = (struct chx_pq *)&q_join.q;
|
||||
q_join.q.next = q_join.q.prev = &q_join.q;
|
||||
chx_spin_init (&q_join.lock);
|
||||
q_intr.q.next = q_intr.q.prev = (struct chx_pq *)&q_intr.q;
|
||||
q_intr.q.next = q_intr.q.prev = &q_intr.q;
|
||||
chx_spin_init (&q_intr.lock);
|
||||
tp->next = tp->prev = (struct chx_pq *)tp;
|
||||
tp->q.next = tp->q.prev = &tp->q;
|
||||
tp->mutex_list = NULL;
|
||||
tp->clp = NULL;
|
||||
tp->state = THREAD_RUNNING;
|
||||
@@ -475,7 +503,6 @@ chx_init (struct chx_thread *tp)
|
||||
tp->prio = 0;
|
||||
tp->parent = NULL;
|
||||
tp->v = 0;
|
||||
running = tp;
|
||||
|
||||
if (CHX_PRIO_MAIN_INIT >= CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
||||
chx_cpu_sched_lock ();
|
||||
@@ -497,6 +524,7 @@ chx_wakeup (struct chx_pq *pq)
|
||||
{
|
||||
int yield = 0;
|
||||
struct chx_thread *tp;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
if (pq->flag_is_proxy)
|
||||
{
|
||||
@@ -536,19 +564,24 @@ chx_wakeup (struct chx_pq *pq)
|
||||
static void __attribute__((noreturn))
|
||||
chx_exit (void *retval)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
if (running->flag_join_req)
|
||||
{ /* wake up a thread which requests to join */
|
||||
chx_spin_lock (&q_join.lock);
|
||||
for (p = q_join.q.next; p != (struct chx_pq *)&q_join.q; p = p->next)
|
||||
for (q = q_join.q.next; q != &q_join.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
if (p->v == (uintptr_t)running)
|
||||
{ /* should be one at most. */
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&q_join.lock);
|
||||
}
|
||||
|
||||
@@ -567,19 +600,22 @@ chx_exit (void *retval)
|
||||
|
||||
/*
|
||||
* Lower layer mutex unlocking. Called with schedule lock held.
|
||||
* Return PRIO of the thread which is waken up.
|
||||
*/
|
||||
static chopstx_prio_t
|
||||
chx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
chopstx_prio_t prio = 0;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
mutex->owner = NULL;
|
||||
running->mutex_list = mutex->list;
|
||||
mutex->list = NULL;
|
||||
|
||||
tp = (struct chx_thread *)ll_pop (&mutex->q);
|
||||
if (tp)
|
||||
if (!tp)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
uint16_t newprio = running->prio_orig;
|
||||
chopstx_mutex_t *m;
|
||||
@@ -589,17 +625,19 @@ chx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
|
||||
/* Examine mutexes we hold, and determine new priority for running. */
|
||||
for (m = running->mutex_list; m; m = m->list)
|
||||
if (!ll_empty (&m->q)
|
||||
&& ((struct chx_thread *)(m->q.next))->prio > newprio)
|
||||
newprio = ((struct chx_thread *)m->q.next)->prio;
|
||||
if (!ll_empty (&m->q))
|
||||
{
|
||||
struct chx_thread *tp_m = (struct chx_thread *)m->q.next;
|
||||
uint16_t prio_m = tp_m->prio;
|
||||
|
||||
if (prio_m > newprio)
|
||||
newprio = prio_m;
|
||||
}
|
||||
/* Then, assign it. */
|
||||
running->prio = newprio;
|
||||
|
||||
if (prio < tp->prio)
|
||||
prio = tp->prio;
|
||||
return tp->prio;
|
||||
}
|
||||
|
||||
return prio;
|
||||
}
|
||||
|
||||
#define CHOPSTX_PRIO_MASK ((1 << CHOPSTX_PRIO_BITS) - 1)
|
||||
@@ -621,10 +659,11 @@ chopstx_create (uint32_t flags_and_prio,
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
chopstx_prio_t prio = (flags_and_prio & CHOPSTX_PRIO_MASK);
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
tp = chopstx_create_arch (stack_addr, stack_size, thread_entry,
|
||||
arg);
|
||||
tp->next = tp->prev = (struct chx_pq *)tp;
|
||||
tp->q.next = tp->q.prev = &tp->q;
|
||||
tp->mutex_list = NULL;
|
||||
tp->clp = NULL;
|
||||
tp->state = THREAD_EXITED;
|
||||
@@ -666,6 +705,7 @@ chopstx_create (uint32_t flags_and_prio,
|
||||
static int
|
||||
chx_snooze (uint32_t state, uint32_t *usec_p)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
uint32_t usec = *usec_p;
|
||||
uint32_t usec0;
|
||||
int r;
|
||||
@@ -689,7 +729,7 @@ chx_snooze (uint32_t state, uint32_t *usec_p)
|
||||
*usec_p -= usec0;
|
||||
else if (r > 0)
|
||||
{
|
||||
*usec_p -= (usec0 - r / MHZ);
|
||||
*usec_p -= (usec0 - ticks_to_usec (r));
|
||||
r = 1;
|
||||
}
|
||||
|
||||
@@ -735,7 +775,7 @@ void
|
||||
chopstx_mutex_init (chopstx_mutex_t *mutex)
|
||||
{
|
||||
chx_spin_init (&mutex->lock);
|
||||
mutex->q.next = mutex->q.prev = (struct chx_pq *)&mutex->q;
|
||||
mutex->q.next = mutex->q.prev = &mutex->q;
|
||||
mutex->list = NULL;
|
||||
mutex->owner = NULL;
|
||||
}
|
||||
@@ -788,7 +828,7 @@ requeue (struct chx_thread *tp)
|
||||
void
|
||||
chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *tp = running;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -847,6 +887,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
void
|
||||
chopstx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
chopstx_prio_t prio;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
@@ -870,7 +911,7 @@ void
|
||||
chopstx_cond_init (chopstx_cond_t *cond)
|
||||
{
|
||||
chx_spin_init (&cond->lock);
|
||||
cond->q.next = cond->q.prev = (struct chx_pq *)&cond->q;
|
||||
cond->q.next = cond->q.prev = &cond->q;
|
||||
}
|
||||
|
||||
|
||||
@@ -884,7 +925,7 @@ chopstx_cond_init (chopstx_cond_t *cond)
|
||||
void
|
||||
chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *tp = running;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
int r;
|
||||
|
||||
chopstx_testcancel ();
|
||||
@@ -1006,17 +1047,21 @@ chx_cond_hook (struct chx_px *px, struct chx_poll_head *pd)
|
||||
void
|
||||
chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num)
|
||||
{
|
||||
int intr_before_claim;
|
||||
|
||||
intr->type = CHOPSTX_POLL_INTR;
|
||||
intr->ready = 0;
|
||||
intr->irq_num = irq_num;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
chx_disable_intr (irq_num);
|
||||
intr_before_claim = chx_disable_intr (irq_num);
|
||||
chx_clr_intr (irq_num);
|
||||
chx_set_intr_prio (irq_num);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
if (intr_before_claim)
|
||||
intr->ready = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1088,6 +1133,8 @@ chopstx_intr_done (chopstx_intr_t *intr)
|
||||
void
|
||||
chopstx_cleanup_push (struct chx_cleanup *clp)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
clp->next = running->clp;
|
||||
running->clp = clp;
|
||||
}
|
||||
@@ -1102,6 +1149,7 @@ chopstx_cleanup_push (struct chx_cleanup *clp)
|
||||
void
|
||||
chopstx_cleanup_pop (int execute)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
struct chx_cleanup *clp = running->clp;
|
||||
|
||||
if (clp)
|
||||
@@ -1126,6 +1174,7 @@ void
|
||||
chopstx_exit (void *retval)
|
||||
{
|
||||
struct chx_mtx *m, *m_next;
|
||||
struct chx_thread *running = chx_running ();
|
||||
struct chx_cleanup *clp = running->clp;
|
||||
|
||||
running->clp = NULL;
|
||||
@@ -1162,6 +1211,7 @@ chopstx_exit (void *retval)
|
||||
int
|
||||
chopstx_join (chopstx_t thd, void **ret)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
struct chx_thread *tp = (struct chx_thread *)thd;
|
||||
int r = 0;
|
||||
|
||||
@@ -1265,6 +1315,7 @@ void
|
||||
chopstx_cancel (chopstx_t thd)
|
||||
{
|
||||
struct chx_thread *tp = (struct chx_thread *)thd;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
tp->flag_got_cancel = 1;
|
||||
@@ -1321,6 +1372,8 @@ chopstx_cancel (chopstx_t thd)
|
||||
void
|
||||
chopstx_testcancel (void)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
if (running->flag_cancelable && running->flag_got_cancel)
|
||||
chopstx_exit (CHOPSTX_CANCELED);
|
||||
}
|
||||
@@ -1337,6 +1390,7 @@ chopstx_testcancel (void)
|
||||
int
|
||||
chopstx_setcancelstate (int cancel_disable)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
int old_state = !running->flag_cancelable;
|
||||
|
||||
running->flag_cancelable = (cancel_disable == 0);
|
||||
@@ -1347,7 +1401,9 @@ chopstx_setcancelstate (int cancel_disable)
|
||||
static void
|
||||
chx_proxy_init (struct chx_px *px, uint32_t *cp)
|
||||
{
|
||||
px->next = px->prev = (struct chx_pq *)px;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
px->q.next = px->q.prev = &px->q;
|
||||
px->flag_is_proxy = 1;
|
||||
px->prio = running->prio;
|
||||
px->parent = NULL;
|
||||
@@ -1378,6 +1434,7 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
struct chx_px px[n];
|
||||
struct chx_poll_head *pd;
|
||||
int r = 0;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_dmb ();
|
||||
chopstx_testcancel ();
|
||||
@@ -1385,6 +1442,7 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
for (i = 0; i < n; i++)
|
||||
chx_proxy_init (&px[i], &counter);
|
||||
|
||||
again:
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
pd = pd_array[i];
|
||||
@@ -1447,6 +1505,20 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
ll_dequeue ((struct chx_pq *)&px[i]);
|
||||
chx_spin_unlock (&pc->cond->lock);
|
||||
}
|
||||
else
|
||||
{ /* Check the condition again after woken up. */
|
||||
if (pc->mutex)
|
||||
chopstx_mutex_lock (pc->mutex);
|
||||
|
||||
if ((*pc->check) (pc->arg) == 0)
|
||||
{ /* Condition doesn't met. */
|
||||
pc->ready = 0;
|
||||
counter--;
|
||||
}
|
||||
|
||||
if (pc->mutex)
|
||||
chopstx_mutex_unlock (pc->mutex);
|
||||
}
|
||||
}
|
||||
else if (pd->type == CHOPSTX_POLL_INTR)
|
||||
{
|
||||
@@ -1478,6 +1550,9 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
if (r < 0)
|
||||
chopstx_exit (CHOPSTX_CANCELED);
|
||||
|
||||
if (counter == 0 && (usec_p == NULL || *usec_p))
|
||||
goto again;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
@@ -1498,7 +1573,7 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
chopstx_prio_t
|
||||
chopstx_setpriority (chopstx_prio_t prio_new)
|
||||
{
|
||||
struct chx_thread *tp = running;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
chopstx_prio_t prio_orig, prio_cur;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
struct chx_qh {
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh *next, *prev;
|
||||
};
|
||||
|
||||
typedef uintptr_t chopstx_t;
|
||||
@@ -163,5 +163,3 @@ 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
|
||||
|
||||
232
contrib/ackbtn-gnu-linux.c
Normal file
232
contrib/ackbtn-gnu-linux.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* ackbtn-gnu-linux.c - Acknowledge button support for GNU/Linux
|
||||
*
|
||||
* Copyright (C) 2021 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
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static pthread_t tid_main;
|
||||
static pthread_t tid_ui;
|
||||
|
||||
static pthread_mutex_t mutex;
|
||||
static pthread_cond_t cond;
|
||||
static int enabled;
|
||||
static int event_fd;
|
||||
|
||||
static void
|
||||
ackbtn_intr (int signum, siginfo_t *siginfo, void *arg)
|
||||
{
|
||||
extern void chx_sigmask (ucontext_t *uc);
|
||||
extern void chx_handle_intr (int signum);
|
||||
|
||||
ucontext_t *uc = arg;
|
||||
(void)signum;
|
||||
(void)siginfo;
|
||||
chx_handle_intr (SIGUSR2);
|
||||
chx_sigmask (uc);
|
||||
}
|
||||
|
||||
|
||||
#define ACKBTN_ACKED (1 << 0)
|
||||
#define ACKBTN_TIMEOUT (1 << 2)
|
||||
|
||||
static void *
|
||||
user_interaction (void *arg)
|
||||
{
|
||||
struct pollfd pollfds[2];
|
||||
|
||||
(void)arg;
|
||||
|
||||
pollfds[0].fd = 0; /* standard input */
|
||||
pollfds[0].events = POLLIN;
|
||||
|
||||
pollfds[1].fd = event_fd;
|
||||
pollfds[1].events = POLLIN;
|
||||
|
||||
fputs ("User interaction thread for AckBtn started.\n", stdout);
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned int acked_or_timeout = 0;
|
||||
char buf[256];
|
||||
|
||||
pthread_mutex_lock (&mutex);
|
||||
while (!enabled)
|
||||
pthread_cond_wait (&cond, &mutex);
|
||||
pthread_mutex_unlock (&mutex);
|
||||
|
||||
/* Consume all input if any. */
|
||||
while (1)
|
||||
{
|
||||
int r;
|
||||
|
||||
pollfds[0].revents = 0;
|
||||
|
||||
r = poll (pollfds, 1, 0);
|
||||
if (r < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
perror ("poll");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if ((pollfds[0].revents & POLLIN))
|
||||
read (0, buf, sizeof buf);
|
||||
}
|
||||
|
||||
fputs ("Type RET to acknowledge (or wait for timeout) > ", stdout);
|
||||
fflush (stdout);
|
||||
|
||||
while (!acked_or_timeout)
|
||||
{
|
||||
pollfds[0].revents = 0;
|
||||
pollfds[1].revents = 0;
|
||||
|
||||
if (poll (pollfds, 2, -1) < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
perror ("poll");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if ((pollfds[0].revents & POLLIN))
|
||||
{
|
||||
read (0, buf, sizeof buf);
|
||||
acked_or_timeout |= ACKBTN_ACKED;
|
||||
}
|
||||
|
||||
if ((pollfds[1].revents & POLLIN))
|
||||
acked_or_timeout |= ACKBTN_TIMEOUT;
|
||||
}
|
||||
|
||||
pthread_mutex_lock (&mutex);
|
||||
if ((acked_or_timeout & ACKBTN_ACKED))
|
||||
{
|
||||
if ((acked_or_timeout & ACKBTN_TIMEOUT))
|
||||
/* No output of newline, as it follows timeout message. */
|
||||
fputs ("Input ignored", stdout);
|
||||
else
|
||||
{
|
||||
pthread_kill (tid_main, SIGUSR2);
|
||||
fputs ("Acknowledged\n", stdout);
|
||||
}
|
||||
}
|
||||
|
||||
if ((acked_or_timeout & ACKBTN_TIMEOUT))
|
||||
fputs ("\nTimeout\n", stdout);
|
||||
|
||||
while (enabled)
|
||||
pthread_cond_wait (&cond, &mutex);
|
||||
|
||||
read (event_fd, buf, sizeof (uint64_t));
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ackbtn_init (chopstx_intr_t *intr)
|
||||
{
|
||||
int r;
|
||||
sigset_t sigset;
|
||||
struct sigaction act;
|
||||
|
||||
event_fd = eventfd (0, EFD_CLOEXEC);
|
||||
if (event_fd < 0)
|
||||
{
|
||||
perror ("eventfd");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
pthread_mutex_init (&mutex, NULL);
|
||||
pthread_cond_init (&cond, NULL);
|
||||
enabled = 0;
|
||||
|
||||
sigemptyset (&sigset);
|
||||
sigaddset (&sigset, SIGUSR2);
|
||||
sigaddset (&sigset, SIGALRM);
|
||||
|
||||
tid_main = pthread_self ();
|
||||
|
||||
/* Launch the thread for user interaction. */
|
||||
pthread_sigmask (SIG_BLOCK, &sigset, NULL);
|
||||
|
||||
r = pthread_create (&tid_ui, NULL, user_interaction, NULL);
|
||||
if (r)
|
||||
{
|
||||
fprintf (stderr, "ackbtn_init: %s\n", strerror (r));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
act.sa_sigaction = ackbtn_intr;
|
||||
sigfillset (&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||
sigaction (SIGUSR2, &act, NULL);
|
||||
|
||||
pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
|
||||
|
||||
chopstx_claim_irq (intr, SIGUSR2);
|
||||
}
|
||||
|
||||
void
|
||||
ackbtn_enable (void)
|
||||
{
|
||||
pthread_mutex_lock (&mutex);
|
||||
enabled = 1;
|
||||
pthread_cond_signal (&cond);
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
void
|
||||
ackbtn_disable (void)
|
||||
{
|
||||
const uint64_t l = 1;
|
||||
|
||||
pthread_mutex_lock (&mutex);
|
||||
enabled = 0;
|
||||
write (event_fd, &l, sizeof (l));
|
||||
pthread_cond_signal (&cond);
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -57,6 +57,7 @@ ackbtn_init (chopstx_intr_t *intr)
|
||||
{
|
||||
case BOARD_ID_FST_01:
|
||||
case BOARD_ID_FST_01G:
|
||||
case BOARD_ID_GNUKEY_DS:
|
||||
/* PA2 can be connected to a hall sensor or a switch */
|
||||
afio_exticr_index = 0;
|
||||
afio_exticr_extiX_pY = AFIO_EXTICR1_EXTI2_PA;
|
||||
@@ -65,6 +66,15 @@ ackbtn_init (chopstx_intr_t *intr)
|
||||
pin_config |= PINCFG_EDGE_RISING;
|
||||
break;
|
||||
|
||||
case BOARD_ID_ST_DONGLE:
|
||||
/* PA5 is connected to a switch */
|
||||
afio_exticr_index = 0;
|
||||
afio_exticr_extiX_pY = AFIO_EXTICR2_EXTI5_PA;
|
||||
irq_num = EXTI9_5_IRQ;
|
||||
pin_config = 0x0020; /* EXTI_PR_PR5 == EXTI_IMR_MR5 == EXTI_RTSR_TR5 */
|
||||
pin_config |= PINCFG_EDGE_RISING;
|
||||
break;
|
||||
|
||||
case BOARD_ID_FST_01SZ:
|
||||
default:
|
||||
/* PA3 is connected to a hall sensor DRV5032FA */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* This ADC driver just fills pseudo random values.
|
||||
* It's completely useless other than for NeuG.
|
||||
*
|
||||
* Copyright (C) 2017 Free Software Initiative of Japan
|
||||
* Copyright (C) 2017, 2021 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -24,7 +24,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <chopstx.h>
|
||||
#include "adc.h"
|
||||
|
||||
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */
|
||||
#include <sys/random.h>
|
||||
|
||||
/*
|
||||
* Do calibration for ADC.
|
||||
@@ -41,7 +41,6 @@
|
||||
int
|
||||
adc_init (void)
|
||||
{
|
||||
srandom (ADC_RANDOM_SEED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -55,8 +54,7 @@ uint32_t adc_buf[64];
|
||||
void
|
||||
adc_start_conversion (int offset, int count)
|
||||
{
|
||||
while (count--)
|
||||
adc_buf[offset++] = random ();
|
||||
getrandom (adc_buf+offset, count, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
428
contrib/usart-common.c
Normal file
428
contrib/usart-common.c
Normal file
@@ -0,0 +1,428 @@
|
||||
static void *usart_main (void *arg);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
/* full && empty -> data is consumed fully */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
else
|
||||
rb->full = 0;
|
||||
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 && !rb->empty)
|
||||
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)
|
||||
{
|
||||
if (!rb->full)
|
||||
rb->full = 1;
|
||||
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 && !rb->empty)
|
||||
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;
|
||||
}
|
||||
|
||||
/* Can be used two ways:
|
||||
*
|
||||
* When the ring buffer is rb_a2h:
|
||||
* Hardware-side polling if data is available from application.
|
||||
*
|
||||
* When the ring buffer is rb_h2a:
|
||||
* Application-side polling if data is available from hardware.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
const struct usart_stat *
|
||||
usart_stat (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].stat;
|
||||
}
|
||||
|
||||
static struct USART *
|
||||
get_usart_dev (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].USART;
|
||||
}
|
||||
|
||||
static struct rb *
|
||||
get_usart_rb_h2a (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].rb_h2a;
|
||||
}
|
||||
|
||||
static struct rb *
|
||||
get_usart_rb_a2h (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].rb_a2h;
|
||||
}
|
||||
|
||||
static struct chx_intr *
|
||||
get_usart_intr (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].intr;
|
||||
}
|
||||
|
||||
void
|
||||
usart_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
|
||||
int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||
{
|
||||
usart_init0 (cb);
|
||||
chopstx_create (prio, stack_addr, stack_size, usart_main, NULL);
|
||||
}
|
||||
|
||||
static int (*ss_notify_callback) (uint8_t dev_no, uint16_t notify_bits);
|
||||
|
||||
static struct chx_poll_head *usart_poll[NUM_USART*2];
|
||||
|
||||
static void *
|
||||
usart_main (void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)arg;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
if (usart_array[i].tx_ready)
|
||||
{
|
||||
*usart_array[i].tx_ready = 1;
|
||||
rb_init (usart_array[i].rb_a2h, usart_array[i].buf_a2h, BUF_A2H_SIZE);
|
||||
rb_init (usart_array[i].rb_h2a, usart_array[i].buf_h2a, BUF_H2A_SIZE);
|
||||
rb_get_prepare_poll (usart_array[i].rb_a2h, usart_array[i].app_write_event);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
if (usart_array[i].tx_ready)
|
||||
{
|
||||
usart_poll[n++] = (struct chx_poll_head *)usart_array[i].intr;
|
||||
if (*usart_array[i].tx_ready)
|
||||
usart_poll[n++] = (struct chx_poll_head *)usart_array[i].app_write_event;
|
||||
else
|
||||
usart_array[i].app_write_event->ready = 0;
|
||||
}
|
||||
|
||||
chopstx_poll (NULL, n, usart_poll);
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
if (usart_array[i].tx_ready)
|
||||
{
|
||||
int tx_done = 0;
|
||||
|
||||
if (usart_array[i].intr->ready)
|
||||
{
|
||||
tx_done = handle_intr (usart_array[i].USART,
|
||||
usart_array[i].rb_h2a, usart_array[i].stat);
|
||||
*usart_array[i].tx_ready |= tx_done;
|
||||
chopstx_intr_done (usart_array[i].intr);
|
||||
}
|
||||
|
||||
if (tx_done || (*usart_array[i].tx_ready
|
||||
&& usart_array[i].app_write_event->ready))
|
||||
*usart_array[i].tx_ready = handle_tx (usart_array[i].USART,
|
||||
usart_array[i].rb_a2h, usart_array[i].stat);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
usart_read (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||
{
|
||||
struct rb *rb = get_usart_rb_h2a (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return -1;
|
||||
|
||||
if (buf == NULL && buflen == 0)
|
||||
{
|
||||
rb_ll_flush (rb);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return rb_read (rb, (uint8_t *)buf, buflen);
|
||||
}
|
||||
|
||||
void
|
||||
usart_read_prepare_poll (uint8_t dev_no, chopstx_poll_cond_t *poll_desc)
|
||||
{
|
||||
struct rb *rb = get_usart_rb_h2a (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return;
|
||||
|
||||
rb_get_prepare_poll (rb, poll_desc);
|
||||
}
|
||||
|
||||
int
|
||||
usart_read_ext (uint8_t dev_no, char *buf, uint16_t buflen, uint32_t *timeout_p)
|
||||
{
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
struct chx_poll_head *ph[] = { (struct chx_poll_head *)&poll_desc };
|
||||
int r;
|
||||
struct rb *rb = get_usart_rb_h2a (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return -1;
|
||||
|
||||
rb_get_prepare_poll (rb, &poll_desc);
|
||||
r = chopstx_poll (timeout_p, 1, ph);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
else
|
||||
return rb_read (rb, (uint8_t *)buf, buflen);
|
||||
}
|
||||
|
||||
static void
|
||||
usart_wait_write_completion (struct rb *rb)
|
||||
{
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
while (!(rb->empty && rb->full))
|
||||
chopstx_cond_wait (&rb->space_available, &rb->m);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
}
|
||||
|
||||
int
|
||||
usart_write (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||
{
|
||||
struct rb *rb = get_usart_rb_a2h (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return -1;
|
||||
|
||||
if (buf == NULL && buflen == 0)
|
||||
rb_ll_flush (rb);
|
||||
else
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 0);
|
||||
|
||||
rb_write (rb, (uint8_t *)buf, buflen);
|
||||
|
||||
if (smartcard_mode)
|
||||
{
|
||||
usart_wait_write_completion (rb);
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
usart_config_baud (uint8_t dev_no, uint8_t baud_spec)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
uint32_t save_bits;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BAUD; i++)
|
||||
if (brr_table[i].baud_spec == baud_spec)
|
||||
break;
|
||||
|
||||
if (i >= NUM_BAUD)
|
||||
return -1;
|
||||
|
||||
save_bits = USARTx->CR1 & (USART_CR1_TE | USART_CR1_RE);
|
||||
USARTx->CR1 &= ~(USART_CR1_TE | USART_CR1_RE | USART_CR1_UE);
|
||||
USARTx->BRR = brr_table[i].brr_value;
|
||||
USARTx->CR1 |= (save_bits | USART_CR1_UE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usart_config_clken (uint8_t dev_no, int on)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
|
||||
if (on)
|
||||
USARTx->CR2 |= (1 << 11);
|
||||
else
|
||||
USARTx->CR2 &= ~(1 << 11);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usart-stm32.c - USART driver for STM32F103 (USART2 and USART3)
|
||||
*
|
||||
* Copyright (C) 2017 g10 Code GmbH
|
||||
* Copyright (C) 2017, 2019 g10 Code GmbH
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <mcu/stm32.h>
|
||||
#include <contrib/usart.h>
|
||||
|
||||
/* Hardware registers */
|
||||
struct USART {
|
||||
volatile uint32_t SR;
|
||||
volatile uint32_t DR;
|
||||
@@ -44,8 +45,8 @@ struct USART {
|
||||
|
||||
#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 USART2 ((struct USART *)USART2_BASE)
|
||||
#define USART3 ((struct USART *)USART3_BASE)
|
||||
|
||||
#define USART_SR_CTS (1 << 9)
|
||||
#define USART_SR_LBD (1 << 8)
|
||||
@@ -74,25 +75,79 @@ static struct USART *const USART3 = (struct USART *)USART3_BASE;
|
||||
#define USART_CR1_RWU (1 << 1)
|
||||
#define USART_CR1_SBK (1 << 0)
|
||||
|
||||
#define USART_CR3_CTSE (1 << 9)
|
||||
#define USART_CR3_RTSE (1 << 8)
|
||||
#define USART_CR3_SCEN (1 << 5)
|
||||
#define USART_CR3_NACK (1 << 4)
|
||||
|
||||
static struct USART *
|
||||
get_usart_dev (uint8_t dev_no)
|
||||
|
||||
static struct usart_stat usart2_stat;
|
||||
static struct usart_stat usart3_stat;
|
||||
|
||||
static struct chx_intr usart2_intr;
|
||||
static struct chx_intr usart3_intr;
|
||||
|
||||
#define BUF_A2H_SIZE 256
|
||||
#define BUF_H2A_SIZE 512
|
||||
static uint8_t buf_usart2_rb_a2h[BUF_A2H_SIZE];
|
||||
static uint8_t buf_usart2_rb_h2a[BUF_H2A_SIZE];
|
||||
static uint8_t buf_usart3_rb_a2h[BUF_A2H_SIZE];
|
||||
static uint8_t buf_usart3_rb_h2a[BUF_H2A_SIZE];
|
||||
|
||||
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;
|
||||
|
||||
/* Global variables so that it can be easier to debug. */
|
||||
static int usart2_tx_ready;
|
||||
static int usart3_tx_ready;
|
||||
|
||||
#define INTR_REQ_USART2 38
|
||||
#define INTR_REQ_USART3 39
|
||||
|
||||
#define USART_DEVNO_START 2
|
||||
#define USART_DEVNO_END 3
|
||||
|
||||
struct usart {
|
||||
struct USART *USART;
|
||||
struct chx_intr *intr;
|
||||
uint8_t irq_num;
|
||||
struct usart_stat *stat;
|
||||
struct rb *rb_a2h;
|
||||
struct rb *rb_h2a;
|
||||
uint8_t *buf_a2h;
|
||||
uint8_t *buf_h2a;
|
||||
chopstx_poll_cond_t *app_write_event;
|
||||
int *tx_ready;
|
||||
};
|
||||
|
||||
|
||||
static const struct usart usart_array[] =
|
||||
{
|
||||
if (dev_no == 2)
|
||||
return USART2;
|
||||
else if (dev_no == 3)
|
||||
return USART3;
|
||||
{ USART2, &usart2_intr, INTR_REQ_USART2,
|
||||
&usart2_stat, &usart2_rb_a2h, &usart2_rb_h2a, buf_usart2_rb_a2h,
|
||||
buf_usart2_rb_h2a, &usart2_app_write_event, &usart2_tx_ready },
|
||||
{ USART3, &usart3_intr, INTR_REQ_USART3,
|
||||
&usart3_stat, &usart3_rb_a2h, &usart3_rb_h2a, buf_usart3_rb_a2h,
|
||||
buf_usart3_rb_h2a, &usart3_app_write_event, &usart3_tx_ready },
|
||||
};
|
||||
#define NUM_USART ((int)(sizeof (usart_array) / sizeof (struct usart)))
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static int handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat);
|
||||
static int handle_tx (struct USART *USARTx, struct rb *rb2h, struct usart_stat *stat);
|
||||
static void usart_config_recv_enable (struct USART *USARTx, int on);
|
||||
|
||||
/* We assume 36MHz f_PCLK */
|
||||
struct brr_setting {
|
||||
uint8_t baud_spec;
|
||||
uint16_t brr_value;
|
||||
uint32_t brr_value;
|
||||
};
|
||||
#define NUM_BAUD (int)(sizeof (brr_table) / sizeof (struct brr_setting))
|
||||
|
||||
/* We assume 36MHz f_PCLK */
|
||||
static const struct brr_setting brr_table[] = {
|
||||
{ B600, (3750 << 4)},
|
||||
{ B1200, (1875 << 4)},
|
||||
@@ -104,12 +159,26 @@ static const struct brr_setting brr_table[] = {
|
||||
{ B230400, ( 9 << 4)|12},
|
||||
{ B460800, ( 4 << 4)|14},
|
||||
{ B921600, ( 2 << 4)|7},
|
||||
{ BSCARD1, ( 232 << 4)|8}, /* 9677 */
|
||||
{ BSCARD2, ( 116 << 4)|4}, /* 19354 */
|
||||
{ BSCARD4, ( 58 << 4)|2}, /* 38709 */
|
||||
{ BSCARD8, ( 29 << 4)|1}, /* 77419 */
|
||||
{ BSCARD12, ( 19 << 4)|6}, /* 116129 */
|
||||
{ BSCARD16, ( 14 << 4)|9}, /* 154506 */
|
||||
{ BSCARD20, ( 11 << 4)|10}, /* 193548 */
|
||||
};
|
||||
|
||||
static void *usart_main (void *arg);
|
||||
#include "usart-common.c"
|
||||
|
||||
static void
|
||||
usart_config_recv_enable (struct USART *USARTx, int on)
|
||||
{
|
||||
if (on)
|
||||
USARTx->CR1 |= USART_CR1_RE;
|
||||
else
|
||||
USARTx->CR1 &= ~USART_CR1_RE;
|
||||
}
|
||||
|
||||
static struct usart_stat usart2_stat;
|
||||
static struct usart_stat usart3_stat;
|
||||
|
||||
int
|
||||
usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
@@ -117,10 +186,10 @@ 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 */
|
||||
uint32_t cr1_config = (USART_CR1_UE | USART_CR1_RXNEIE | USART_CR1_TE);
|
||||
/* TXEIE/TCIE will be enabled when
|
||||
putting char */
|
||||
/* No CTSIE, PEIE, IDLEIE, LBDIE */
|
||||
if (USARTx == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -136,9 +205,9 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
return -1;
|
||||
|
||||
if ((config_bits & PARENB) == 0)
|
||||
cr1_config &= ~USART_CR1_PCE;
|
||||
cr1_config &= ~(USART_CR1_PCE | USART_CR1_PEIE);
|
||||
else
|
||||
cr1_config |= USART_CR1_PCE;
|
||||
cr1_config |= (USART_CR1_PCE | USART_CR1_PEIE);
|
||||
|
||||
if ((config_bits & PARODD) == 0)
|
||||
cr1_config &= ~USART_CR1_PS;
|
||||
@@ -164,246 +233,53 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
USARTx->BRR = brr_table[i].brr_value;
|
||||
|
||||
if ((config_bits & MASK_FLOW))
|
||||
USARTx->CR3 = (1 << 9) | (1 << 8);
|
||||
USARTx->CR3 = USART_CR3_CTSE | USART_CR3_RTSE;
|
||||
else
|
||||
USARTx->CR3 = 0;
|
||||
|
||||
if (!(config_bits & MASK_MODE))
|
||||
cr1_config |= USART_CR1_RE;
|
||||
|
||||
USARTx->CR1 = cr1_config;
|
||||
|
||||
/* SCEN (smartcard enable) should be set _after_ CR1. */
|
||||
if ((config_bits & MASK_MODE))
|
||||
{
|
||||
if ((config_bits & MASK_MODE) == MODE_SMARTCARD)
|
||||
{
|
||||
USARTx->GTPR = (1 << 8) | 5;
|
||||
USARTx->CR3 |= (USART_CR3_SCEN | USART_CR3_NACK);
|
||||
}
|
||||
else if ((config_bits & MASK_MODE) == MODE_IRDA)
|
||||
USARTx->CR3 |= (1 << 1);
|
||||
else if ((config_bits & MASK_MODE) == MODE_IRDA_LP)
|
||||
USARTx->CR3 |= (1 << 2) | (1 << 1);
|
||||
}
|
||||
|
||||
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))
|
||||
usart_init0 (int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||
{
|
||||
int i;
|
||||
|
||||
ss_notify_callback = cb;
|
||||
usart2_stat.dev_no = 2;
|
||||
usart3_stat.dev_no = 3;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
{
|
||||
if (usart_array[i].stat)
|
||||
usart_array[i].stat->dev_no = i + USART_DEVNO_START;
|
||||
chopstx_claim_irq (usart_array[i].intr, usart_array[i].irq_num);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
@@ -418,12 +294,24 @@ 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;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if ((r & USART_SR_TC))
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_SR_TXE))
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r & USART_SR_RXNE))
|
||||
{
|
||||
@@ -473,7 +361,8 @@ handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat)
|
||||
|
||||
if (notify_bits)
|
||||
{
|
||||
if ((*ss_notify_callback) (stat->dev_no, notify_bits))
|
||||
if (ss_notify_callback
|
||||
&& (*ss_notify_callback) (stat->dev_no, notify_bits))
|
||||
stat->err_notify_overflow++;
|
||||
}
|
||||
|
||||
@@ -481,8 +370,7 @@ handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat)
|
||||
}
|
||||
|
||||
static int
|
||||
handle_tx_ready (struct USART *USARTx, struct rb *rb2h,
|
||||
struct usart_stat *stat)
|
||||
handle_tx (struct USART *USARTx, struct rb *rb2h, struct usart_stat *stat)
|
||||
{
|
||||
int tx_ready = 1;
|
||||
int c = rb_ll_get (rb2h);
|
||||
@@ -490,131 +378,32 @@ handle_tx_ready (struct USART *USARTx, struct rb *rb2h,
|
||||
if (c >= 0)
|
||||
{
|
||||
uint32_t r;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
USARTx->DR = (c & 0xff);
|
||||
stat->tx++;
|
||||
r = USARTx->SR;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if ((r & USART_SR_TC) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -628,3 +417,145 @@ usart_send_break (uint8_t dev_no)
|
||||
USARTx->CR1 |= 0x01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
usart_block_sendrecv (uint8_t dev_no, const char *s_buf, uint16_t s_buflen,
|
||||
char *r_buf, uint16_t r_buflen,
|
||||
uint32_t *timeout_block_p, uint32_t timeout_char)
|
||||
{
|
||||
uint32_t timeout;
|
||||
uint8_t *p;
|
||||
int len;
|
||||
uint32_t r;
|
||||
uint32_t data;
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
struct chx_intr *usartx_intr = get_usart_intr (dev_no);
|
||||
struct chx_poll_head *ph[1];
|
||||
|
||||
if (usartx_intr == NULL)
|
||||
return -1;
|
||||
|
||||
ph[0] = (struct chx_poll_head *)usartx_intr;
|
||||
|
||||
p = (uint8_t *)s_buf;
|
||||
if (p)
|
||||
{
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 0);
|
||||
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
|
||||
/* Sending part */
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (NULL, 1, ph);
|
||||
|
||||
r = USARTx->SR;
|
||||
|
||||
/* Here, ignore recv error(s). */
|
||||
if ((r & USART_SR_RXNE) || (r & USART_SR_ORE))
|
||||
{
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
if ((r & USART_SR_TXE))
|
||||
{
|
||||
if (s_buflen == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Keep TXEIE bit */
|
||||
USARTx->DR = *p++;
|
||||
s_buflen--;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if (timeout_block_p && (*timeout_block_p))
|
||||
do
|
||||
r = USARTx->SR;
|
||||
while (((r & USART_SR_TC) == 0));
|
||||
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
if (timeout_block_p && *timeout_block_p == 0)
|
||||
{
|
||||
/* Ignoring the echo back. */
|
||||
do
|
||||
r = USARTx->SR;
|
||||
while (((r & USART_SR_TC) == 0));
|
||||
|
||||
if ((r & USART_SR_RXNE))
|
||||
{
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
*timeout_block_p = timeout_char;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
if (r_buf == NULL)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
/* Receiving part */
|
||||
r = chopstx_poll (timeout_block_p, 1, ph);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
p = (uint8_t *)r_buf;
|
||||
len = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = USARTx->SR;
|
||||
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
if ((r & USART_SR_RXNE))
|
||||
{
|
||||
if ((r & USART_SR_NE) || (r & USART_SR_FE) || (r & USART_SR_PE))
|
||||
/* ignore error, for now. XXX: ss_notify */
|
||||
;
|
||||
else
|
||||
{
|
||||
*p++ = (data & 0xff);
|
||||
len++;
|
||||
r_buflen--;
|
||||
if (r_buflen == 0)
|
||||
{
|
||||
chopstx_intr_done (usartx_intr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((r & USART_SR_ORE))
|
||||
{
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
timeout = timeout_char;
|
||||
r = chopstx_poll (&timeout, 1, ph);
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
559
contrib/usart-stm32l4.c
Normal file
559
contrib/usart-stm32l4.c
Normal file
@@ -0,0 +1,559 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <mcu/stm32l.h>
|
||||
#include <contrib/usart.h>
|
||||
|
||||
|
||||
#define RCC_APB1_1_USART2 (1 << 17)
|
||||
#define RCC_APB2_USART1 (1 << 14)
|
||||
|
||||
/* Hardware registers */
|
||||
struct USART {
|
||||
volatile uint32_t CR1;
|
||||
volatile uint32_t CR2;
|
||||
volatile uint32_t CR3;
|
||||
volatile uint32_t BRR;
|
||||
volatile uint32_t GTPR;
|
||||
volatile uint32_t RTOR;
|
||||
volatile uint32_t RQR;
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t ICR;
|
||||
volatile uint32_t RDR;
|
||||
volatile uint32_t TDR;
|
||||
};
|
||||
|
||||
#define USART1_BASE (APB2PERIPH_BASE + 0x3800)
|
||||
#define USART1 ((struct USART *)USART1_BASE)
|
||||
|
||||
#define USART2_BASE (APB1PERIPH_BASE + 0x4400)
|
||||
#define USART2 ((struct USART *)USART2_BASE)
|
||||
|
||||
#define USART_ISR_CTS (1 << 10)
|
||||
#define USART_ISR_LBDF (1 << 8)
|
||||
#define USART_ISR_TXE (1 << 7)
|
||||
#define USART_ISR_TC (1 << 6)
|
||||
#define USART_ISR_RXNE (1 << 5)
|
||||
#define USART_ISR_IDLE (1 << 4)
|
||||
#define USART_ISR_ORE (1 << 3)
|
||||
#define USART_ISR_NE (1 << 2)
|
||||
#define USART_ISR_FE (1 << 1)
|
||||
#define USART_ISR_PE (1 << 0)
|
||||
|
||||
#define USART_CR1_M1 (1 << 28)
|
||||
#define USART_CR1_M0 (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_UESM (1 << 1)
|
||||
#define USART_CR1_UE (1 << 0)
|
||||
|
||||
#define USART_CR3_CTSE (1 << 9)
|
||||
#define USART_CR3_RTSE (1 << 8)
|
||||
#define USART_CR3_SCEN (1 << 5)
|
||||
#define USART_CR3_NACK (1 << 4)
|
||||
|
||||
static struct usart_stat usart2_stat;
|
||||
|
||||
static struct chx_intr usart1_intr;
|
||||
static struct chx_intr usart2_intr;
|
||||
|
||||
#define BUF_A2H_SIZE 256
|
||||
#define BUF_H2A_SIZE 512
|
||||
static uint8_t buf_usart2_rb_a2h[BUF_A2H_SIZE];
|
||||
static uint8_t buf_usart2_rb_h2a[BUF_H2A_SIZE];
|
||||
|
||||
static struct rb usart2_rb_a2h;
|
||||
static struct rb usart2_rb_h2a;
|
||||
|
||||
static chopstx_poll_cond_t usart2_app_write_event;
|
||||
|
||||
/* Global variables so that it can be easier to debug. */
|
||||
static int usart2_tx_ready;
|
||||
|
||||
#define INTR_REQ_USART1 37
|
||||
#define INTR_REQ_USART2 38
|
||||
|
||||
#define USART_DEVNO_START 1
|
||||
#define USART_DEVNO_END 2
|
||||
|
||||
struct usart {
|
||||
struct USART *USART;
|
||||
struct chx_intr *intr;
|
||||
uint8_t irq_num;
|
||||
struct usart_stat *stat;
|
||||
struct rb *rb_a2h;
|
||||
struct rb *rb_h2a;
|
||||
uint8_t *buf_a2h;
|
||||
uint8_t *buf_h2a;
|
||||
chopstx_poll_cond_t *app_write_event;
|
||||
int *tx_ready;
|
||||
};
|
||||
|
||||
|
||||
static const struct usart usart_array[] =
|
||||
{
|
||||
{ USART1, &usart1_intr, INTR_REQ_USART1,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
},
|
||||
{ USART2, &usart2_intr, INTR_REQ_USART2,
|
||||
&usart2_stat, &usart2_rb_a2h, &usart2_rb_h2a, buf_usart2_rb_a2h,
|
||||
buf_usart2_rb_h2a, &usart2_app_write_event, &usart2_tx_ready,
|
||||
},
|
||||
};
|
||||
#define NUM_USART ((int)(sizeof (usart_array) / sizeof (struct usart)))
|
||||
|
||||
static int handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat);
|
||||
static int handle_tx (struct USART *USARTx, struct rb *rb2h, struct usart_stat *stat);
|
||||
static void usart_config_recv_enable (struct USART *USARTx, int on);
|
||||
|
||||
struct brr_setting {
|
||||
uint8_t baud_spec;
|
||||
uint32_t brr_value;
|
||||
};
|
||||
#define NUM_BAUD (int)(sizeof (brr_table) / sizeof (struct brr_setting))
|
||||
|
||||
/* We assume 40MHz f_CK */
|
||||
static const struct brr_setting brr_table[] = {
|
||||
{ B600, 66667 },
|
||||
{ B1200, 33333 },
|
||||
{ B2400, 16667 },
|
||||
{ B9600, 4167 },
|
||||
{ B19200, 2083 },
|
||||
{ B57600, 694 },
|
||||
{ B115200, 347 },
|
||||
{ B230400, 174 },
|
||||
{ B460800, 87 },
|
||||
{ B921600, 43 },
|
||||
{ BSCARD1, 3720 },
|
||||
{ BSCARD2, 1860 },
|
||||
{ BSCARD4, 930 },
|
||||
{ BSCARD8, 465 },
|
||||
{ BSCARD12, 310 },
|
||||
{ BSCARD16, 233 },
|
||||
{ BSCARD20, 186 },
|
||||
};
|
||||
|
||||
#include "usart-common.c"
|
||||
|
||||
static void
|
||||
usart_config_recv_enable (struct USART *USARTx, int on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
USARTx->CR1 |= USART_CR1_RE;
|
||||
/* Wait for REACK bit. */
|
||||
while ((USARTx->ISR & (1 << 22)) == 0)
|
||||
;
|
||||
}
|
||||
else
|
||||
USARTx->CR1 &= ~USART_CR1_RE;
|
||||
}
|
||||
|
||||
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);
|
||||
/* TXEIE/TCIE will be enabled when
|
||||
putting char */
|
||||
/* No CTSIE, PEIE, 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))
|
||||
cr1_config |= USART_CR1_M1;
|
||||
else if (((config_bits & MASK_CS) == CS7 && (config_bits & PARENB))
|
||||
|| ((config_bits & MASK_CS) == CS8 && (config_bits & PARENB) == 0))
|
||||
;
|
||||
else if ((config_bits & MASK_CS) == CS8)
|
||||
cr1_config |= USART_CR1_M0;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if ((config_bits & PARENB))
|
||||
cr1_config |= (USART_CR1_PCE | USART_CR1_PEIE);
|
||||
|
||||
if ((config_bits & PARODD))
|
||||
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 = USART_CR3_CTSE | USART_CR3_RTSE;
|
||||
else
|
||||
USARTx->CR3 = 0;
|
||||
|
||||
if ((config_bits & MASK_MODE))
|
||||
{
|
||||
if ((config_bits & MASK_MODE) == MODE_SMARTCARD)
|
||||
{
|
||||
USARTx->GTPR = (1 << 8) | 5;
|
||||
USARTx->CR3 |= (USART_CR3_SCEN | USART_CR3_NACK);
|
||||
}
|
||||
else if ((config_bits & MASK_MODE) == MODE_IRDA)
|
||||
USARTx->CR3 |= (1 << 1);
|
||||
else if ((config_bits & MASK_MODE) == MODE_IRDA_LP)
|
||||
USARTx->CR3 |= (1 << 2) | (1 << 1);
|
||||
}
|
||||
else
|
||||
cr1_config |= USART_CR1_RE;
|
||||
|
||||
USARTx->CR1 = cr1_config;
|
||||
|
||||
/* Wait for TEACK bit. */
|
||||
while ((USARTx->ISR & (1 << 21)) == 0)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usart_init0 (int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||
{
|
||||
int i;
|
||||
|
||||
ss_notify_callback = cb;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
{
|
||||
if (usart_array[i].stat)
|
||||
usart_array[i].stat->dev_no = i + USART_DEVNO_START;
|
||||
chopstx_claim_irq (usart_array[i].intr, usart_array[i].irq_num);
|
||||
}
|
||||
|
||||
/* Enable USART1 clock, and strobe reset. */
|
||||
RCC->APB2ENR |= RCC_APB2_USART1;
|
||||
RCC->APB2RSTR = RCC_APB2_USART1;
|
||||
RCC->APB2RSTR = 0;
|
||||
|
||||
/* Enable USART2 clock, and strobe reset. */
|
||||
RCC->APB1ENR1 |= RCC_APB1_1_USART2;
|
||||
RCC->APB1RSTR1 = RCC_APB1_1_USART2;
|
||||
RCC->APB1RSTR1 = 0;
|
||||
}
|
||||
|
||||
#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->ISR;
|
||||
int notify_bits = 0;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if ((r & USART_ISR_TC))
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_ISR_TXE))
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
uint32_t data = USARTx->RDR;
|
||||
|
||||
/* RDR register should be accessed even if data is not used. */
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
if ((r & USART_ISR_NE))
|
||||
{
|
||||
USARTx->ICR |= (1 << 2);
|
||||
stat->err_rx_noise++;
|
||||
}
|
||||
else if ((r & USART_ISR_FE))
|
||||
{
|
||||
/* NOTE: Noway to distinguish framing error and break */
|
||||
|
||||
USARTx->ICR |= (1 << 1);
|
||||
stat->rx_break++;
|
||||
notify_bits |= UART_STATE_BITMAP_BREAK;
|
||||
}
|
||||
else if ((r & USART_ISR_PE))
|
||||
{
|
||||
USARTx->ICR |= (1 << 0);
|
||||
stat->err_rx_parity++;
|
||||
notify_bits |= UART_STATE_BITMAP_PARITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_ISR_ORE))
|
||||
{
|
||||
USARTx->ICR |= (1 << 3);
|
||||
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_ISR_ORE))
|
||||
{ /* Clear ORE */
|
||||
USARTx->ICR |= (1 << 3);
|
||||
stat->err_rx_overrun++;
|
||||
notify_bits |= UART_STATE_BITMAP_OVERRUN;
|
||||
}
|
||||
|
||||
if (notify_bits)
|
||||
{
|
||||
if (ss_notify_callback
|
||||
&& (*ss_notify_callback) (stat->dev_no, notify_bits))
|
||||
stat->err_notify_overflow++;
|
||||
}
|
||||
|
||||
return tx_ready;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_tx (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;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
USARTx->TDR = (c & 0xff);
|
||||
stat->tx++;
|
||||
r = USARTx->ISR;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if ((r & USART_ISR_TC) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_ISR_TXE) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tx_ready;
|
||||
}
|
||||
|
||||
int
|
||||
usart_send_break (uint8_t dev_no)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
if (USARTx == NULL)
|
||||
return -1;
|
||||
|
||||
if ((USARTx->ISR & (1 << 18)))
|
||||
return 1; /* Busy sending break, which was requested before. */
|
||||
|
||||
/* ??? Should we check TX is empty? */
|
||||
|
||||
USARTx->RQR |= 0x02;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
usart_block_sendrecv (uint8_t dev_no, const char *s_buf, uint16_t s_buflen,
|
||||
char *r_buf, uint16_t r_buflen,
|
||||
uint32_t *timeout_block_p, uint32_t timeout_char)
|
||||
{
|
||||
uint32_t timeout;
|
||||
uint8_t *p;
|
||||
int len;
|
||||
uint32_t r;
|
||||
uint32_t data;
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
struct chx_intr *usartx_intr = get_usart_intr (dev_no);
|
||||
struct chx_poll_head *ph[1];
|
||||
|
||||
if (usartx_intr == NULL)
|
||||
return -1;
|
||||
|
||||
ph[0] = (struct chx_poll_head *)usartx_intr;
|
||||
|
||||
p = (uint8_t *)s_buf;
|
||||
if (p)
|
||||
{
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 0);
|
||||
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
|
||||
/* Sending part */
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (NULL, 1, ph);
|
||||
|
||||
r = USARTx->ISR;
|
||||
|
||||
/* Here, ignore recv error(s). */
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
data = USARTx->RDR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
USARTx->ICR |= ((1 << 2) | (1 << 1) | (1 << 0));
|
||||
}
|
||||
else if ((r & USART_ISR_ORE))
|
||||
{
|
||||
USARTx->ICR |= (1 << 3);
|
||||
}
|
||||
|
||||
if ((r & USART_ISR_TXE))
|
||||
{
|
||||
if (s_buflen == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Keep TXEIE bit */
|
||||
USARTx->TDR = *p++;
|
||||
s_buflen--;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if (timeout_block_p && (*timeout_block_p))
|
||||
do
|
||||
r = USARTx->ISR;
|
||||
while (((r & USART_ISR_TC) == 0));
|
||||
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
if (timeout_block_p && *timeout_block_p == 0)
|
||||
{
|
||||
/* Ignoring the echo back. */
|
||||
do
|
||||
r = USARTx->ISR;
|
||||
while (((r & USART_ISR_TC) == 0));
|
||||
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
data = USARTx->RDR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
*timeout_block_p = timeout_char;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
if (r_buf == NULL)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
/* Receiving part */
|
||||
r = chopstx_poll (timeout_block_p, 1, ph);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
p = (uint8_t *)r_buf;
|
||||
len = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = USARTx->ISR;
|
||||
|
||||
data = USARTx->RDR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
if ((r & USART_ISR_NE) || (r & USART_ISR_FE) || (r & USART_ISR_PE))
|
||||
{
|
||||
/* ignore error, for now. XXX: ss_notify */
|
||||
/* Clear the error flag(s) */
|
||||
USARTx->ICR |= ((1 << 2) | (1 << 1) | (1 << 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = (data & 0xff);
|
||||
len++;
|
||||
r_buflen--;
|
||||
if (r_buflen == 0)
|
||||
{
|
||||
chopstx_intr_done (usartx_intr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((r & USART_ISR_ORE))
|
||||
{
|
||||
/* ignore error, for now. XXX: ss_notify */
|
||||
/* Clear the error flag */
|
||||
USARTx->ICR |= (1 << 3);
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
timeout = timeout_char;
|
||||
r = chopstx_poll (&timeout, 1, ph);
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -11,6 +11,13 @@
|
||||
#define B230400 26
|
||||
#define B460800 27
|
||||
#define B921600 28
|
||||
#define BSCARD1 57
|
||||
#define BSCARD2 58
|
||||
#define BSCARD4 59
|
||||
#define BSCARD8 60
|
||||
#define BSCARD12 61
|
||||
#define BSCARD16 62
|
||||
#define BSCARD20 63
|
||||
#define MASK_BAUD 0x3f
|
||||
|
||||
/* POSIX supports 5, 6. USB suppots 16 */
|
||||
@@ -43,6 +50,13 @@ PAR_BITS 3
|
||||
/* USB: SERIAL_STATE
|
||||
DSR DCD RI */
|
||||
|
||||
/* non-POSIX, non-USB-CDC configs */
|
||||
#define MODE_SMARTCARD (1 << 30)
|
||||
#define MODE_IRDA (2UL << 30)
|
||||
#define MODE_IRDA_LP (3UL << 30)
|
||||
#define MASK_MODE (0x3UL << 30)
|
||||
/* 0: standard, 1: smartcard, 2: IrDA, 3: IrDA-LP */
|
||||
|
||||
struct usart_stat {
|
||||
uint8_t dev_no;
|
||||
|
||||
@@ -64,3 +78,13 @@ 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);
|
||||
void usart_config_clken (uint8_t dev_no, int on);
|
||||
int usart_config_baud (uint8_t dev_no, uint8_t baud_spec);
|
||||
|
||||
void usart_read_prepare_poll (uint8_t dev_no, chopstx_poll_cond_t *poll_desc);
|
||||
int usart_read_ext (uint8_t dev_no, char *buf, uint16_t buflen, uint32_t *timeout_p);
|
||||
|
||||
void usart_init0 (int (*cb) (uint8_t dev_no, uint16_t notify_bits));
|
||||
int usart_block_sendrecv (uint8_t dev_no, const char *s_buf, uint16_t s_buflen,
|
||||
char *r_buf, uint16_t r_buflen,
|
||||
uint32_t *timeout_block_p, uint32_t timeout_char);
|
||||
|
||||
@@ -185,7 +185,8 @@ Returns old state which is 0 when it was enabled.
|
||||
@subheading chopstx_poll
|
||||
@anchor{chopstx_poll}
|
||||
@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. It is
|
||||
updated on return
|
||||
|
||||
@var{n}: Number of poll descriptors
|
||||
|
||||
|
||||
106
doc/chopstx.texi
106
doc/chopstx.texi
@@ -1,7 +1,7 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename chopstx.info
|
||||
@set VERSION 1.13
|
||||
@set VERSION 1.21
|
||||
@settitle Chopstx Reference Manual
|
||||
@c Unify some of the indices.
|
||||
@syncodeindex tp fn
|
||||
@@ -11,7 +11,7 @@
|
||||
This manual is for Chopstx (version @value{VERSION}).
|
||||
|
||||
@noindent
|
||||
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018 Flying Stone Technology @*
|
||||
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018, 2019 Flying Stone Technology @*
|
||||
|
||||
@quotation
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
@@ -60,10 +60,11 @@ section entitled ``Copying''.
|
||||
@menu
|
||||
* 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.
|
||||
* Poll or Pole::
|
||||
* Use of sleep mode:: Use it carefully.
|
||||
* Compile-time macro:: Macro to be defined.
|
||||
* API:: API.
|
||||
* Memorandom:: Memorandom for the implementation.
|
||||
|
||||
Appendix
|
||||
|
||||
@@ -88,8 +89,9 @@ Indexes
|
||||
@chapter Introduction
|
||||
|
||||
Chopstx is an RT thread library for ARM Cortex-M0, Cortex-M0plus,
|
||||
Cortex-M3 and GNU/Linux emulation. Specifically, it is used for
|
||||
STM32F030, MKL27Z, STM32F103, GD32F103 and as a command on GNU/Linux.
|
||||
Cortex-M3, Cortex-M4 with no FPU or DSP, and GNU/Linux emulation.
|
||||
Specifically, it is used for STM32F030, MKL27Z, STM32F103, GD32F103,
|
||||
STM32L432 and as a command on GNU/Linux.
|
||||
|
||||
While most RTOSes come with many features, drivers, and stacks,
|
||||
Chopstx just offers an RT thread library.
|
||||
@@ -99,7 +101,7 @@ 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.
|
||||
handle multiple events by a single thread.
|
||||
|
||||
|
||||
@node Threads and only Threads
|
||||
@@ -107,7 +109,7 @@ minimize use of 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
|
||||
single entry of chx_handle_intr which just wakes up a corresponding
|
||||
thread. This is the feature of Chopstx.
|
||||
|
||||
Nested vector interrupt machanism would be useful for interrupt-driven
|
||||
@@ -145,8 +147,8 @@ programming style, with minimum number of threads, avoiding
|
||||
complicated dependency between threads.
|
||||
|
||||
|
||||
@node Note (Use of sleep mode)
|
||||
@chapter Note (Use of sleep mode)
|
||||
@node Use of sleep mode
|
||||
@chapter 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
|
||||
@@ -178,6 +180,90 @@ Running CPU clock in MHz. Used for chopstx_usec_wait.
|
||||
|
||||
@include chopstx-api.texi
|
||||
|
||||
@node Memorandom
|
||||
@chapter Memorandom for the implementation
|
||||
|
||||
@menu
|
||||
* Honourable poverty:: Wabi and Sabi.
|
||||
* Better interrupt handling::
|
||||
* Static and deterministic when possible::
|
||||
@end menu
|
||||
|
||||
@node Honourable poverty
|
||||
@section Honourable poverty
|
||||
|
||||
Chopstx is an effort against many features. It encourages doing
|
||||
harder decision earlier (because of less features).
|
||||
|
||||
Along with Moore's law, MCU implementations and their software are
|
||||
getting more complex. It's been getting more flexibile, versatile,
|
||||
and powerful.
|
||||
|
||||
Here is a question: the bigger is the better?
|
||||
|
||||
Historically, it used to be ``Yes, and it's even cheaper!''. And, for
|
||||
a while, this trend continues.
|
||||
|
||||
However, in my opinion, it has been arrived to the point where
|
||||
complexity matters. Now, it's more difficult to manage the
|
||||
complexity.
|
||||
|
||||
With full of resources, it became possible deferring difficult
|
||||
hardware or lower-level decisions to upper layer, by supporting both
|
||||
ways, when we have a choice. It used to be considered a good
|
||||
practice.
|
||||
|
||||
But, eventually, as a system, it may result many knobs, full of
|
||||
options, which might be too difficult to manage.
|
||||
|
||||
In this situation, against existing practice, Chopstx is a challenge
|
||||
to handle all food by only two wooden sticks. It's not fork and exec
|
||||
nor forks and knives.
|
||||
|
||||
In Japan, it is common among families, to have private chopsticks for
|
||||
each individual at home. It's like: these chopsticks are father's,
|
||||
these chopsticks are mother's... son's and daughter's.
|
||||
|
||||
I hope Chopstx is the one for you.
|
||||
|
||||
|
||||
@node Better interrupt handling
|
||||
@section Better interrupt handling
|
||||
|
||||
In Chopstx, all interrupt handling is done by a single routine named
|
||||
chx_handle_intr. It uses linear list search to find a thread which
|
||||
handles the interrupt. In the fixed vector_table, we see many of
|
||||
chx_handle_intr entries.
|
||||
|
||||
Obviously, this is suboptimal. It kills the hardware effort to
|
||||
decrease interrupt latency.
|
||||
|
||||
I is certainly possible to support configurable vector table and/or
|
||||
better dispatch.
|
||||
|
||||
The reason why I keep this badness is that I believe that when
|
||||
interrupt latency matters (to the level of supporting larger vector
|
||||
table, despite only few cycles elimination), something is going wrong.
|
||||
You should have better solution or work around, instead of eliminating
|
||||
few cycles in an interrupt handler.
|
||||
|
||||
When I have an opportunity to design MCU, I don't support larger
|
||||
interrupt vector table.
|
||||
|
||||
|
||||
@node Static and deterministic when possible
|
||||
@section Static and deterministic when possible
|
||||
|
||||
When an application enables features dynamically, it may invite
|
||||
non-deterministic bugs. Typical example: the order of driver
|
||||
initialization matters, because of hidden dependency in a hardware
|
||||
implementation. To cover all the cases, tests needed can become huge.
|
||||
|
||||
A simple practice like following is good when it's enough: doing all
|
||||
initialization at start, then running threads to work.
|
||||
|
||||
If possible, it's better to avoid supporting fine grain power control
|
||||
and/or dynamic clock frequency change.
|
||||
|
||||
@c ********************************************
|
||||
|
||||
|
||||
45
entry-gnu-linux.c
Normal file
45
entry-gnu-linux.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* entry.c - Entry routine.
|
||||
*
|
||||
* Copyright (C) 2017, 2019
|
||||
* 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
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
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);
|
||||
}
|
||||
50
entry.c
50
entry.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* entry.c - Entry routine when reset and interrupt vectors.
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2019
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -23,30 +23,16 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <chopstx-cortex-m.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
int emulated_main (int, const char **);
|
||||
void chx_init (struct chx_thread *);
|
||||
void chx_systick_init (void);
|
||||
extern struct chx_thread main_thread;
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
chx_init (&main_thread);
|
||||
chx_systick_init ();
|
||||
emulated_main (argc, argv);
|
||||
}
|
||||
#else
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
|
||||
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
|
||||
#include "sys.h"
|
||||
@@ -54,12 +40,16 @@ main (int argc, const char *argv[])
|
||||
* Avoid medium density specific code and prepare for high density
|
||||
* device, too.
|
||||
*/
|
||||
#undef STM32F10X_MD
|
||||
#if !defined(MCU_STM32L4)
|
||||
#define STM32F10X_HD
|
||||
#endif
|
||||
#else
|
||||
#if defined (MCU_KINETIS_L)
|
||||
#include "mcu/clk_gpio_init-mkl27z.c"
|
||||
#elif defined (MCU_STM32L4)
|
||||
#include "mcu/clk_gpio_init-stm32l.c"
|
||||
#else
|
||||
#include "mcu/clk_gpio_init-stm32.c"
|
||||
#include "mcu/clk_gpio_init-stm32f.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -71,7 +61,7 @@ main (int argc, const char *argv[])
|
||||
#endif
|
||||
|
||||
extern uint8_t __main_stack_end__;
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
extern void svc (void);
|
||||
#endif
|
||||
extern void preempt (void);
|
||||
@@ -167,7 +157,7 @@ entry (void)
|
||||
"bl chx_systick_init\n\t"
|
||||
"bl gpio_init\n\t"
|
||||
/* Enable interrupts. */
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
"mov r0, #0\n\t"
|
||||
"msr BASEPRI, r0\n\t"
|
||||
#endif
|
||||
@@ -197,7 +187,7 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
||||
none, none, none, /* reserved */
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
none, /* SVCall */
|
||||
#elif defined(__ARM_ARCH_7M__)
|
||||
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
svc, /* SVCall */
|
||||
#endif
|
||||
none, /* Debug */
|
||||
@@ -233,12 +223,24 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
||||
chx_handle_intr /* EXT15_10 */, chx_handle_intr /* RTCAlarm */,
|
||||
chx_handle_intr /* USBWakeup */, chx_handle_intr,
|
||||
#endif
|
||||
#if !defined(STM32F10X_MD)
|
||||
#if defined(STM32F10X_HD)
|
||||
/* 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,
|
||||
#elif defined(MCU_STM32L4)
|
||||
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, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,9 @@ eventflag_prepare_poll (struct eventflag *ev, chopstx_poll_cond_t *poll_desc)
|
||||
}
|
||||
|
||||
|
||||
/* When multiple events are marked, event with lower bit has precedence.
|
||||
Because __builtin_ffs returns the least significant 1-bit. */
|
||||
|
||||
eventmask_t
|
||||
eventflag_get (struct eventflag *ev)
|
||||
{
|
||||
|
||||
@@ -179,7 +179,14 @@ main (int argc, const char *argv[])
|
||||
if (size < 0)
|
||||
goto connection_loop;
|
||||
|
||||
if (size == 1)
|
||||
if (size == 0)
|
||||
/* Timeout */
|
||||
{
|
||||
if (tty_send (tty, "\r\n", 2) < 0)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
else if (size == 1)
|
||||
/* Do nothing but prompt again. */
|
||||
break;
|
||||
else if (size)
|
||||
|
||||
@@ -660,31 +660,8 @@ tty_main (void *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)
|
||||
{
|
||||
@@ -692,9 +669,7 @@ tty_main (void *arg)
|
||||
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:
|
||||
@@ -793,7 +768,7 @@ tty_main (void *arg)
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
|
||||
|
||||
if (len)
|
||||
{
|
||||
@@ -929,8 +904,18 @@ tty_recv (struct tty *t, char *buf, uint32_t *timeout)
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
r = check_rx (t);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
if (r || (timeout != NULL && *timeout == 0))
|
||||
if (r)
|
||||
break;
|
||||
else if (timeout != NULL && *timeout == 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Cancel the input. */
|
||||
for (i = 0; i < t->inputline_len; i++)
|
||||
tty_send (t, "\x08\x20\x08", 3);
|
||||
t->inputline_len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
PROJECT = sample
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT= sample.ld
|
||||
LDSCRIPT= sample.ld.m4
|
||||
CSRC = sample.c usb-cdc.c
|
||||
|
||||
CHIP=stm32f103
|
||||
CHIP=stm32l4
|
||||
|
||||
USE_SYS = yes
|
||||
USE_USB = yes
|
||||
@@ -18,9 +18,9 @@ CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
MCU = cortex-m3
|
||||
MCU = cortex-m4
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=72
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
../board/board-fst-01.h
|
||||
../board/board-st-nucleo-l432.h
|
||||
107
example-cdc/sample.ld.m4
Normal file
107
example-cdc/sample.ld.m4
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* ST32L4 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash : org = 0x08000000, len = 256k
|
||||
ram : org = 0x20000000, len = 48k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN(16);
|
||||
_sys = .;
|
||||
. = 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);
|
||||
} > 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;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = 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__;
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <string.h>
|
||||
#include "board.h"
|
||||
#include "usb_lld.h"
|
||||
#include "tty.h"
|
||||
|
||||
@@ -671,31 +672,8 @@ tty_main (void *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)
|
||||
{
|
||||
@@ -703,9 +681,7 @@ tty_main (void *arg)
|
||||
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:
|
||||
@@ -804,7 +780,7 @@ tty_main (void *arg)
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
|
||||
|
||||
if (len)
|
||||
{
|
||||
|
||||
@@ -173,7 +173,6 @@ usb_main (void *arg)
|
||||
(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)
|
||||
{
|
||||
@@ -183,7 +182,6 @@ usb_main (void *arg)
|
||||
{
|
||||
uint8_t ep_num;
|
||||
|
||||
event_handle:
|
||||
e = usb_lld_event_handler (&dev);
|
||||
chopstx_intr_done (&interrupt);
|
||||
ep_num = USB_EVENT_ENDP (e);
|
||||
|
||||
@@ -657,31 +657,8 @@ tty_main (void *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)
|
||||
{
|
||||
@@ -692,9 +669,7 @@ tty_main (void *arg)
|
||||
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:
|
||||
@@ -793,7 +768,7 @@ tty_main (void *arg)
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
|
||||
|
||||
if (len)
|
||||
{
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
|
||||
PROJECT = sample
|
||||
|
||||
### Currently, it's for STM32F0 Discovery.
|
||||
### Currently, it is for STM32 Nucleo L432
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M3 board.
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M0+ board
|
||||
### (STM32F0 Discovery).
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT= sample.ld
|
||||
LDSCRIPT= sample.ld.m4
|
||||
### LDSCRIPT= sample.ld
|
||||
### LDSCRIPT= sample.ld.m3
|
||||
CSRC = sample.c
|
||||
|
||||
CHIP=stm32f0
|
||||
CHIP=stm32l4
|
||||
USE_SYS = yes
|
||||
|
||||
###################################
|
||||
@@ -20,9 +25,10 @@ LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
### MCU = cortex-m3
|
||||
MCU = cortex-m0
|
||||
### MCU = cortex-m0
|
||||
MCU = cortex-m4
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=48
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
|
||||
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
|
||||
@@ -1 +1 @@
|
||||
../board/board-stm32f0-discovery.h
|
||||
../board/board-st-nucleo-l432.h
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "sys.h" /* for set_led */
|
||||
|
||||
static chopstx_mutex_t mtx;
|
||||
|
||||
107
example-led/sample.ld.m4
Normal file
107
example-led/sample.ld.m4
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* ST32L4 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash : org = 0x08000000, len = 256k
|
||||
ram : org = 0x20000000, len = 48k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN(16);
|
||||
_sys = .;
|
||||
. = 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);
|
||||
} > 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;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = 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__;
|
||||
47
example-usart/Makefile
Normal file
47
example-usart/Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
# Makefile for example application of Chopstx
|
||||
|
||||
PROJECT = sample
|
||||
|
||||
### Currently, it is for STM32 Nucleo L432
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M3 board.
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M0+ board
|
||||
### (STM32F0 Discovery).
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT= sample.ld.m4
|
||||
### LDSCRIPT= sample.ld
|
||||
### LDSCRIPT= sample.ld.m3
|
||||
CSRC = sample.c
|
||||
|
||||
CHIP=stm32l4
|
||||
USE_SYS = yes
|
||||
USE_USART = yes
|
||||
|
||||
###################################
|
||||
CROSS = arm-none-eabi-
|
||||
CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
### MCU = cortex-m3
|
||||
### MCU = cortex-m0
|
||||
MCU = cortex-m4
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
|
||||
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
|
||||
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
|
||||
1
example-usart/board.h
Symbolic link
1
example-usart/board.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../board/board-st-nucleo-l432.h
|
||||
156
example-usart/sample.c
Normal file
156
example-usart/sample.c
Normal file
@@ -0,0 +1,156 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "sys.h" /* for set_led */
|
||||
#include <contrib/usart.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
|
||||
wait_for (uint32_t usec)
|
||||
{
|
||||
#if defined(BUSY_LOOP)
|
||||
uint32_t count = usec * 6;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
#else
|
||||
chopstx_usec_wait (usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *
|
||||
pwm (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd0, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
set_led (u&v);
|
||||
wait_for (m);
|
||||
set_led (0);
|
||||
wait_for (100-m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
blk (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd1, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
v = 0;
|
||||
wait_for (200*1000);
|
||||
v = 1;
|
||||
wait_for (200*1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(BUSY_LOOP)
|
||||
#define PRIO_PWM (CHOPSTX_SCHED_RR|1)
|
||||
#define PRIO_BLK (CHOPSTX_SCHED_RR|1)
|
||||
#else
|
||||
#define PRIO_PWM 3
|
||||
#define PRIO_BLK 2
|
||||
#endif
|
||||
|
||||
#define STACK_MAIN
|
||||
#define STACK_PROCESS_1
|
||||
#define STACK_PROCESS_2
|
||||
#define STACK_PROCESS_3
|
||||
#include "stack-def.h"
|
||||
|
||||
|
||||
#define STACK_ADDR_PWM ((uint32_t)process1_base)
|
||||
#define STACK_SIZE_PWM (sizeof process1_base)
|
||||
|
||||
#define STACK_ADDR_BLK ((uint32_t)process2_base)
|
||||
#define STACK_SIZE_BLK (sizeof process2_base)
|
||||
|
||||
#define PRIO_USART 4
|
||||
#define STACK_ADDR_USART ((uint32_t)process3_base)
|
||||
#define STACK_SIZE_USART (sizeof process3_base)
|
||||
|
||||
static int
|
||||
ss_notify (uint8_t dev_no, uint16_t state_bits)
|
||||
{
|
||||
(void)dev_no;
|
||||
(void)state_bits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
uint32_t timeout;
|
||||
struct chx_poll_head *ph[1];
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
chopstx_mutex_init (&mtx);
|
||||
chopstx_cond_init (&cnd0);
|
||||
chopstx_cond_init (&cnd1);
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_signal (&cnd0);
|
||||
chopstx_cond_signal (&cnd1);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify);
|
||||
usart_config (2, B115200 | CS8 | STOP1B);
|
||||
|
||||
usart_read_prepare_poll (2, &poll_desc);
|
||||
ph[0] = (struct chx_poll_head *)&poll_desc;
|
||||
|
||||
timeout = 200*1000*6;
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (&timeout, 1, ph);
|
||||
if (timeout == 0)
|
||||
{
|
||||
usart_write (2, "Hello\r\n", 7);
|
||||
u ^= 1;
|
||||
timeout = 200*1000*6;
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[256];
|
||||
int r;
|
||||
r = usart_read (2, buf, 256);
|
||||
if (r)
|
||||
usart_write (2, buf, r);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
126
example-usart/sample.ld
Normal file
126
example-usart/sample.ld
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* ST32F0 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 =0xffffffff
|
||||
|
||||
_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;
|
||||
|
||||
.vectors_in_ram :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
__vector_ram_addr__ = .;
|
||||
KEEP(*(.bss.startup.*))
|
||||
} > ram
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = 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__;
|
||||
116
example-usart/sample.ld.m3
Normal file
116
example-usart/sample.ld.m3
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = 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__;
|
||||
107
example-usart/sample.ld.m4
Normal file
107
example-usart/sample.ld.m4
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* ST32L4 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash : org = 0x08000000, len = 256k
|
||||
ram : org = 0x20000000, len = 48k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN(16);
|
||||
_sys = .;
|
||||
. = 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);
|
||||
} > 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;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = 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__;
|
||||
54
example-usart/stack-def.h
Normal file
54
example-usart/stack-def.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#define MAIN_SIZE 0x0080 /* Idle+Exception handlers */
|
||||
#define SIZE_0 0x0300 /* Main program */
|
||||
#define SIZE_1 0x0100 /* first thread program */
|
||||
#define SIZE_2 0x0100 /* second thread program */
|
||||
#define SIZE_3 0x0200 /* 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
|
||||
@@ -1,12 +1,19 @@
|
||||
This is an application example using ST Nucleo F103 board.
|
||||
|
||||
SB62 and SB63 should be soldered.
|
||||
ST-Link/V2 is disconnected (SB13 and SB14).
|
||||
SB62 and SB63 should be soldered to connect PA2 and PA3 to CN10
|
||||
connector.
|
||||
|
||||
ST-Link/V2's TX and RX are disconnected (by removing SB13 and SB14).
|
||||
|
||||
Smartcard can be connected, by using USART3_TX for I/O and USART3_CK
|
||||
for CLK, PB6 for Vcc, PB8 for Vpp, and PB9 for RST.
|
||||
|
||||
|
||||
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.
|
||||
because it's designed for modem; In the protocol, we have no way to
|
||||
control the CTSRTS signal.
|
||||
|
||||
TIOCGICOUNT
|
||||
|
||||
@@ -19,4 +26,4 @@ TODO:
|
||||
* stats report control
|
||||
By vendor specific control?
|
||||
* Half-duplex support
|
||||
* Support of other communication mode: smartcard, IrDA, etc.
|
||||
* Support of other communication mode: IrDA, etc.
|
||||
|
||||
@@ -238,6 +238,9 @@ main (int argc, const char *argv[])
|
||||
|
||||
usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify);
|
||||
|
||||
usart_config (2, B115200 | CS8 | STOP1B);
|
||||
usart_config (3, B115200 | CS8 | STOP1B);
|
||||
|
||||
cdc_usart0.cdc = cdc_open (0);
|
||||
cdc_usart0.dev_no = 2;
|
||||
cdc_usart1.cdc = cdc_open (1);
|
||||
|
||||
@@ -722,31 +722,8 @@ cdc_main (void *arg)
|
||||
|
||||
(void)arg;
|
||||
|
||||
#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)
|
||||
{
|
||||
@@ -754,9 +731,7 @@ cdc_main (void *arg)
|
||||
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,8 +1,7 @@
|
||||
Consideration about SYS and the first pages of flash ROM
|
||||
========================================================
|
||||
|
||||
Now, I'm developing something like SYS for Kinetis L MCU, so, I write
|
||||
this document.
|
||||
This document was written when I was porting Chopstx to Kinetis L.
|
||||
|
||||
* Compatibility
|
||||
|
||||
@@ -10,7 +9,8 @@ this document.
|
||||
SYS 2.0: Added clock_init, gpio_init
|
||||
SYS 2.1: Added sys_board_id, sys_board_name
|
||||
SYS 3.0: Don't setup NVIC priority by usb_lld_sys_init
|
||||
|
||||
SYS 4.0: For USB, only do usb_cable_config. Enabling/disabling the
|
||||
USB module is the role of USB driver.
|
||||
|
||||
* Macro definition by DEFS in Makefile
|
||||
|
||||
@@ -131,23 +131,24 @@ and here is the list of all.
|
||||
|
||||
nvic_system_reset
|
||||
|
||||
The routines of clock_init and gpio_init are here because of some
|
||||
historical reasons. (We could design a system with no such exported
|
||||
routines: by defining: those things done internally after reset and
|
||||
before calling the application.)
|
||||
The routines of clock_init and gpio_init exist in SYS, because of some
|
||||
historical reasons; Without such exported routines, we could design a
|
||||
system having an assumption: important clock and gpio initialization
|
||||
is done internally after reset, so that an application can just work.
|
||||
|
||||
Those are exported as entries of SYS, and it is the responsibility of
|
||||
the application which do initialize clock and GPIO, calling those
|
||||
routines.
|
||||
|
||||
USB routines are needed because of hardware practice of STM32F103.
|
||||
With STM32F103, each board has different way for handling the pull up
|
||||
of USB D+ and how the device asks re-enumeration to host PC. In my
|
||||
opinion, if it's defined as full speed device and it's OK for us not
|
||||
to use high impedance (but asserting to LOW, instead) of D+ to ask
|
||||
re-enumeration, we can just pull up D+ always. And we wouldn't need
|
||||
such routines in SYS.
|
||||
USB routines are needed because of hardware practice of STM32F103. (It
|
||||
can support low speed device. It can support self powered USB
|
||||
system.) With STM32F103 (for allowing low speed device and self
|
||||
powered system), each board has different way for handling the pull up
|
||||
of USB D+ and how the device asks re-enumeration to host PC.
|
||||
|
||||
For bus-powered system and full speed device, we can just pull up D+
|
||||
always. Still, support of high impedance state of D+ line would be
|
||||
ideal when asking re-enumeration, asserting to LOW works.
|
||||
|
||||
|
||||
About SYS on Kinetis L
|
||||
|
||||
32
mcu/ABOUT-USB
Normal file
32
mcu/ABOUT-USB
Normal file
@@ -0,0 +1,32 @@
|
||||
USB driver in Chopstx
|
||||
|
||||
Full speed device is assumed. Bus powered system is assumed.
|
||||
API-wise, self powered system is not supported (yet) by this USB driver.
|
||||
|
||||
The driver can be used without Chopstx. An example can be find in
|
||||
Gnuk (gnuk/regnual).
|
||||
|
||||
The USB driver was originally written for STM32F103, which USB
|
||||
hardware design is considered not mature. Modern USB hardware design
|
||||
allows crystal-less design, and/or comes with internal 5V->3V3
|
||||
regulator, D+-line pull-up support, and VBUS detection. STM32F103 has
|
||||
nothing.
|
||||
|
||||
To support self powered system, we need to define a hardware interface
|
||||
for a board detecting VBUS voltage. Only after detecting VBUS power,
|
||||
we can enable USB driver (D+/D- lines). For self powered system,
|
||||
driving D+/D- lines by fixed pull-up resistor violates the USB
|
||||
specification.
|
||||
|
||||
With STM32F103, there is a common hardware practice having a
|
||||
gate/transistor for pull-up D+ line. If it also supports detecting
|
||||
VBUS, self powerd system can be supported with the gate/transistor.
|
||||
|
||||
Such a gate/transistor can be also used for the board to ask
|
||||
re-enumeration of USB device. Asking re-enumeration, it is enough to
|
||||
have SE0 (Single-Ended Zero) state.
|
||||
|
||||
The USB driver doesn't touch such a gate/transistor. By gpio_init,
|
||||
the D+-line should be asserted, USB D+ and D- lines should be drived
|
||||
to 0 (SE0). When the USB module is enabled, it goes into J and K
|
||||
state (from SE0 state).
|
||||
29
mcu/chx-stm32l4.c
Normal file
29
mcu/chx-stm32l4.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdint.h>
|
||||
#include <mcu/cortex-m.h>
|
||||
#include <mcu/stm32l.h>
|
||||
|
||||
extern int chx_allow_sleep;
|
||||
|
||||
void
|
||||
chx_sleep_mode (int how)
|
||||
{
|
||||
/*TBD*/
|
||||
(void)how;
|
||||
}
|
||||
|
||||
void __attribute__((naked))
|
||||
chx_idle (void)
|
||||
{
|
||||
/*TBD*/
|
||||
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. */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
115
mcu/clk_gpio_init-stm32l.c
Normal file
115
mcu/clk_gpio_init-stm32l.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* clk_gpio_init-stm32l.c - Clock and GPIO initialization for STM32L.
|
||||
*
|
||||
* Copyright (C) 2019 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
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <mcu/stm32l.h>
|
||||
|
||||
#define STM32_FLASHBITS 0x00000704
|
||||
|
||||
void
|
||||
clock_init (void)
|
||||
{
|
||||
/* MSI: 4MHz (keep the default value) */
|
||||
|
||||
/* PLL input: MSI at 4MHz, VCO: 160 MHz, output 80MHz */
|
||||
RCC->PLLCFGR = ((1 << 24) | (40 << 8)) | 0x01;
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CR |= (1 << 24);
|
||||
while (!(RCC->CR & (1 << 25)))
|
||||
;
|
||||
|
||||
/* Flash setup: four wait states at 80MHz */
|
||||
FLASH->ACR = STM32_FLASHBITS;
|
||||
while ((FLASH->ACR & 0x07) != (STM32_FLASHBITS & 0x07))
|
||||
;
|
||||
|
||||
/* Configure bus clocks: AHB: 80MHz, APB1: 40MHz, APB2: 40MHz */
|
||||
RCC->CFGR = ((0x04 << 11) | (0x04 << 8));
|
||||
|
||||
/* Switch SYSCLOCK using PLL */
|
||||
RCC->CFGR |= 0x03;
|
||||
while ((RCC->CFGR & 0x0C) != 0x0C)
|
||||
;
|
||||
|
||||
/* Peripheral clock selection */
|
||||
RCC->CCIPR = ( (0x00 << 26) | /* HSI48 for USB */
|
||||
(0x00 << 2) | /* PCLK for USART2 */
|
||||
(0x00 << 0) ); /* PCLK for USART1 */
|
||||
|
||||
/* Enable PWR clock */
|
||||
RCC->APB1ENR1 |= (1 << 28);
|
||||
RCC->APB1RSTR1 = (1 << 28);
|
||||
RCC->APB1RSTR1 = 0;
|
||||
|
||||
/* Enable HSI48 clock */
|
||||
RCC->CRRCR |= 1;
|
||||
while ((RCC->CRRCR & 0x02) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
static struct GPIO *const GPIO_LED = (struct GPIO *)GPIO_LED_BASE;
|
||||
#ifdef GPIO_USB_BASE
|
||||
static struct GPIO *const GPIO_USB = (struct GPIO *)GPIO_USB_BASE;
|
||||
#endif
|
||||
#ifdef GPIO_OTHER_BASE
|
||||
static struct GPIO *const GPIO_OTHER = (struct GPIO *)GPIO_OTHER_BASE;
|
||||
#endif
|
||||
|
||||
void
|
||||
gpio_init (void)
|
||||
{
|
||||
/* Enable GPIO clock. */
|
||||
RCC->AHB2ENR |= RCC_AHB2_GPIO;
|
||||
/* Delay (more than two clocks) is needed. */
|
||||
while ((RCC->AHB2ENR & RCC_AHB2_GPIO) == 0)
|
||||
;
|
||||
|
||||
RCC->AHB2RSTR = RCC_AHB2_GPIO;
|
||||
RCC->AHB2RSTR = 0;
|
||||
|
||||
/* Delay (more than two clocks) is needed. */
|
||||
while (RCC->AHB2RSTR != 0)
|
||||
;
|
||||
|
||||
/* LED is mandatory. We configure it always. */
|
||||
GPIO_LED->OSPEEDR = VAL_GPIO_LED_OSPEEDR;
|
||||
GPIO_LED->OTYPER = VAL_GPIO_LED_OTYPER;
|
||||
GPIO_LED->MODER = VAL_GPIO_LED_MODER;
|
||||
GPIO_LED->PUPDR = VAL_GPIO_LED_PUPDR;
|
||||
GPIO_LED->AFRL = VAL_GPIO_LED_AFRL;
|
||||
GPIO_LED->AFRH = VAL_GPIO_LED_AFRH;
|
||||
|
||||
#ifdef GPIO_OTHER_BASE
|
||||
GPIO_OTHER->OSPEEDR = VAL_GPIO_OTHER_OSPEEDR;
|
||||
GPIO_OTHER->OTYPER = VAL_GPIO_OTHER_OTYPER;
|
||||
GPIO_OTHER->MODER = VAL_GPIO_OTHER_MODER;
|
||||
GPIO_OTHER->PUPDR = VAL_GPIO_OTHER_PUPDR;
|
||||
GPIO_OTHER->AFRL = VAL_GPIO_OTHER_AFRL;
|
||||
GPIO_OTHER->AFRH = VAL_GPIO_OTHER_AFRH;
|
||||
#endif
|
||||
}
|
||||
197
mcu/stm32l.h
Normal file
197
mcu/stm32l.h
Normal file
@@ -0,0 +1,197 @@
|
||||
#define PERIPH_BASE 0x40000000
|
||||
#define APB1PERIPH_BASE PERIPH_BASE
|
||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x20000)
|
||||
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
||||
|
||||
struct RCC {
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t ICSCR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t PLLCFGR;
|
||||
|
||||
volatile uint32_t PLLSAI1CFGR;
|
||||
volatile uint32_t RESERVED0;
|
||||
volatile uint32_t CIER;
|
||||
volatile uint32_t CIFR;
|
||||
|
||||
volatile uint32_t CICR;
|
||||
volatile uint32_t RESERVED1;
|
||||
volatile uint32_t AHB1RSTR;
|
||||
volatile uint32_t AHB2RSTR;
|
||||
|
||||
volatile uint32_t AHB3RSTR;
|
||||
volatile uint32_t RESERVED2;
|
||||
volatile uint32_t APB1RSTR1;
|
||||
volatile uint32_t APB1RSTR2;
|
||||
|
||||
volatile uint32_t APB2RSTR;
|
||||
volatile uint32_t RESERVED3;
|
||||
volatile uint32_t AHB1ENR;
|
||||
volatile uint32_t AHB2ENR;
|
||||
|
||||
volatile uint32_t AHB3ENR;
|
||||
volatile uint32_t RESERVED4;
|
||||
volatile uint32_t APB1ENR1;
|
||||
volatile uint32_t APB1ENR2;
|
||||
|
||||
volatile uint32_t APB2ENR;
|
||||
volatile uint32_t RESERVED5;
|
||||
volatile uint32_t AHB1SMENR;
|
||||
volatile uint32_t AHB2SMENR;
|
||||
|
||||
volatile uint32_t AHB3SMENR;
|
||||
volatile uint32_t RESERVED6;
|
||||
volatile uint32_t APB1SMENR1;
|
||||
volatile uint32_t APB1SMENR2;
|
||||
|
||||
volatile uint32_t APB2SMENR;
|
||||
volatile uint32_t RESERVED7;
|
||||
volatile uint32_t CCIPR;
|
||||
volatile uint32_t RESERVED8;
|
||||
|
||||
volatile uint32_t BDCR;
|
||||
volatile uint32_t CSR;
|
||||
volatile uint32_t CRRCR;
|
||||
volatile uint32_t CCIPR2;
|
||||
};
|
||||
|
||||
#define RCC_BASE (AHB1PERIPH_BASE + 0x1000)
|
||||
static struct RCC *const RCC = (struct RCC *)RCC_BASE;
|
||||
|
||||
#define RCC_AHB2_GPIOA 0x00000001
|
||||
#define RCC_AHB2_GPIOB 0x00000002
|
||||
#define RCC_AHB2_GPIOC 0x00000004
|
||||
#define RCC_AHB2_GPIOD 0x00000008
|
||||
#define RCC_AHB2_GPIOE 0x00000010
|
||||
#define RCC_AHB2_GPIOH 0x00000080
|
||||
|
||||
#define RCC_APB1_1_USB (1 << 26)
|
||||
#define RCC_APB1_1_CRS (1 << 24)
|
||||
|
||||
|
||||
struct PWR
|
||||
{
|
||||
volatile uint32_t CR1;
|
||||
volatile uint32_t CR2;
|
||||
volatile uint32_t CR3;
|
||||
volatile uint32_t CR4;
|
||||
volatile uint32_t SR1;
|
||||
volatile uint32_t SR2;
|
||||
volatile uint32_t SCR;
|
||||
volatile uint32_t PUCRA;
|
||||
volatile uint32_t PDCRA;
|
||||
volatile uint32_t PUCRB;
|
||||
volatile uint32_t PDCRB;
|
||||
volatile uint32_t PUCRC;
|
||||
volatile uint32_t PDCRC;
|
||||
volatile uint32_t PUCRD;
|
||||
volatile uint32_t PDCRD;
|
||||
volatile uint32_t PUCRE;
|
||||
volatile uint32_t PDCRE;
|
||||
volatile uint32_t PUCRH;
|
||||
volatile uint32_t PDCRH;
|
||||
};
|
||||
static struct PWR *const PWR = ((struct PWR *)0x40007000);
|
||||
|
||||
struct GPIO {
|
||||
volatile uint32_t MODER;
|
||||
volatile uint32_t OTYPER;
|
||||
volatile uint32_t OSPEEDR;
|
||||
volatile uint32_t PUPDR;
|
||||
volatile uint32_t IDR;
|
||||
volatile uint32_t ODR;
|
||||
volatile uint32_t BSRR;
|
||||
volatile uint32_t LCKR;
|
||||
volatile uint32_t AFRL;
|
||||
volatile uint32_t AFRH;
|
||||
volatile uint32_t BRR;
|
||||
};
|
||||
|
||||
#define GPIOA_BASE (AHB2PERIPH_BASE)
|
||||
static struct GPIO *const GPIOA = (struct GPIO *)GPIOA_BASE;
|
||||
#define GPIOB_BASE (AHB2PERIPH_BASE + 0x0400)
|
||||
static struct GPIO *const GPIOB = (struct GPIO *)GPIOB_BASE;
|
||||
|
||||
|
||||
struct FLASH {
|
||||
volatile uint32_t ACR;
|
||||
volatile uint32_t PDKEYR;
|
||||
volatile uint32_t KEYR;
|
||||
volatile uint32_t OPTKEYR;
|
||||
volatile uint32_t SR;
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t ECCR;
|
||||
volatile uint32_t RESERVED;
|
||||
volatile uint32_t OPTR;
|
||||
volatile uint32_t PCROP1SR;
|
||||
volatile uint32_t PCROP1ER;
|
||||
volatile uint32_t WRP1AR;
|
||||
volatile uint32_t WRP1BR;
|
||||
};
|
||||
|
||||
#define FLASH_R_BASE (AHB1PERIPH_BASE + 0x2000)
|
||||
static struct FLASH *const FLASH = (struct FLASH *)FLASH_R_BASE;
|
||||
|
||||
struct USB_STM32L4 {
|
||||
volatile uint16_t LPMCSR;
|
||||
volatile uint16_t reserved0;
|
||||
volatile uint16_t BCDR;
|
||||
volatile uint16_t reserved1;
|
||||
};
|
||||
|
||||
#define USB_STM32L4_BASE (0x40006854UL)
|
||||
static struct USB_STM32L4 *const USB_STM32L4 = (struct USB_STM32L4 *)USB_STM32L4_BASE;
|
||||
|
||||
struct SYSCFG {
|
||||
volatile uint32_t MEMRMP;
|
||||
volatile uint32_t CFGR1;
|
||||
volatile uint32_t EXTICR[4];
|
||||
volatile uint32_t SCSR;
|
||||
volatile uint32_t CFGR2;
|
||||
volatile uint32_t SWPR;
|
||||
volatile uint32_t SKR;
|
||||
};
|
||||
|
||||
#define SYSCFG_BASE (APB2PERIPH_BASE+0UL)
|
||||
static struct SYSCFG *const SYSCFG = (struct SYSCFG *)SYSCFG_BASE;
|
||||
|
||||
#define EXTI0_IRQ 6
|
||||
#define SYSCFG_EXTICR1_EXTI0_PA 0
|
||||
|
||||
struct EXTI {
|
||||
union {
|
||||
volatile uint32_t IMR1;
|
||||
volatile uint32_t IMR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t EMR1;
|
||||
volatile uint32_t EMR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t RTSR1;
|
||||
volatile uint32_t RTSR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t FTSR1;
|
||||
volatile uint32_t FTSR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t SWIER1;
|
||||
volatile uint32_t SWIER;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t PR1;
|
||||
volatile uint32_t PR;
|
||||
};
|
||||
volatile uint32_t reserved;
|
||||
volatile uint32_t IMR2;
|
||||
volatile uint32_t EMR2;
|
||||
volatile uint32_t RTSR2;
|
||||
volatile uint32_t FTSR2;
|
||||
volatile uint32_t SWIER2;
|
||||
volatile uint32_t PR2;
|
||||
};
|
||||
|
||||
#define EXTI_BASE (APB2PERIPH_BASE+0x0400)
|
||||
static struct EXTI *const EXTI = (struct EXTI *)EXTI_BASE;
|
||||
@@ -16,8 +16,8 @@
|
||||
const uint8_t sys_version[8] = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
#include "board.h"
|
||||
|
||||
#define ADDR_VECTORS (0x00000900)
|
||||
#define ADDR_SCR_VTOR 0xe000ed08
|
||||
#define ADDR_SCB_VTOR 0xe000ed08
|
||||
|
||||
static void __attribute__ ((naked,section(".fixed_function.reset")))
|
||||
reset (void)
|
||||
{
|
||||
uint32_t r3 = ADDR_SCR_VTOR;
|
||||
uint32_t r3 = ADDR_SCB_VTOR;
|
||||
|
||||
asm volatile ("str %2, [%0]\n\t" /* Set SCR->VTOR */
|
||||
asm volatile ("str %2, [%0]\n\t" /* Set SCB->VTOR */
|
||||
"ldr %0, [%2]\n\t" /* Stack address */
|
||||
"msr MSP, %0\n\t" /* Exception handler stack. */
|
||||
"ldr %0, [%2, #4]\n\t" /* The entry address */
|
||||
@@ -69,8 +69,8 @@ set_led (int on)
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = STRING_DESCRIPTOR */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
static const uint8_t board_name_string[] = BOARD_NAME;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#define STM32F0_USE_VECTOR_ON_RAM
|
||||
#include "mcu/cortex-m.h"
|
||||
#include "mcu/clk_gpio_init-stm32.c"
|
||||
#include "mcu/clk_gpio_init-stm32f.c"
|
||||
|
||||
|
||||
static void
|
||||
@@ -69,27 +69,13 @@ static void wait (int count)
|
||||
static void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
usb_cable_config (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
if ((RCC->APB1ENR & RCC_APB1ENR_USBEN)
|
||||
&& (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0)
|
||||
/* Make sure the device is disconnected, even after core reset. */
|
||||
{
|
||||
usb_lld_sys_shutdown ();
|
||||
/* Disconnect requires SE0 (>= 2.5uS). */
|
||||
wait (300);
|
||||
}
|
||||
|
||||
usb_cable_config (1);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
}
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
@@ -340,13 +326,13 @@ reset (void)
|
||||
#else
|
||||
extern const uint32_t FT0[256], FT1[256], FT2[256];
|
||||
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
|
||||
"ldr r0, 1f\n\t" /* r0 = SCR */
|
||||
"ldr r0, 1f\n\t" /* r0 = SCB start */
|
||||
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
|
||||
"mov r2, #0x1000\n\t"
|
||||
"add r1, r1, r2\n\t"
|
||||
"sub r2, r2, #1\n\t"
|
||||
"bic r1, r1, r2\n\t"
|
||||
"str r1, [r0, #8]\n\t" /* Set SCR->VCR */
|
||||
"str r1, [r0, #8]\n\t" /* Set SCB->VTOR */
|
||||
"ldr r0, [r1], #4\n\t"
|
||||
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
|
||||
"ldr r0, [r1]\n\t" /* Reset handler. */
|
||||
@@ -386,8 +372,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
const uint32_t __attribute__((section(".sys.board_id")))
|
||||
|
||||
@@ -18,9 +18,18 @@
|
||||
#include <stdlib.h>
|
||||
#include "board.h"
|
||||
|
||||
#include "mcu/clk_gpio_init-stm32.c"
|
||||
#include "mcu/clk_gpio_init-stm32f.c"
|
||||
|
||||
|
||||
/*
|
||||
* When a board supports USB self-powered configuration, there is a
|
||||
* control to enable external pull-up 1K5 resistor. The voltage
|
||||
* source on the pull-up resistor should be only supplied when VBUS
|
||||
* from the cable is available. This routine is for such a board.
|
||||
*
|
||||
* For a board for USB bus-powered configuration, it is common that
|
||||
* there is no such control, but 1K5 resistor is fixed to +3V3.
|
||||
*/
|
||||
static void
|
||||
usb_cable_config (int enable)
|
||||
{
|
||||
@@ -55,39 +64,16 @@ set_led (int on)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wait (int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
usb_cable_config (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
if ((RCC->APB1ENR & RCC_APB1ENR_USBEN)
|
||||
&& (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0)
|
||||
/* Make sure the device is disconnected, even after core reset. */
|
||||
{
|
||||
usb_lld_sys_shutdown ();
|
||||
/* Disconnect requires SE0 (>= 2.5uS). */
|
||||
wait (5*MHZ);
|
||||
}
|
||||
|
||||
usb_cable_config (1);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
}
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
@@ -321,13 +307,13 @@ reset (void)
|
||||
* So, we take the address from PC.
|
||||
*/
|
||||
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
|
||||
"ldr r0, 1f\n\t" /* r0 = SCR */
|
||||
"ldr r0, 1f\n\t" /* r0 = SCB start */
|
||||
"mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */
|
||||
"mov r2, #0x1000\n\t"
|
||||
"add r1, r1, r2\n\t"
|
||||
"sub r2, r2, #1\n\t"
|
||||
"bic r1, r1, r2\n\t"
|
||||
"str r1, [r0, #8]\n\t" /* Set SCR->VCR */
|
||||
"str r1, [r0, #8]\n\t" /* Set SCB->VTOR */
|
||||
"ldr r0, [r1], #4\n\t"
|
||||
"msr MSP, r0\n\t" /* Main (exception handler) stack. */
|
||||
"ldr r0, [r1]\n\t" /* Reset handler. */
|
||||
@@ -367,8 +353,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
const uint32_t __attribute__((section(".sys.board_id")))
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define BOARD_ID_ST_DONGLE 0x2cd4e471
|
||||
#define BOARD_ID_ST_NUCLEO_F103 0x9b87c16d
|
||||
#define BOARD_ID_NITROKEY_START 0xad1e7ebd
|
||||
#define BOARD_ID_GNUKEY_DS 0x67ee65a3
|
||||
|
||||
extern const uint8_t sys_version[8];
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
|
||||
134
mcu/sys-stm32l4.c
Normal file
134
mcu/sys-stm32l4.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* sys-stm32l432.c - system routines for STM32L432.
|
||||
*
|
||||
* Copyright (C) 2019 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*
|
||||
* We put some system routines (which is useful for any program) here.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <mcu/cortex-m.h>
|
||||
#include "board.h"
|
||||
|
||||
#include "mcu/clk_gpio_init-stm32l.c"
|
||||
|
||||
void
|
||||
set_led (int on)
|
||||
{
|
||||
#if defined(GPIO_LED_CLEAR_TO_EMIT)
|
||||
if (on)
|
||||
GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
|
||||
else
|
||||
GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
|
||||
#else
|
||||
if (on)
|
||||
GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT);
|
||||
else
|
||||
GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nvic_system_reset (void)
|
||||
{
|
||||
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SCB_AIRCR_SYSRESETREQ);
|
||||
asm volatile ("dsb");
|
||||
for (;;);
|
||||
}
|
||||
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
const uint32_t __attribute__((section(".sys.board_id")))
|
||||
sys_board_id = BOARD_ID;
|
||||
|
||||
const uint8_t __attribute__((section(".sys.board_name")))
|
||||
sys_board_name[] = BOARD_NAME;
|
||||
#endif
|
||||
|
||||
/* Not yet implemented, API should be reconsidered */
|
||||
|
||||
void
|
||||
flash_unlock (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#define intr_disable() asm volatile ("cpsid i" : : : "memory")
|
||||
#define intr_enable() asm volatile ("cpsie i" : : : "memory")
|
||||
|
||||
|
||||
int
|
||||
flash_wait_for_last_operation (uint32_t timeout)
|
||||
{
|
||||
(void)timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_program_halfword (uintptr_t addr, uint16_t data)
|
||||
{
|
||||
(void)addr;
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_erase_page (uintptr_t addr)
|
||||
{
|
||||
(void)addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_check_blank (const uint8_t *p_start, size_t size)
|
||||
{
|
||||
(void)p_start;
|
||||
(void)size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
(void)dst_addr;
|
||||
(void)src;
|
||||
(void)len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
flash_protect (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __attribute__((naked))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
(void)entry;
|
||||
}
|
||||
33
mcu/sys-stm32l4.h
Normal file
33
mcu/sys-stm32l4.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#define BOARD_ID_ST_NUCLEO_L432 0x3a8d5116
|
||||
|
||||
extern const uint8_t sys_version[8];
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
extern const uint32_t sys_board_id;
|
||||
extern const uint8_t sys_board_name[];
|
||||
# define SYS_BOARD_ID sys_board_id
|
||||
#else
|
||||
# define SYS_BOARD_ID BOARD_ID
|
||||
#endif
|
||||
|
||||
/* XXX: unique_device_id */
|
||||
|
||||
void set_led (int on);
|
||||
|
||||
uintptr_t flash_init (const char *f_name);
|
||||
void flash_unlock (void);
|
||||
int flash_program_halfword (uintptr_t addr, uint16_t data);
|
||||
int flash_erase_page (uintptr_t addr);
|
||||
int flash_check_blank (const uint8_t *p_start, size_t size);
|
||||
int flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len);
|
||||
int flash_protect (void);
|
||||
void __attribute__((noreturn))
|
||||
flash_erase_all_and_exec (void (*entry)(void));
|
||||
|
||||
void usb_lld_sys_init (void);
|
||||
void usb_lld_sys_shutdown (void);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
nvic_system_reset (void);
|
||||
|
||||
void clock_init (void);
|
||||
void gpio_init (void);
|
||||
@@ -22,7 +22,7 @@
|
||||
* 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.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -956,7 +956,7 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len < USB_MAX_PACKET_SIZE)
|
||||
if (data_p->len <= USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
|
||||
917
mcu/usb-st-common.c
Normal file
917
mcu/usb-st-common.c
Normal file
@@ -0,0 +1,917 @@
|
||||
/*
|
||||
* usb-st-common.c - USB driver common part for STM chips.
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
struct USB {
|
||||
volatile uint32_t EPR[8];
|
||||
volatile uint32_t reserved[8];
|
||||
volatile uint16_t CNTR; /* Control register */
|
||||
volatile uint16_t reserved0;
|
||||
volatile uint16_t ISTR; /* Interrupt status register */
|
||||
volatile uint16_t reserved1;
|
||||
volatile uint16_t FNR; /* Frame number register */
|
||||
volatile uint16_t reserved2;
|
||||
volatile uint16_t DADDR; /* Device address register */
|
||||
volatile uint16_t reserved3;
|
||||
volatile uint16_t BTABLE; /* Buffer Table address register */
|
||||
volatile uint16_t reserved4;
|
||||
};
|
||||
|
||||
static struct USB *const USB = (struct USB *)REG_BASE;
|
||||
|
||||
#define ISTR_CTR (0x8000) /* Correct TRansfer (read-only bit) */
|
||||
#define ISTR_OVR (0x4000) /* OVeR/underrun (clear-only bit) */
|
||||
#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */
|
||||
#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */
|
||||
#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */
|
||||
#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */
|
||||
#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */
|
||||
#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */
|
||||
|
||||
#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */
|
||||
#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */
|
||||
|
||||
#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */
|
||||
#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */
|
||||
|
||||
#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */
|
||||
#define CNTR_OVRM (0x4000) /* OVeR/underrun Mask */
|
||||
#define CNTR_ERRM (0x2000) /* ERRor Mask */
|
||||
#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */
|
||||
#define CNTR_SUSPM (0x0800) /* SUSPend Mask */
|
||||
#define CNTR_RESETM (0x0400) /* RESET Mask */
|
||||
#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */
|
||||
#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */
|
||||
|
||||
#define CNTR_RESUME (0x0010) /* RESUME request */
|
||||
#define CNTR_FSUSP (0x0008) /* Force SUSPend */
|
||||
#define CNTR_LPMODE (0x0004) /* Low-power MODE */
|
||||
#define CNTR_PDWN (0x0002) /* Power DoWN */
|
||||
#define CNTR_FRES (0x0001) /* Force USB RESet */
|
||||
|
||||
#define DADDR_EF (0x80)
|
||||
#define DADDR_ADD (0x7F)
|
||||
|
||||
#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX (clear-only) */
|
||||
#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX (toggle) */
|
||||
#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field (toggle) */
|
||||
#define EP_SETUP (0x0800) /* EndPoint SETUP (read-only) */
|
||||
#define EP_T_FIELD (0x0600) /* EndPoint TYPE */
|
||||
#define EP_KIND (0x0100) /* EndPoint KIND */
|
||||
#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX (clear-only) */
|
||||
#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX (toggle) */
|
||||
#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field (toggle) */
|
||||
#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */
|
||||
|
||||
#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
|
||||
|
||||
/* STAT_TX[1:0] STATus for TX transfer */
|
||||
#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */
|
||||
#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */
|
||||
#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */
|
||||
#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */
|
||||
#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */
|
||||
#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */
|
||||
|
||||
/* STAT_RX[1:0] STATus for RX transfer */
|
||||
#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */
|
||||
#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */
|
||||
#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */
|
||||
#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */
|
||||
#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */
|
||||
#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */
|
||||
|
||||
static int handle_setup0 (struct usb_dev *dev);
|
||||
static int usb_handle_transfer (struct usb_dev *dev, uint16_t istr_value);
|
||||
|
||||
/* Clear CTR_RX bit by writing the 0-bit, keeping rw bits and toggle bits. */
|
||||
static void
|
||||
ep_clear_ctr_rx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num] & ~EP_CTR_RX & EPREG_MASK;
|
||||
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
/* Clear CTR_TX bit by writing the 0-bit, keeping rw bits and toggle bits. */
|
||||
static void
|
||||
ep_clear_ctr_tx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num] & ~EP_CTR_TX & EPREG_MASK;
|
||||
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_set_rxtx_status (uint8_t ep_num, uint16_t st_rx, uint16_t st_tx)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
value &= (EPREG_MASK|EPRX_STAT|EPTX_STAT);
|
||||
value ^= (EPRX_DTOG1 & st_rx);
|
||||
value ^= (EPRX_DTOG2 & st_rx);
|
||||
value ^= (EPTX_DTOG1 & st_tx);
|
||||
value ^= (EPTX_DTOG2 & st_tx);
|
||||
value |= EP_CTR_RX | EP_CTR_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_set_rx_status (uint8_t ep_num, uint16_t st_rx)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
value &= (EPREG_MASK|EPRX_STAT);
|
||||
value ^= (EPRX_DTOG1 & st_rx);
|
||||
value ^= (EPRX_DTOG2 & st_rx);
|
||||
value |= EP_CTR_RX | EP_CTR_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ep_get_rx_status (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
return value & EPRX_STAT;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_set_tx_status (uint8_t ep_num, uint16_t st_tx)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
value &= (EPREG_MASK|EPTX_STAT);
|
||||
value ^= (EPTX_DTOG1 & st_tx);
|
||||
value ^= (EPTX_DTOG2 & st_tx);
|
||||
value |= EP_CTR_RX | EP_CTR_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ep_get_tx_status (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
return value & EPTX_STAT;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_clear_dtog_rx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
if ((value & EP_DTOG_RX))
|
||||
{
|
||||
value &= EPREG_MASK;
|
||||
value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_RX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ep_clear_dtog_tx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
if ((value & EP_DTOG_TX))
|
||||
{
|
||||
value &= EPREG_MASK;
|
||||
value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_ctrl_error (struct usb_dev *dev)
|
||||
{
|
||||
dev->state = STALLED;
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
|
||||
}
|
||||
|
||||
int
|
||||
usb_lld_ctrl_ack (struct usb_dev *dev)
|
||||
{
|
||||
dev->state = WAIT_STATUS_IN;
|
||||
epbuf_set_tx_count (ENDP0, 0);
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_NAK, EP_TX_VALID);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_init (struct usb_dev *dev, uint8_t feature)
|
||||
{
|
||||
usb_lld_init_chip_specific ();
|
||||
|
||||
dev->configuration = 0;
|
||||
dev->feature = feature;
|
||||
dev->state = WAIT_SETUP;
|
||||
|
||||
/* Reset USB */
|
||||
USB->CNTR = CNTR_FRES;
|
||||
USB->CNTR = 0;
|
||||
|
||||
/* Clear Interrupt Status Register, and enable interrupt for USB */
|
||||
USB->ISTR = 0;
|
||||
USB->BTABLE = 0;
|
||||
USB->CNTR = (CNTR_CTRM | CNTR_OVRM | CNTR_ERRM
|
||||
| CNTR_WKUPM | CNTR_SUSPM | CNTR_RESETM);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_prepare_shutdown (void)
|
||||
{
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = 0;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_shutdown (void)
|
||||
{
|
||||
USB->CNTR = CNTR_PDWN;
|
||||
usb_lld_shutdown_chip_specific ();
|
||||
}
|
||||
|
||||
#define USB_MAKE_EV(event) (event<<24)
|
||||
#define USB_MAKE_TXRX(ep_num,txrx,len) ((txrx? (1<<23):0)|(ep_num<<16)|len)
|
||||
|
||||
int
|
||||
usb_lld_event_handler (struct usb_dev *dev)
|
||||
{
|
||||
uint16_t istr_value = USB->ISTR;
|
||||
|
||||
if ((istr_value & ISTR_RESET))
|
||||
{
|
||||
USB->ISTR = ~ISTR_RESET; /* clear RESET bit */
|
||||
return USB_MAKE_EV (USB_EVENT_DEVICE_RESET);
|
||||
}
|
||||
else if ((istr_value & ISTR_WKUP))
|
||||
{
|
||||
USB->CNTR &= ~CNTR_FSUSP;
|
||||
USB->ISTR = ~ISTR_WKUP; /* clear WaKe UP bit */
|
||||
return USB_MAKE_EV (USB_EVENT_DEVICE_WAKEUP);
|
||||
}
|
||||
else if ((istr_value & ISTR_SUSP))
|
||||
{
|
||||
USB->CNTR |= CNTR_FSUSP;
|
||||
USB->ISTR = ~ISTR_SUSP; /* clear SUSPend bit */
|
||||
USB->CNTR |= CNTR_LPMODE;
|
||||
return USB_MAKE_EV (USB_EVENT_DEVICE_SUSPEND);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((istr_value & ISTR_OVR))
|
||||
USB->ISTR = ~ISTR_OVR; /* clear OVeR/underrun bit */
|
||||
|
||||
if ((istr_value & ISTR_ERR))
|
||||
USB->ISTR = ~ISTR_ERR; /* clear ERRor bit */
|
||||
|
||||
if ((istr_value & ISTR_CTR))
|
||||
return usb_handle_transfer (dev, istr_value);
|
||||
}
|
||||
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_datastage_out (struct usb_dev *dev)
|
||||
{
|
||||
if (dev->ctrl_data.addr && dev->ctrl_data.len)
|
||||
{
|
||||
uint16_t len = epbuf_get_rx_count (ENDP0);
|
||||
|
||||
if (len > dev->ctrl_data.len)
|
||||
len = dev->ctrl_data.len;
|
||||
|
||||
usb_lld_from_pmabuf (dev->ctrl_data.addr, epbuf_get_rx_addr (ENDP0), len);
|
||||
dev->ctrl_data.len -= len;
|
||||
dev->ctrl_data.addr += len;
|
||||
}
|
||||
|
||||
if (dev->ctrl_data.len == 0)
|
||||
{
|
||||
dev->state = WAIT_STATUS_IN;
|
||||
epbuf_set_tx_count (ENDP0, 0);
|
||||
ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->state = OUT_DATA;
|
||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_datastage_in (struct usb_dev *dev)
|
||||
{
|
||||
uint32_t len = USB_MAX_PACKET_SIZE;
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
|
||||
if ((data_p->len == 0) && (dev->state == LAST_IN_DATA))
|
||||
{
|
||||
if (data_p->require_zlp)
|
||||
{
|
||||
data_p->require_zlp = 0;
|
||||
|
||||
/* No more data to send. Send empty packet */
|
||||
epbuf_set_tx_count (ENDP0, 0);
|
||||
ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more data to send, proceed to receive OUT acknowledge. */
|
||||
dev->state = WAIT_STATUS_OUT;
|
||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dev->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA;
|
||||
|
||||
if (len > data_p->len)
|
||||
len = data_p->len;
|
||||
|
||||
usb_lld_to_pmabuf (data_p->addr, epbuf_get_tx_addr (ENDP0), len);
|
||||
data_p->len -= len;
|
||||
data_p->addr += len;
|
||||
epbuf_set_tx_count (ENDP0, len);
|
||||
ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
|
||||
typedef int (*HANDLER) (struct usb_dev *dev);
|
||||
|
||||
static int
|
||||
std_none (struct usb_dev *dev)
|
||||
{
|
||||
(void)dev;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_status (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = (arg->type & RECIPIENT);
|
||||
uint16_t status_info = 0;
|
||||
|
||||
if (arg->value != 0 || arg->len != 2 || (arg->index >> 8) != 0
|
||||
|| USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (arg->index == 0)
|
||||
{
|
||||
/* Get Device Status */
|
||||
uint8_t feature = dev->feature;
|
||||
|
||||
/* Remote Wakeup enabled */
|
||||
if ((feature & (1 << 5)))
|
||||
status_info |= 2;
|
||||
else
|
||||
status_info &= ~2;
|
||||
|
||||
/* Bus-powered */
|
||||
if ((feature & (1 << 6)))
|
||||
status_info |= 1;
|
||||
else /* Self-powered */
|
||||
status_info &= ~1;
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
}
|
||||
else if (rcp == INTERFACE_RECIPIENT)
|
||||
{
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
return USB_EVENT_GET_STATUS_INTERFACE;
|
||||
}
|
||||
else if (rcp == ENDPOINT_RECIPIENT)
|
||||
{
|
||||
uint8_t endpoint = (arg->index & 0x0f);
|
||||
uint16_t status;
|
||||
|
||||
if ((arg->index & 0x70) || endpoint == ENDP0)
|
||||
return -1;
|
||||
|
||||
if ((arg->index & 0x80))
|
||||
{
|
||||
status = ep_get_tx_status (endpoint);
|
||||
if (status == 0) /* Disabled */
|
||||
return -1;
|
||||
else if (status == EP_TX_STALL)
|
||||
status_info |= 1; /* IN Endpoint stalled */
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ep_get_rx_status (endpoint);
|
||||
if (status == 0) /* Disabled */
|
||||
return -1;
|
||||
else if (status == EP_RX_STALL)
|
||||
status_info |= 1; /* OUT Endpoint stalled */
|
||||
}
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_clear_feature (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (arg->len != 0 || arg->index != 0)
|
||||
return -1;
|
||||
|
||||
if (arg->value == FEATURE_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->feature &= ~(1 << 5);
|
||||
return USB_EVENT_CLEAR_FEATURE_DEVICE;
|
||||
}
|
||||
}
|
||||
else if (rcp == ENDPOINT_RECIPIENT)
|
||||
{
|
||||
uint8_t endpoint = (arg->index & 0x0f);
|
||||
uint16_t status;
|
||||
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
if (arg->len != 0 || (arg->index >> 8) != 0
|
||||
|| arg->value != FEATURE_ENDPOINT_HALT || endpoint == ENDP0)
|
||||
return -1;
|
||||
|
||||
if ((arg->index & 0x80))
|
||||
status = ep_get_tx_status (endpoint);
|
||||
else
|
||||
status = ep_get_rx_status (endpoint);
|
||||
|
||||
if (status == 0) /* It's disabled endpoint. */
|
||||
return -1;
|
||||
|
||||
if (arg->index & 0x80) /* IN endpoint */
|
||||
ep_clear_dtog_tx (endpoint);
|
||||
else /* OUT endpoint */
|
||||
ep_clear_dtog_rx (endpoint);
|
||||
|
||||
return USB_EVENT_CLEAR_FEATURE_ENDPOINT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_feature (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (arg->len != 0 || arg->index != 0)
|
||||
return -1;
|
||||
|
||||
if (arg->value == FEATURE_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->feature |= 1 << 5;
|
||||
return USB_EVENT_SET_FEATURE_DEVICE;
|
||||
}
|
||||
}
|
||||
else if (rcp == ENDPOINT_RECIPIENT)
|
||||
{
|
||||
uint8_t endpoint = (arg->index & 0x0f);
|
||||
uint32_t status;
|
||||
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
if (arg->len != 0 || (arg->index >> 8) != 0
|
||||
|| arg->value != FEATURE_ENDPOINT_HALT || endpoint == ENDP0)
|
||||
return -1;
|
||||
|
||||
if ((arg->index & 0x80))
|
||||
status = ep_get_tx_status (endpoint);
|
||||
else
|
||||
status = ep_get_rx_status (endpoint);
|
||||
|
||||
if (status == 0) /* It's disabled endpoint. */
|
||||
return -1;
|
||||
|
||||
if (arg->index & 0x80) /* IN endpoint */
|
||||
ep_set_tx_status (endpoint, EP_TX_STALL);
|
||||
else /* OUT endpoint */
|
||||
ep_set_rx_status (endpoint, EP_RX_STALL);
|
||||
|
||||
return USB_EVENT_SET_FEATURE_ENDPOINT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_address (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT && arg->len == 0 && arg->value <= 127
|
||||
&& arg->index == 0 && dev->configuration == 0)
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_descriptor (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
return USB_EVENT_GET_DESCRIPTOR;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_configuration (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (arg->value != 0 || arg->index != 0 || arg->len != 1)
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
return usb_lld_ctrl_send (dev, &dev->configuration, 1);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_configuration (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (arg->index != 0 || arg->len != 0)
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
return USB_EVENT_SET_CONFIGURATION;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_interface (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (arg->value != 0 || (arg->index >> 8) != 0 || arg->len != 1)
|
||||
return -1;
|
||||
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
if (rcp == INTERFACE_RECIPIENT)
|
||||
return USB_EVENT_GET_INTERFACE;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_interface (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type) || rcp != INTERFACE_RECIPIENT
|
||||
|| arg->len != 0 || (arg->index >> 8) != 0
|
||||
|| (arg->value >> 8) != 0 || dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
return USB_EVENT_SET_INTERFACE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
handle_in0 (struct usb_dev *dev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (dev->state == IN_DATA || dev->state == LAST_IN_DATA)
|
||||
handle_datastage_in (dev);
|
||||
else if (dev->state == WAIT_STATUS_IN)
|
||||
{
|
||||
dev->state = WAIT_SETUP;
|
||||
|
||||
if ((dev->dev_req.request == SET_ADDRESS) &&
|
||||
((dev->dev_req.type & (REQUEST_TYPE | RECIPIENT))
|
||||
== (STANDARD_REQUEST | DEVICE_RECIPIENT)))
|
||||
{
|
||||
USB->DADDR = (DADDR_EF | dev->dev_req.value);
|
||||
r = USB_EVENT_DEVICE_ADDRESSED;
|
||||
}
|
||||
else
|
||||
r = USB_EVENT_CTRL_WRITE_FINISH;
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->state = STALLED;
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_out0 (struct usb_dev *dev)
|
||||
{
|
||||
if (dev->state == OUT_DATA)
|
||||
/* Usual case. */
|
||||
handle_datastage_out (dev);
|
||||
else if (dev->state == WAIT_STATUS_OUT)
|
||||
/*
|
||||
* Control READ transfer finished by ZLP.
|
||||
* Leave ENDP0 status RX_NAK, TX_NAK.
|
||||
*/
|
||||
dev->state = WAIT_SETUP;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* dev->state == IN_DATA || dev->state == LAST_IN_DATA
|
||||
* (Host aborts the transfer before finish)
|
||||
* Or else, unexpected state.
|
||||
* STALL the endpoint, until we receive the next SETUP token.
|
||||
*/
|
||||
dev->state = STALLED;
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_handle_transfer (struct usb_dev *dev, uint16_t istr_value)
|
||||
{
|
||||
uint16_t ep_value = 0;
|
||||
uint8_t ep_num = (istr_value & ISTR_EP_ID);
|
||||
|
||||
ep_value = USB->EPR[ep_num];
|
||||
|
||||
if (ep_num == 0)
|
||||
{
|
||||
if ((ep_value & EP_CTR_TX))
|
||||
{
|
||||
ep_clear_ctr_tx (ep_num);
|
||||
return USB_MAKE_EV (handle_in0 (dev));
|
||||
}
|
||||
|
||||
if ((ep_value & EP_CTR_RX))
|
||||
{
|
||||
ep_clear_ctr_rx (ep_num);
|
||||
|
||||
if ((ep_value & EP_SETUP))
|
||||
return USB_MAKE_EV (handle_setup0 (dev));
|
||||
else
|
||||
{
|
||||
handle_out0 (dev);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
if ((ep_value & EP_CTR_RX))
|
||||
{
|
||||
len = epbuf_get_rx_count (ep_num);
|
||||
ep_clear_ctr_rx (ep_num);
|
||||
return USB_MAKE_TXRX (ep_num, 0, len);
|
||||
}
|
||||
|
||||
if ((ep_value & EP_CTR_TX))
|
||||
{
|
||||
len = epbuf_get_tx_count (ep_num);
|
||||
ep_clear_ctr_tx (ep_num);
|
||||
return USB_MAKE_TXRX (ep_num, 1, len);
|
||||
}
|
||||
}
|
||||
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_reset (struct usb_dev *dev, uint8_t feature)
|
||||
{
|
||||
usb_lld_set_configuration (dev, 0);
|
||||
dev->feature = feature;
|
||||
USB->DADDR = DADDR_EF; /* Initially, device responds to address 0 */
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len)
|
||||
{
|
||||
usb_lld_to_pmabuf (src, epbuf_get_tx_addr (ep_num) + offset, len);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_write (uint8_t ep_num, const void *buf, size_t len)
|
||||
{
|
||||
usb_lld_to_pmabuf (buf, epbuf_get_tx_addr (ep_num), len);
|
||||
epbuf_set_tx_count (ep_num, len);
|
||||
ep_set_tx_status (ep_num, EP_TX_VALID);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len)
|
||||
{
|
||||
usb_lld_from_pmabuf (dst, epbuf_get_rx_addr (ep_num) + offset, len);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_tx_enable (int ep_num, size_t len)
|
||||
{
|
||||
epbuf_set_tx_count (ep_num, len);
|
||||
ep_set_tx_status (ep_num, EP_TX_VALID);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_stall_tx (int ep_num)
|
||||
{
|
||||
ep_set_tx_status (ep_num, EP_TX_STALL);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_stall_rx (int ep_num)
|
||||
{
|
||||
ep_set_rx_status (ep_num, EP_RX_STALL);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_rx_enable (int ep_num)
|
||||
{
|
||||
ep_set_rx_status (ep_num, EP_RX_VALID);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
|
||||
int ep_rx_addr, int ep_tx_addr,
|
||||
int ep_rx_buf_size)
|
||||
{
|
||||
uint16_t epreg_value = USB->EPR[ep_num];
|
||||
uint16_t ep_rxtx_status = 0; /* Both disabled */
|
||||
|
||||
/* Clear: Write 1 if 1: EP_DTOG_RX, EP_DTOG_TX */
|
||||
/* Set: Write: EP_T_FIELD, EP_KIND, EPADDR_FIELD */
|
||||
/* Set: Toggle: EPRX_STAT, EPTX_STAT */
|
||||
epreg_value &= (EPRX_STAT | EP_SETUP | EPTX_STAT | EP_DTOG_RX | EP_DTOG_TX);
|
||||
#if USB_KEEP_CORRECT_TRANSFER_FLAGS
|
||||
/* Keep: Write 1: EP_CTR_RX, EP_CTR_TX */
|
||||
epreg_value |= (EP_CTR_RX|EP_CTR_TX);
|
||||
#else
|
||||
/* Clear: Write 0: EP_CTR_RX, EP_CTR_TX */
|
||||
#endif
|
||||
epreg_value |= ep_type;
|
||||
epreg_value |= ep_kind;
|
||||
epreg_value |= ep_num;
|
||||
|
||||
if (ep_rx_addr)
|
||||
{
|
||||
ep_rxtx_status |= EP_RX_NAK;
|
||||
epbuf_set_rx_addr (ep_num, ep_rx_addr);
|
||||
epbuf_set_rx_buf_size (ep_num, ep_rx_buf_size);
|
||||
}
|
||||
|
||||
if (ep_tx_addr)
|
||||
{
|
||||
ep_rxtx_status |= EP_TX_NAK;
|
||||
epbuf_set_tx_addr (ep_num, ep_tx_addr);
|
||||
}
|
||||
|
||||
epreg_value ^= (EPRX_DTOG1 & ep_rxtx_status);
|
||||
epreg_value ^= (EPRX_DTOG2 & ep_rxtx_status);
|
||||
epreg_value ^= (EPTX_DTOG1 & ep_rxtx_status);
|
||||
epreg_value ^= (EPTX_DTOG2 & ep_rxtx_status);
|
||||
|
||||
USB->EPR[ep_num] = epreg_value;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_set_configuration (struct usb_dev *dev, uint8_t config)
|
||||
{
|
||||
dev->configuration = config;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
usb_lld_current_configuration (struct usb_dev *dev)
|
||||
{
|
||||
return dev->configuration;
|
||||
}
|
||||
|
||||
int
|
||||
usb_lld_ctrl_recv (struct usb_dev *dev, void *p, size_t len)
|
||||
{
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
data_p->addr = p;
|
||||
data_p->len = len;
|
||||
dev->state = OUT_DATA;
|
||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BUF: Pointer to data memory. Data memory should not be allocated
|
||||
* on stack when BUFLEN > USB_MAX_PACKET_SIZE.
|
||||
*
|
||||
* BUFLEN: size of the data.
|
||||
*/
|
||||
int
|
||||
usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
{
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
uint32_t len_asked = dev->dev_req.len;
|
||||
uint32_t len;
|
||||
|
||||
data_p->addr = (void *)buf;
|
||||
data_p->len = buflen;
|
||||
|
||||
/* Restrict the data length to be the one which host asks for. */
|
||||
if (data_p->len >= len_asked)
|
||||
data_p->len = len_asked;
|
||||
/* ZLP is only required when host doesn't expect the end of packets. */
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len <= USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = USB_MAX_PACKET_SIZE;
|
||||
dev->state = IN_DATA;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
usb_lld_to_pmabuf (data_p->addr, epbuf_get_tx_addr (ENDP0), len);
|
||||
data_p->len -= len;
|
||||
data_p->addr += len;
|
||||
}
|
||||
|
||||
epbuf_set_tx_count (ENDP0, len);
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_NAK, EP_TX_VALID);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
294
mcu/usb-stm32l4.c
Normal file
294
mcu/usb-stm32l4.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* usb-stm32l4.c - USB driver for STM32L4
|
||||
*
|
||||
* Copyright (C) 2019 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
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <mcu/stm32l.h>
|
||||
#include "usb_lld.h"
|
||||
#include "usb_lld_driver.h"
|
||||
|
||||
#define REG_BASE (0x40006800UL) /* USB Peripheral Registers base address */
|
||||
#define PMA_ADDR (0x40006C00UL) /* USB Packet Memory Area base address */
|
||||
|
||||
static void
|
||||
epbuf_set_tx_addr (uint8_t ep_num, uint16_t addr)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0));
|
||||
|
||||
*reg_p = addr;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_tx_addr (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0));
|
||||
|
||||
return *reg_p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
epbuf_set_tx_count (uint8_t ep_num, uint16_t size)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2));
|
||||
|
||||
*reg_p = size;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_tx_count (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2));
|
||||
|
||||
return *reg_p & 0x03ff;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
epbuf_set_rx_addr (uint8_t ep_num, uint16_t addr)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4));
|
||||
|
||||
*reg_p = addr;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_rx_addr (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4));
|
||||
|
||||
return *reg_p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
epbuf_set_rx_buf_size (uint8_t ep_num, uint16_t size)
|
||||
{ /* Assume size is even */
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6));
|
||||
uint16_t value;
|
||||
|
||||
if (size <= 62)
|
||||
value = (size & 0x3e) << 9;
|
||||
else
|
||||
value = 0x8000 | (((size >> 5) - 1) << 10);
|
||||
|
||||
*reg_p = value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_rx_count (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6));
|
||||
|
||||
return *reg_p & 0x03ff;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_lld_shutdown_chip_specific (void)
|
||||
{
|
||||
USB_STM32L4->BCDR &= 0x7fff; /* DP disable */
|
||||
RCC->APB1ENR1 &= ~(RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
RCC->APB1RSTR1 |= (RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
}
|
||||
|
||||
static void
|
||||
wait (int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
}
|
||||
|
||||
struct CRS
|
||||
{
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t ICR;
|
||||
};
|
||||
static struct CRS *const CRS = ((struct CRS *)(APB1PERIPH_BASE + 0x6000));
|
||||
|
||||
|
||||
static void
|
||||
usb_lld_init_chip_specific (void)
|
||||
{
|
||||
PWR->CR2 |= (1 << 10); /* USB supply valid */
|
||||
|
||||
if ((RCC->APB1ENR1 & RCC_APB1_1_USB)
|
||||
&& (RCC->APB1RSTR1 & RCC_APB1_1_USB) == 0)
|
||||
/* Make sure the device is disconnected, even after core reset. */
|
||||
{
|
||||
usb_lld_shutdown_chip_specific ();
|
||||
/* Disconnect requires SE0 (>= 2.5uS). */
|
||||
wait (5*MHZ);
|
||||
}
|
||||
|
||||
/* Enable USB clock and CRC clock */
|
||||
RCC->APB1ENR1 |= (RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
RCC->APB1RSTR1 = (RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
RCC->APB1RSTR1 = 0;
|
||||
|
||||
USB_STM32L4->BCDR |= 0x8000; /* DP enable */
|
||||
|
||||
/* Configure CRS (clock recovery system) for HSI48 clock */
|
||||
CRS->CFGR = ( (0x00 << 31) | /* Polarity rising */
|
||||
(0x02 << 28) | /* USB SOF for Sync */
|
||||
(0x00 << 24) | /* divider = 1 */
|
||||
(0x22 << 16) | /* Frequency error limit */
|
||||
0xBB7F ); /* Reload value */
|
||||
|
||||
CRS->CR |= ( (1 << 6) | /* Automatic trimming enable */
|
||||
(1 << 5) ); /* Frequency error counter enable */
|
||||
}
|
||||
|
||||
#include "usb-st-common.c"
|
||||
|
||||
static int
|
||||
handle_setup0 (struct usb_dev *dev)
|
||||
{
|
||||
const uint16_t *pw;
|
||||
uint16_t w;
|
||||
uint8_t req_no;
|
||||
HANDLER handler;
|
||||
|
||||
pw = (uint16_t *)(PMA_ADDR + epbuf_get_rx_addr (ENDP0));
|
||||
w = *pw++;
|
||||
|
||||
dev->dev_req.type = (w & 0xff);
|
||||
dev->dev_req.request = req_no = (w >> 8);
|
||||
dev->dev_req.value = *pw++;
|
||||
dev->dev_req.index = *pw++;
|
||||
dev->dev_req.len = *pw;
|
||||
|
||||
dev->ctrl_data.addr = NULL;
|
||||
dev->ctrl_data.len = 0;
|
||||
dev->ctrl_data.require_zlp = 0;
|
||||
|
||||
if ((dev->dev_req.type & REQUEST_TYPE) == STANDARD_REQUEST)
|
||||
{
|
||||
int r;
|
||||
|
||||
switch (req_no)
|
||||
{
|
||||
case 0: handler = std_get_status; break;
|
||||
case 1: handler = std_clear_feature; break;
|
||||
case 3: handler = std_set_feature; break;
|
||||
case 5: handler = std_set_address; break;
|
||||
case 6: handler = std_get_descriptor; break;
|
||||
case 8: handler = std_get_configuration; break;
|
||||
case 9: handler = std_set_configuration; break;
|
||||
case 10: handler = std_get_interface; break;
|
||||
case 11: handler = std_set_interface; break;
|
||||
default: handler = std_none; break;
|
||||
}
|
||||
|
||||
if ((r = (*handler) (dev)) < 0)
|
||||
{
|
||||
usb_lld_ctrl_error (dev);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
else
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return USB_EVENT_CTRL_REQUEST;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
uint16_t *p;
|
||||
uint16_t w;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
if ((addr & 1))
|
||||
{
|
||||
p = (uint16_t *)(PMA_ADDR + (addr - 1));
|
||||
w = *p;
|
||||
w = (w & 0xff) | (*s++) << 8;
|
||||
*p++ = w;
|
||||
n--;
|
||||
}
|
||||
else
|
||||
p = (uint16_t *)(PMA_ADDR + addr);
|
||||
|
||||
while (n >= 2)
|
||||
{
|
||||
w = *s++;
|
||||
w |= (*s++) << 8;
|
||||
*p++ = w;
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
w = *s;
|
||||
*p = w;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n)
|
||||
{
|
||||
uint8_t *d = (uint8_t *)dst;
|
||||
uint16_t *p;
|
||||
uint16_t w;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
if ((addr & 1))
|
||||
{
|
||||
p = (uint16_t *)(PMA_ADDR + (addr - 1));
|
||||
w = *p++;
|
||||
*d++ = (w >> 8);
|
||||
n--;
|
||||
}
|
||||
else
|
||||
p = (uint16_t *)(PMA_ADDR + addr);
|
||||
|
||||
while (n >= 2)
|
||||
{
|
||||
w = *p++;
|
||||
*d++ = (w & 0xff);
|
||||
*d++ = (w >> 8);
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
w = *p;
|
||||
*d = (w & 0xff);
|
||||
}
|
||||
}
|
||||
135
mcu/usb-usbip.c
135
mcu/usb-usbip.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* usb-usbip.c - USB Device Emulation (server side) by USBIP
|
||||
*
|
||||
* Copyright (C) 2017, 2018 g10 Code GmbH
|
||||
* Copyright (C) 2017, 2018, 2021 g10 Code GmbH
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -22,10 +22,26 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
RESET handling
|
||||
USB Shutdown
|
||||
Use reply structure of its own
|
||||
* This driver is intended to emulate USB full-speed device, which
|
||||
* maximum packet size is 64.
|
||||
*
|
||||
* "USBIP" is actually URB over network (instead of USB packet over
|
||||
* network), and its (current) naive protocol may expose possible
|
||||
* demarcation problem, which never occurs in real host-device; In
|
||||
* real host-device relationship, it is host side, which does
|
||||
* composition/decomposition of URB to/from packets. In an
|
||||
* implmentation of USB device with USBIP, it needs to be device side,
|
||||
* which does composition/decomposition of URB to/from packets.
|
||||
*
|
||||
* In this implementation of USB driver, URB_DATA_SIZE is defined as
|
||||
* (65544+10), because (major) target device intended is CCID. In the
|
||||
* CCID specification, you can find the value 65544+10.
|
||||
*/
|
||||
/*
|
||||
* FIXME:
|
||||
* RESET handling
|
||||
* USB Shutdown
|
||||
* Use reply structure of its own
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
@@ -96,7 +112,7 @@ struct urb {
|
||||
struct urb *next;
|
||||
struct urb *prev;
|
||||
|
||||
uint16_t remain;
|
||||
uint32_t remain;
|
||||
char *data_p;
|
||||
|
||||
pthread_t tid;
|
||||
@@ -236,7 +252,67 @@ attach_device (char busid[32], size_t *len_p)
|
||||
return (const char *)&usbip_usb_device;
|
||||
}
|
||||
|
||||
#define URB_DATA_SIZE 65535
|
||||
/*
|
||||
* The number 65544 comes from ISO 7816-4, which defines data format
|
||||
* of smartcard; CLS INS P1 P2 occupies four octets. Then, Lc-octet
|
||||
* to represent size of command data block, then command data block.
|
||||
* Lastly, Le-octet to represent size of response data block to be
|
||||
* returned.
|
||||
*
|
||||
* /----- for CLS INS P1 P2
|
||||
* |
|
||||
* | /-- for Lc
|
||||
* | |
|
||||
* | | /-- for data block
|
||||
* | | |
|
||||
* | | | /-- for Le
|
||||
* | | | |
|
||||
* v v v v
|
||||
* 4 + 3 + 65535 + 2 = 65544
|
||||
*
|
||||
* The number 10 comes from the CCID protocol specification; It is the
|
||||
* header size of CCID. Besides, we can find the number 65544 in the
|
||||
* CCID protocol specification, too.
|
||||
*
|
||||
* And... we have "AND ONE MORE" three times.
|
||||
*
|
||||
* We accept that, as Buddha did.
|
||||
*
|
||||
* There are different interpretations for the historical fact and the
|
||||
* idiom. Most likely, nowadays, here, third-time is considered a
|
||||
* strikeout, perhaps, due to popularity of baseball.
|
||||
*/
|
||||
#define URB_DATA_SIZE (65544+10+1+1+1)
|
||||
|
||||
/*
|
||||
* The reasons why there are "+1" three times.
|
||||
*
|
||||
* Wrong (1): +1, because of confusion of data size maximum.
|
||||
* Wrong (2): +1, because of confusion of the size for Le.
|
||||
* Wrong (3): +1, because of keeping applying old patch.
|
||||
*
|
||||
* Something like this may occur, unfortunately, in our world.
|
||||
*
|
||||
* We need to consider the real case of the max buffer size for
|
||||
* libusb_bulk_transfer with CCID (let us call this "CASE_MAX").
|
||||
*
|
||||
* (1) Although the data size maximum (for all cases) is 65536, it
|
||||
* only occurs when Le size is zero. In the particular case of
|
||||
* CASE_MAX, it is actually 65535. When just applying the max value
|
||||
* 65536, +1 occurs.
|
||||
*
|
||||
* (2) Although maximum size to represent Le is 3, it only occurs when
|
||||
* Lc size is zero. In the particular case of CASE_MAX, it is
|
||||
* actually 2. When just applying the max value 3, +1 occurs.
|
||||
*
|
||||
* (3) Fedora keeps a old patch for Ominikey 3121. The patch was
|
||||
* written when the value of CMD_BUF_SIZE in libccid was small for
|
||||
* short extended APDU exchange. In the patch, it uses the value 11
|
||||
* for the header size (instead of 10) of TPDU, for its special
|
||||
* support. Historically, CMD_BUF_SIZE in libccid was updated
|
||||
* to bigger value to handle extended APDU exchange. When just applying
|
||||
* the old patch using 11, +1 occurs.
|
||||
*/
|
||||
|
||||
struct usbip_msg_cmd {
|
||||
uint32_t devid;
|
||||
@@ -299,12 +375,14 @@ static int write_data_transaction (struct usb_control *usbc_p,
|
||||
static int read_data_transaction (struct usb_control *usbc_p,
|
||||
int ep_num, char *buf, uint16_t count);
|
||||
|
||||
#define USB_MAX_PACKET_SIZE 64 /* For USB fullspeed device. */
|
||||
|
||||
static int
|
||||
hc_handle_control_urb (struct urb *urb)
|
||||
{
|
||||
int r;
|
||||
uint16_t count;
|
||||
uint16_t remain = urb->len;
|
||||
uint32_t remain = urb->len;
|
||||
uint64_t l;
|
||||
|
||||
if ((debug & DEBUG_USB))
|
||||
@@ -325,10 +403,10 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
while (r == 0)
|
||||
{
|
||||
if (remain > 64)
|
||||
count = 64;
|
||||
if (remain > USB_MAX_PACKET_SIZE)
|
||||
count = USB_MAX_PACKET_SIZE;
|
||||
else
|
||||
count = remain;
|
||||
count = (uint16_t)remain;
|
||||
|
||||
read (usbc_ep0.eventfd, &l, sizeof (l));
|
||||
r = control_write_data_transaction (urb->data_p, count);
|
||||
@@ -337,7 +415,7 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
urb->data_p += count;
|
||||
remain -= count;
|
||||
if (count < 64)
|
||||
if (count < USB_MAX_PACKET_SIZE)
|
||||
break;
|
||||
}
|
||||
if (r >= 0)
|
||||
@@ -353,10 +431,10 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (remain > 64)
|
||||
count = 64;
|
||||
if (remain > USB_MAX_PACKET_SIZE)
|
||||
count = USB_MAX_PACKET_SIZE;
|
||||
else
|
||||
count = remain;
|
||||
count = (uint16_t)remain;
|
||||
|
||||
read (usbc_ep0.eventfd, &l, sizeof (l));
|
||||
r = control_read_data_transaction (urb->data_p, count);
|
||||
@@ -368,7 +446,7 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
remain -= r;
|
||||
urb->data_p += r;
|
||||
if (r < 64)
|
||||
if (r < USB_MAX_PACKET_SIZE)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -516,10 +594,10 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
||||
if ((debug & DEBUG_USB))
|
||||
puts ("hc_hdu 0");
|
||||
|
||||
if (urb->remain > 64)
|
||||
count = 64;
|
||||
if (urb->remain > USB_MAX_PACKET_SIZE)
|
||||
count = USB_MAX_PACKET_SIZE;
|
||||
else
|
||||
count = urb->remain;
|
||||
count = (uint16_t)urb->remain;
|
||||
|
||||
if (urb->dir == USBIP_DIR_OUT)
|
||||
{ /* Output from host to device. */
|
||||
@@ -533,7 +611,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
||||
urb->data_p += count;
|
||||
urb->remain -= count;
|
||||
|
||||
if (urb->remain == 0 || count < 64)
|
||||
if (urb->remain == 0 || count < USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
size_t len = urb->len - urb->remain;
|
||||
|
||||
@@ -565,7 +643,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
||||
|
||||
urb->remain -= r;
|
||||
urb->data_p += r;
|
||||
if (urb->remain == 0 || r < 64)
|
||||
if (urb->remain == 0 || r < USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
size_t len = urb->len - urb->remain;
|
||||
|
||||
@@ -596,7 +674,7 @@ issue_get_desc (void)
|
||||
{
|
||||
struct urb *urb;
|
||||
|
||||
urb = malloc (sizeof (struct urb) + 64);
|
||||
urb = malloc (sizeof (struct urb) + USB_MAX_PACKET_SIZE);
|
||||
|
||||
urb->next = urb->prev = urb;
|
||||
|
||||
@@ -606,14 +684,14 @@ issue_get_desc (void)
|
||||
urb->setup[3] = 1; /* Value H: desc_type */
|
||||
urb->setup[4] = 0; /* Index */
|
||||
urb->setup[5] = 0;
|
||||
urb->setup[6] = 64; /* Length */
|
||||
urb->setup[6] = USB_MAX_PACKET_SIZE; /* Length */
|
||||
urb->setup[7] = 0;
|
||||
urb->data_p = urb->data;
|
||||
urb->seq = 0;
|
||||
urb->devid = 0;
|
||||
urb->dir = USBIP_DIR_IN;
|
||||
urb->ep = 0;
|
||||
urb->remain = urb->len = 64;
|
||||
urb->remain = urb->len = USB_MAX_PACKET_SIZE;
|
||||
hc_handle_control_urb (urb);
|
||||
return urb;
|
||||
}
|
||||
@@ -729,7 +807,7 @@ usbip_handle_urb (uint32_t seq)
|
||||
|
||||
leave:
|
||||
msg.cmd = htonl (REP_URB_SUBMIT);
|
||||
msg.seq = htonl (urb->seq);
|
||||
msg.seq = htonl (seq);
|
||||
|
||||
memset (&msg_rep, 0, sizeof (msg_rep));
|
||||
msg_rep.status = htonl (r);
|
||||
@@ -1080,6 +1158,11 @@ usbip_run_server (void *arg)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
fputs ("USBIP thread started.\n", stdout);
|
||||
fputs ("You can use this by attaching following commands:\n", stdout);
|
||||
fputs (" # modprobe vhci_hcd\n", stdout);
|
||||
fputs (" # usbip attach -r 127.0.0.1 -b 1-1\n", stdout);
|
||||
|
||||
pollfds[1].fd = shutdown_notify_fd;
|
||||
pollfds[1].events = POLLIN;
|
||||
pollfds[1].revents = 0;
|
||||
@@ -2175,7 +2258,7 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len < USB_MAX_PACKET_SIZE)
|
||||
if (data_p->len <= USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
|
||||
9
rules.mk
9
rules.mk
@@ -1,6 +1,12 @@
|
||||
# Chopstx make rules.
|
||||
|
||||
CSRC += $(CHOPSTX)/entry.c $(CHOPSTX)/chopstx.c
|
||||
ifeq ($(EMULATION),)
|
||||
CSRC += $(CHOPSTX)/entry.c
|
||||
else
|
||||
CSRC += $(CHOPSTX)/entry-gnu-linux.c
|
||||
endif
|
||||
|
||||
CSRC += $(CHOPSTX)/chopstx.c
|
||||
|
||||
ifneq ($(USE_EVENTFLAG),)
|
||||
CSRC += $(CHOPSTX)/eventflag.c
|
||||
@@ -13,6 +19,7 @@ CSRC += $(CHOPSTX)/mcu/chx-gnu-linux.c
|
||||
endif
|
||||
|
||||
ifneq ($(USE_SYS),)
|
||||
DEFS += -DUSE_SYS
|
||||
CSRC += $(CHOPSTX)/mcu/sys-$(CHIP).c
|
||||
endif
|
||||
ifneq ($(USE_USB),)
|
||||
|
||||
2
sys.h
2
sys.h
@@ -4,6 +4,8 @@
|
||||
#include "mcu/sys-mkl27z.h"
|
||||
#elif defined(MCU_STM32F0)
|
||||
#include "mcu/sys-stm32f0.h"
|
||||
#elif defined(MCU_STM32L4)
|
||||
#include "mcu/sys-stm32l4.h"
|
||||
#else
|
||||
#include "mcu/sys-stm32f103.h"
|
||||
#endif
|
||||
|
||||
@@ -153,7 +153,11 @@ void usb_lld_setup_endp (struct usb_dev *dev, int ep_num, int rx_en, int tx_en);
|
||||
void usb_lld_stall_tx (int ep_num);
|
||||
void usb_lld_stall_rx (int ep_num);
|
||||
#else
|
||||
#if defined(MCU_STM32L4)
|
||||
#define INTR_REQ_USB 67
|
||||
#else
|
||||
#define INTR_REQ_USB 20
|
||||
#endif
|
||||
/* EP_TYPE[1:0] EndPoint TYPE */
|
||||
#define EP_BULK (0x0000) /* EndPoint BULK */
|
||||
#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
|
||||
|
||||
Reference in New Issue
Block a user