Compare commits

78 Commits

Author SHA1 Message Date
NIIBE Yutaka
cc49f4ef23 Version 1.18.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-30 10:43:35 +09:00
NIIBE Yutaka
a0732c125a Add ChangeLog entry.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-27 10:20:27 +09:00
NIIBE Yutaka
6be482413c chopstx_poll: More change.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-27 10:20:07 +09:00
NIIBE Yutaka
9253777f5f Fix chopstx_poll for condition variables, check after woken up.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-27 10:19:50 +09:00
NIIBE Yutaka
63f47cede3 example-cdc,etc.: Bug fix of examples.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-20 14:39:38 +09:00
NIIBE Yutaka
4c0c15588e Add a ChangeLog entry for USB fix.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-20 08:27:33 +09:00
NIIBE Yutaka
e58e134b42 Fix EP0 receiving more packets.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-20 08:26:49 +09:00
NIIBE Yutaka
4cd47453ae Fix GNU/Linux emulation about termination of a thread.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-04 13:44:57 +09:00
NIIBE Yutaka
89523f22bf more clean up.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-21 08:01:25 +09:00
NIIBE Yutaka
0e5994506a Version 1.17.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-20 11:32:27 +09:00
NIIBE Yutaka
bdbc84ba18 chx_running for GNU/Linux port.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-20 11:24:21 +09:00
NIIBE Yutaka
c73258138c Use chx_running function.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-19 08:40:38 +09:00
NIIBE Yutaka
2180ed24be Rename internal functions to express meaning well.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 13:04:12 +09:00
NIIBE Yutaka
b70de1b98d Change chx_ready_pop implementation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 11:55:22 +09:00
NIIBE Yutaka
355482550b New: ticks_to_usec.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 08:28:05 +09:00
NIIBE Yutaka
858a9f5d01 Have a entry-gnu-linux.c.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 08:25:56 +09:00
NIIBE Yutaka
c7b83fd51c Move CHOPSTX_THREAD_SIZE, it's core specific.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 08:13:33 +09:00
Jeremy Drake
8e55209f33 Fix USB driver. 2019-10-07 16:07:31 +09:00
NIIBE Yutaka
4bde2ae1fc Fix USB drivers.
Thanks to Jeremy Drake for the report.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-09-04 08:57:47 +09:00
NIIBE Yutaka
d4ba52b0d1 Version 1.16. 2019-05-22 14:22:29 +09:00
NIIBE Yutaka
b483dc460d Add ChangLog entry. 2019-05-22 08:25:10 +09:00
Evangelos Rigas
9ff47d75b5 Add support for Gnukey-DS. 2019-05-22 08:20:36 +09:00
NIIBE Yutaka
d66481d67c Fix Nucleo-32 STM32L432 board. 2019-05-20 15:40:19 +09:00
NIIBE Yutaka
b539f27475 Fix USART driver. 2019-05-20 14:26:15 +09:00
NIIBE Yutaka
128cd508b6 examples: Fixes for new USB driver which does not use SYS. 2019-05-16 11:43:08 +09:00
NIIBE Yutaka
4f46af7557 Version 1.15. 2019-05-14 10:31:24 +09:00
NIIBE Yutaka
0de43691ab Changes for USB driver. 2019-05-13 09:37:18 +09:00
NIIBE Yutaka
79305c3de4 Allow calling chopstx_claim_irq when ready (disabled). 2019-05-10 12:05:35 +09:00
NIIBE Yutaka
c1ea549995 usb: FREE_STANDING should come with USE_SYS. 2019-05-10 10:17:48 +09:00
NIIBE Yutaka
fee2cae8c4 SYS 4.0. 2019-05-10 09:59:57 +09:00
NIIBE Yutaka
3317fb39ab Add mcu/ABOUT-USB. 2019-05-10 09:37:20 +09:00
NIIBE Yutaka
de4ab0d3c9 Fix usb driver for STM32L4. 2019-05-08 12:23:53 +09:00
NIIBE Yutaka
be43aa3051 usb driver: Only board specific function of cable config is in SYS. 2019-05-08 12:07:28 +09:00
NIIBE Yutaka
e7e6f5b184 usart: move to common code. 2019-04-26 10:21:29 +09:00
NIIBE Yutaka
74e52fd7f9 usart: usart_block_sendrecv: Fix receive when no data to send. 2019-04-25 18:36:24 +09:00
NIIBE Yutaka
fe1ca5f055 usart: stm32l4 change. 2019-04-25 17:04:13 +09:00
NIIBE Yutaka
3199ac7aae Better API for baud setting for smartcard communication. 2019-04-25 11:08:46 +09:00
NIIBE Yutaka
d22ffb2d07 Fix USART driver. 2019-04-24 20:22:57 +09:00
NIIBE Yutaka
c818ec89a4 Add EXTI for STM32L. 2019-04-24 11:42:40 +09:00
NIIBE Yutaka
2d2d544c5d Add ChangLog entries, update NEWS and README.
I should have called version 1.10 as 2.0, becase it introduced API
change.
2019-04-24 09:57:51 +09:00
NIIBE Yutaka
97811f2e1c Add SYSCFG to mcu/stm32l.h. 2019-04-24 09:37:55 +09:00
NIIBE Yutaka
2db324e93d doc: Add a memo. 2019-04-24 09:35:29 +09:00
NIIBE Yutaka
886343d40d Board: Nucleo L432: Decide assignment of pin. 2019-04-22 15:40:00 +09:00
NIIBE Yutaka
f6c29ab274 Implement usart_block_sendrecv for STM32L432. Not tested. 2019-04-19 17:04:28 +09:00
NIIBE Yutaka
8afabfa301 Fix entry.c for STM32L4. Now, USB works. 2019-04-18 19:14:08 +09:00
NIIBE Yutaka
1d2aacd0a4 stm32l4: Enable PWR module and USV-bit in CR2. 2019-04-18 19:13:23 +09:00
NIIBE Yutaka
359082f80a Testing USB on STM32L4. 2019-04-18 17:12:41 +09:00
NIIBE Yutaka
1f159888a0 doc: Add memorandom chapter. 2019-04-18 10:25:19 +09:00
NIIBE Yutaka
f37d83e55d New: mcu/usb-stm32l.c (not yet tested). 2019-04-17 16:13:58 +09:00
NIIBE Yutaka
b20f66b5e4 Factor out usb-st-common.c. 2019-04-17 15:20:31 +09:00
NIIBE Yutaka
5d344acad9 usb driver: I/O access style fix. 2019-04-17 15:07:12 +09:00
NIIBE Yutaka
06eef36868 usart: Fix smartcard communication. Only ignoring echo back. 2019-04-15 12:06:57 +09:00
NIIBE Yutaka
ca06df793a Add example-usart, which works well with ST Nucleo L432. 2019-04-12 20:20:16 +09:00
NIIBE Yutaka
92de60e5f2 Fix struct usart member mistake. Add example-usart. 2019-04-12 20:05:35 +09:00
NIIBE Yutaka
61c0edcc96 Add USART driver for STM32L. 2019-04-12 17:28:41 +09:00
NIIBE Yutaka
7b129cd50f Factor out USART routines. 2019-04-12 17:08:51 +09:00
NIIBE Yutaka
f237314ebf Rename _PHR_ (as peripheral) to specific bus (AHB, APB, etc.). 2019-04-12 10:45:12 +09:00
NIIBE Yutaka
52efc84f5c Now, example-led works fine with -mcortex-m4. 2019-04-12 10:30:53 +09:00
NIIBE Yutaka
5a326eee54 Example-led works fine with -mcpu=cortex-m3. 2019-04-11 17:11:47 +09:00
NIIBE Yutaka
054950bc9a Try STM Nucleo L432 LED. 2019-04-11 15:36:51 +09:00
NIIBE Yutaka
e5e46b5de5 Add mcu/*stm32l4. 2019-04-11 15:34:57 +09:00
NIIBE Yutaka
8b9d2c007a Add comment of usb_cable_config. 2019-04-11 13:48:26 +09:00
NIIBE Yutaka
5a6910a45b Adding STM32L432 support for USART (not yet USB, ADC, Flash, etc.). 2019-04-11 11:08:17 +09:00
NIIBE Yutaka
f8880aafec Coding style fix for SYST registers. 2019-04-11 09:08:33 +09:00
NIIBE Yutaka
681a0055e4 Rename clk_gpio_init-stm32f.c. 2019-04-10 16:17:19 +09:00
NIIBE Yutaka
69a7960876 Start experiment with STM32L432. 2019-04-10 12:39:07 +09:00
NIIBE Yutaka
7f77e5a13d Use STM32F10X_HD. 2019-04-10 12:38:45 +09:00
NIIBE Yutaka
bf585aba18 Use 9600 bps for BSCARD. 2019-04-09 13:35:59 +09:00
NIIBE Yutaka
bf7afa7348 usart: Support busy-wait in usart_block_sendrecv.
chopstx_poll is heavy.
2019-04-09 10:43:53 +09:00
NIIBE Yutaka
7f4eae6c56 Modify the loop of usart_block_sendrecv. 2019-04-09 08:51:23 +09:00
NIIBE Yutaka
8c045a6b8d usart: New API for block send-recv. 2019-04-08 11:49:13 +09:00
NIIBE Yutaka
ac026cc501 St Nucleo 32: Enable AFIO clock. 2019-04-02 13:39:29 +09:00
NIIBE Yutaka
8d7106d992 Change internal function name of USART driver. 2019-04-01 21:18:03 +09:00
NIIBE Yutaka
2c0b1eee03 Fix gaurd time for 1 etu. 2019-04-01 15:33:07 +09:00
NIIBE Yutaka
83817af2d7 Enhancement for smartcard communication. 2019-03-30 19:27:53 +09:00
NIIBE Yutaka
339da2901c Fix typo. 2019-03-29 16:08:30 +09:00
NIIBE Yutaka
06130d071b Add read with timeout for USART driver. 2019-03-29 11:53:41 +09:00
NIIBE Yutaka
02ca3a6cd5 Fix typo in copyright notice. 2019-03-26 18:18:39 +09:00
77 changed files with 4760 additions and 1629 deletions

View File

@@ -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,

219
ChangeLog
View File

@@ -1,3 +1,222 @@
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-20 NIIBE Yutaka <gniibe@fsij.org>
* mcu/usb-st-common.c (usb_lld_ctrl_recv): Fix receiving
more than one packet.
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.

View File

@@ -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.
--------------------

72
NEWS
View File

@@ -1,6 +1,78 @@
NEWS - Noteworthy changes
* 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

13
README
View File

@@ -1,6 +1,6 @@
Chopstx - Threads and only Threads
Version 1.14
2018-03-02
Version 1.18
2019-12-30
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,6 +60,9 @@ For STM32 Primer2, see the directory: example-primer2.
Future Works
============
RISC-V port (for GD32VF103) is under development. Please have a look
at the master branch.
Convenience function to determine the bottom of thread stack,
configuration of thread size by compiler's output would be next things
to be done.

View File

@@ -1 +1 @@
release/1.14
release/1.18

View File

@@ -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

View File

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

View File

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

View File

@@ -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.

View File

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

View File

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

View File

@@ -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
*/
@@ -70,5 +72,5 @@
#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)

View 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)

View File

@@ -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

View File

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

View File

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

View File

@@ -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);
@@ -265,6 +293,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 +331,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 +388,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 +578,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 +660,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 +697,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"

View File

@@ -10,3 +10,5 @@ struct tcontext {
};
typedef struct tcontext tcontext_t;
#define CHOPSTX_THREAD_SIZE 64

View File

@@ -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 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)
{
}
@@ -197,19 +220,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 +248,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);
}
}
tcp = &tp->tc;
else
tcp = &idle_tc;
chx_set_running (tp);
if (tp_prev)
{
/*
@@ -283,10 +301,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 +311,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;
}
tcp = &tp->tc;
else
{
v = 0;
tcp = &idle_tc;
}
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 *

View File

@@ -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,9 +83,6 @@ 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;
@@ -271,6 +268,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;
}
@@ -385,6 +388,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);
@@ -433,10 +437,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,7 +456,7 @@ 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);
@@ -475,7 +481,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 +502,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)
{
@@ -537,6 +543,7 @@ static void __attribute__((noreturn))
chx_exit (void *retval)
{
struct chx_pq *p;
struct chx_thread *running = chx_running ();
chx_cpu_sched_lock ();
if (running->flag_join_req)
@@ -573,6 +580,7 @@ static chopstx_prio_t
chx_mutex_unlock (chopstx_mutex_t *mutex)
{
struct chx_thread *tp;
struct chx_thread *running = chx_running ();
mutex->owner = NULL;
running->mutex_list = mutex->list;
@@ -620,6 +628,7 @@ 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);
@@ -665,6 +674,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;
@@ -688,7 +698,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;
}
@@ -787,7 +797,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)
{
@@ -846,6 +856,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 ();
@@ -883,7 +894,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 ();
@@ -1005,17 +1016,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;
}
@@ -1087,6 +1102,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;
}
@@ -1101,6 +1118,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)
@@ -1125,6 +1143,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;
@@ -1161,6 +1180,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;
@@ -1264,6 +1284,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;
@@ -1320,6 +1341,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);
}
@@ -1336,6 +1359,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);
@@ -1346,6 +1370,8 @@ chopstx_setcancelstate (int cancel_disable)
static void
chx_proxy_init (struct chx_px *px, uint32_t *cp)
{
struct chx_thread *running = chx_running ();
px->next = px->prev = (struct chx_pq *)px;
px->flag_is_proxy = 1;
px->prio = running->prio;
@@ -1377,6 +1403,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 ();
@@ -1384,6 +1411,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];
@@ -1446,6 +1474,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)
{
@@ -1477,6 +1519,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;
}
@@ -1497,7 +1542,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 ();

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
View 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);
}

View File

@@ -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)
{
if (dev_no == 2)
return USART2;
else if (dev_no == 3)
return USART3;
return NULL;
}
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[] =
{
{ 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)))
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,23 +159,24 @@ static const struct brr_setting brr_table[] = {
{ B230400, ( 9 << 4)|12},
{ B460800, ( 4 << 4)|14},
{ B921600, ( 2 << 4)|7},
{ BSCARD, ( 232 << 4)|8},
{ 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);
static struct usart_stat usart2_stat;
static struct usart_stat usart3_stat;
void
usart_config_clken (uint8_t dev_no, int on)
#include "usart-common.c"
static void
usart_config_recv_enable (struct USART *USARTx, int on)
{
struct USART *USARTx = get_usart_dev (dev_no);
if (on)
USARTx->CR2 |= (1 << 11);
USARTx->CR1 |= USART_CR1_RE;
else
USARTx->CR2 &= ~(1 << 11);
USARTx->CR1 &= ~USART_CR1_RE;
}
@@ -130,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;
@@ -177,10 +233,13 @@ 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. */
@@ -188,8 +247,8 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
{
if ((config_bits & MASK_MODE) == MODE_SMARTCARD)
{
USARTx->GTPR = (16 << 8) | 5;
USARTx->CR3 |= ((1 << 5) | (1 << 4));
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);
@@ -200,236 +259,27 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
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;
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)
@@ -444,11 +294,23 @@ 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 ((r & USART_SR_TXE))
if (smartcard_mode)
{
tx_ready = 1;
USARTx->CR1 &= ~USART_CR1_TXEIE;
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))
@@ -499,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++;
}
@@ -507,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);
@@ -516,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 ((r & USART_SR_TXE) == 0)
if (smartcard_mode)
{
tx_ready = 0;
USARTx->CR1 |= USART_CR1_TXEIE;
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)
{
@@ -654,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
View 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;
}

View File

@@ -11,7 +11,13 @@
#define B230400 26
#define B460800 27
#define B921600 28
#define BSCARD 63
#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 */
@@ -73,3 +79,12 @@ 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);

View File

@@ -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

View File

@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename chopstx.info
@set VERSION 1.14
@set VERSION 1.18
@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
View 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
View File

@@ -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

View File

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

View File

@@ -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)
{

View File

@@ -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 =

View File

@@ -1 +1 @@
../board/board-fst-01.h
../board/board-st-nucleo-l432.h

107
example-cdc/sample.ld.m4 Normal file
View 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__;

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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 =

View File

@@ -1 +1 @@
../board/board-stm32f0-discovery.h
../board/board-st-nucleo-l432.h

View File

@@ -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
View 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
View 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
View File

@@ -0,0 +1 @@
../board/board-st-nucleo-l432.h

156
example-usart/sample.c Normal file
View 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
View 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
View 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
View 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
View 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

View File

@@ -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:

View File

@@ -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
View 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
View 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. */
}
}
}

View File

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

View File

@@ -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
View 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
View 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;

View File

@@ -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)

View File

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

View File

@@ -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
@@ -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")))

View File

@@ -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
@@ -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")))

View File

@@ -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
View 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
View 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);

View File

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

919
mcu/usb-st-common.c Normal file
View File

@@ -0,0 +1,919 @@
/*
* 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;
if (len > USB_MAX_PACKET_SIZE)
len = USB_MAX_PACKET_SIZE;
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
View 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);
}
}

View File

@@ -2175,7 +2175,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;

View File

@@ -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
View File

@@ -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

View File

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