Compare commits

381 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
NIIBE Yutaka
aeea3c31f8 Version 1.14. 2019-03-02 08:48:11 +09:00
NIIBE Yutaka
91dbfaf6b7 usart: SCEN should be configured after CR1 enabled. 2019-03-01 22:22:25 +09:00
NIIBE Yutaka
304441d393 usart: usart_config should be called by application. 2019-03-01 20:02:15 +09:00
NIIBE Yutaka
4780da5b5b Parity error enabled when parity is in use. 2019-03-01 20:01:43 +09:00
NIIBE Yutaka
a4aa99f772 Add smartcard interface support for ST Nucleo Board. 2019-02-28 22:35:55 +09:00
NIIBE Yutaka
3315435579 Fix unsigned-ness of MASK_MODE. 2019-02-25 17:00:42 +09:00
NIIBE Yutaka
bd330d81c3 Add comment for eventflag. 2019-02-22 14:00:44 +09:00
NIIBE Yutaka
078c8db5d7 Minor code-cleanup for priority inheritance. 2019-02-22 09:52:28 +09:00
NIIBE Yutaka
53e4d1a371 Add usart modes. 2019-02-21 16:44:01 +09:00
NIIBE Yutaka
2b18685cbf Use "System Control Block" instead of "System Control Registers". 2018-12-29 09:33:19 +09:00
NIIBE Yutaka
b6c90e3df4 Version 1.13. 2018-12-19 12:52:26 +09:00
NIIBE Yutaka
4d4f82fd06 Update copyright notice. 2018-12-19 12:47:20 +09:00
NIIBE Yutaka
1ef6256784 Fix calculation of ticks remained. 2018-12-08 10:06:33 +09:00
NIIBE Yutaka
1400e677e3 Change behavior of chopstx_poll to correctly update *USEC_P. 2018-12-07 18:01:39 +09:00
NIIBE Yutaka
39683dbc5f Version 1.12. 2018-11-12 14:09:25 +09:00
NIIBE Yutaka
fd98c5e162 ackbtn driver: Add possible FST-01 and FST-01G support. 2018-11-12 14:06:13 +09:00
NIIBE Yutaka
1369361e59 Add eventflag_set_mask, removing eventflag_wait_all. 2018-11-09 20:49:39 +09:00
NIIBE Yutaka
2992b894e0 Add eventflag_wait_all. 2018-11-09 16:04:42 +09:00
NIIBE Yutaka
fffb8aa3b3 Version 1.11. 2018-10-02 09:58:45 +09:00
NIIBE Yutaka
0ed2e95ea2 Fix ackbtn clearing the edge detector. 2018-10-01 12:56:41 +09:00
NIIBE Yutaka
02aa678d4c Fix interrupt handling. 2018-10-01 10:10:09 +09:00
NIIBE Yutaka
d25cee5040 Version 1.10. 2018-09-29 11:03:32 +09:00
NIIBE Yutaka
e420168c82 doc: Update chopstx-api.texi. 2018-09-27 15:14:00 +09:00
NIIBE Yutaka
7dc67d2210 Minor change for ackbtn driver. 2018-09-27 12:53:43 +09:00
NIIBE Yutaka
49b0556a24 Add ack-botton driver. 2018-09-27 10:36:36 +09:00
NIIBE Yutaka
43bbdb44dc Fix examples. 2018-09-26 10:47:42 +09:00
NIIBE Yutaka
d4f4f80ad9 New API: chopstx_intr_done. 2018-09-26 10:18:23 +09:00
NIIBE Yutaka
7ad7527e81 Add defninitions of EXTI use for FST-01SZ. 2018-09-25 16:17:26 +09:00
NIIBE Yutaka
951afbad3a Consolidate definitions for STM32F103. 2018-09-21 14:47:16 +09:00
NIIBE Yutaka
2b717c91da Add FST-01SZ support. 2018-09-21 10:37:11 +09:00
NIIBE Yutaka
05732b445a Add MHZ for examples. 2018-08-23 14:36:22 +09:00
NIIBE Yutaka
1cbe0abdee usb: Fix for ZLP. 2018-08-20 12:43:35 +09:00
NIIBE Yutaka
802dbbd639 Version 1.9. 2018-05-09 12:29:52 +09:00
NIIBE Yutaka
2764fc4ea2 Fix flash_protect for GD32F103. 2018-05-08 17:38:39 +09:00
NIIBE Yutaka
f500ac03da Fix for Blue Pill, wait using MHZ. 2018-05-08 13:16:58 +09:00
NIIBE Yutaka
808aa5b186 Fix example-fraucheky. 2018-04-27 05:31:32 +09:00
NIIBE Yutaka
f781ac9e6a Fix usb_device_reset of example-fraucheky. 2018-04-26 21:15:13 +09:00
NIIBE Yutaka
32d0b8200d Add board/board-blue-pill-g.h. 2018-04-26 10:55:08 +09:00
NIIBE Yutaka
05382581e8 More. 2018-01-30 13:52:09 +09:00
NIIBE Yutaka
aa97af66db More update of CI/CD. 2018-01-30 13:49:59 +09:00
NIIBE Yutaka
e6a53c99c4 Update CI/CD setting to generate HTML. 2018-01-30 13:24:34 +09:00
NIIBE Yutaka
cb770e9ae3 Add .gitlab-ci.yml. 2018-01-30 13:07:11 +09:00
NIIBE Yutaka
aa63ac79bc Version 1.8. 2018-01-19 10:12:16 +09:00
NIIBE Yutaka
74cff25b78 Clean up example-usb-serial. 2018-01-18 15:15:42 +09:00
NIIBE Yutaka
5cd4871a94 Fix mcu/stm32f103.h. 2018-01-18 15:12:52 +09:00
Anthony Romano
c0a84627b6 Support IN8 config for ADC. 2018-01-09 09:26:44 +09:00
NIIBE Yutaka
8dabbe6e1c Version 1.7. 2017-12-19 09:33:27 +09:00
NIIBE Yutaka
0a68140530 Prepare 1.7 release. 2017-12-18 14:45:41 +09:00
NIIBE Yutaka
ce3cd63144 USB-USART improvement: flush buffer, send_break, use callbacks. 2017-12-18 13:53:01 +09:00
NIIBE Yutaka
199db97025 USB-USART supports notification of serial error. 2017-12-18 11:11:25 +09:00
NIIBE Yutaka
1533284ace USB-USART config setup support. 2017-12-17 11:52:17 +09:00
NIIBE Yutaka
0e9737eb61 Fix priority setting of USART (serial needs tight timing). 2017-12-16 17:17:58 +09:00
NIIBE Yutaka
265fb971c0 Fix USART for overrun error. 2017-12-16 17:01:58 +09:00
NIIBE Yutaka
26d5bb0115 Remove debug output for USART example. 2017-12-16 16:20:12 +09:00
NIIBE Yutaka
bf1ac08e6c Fix usb-cdc.c in USART example. 2017-12-16 16:14:43 +09:00
NIIBE Yutaka
530ddcfeda Fix timer expiration. 2017-12-16 15:00:55 +09:00
NIIBE Yutaka
19b0590c1f USART fix handle_tx_ready, tweak priority of the sample. 2017-12-16 14:33:40 +09:00
NIIBE Yutaka
72210e4250 Fix USART README and Alternate input config. 2017-12-15 22:18:22 +09:00
NIIBE Yutaka
61892c85b0 Fix USART rb_read. 2017-12-15 21:48:54 +09:00
NIIBE Yutaka
75e6b06dd5 Fix USART driver. 2017-12-15 18:11:25 +09:00
NIIBE Yutaka
dd190c8207 Add link for example-usb-serial. 2017-12-15 17:07:50 +09:00
NIIBE Yutaka
22039ee717 Modify USB<->USART example. 2017-12-15 16:00:59 +09:00
NIIBE Yutaka
cb628fe317 Fix rough edges of USART driver. 2017-12-15 15:18:17 +09:00
NIIBE Yutaka
f3cc662548 Remove bb.c. 2017-12-15 15:08:39 +09:00
NIIBE Yutaka
b58dd05c9d USART access functions implemented. 2017-12-15 15:07:13 +09:00
NIIBE Yutaka
7b1c442d88 USART: Main implemented. 2017-12-15 13:51:55 +09:00
NIIBE Yutaka
b4b9aace03 Add ring buffer for USART. 2017-12-15 09:46:28 +09:00
NIIBE Yutaka
741aba1997 Add ChangeLog. 2017-12-14 20:41:54 +09:00
NIIBE Yutaka
022666402c Start writing USART driver of STM32. 2017-12-14 20:34:24 +09:00
NIIBE Yutaka
69677aecd4 Change ADC setting of ST Nucleo STM32F103. 2017-12-14 20:31:28 +09:00
NIIBE Yutaka
bc35bc81cf APB -> APB1. 2017-12-14 19:04:16 +09:00
NIIBE Yutaka
499e575528 Fix bb. 2017-12-14 19:04:01 +09:00
NIIBE Yutaka
9f9aeae4bf Add bb.c, bb.h. 2017-12-14 15:47:18 +09:00
NIIBE Yutaka
ecd90b1b99 Testing loopback from ttyACM0 <-> ttyACM1. 2017-12-14 15:46:38 +09:00
NIIBE Yutaka
39e53ae747 Rename serial->cdc for no confusion between USART. 2017-12-14 12:24:59 +09:00
NIIBE Yutaka
9b9d40c16b No line editing. 2017-12-14 12:10:27 +09:00
NIIBE Yutaka
1eff465303 Modification to support multiple serial lines. 2017-12-14 11:25:14 +09:00
NIIBE Yutaka
de895e6b65 Add another interface. 2017-12-14 10:55:55 +09:00
NIIBE Yutaka
d4cca9f0dc It's not TTY but USB to serial driver. 2017-12-14 10:19:01 +09:00
NIIBE Yutaka
de9eb6f1e7 Try to support multiple serial lines. 2017-12-14 10:16:53 +09:00
NIIBE Yutaka
2c14f21b20 Copied from example-cde (except README). 2017-12-14 09:34:16 +09:00
NIIBE Yutaka
9e527b0532 Version 1.6. 2017-11-24 13:41:22 +09:00
NIIBE Yutaka
817167dbcc Update example-fsm-55. 2017-11-21 13:51:29 +09:00
NIIBE Yutaka
63974743b4 Forgotten example-led/stack-def.h. 2017-11-21 13:16:50 +09:00
NIIBE Yutaka
14c4256337 Update example-led. 2017-11-20 10:14:34 +09:00
NIIBE Yutaka
8c4ea854cb Fix for Cortex-M0. 2017-11-20 10:12:55 +09:00
NIIBE Yutaka
a610821458 Fix example-fsm-55. 2017-11-18 10:40:48 +09:00
NIIBE Yutaka
3071929c62 More change for clock setting. 2017-11-17 15:32:51 +09:00
NIIBE Yutaka
14cb38e56f More clean up. 2017-11-17 14:55:59 +09:00
NIIBE Yutaka
a362f32cdd Factor out RCC definition into stm32.h (common for STM32F0/STM32F1). 2017-11-17 14:33:16 +09:00
NIIBE Yutaka
e684e853c8 Fix for MKL27Z. 2017-11-17 11:45:18 +09:00
NIIBE Yutaka
2b98dc3de8 Update example-fsm-55. 2017-11-17 11:44:56 +09:00
NIIBE Yutaka
44054415c8 MCU specific sleep feature is now defined in MCU specific file. 2017-11-17 11:43:05 +09:00
NIIBE Yutaka
66b4eb3058 Update mcu/stm32f103.h. 2017-11-17 11:36:08 +09:00
NIIBE Yutaka
b72154f47b Factor out mcu/cortex-m.h. 2017-11-17 11:34:28 +09:00
NIIBE Yutaka
378201a1c7 Call chx_sleep_mode change. 2017-11-17 11:28:05 +09:00
NIIBE Yutaka
1a7bd3e202 Add MCU_STM32F1. 2017-11-17 11:25:57 +09:00
NIIBE Yutaka
b34b9b6440 Use HSI clock on sleep mode for STM32F103. 2017-11-16 13:04:08 +09:00
NIIBE Yutaka
d745c9fdb9 Only sleep mode can be used for USB suspend on STM32F103. 2017-11-16 12:19:25 +09:00
NIIBE Yutaka
3552fc5615 chopstx_poll: Use const pointer for the third argument. 2017-11-16 09:15:03 +09:00
NIIBE Yutaka
621dff7cb3 Fix for Cortex-M0. 2017-11-16 09:02:16 +09:00
NIIBE Yutaka
83643c53ca Use event instead of interrupt (STM32F103 USB). 2017-11-16 08:39:30 +09:00
NIIBE Yutaka
040f389449 Add INTR_REQ_USB_WAKEUP. 2017-11-15 17:51:08 +09:00
NIIBE Yutaka
44273a70fc USB driver for STM32F103 update for USB suspend/resume support. 2017-11-15 17:23:02 +09:00
NIIBE Yutaka
7257f30636 Use deep sleep API for example-fsm-55. 2017-11-15 17:09:47 +09:00
NIIBE Yutaka
941a8f6fbd Add chx_sleep_mode. 2017-11-15 17:09:30 +09:00
NIIBE Yutaka
13926ac05a Fix Cortex-M0 version. 2017-11-15 16:47:26 +09:00
NIIBE Yutaka
bbe09de209 Fix example-fsm-55 and documentation. 2017-11-15 10:46:49 +09:00
NIIBE Yutaka
f161928b0b Support sleep on idle. 2017-11-15 10:22:30 +09:00
NIIBE Yutaka
035057db24 Fix USB driver for STM32F103. 2017-11-15 09:34:13 +09:00
NIIBE Yutaka
5ac8a1f251 Fix example-fraucheky. 2017-11-14 11:30:20 +09:00
NIIBE Yutaka
168af852a5 Support USB suspend/resume defined in USB 2.0 spec. 2017-11-14 11:17:49 +09:00
NIIBE Yutaka
e398fc9689 Modify place where INTR_REQ_USB is defined. 2017-11-13 11:44:53 +09:00
NIIBE Yutaka
5a08752b9c Fix cancellation (svc and ->v handling). 2017-11-10 16:09:46 +09:00
NIIBE Yutaka
b572e3f8e0 Fix timeout. 2017-11-10 16:09:32 +09:00
NIIBE Yutaka
55b011a721 Fix use of noreturn attribute. 2017-10-11 17:01:53 +09:00
NIIBE Yutaka
c191d86bf2 GNU/Linux USB driver shutdown support. 2017-10-10 21:02:29 +09:00
NIIBE Yutaka
96d2a81331 Version 1.5.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-10-10 13:53:58 +09:00
NIIBE Yutaka
fa7cecc0b4 Support --debug option for exacmple-cdc-gnu-linux. 2017-10-10 12:18:35 +09:00
NIIBE Yutaka
a34937453c New: debug option. 2017-10-10 12:16:03 +09:00
NIIBE Yutaka
dd54b5ff20 Fix example-cdc. 2017-10-10 12:07:02 +09:00
NIIBE Yutaka
c08044e22b Fix sys for STM32F103. 2017-09-29 13:50:06 +09:00
NIIBE Yutaka
5b7c5a9996 Use flash routines in example-cdc-gnu-linux. 2017-09-27 19:24:08 +09:00
NIIBE Yutaka
bc39f0e582 update flash routines for GNU/Linux. 2017-09-27 19:07:14 +09:00
NIIBE Yutaka
e671a539b0 Fix flash routines on GNU/Linux.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-09-08 20:56:23 +09:00
NIIBE Yutaka
2c9191c4b3 Implement flash ROM emulation on GNU/LInux.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-09-08 20:44:56 +09:00
NIIBE Yutaka
af5982507f Define threads stack size by stack-def.h.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-09-05 14:34:25 +09:00
NIIBE Yutaka
a1b993c2e2 Minor changes for SYS.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-09-04 15:23:35 +09:00
NIIBE Yutaka
e73d14ca27 Add muc/sys-gnu-linux.*.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-09-04 15:23:02 +09:00
NIIBE Yutaka
d8df82badf Version 1.4. 2017-08-11 19:57:57 +09:00
NIIBE Yutaka
f51a54e4c6 Version 1.4.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-11 19:50:56 +09:00
Jeremy Drake
5fe5ff36c4 Allow compile-time override of detected flash size.
On the STM32F103C8, as used in the "blue pill" boards, it has been
determined that, despite these only officially having 64KiB flash, it is
possible to actually use 128KiB of flash.

This commit allows for a preprocessor define
STM32F103_OVERRIDE_FLASH_SIZE which, when set, is used as the size of
flash in KiB instead of reading it from the FLASH_SIZE_REG.
2017-08-03 20:48:13 +09:00
NIIBE Yutaka
a4f28ee176 Add adc-gnu-linux driver.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-08-02 14:19:10 +09:00
NIIBE Yutaka
87767f1be5 Fix error handling of USB-USBIP driver. 2017-07-07 15:46:37 +09:00
NIIBE Yutaka
8b018df382 Add EXAMPLE-README. 2017-07-06 16:06:46 +09:00
NIIBE Yutaka
5d9802388c Fix USB driver on GNU/Linux. 2017-07-06 15:52:46 +09:00
NIIBE Yutaka
478dd2c784 Add example-fraucheky. 2017-07-05 19:37:41 +09:00
NIIBE Yutaka
6f7a591417 Fix usb-usbip.c. 2017-06-28 16:23:41 +09:00
NIIBE Yutaka
d142cbbea3 Added CDC-ACM sample of USBIP. 2017-06-27 15:46:04 +09:00
NIIBE Yutaka
f011d643e9 Add board-gnu-linux.h for emulation. 2017-06-26 19:53:26 +09:00
NIIBE Yutaka
1fbbf66e8e Fix for GNU/Linux emulation. 2017-06-26 19:52:19 +09:00
NIIBE Yutaka
1f7d4a6aac Fix usb drivers. 2017-06-26 19:50:55 +09:00
NIIBE Yutaka
526b8fec2a Added USBIP driver for emulation. 2017-06-26 19:32:43 +09:00
NIIBE Yutaka
5419580519 Support emulation on GNU/Linux. 2017-06-26 19:32:23 +09:00
NIIBE Yutaka
78c825afe8 Add GNU/Linux support (not yet makefile). 2017-06-23 09:05:11 +09:00
NIIBE Yutaka
1bd14d8d40 Factor out arch dependent code. 2017-06-23 09:03:26 +09:00
NIIBE Yutaka
80258ba7c7 Remove naked attribute from chopstx_exit. 2017-06-22 10:04:45 +09:00
NIIBE Yutaka
ca1b22c3eb Use ->V for the return value of chx_sched. 2017-06-21 20:48:50 +09:00
NIIBE Yutaka
6c68c55301 Change exit value access. 2017-06-21 17:16:01 +09:00
NIIBE Yutaka
d941299149 Fix chx_wakeup. 2017-06-16 10:31:40 +09:00
NIIBE Yutaka
b2b0eb7418 Fix MKL27Z USB. 2017-06-16 10:29:00 +09:00
NIIBE Yutaka
7798e620a6 Fix access to REG_R0 at chx_wakeup. 2017-05-18 11:09:03 +09:00
NIIBE Yutaka
89eb54929e Version 1.3. 2017-02-02 12:56:13 +09:00
NIIBE Yutaka
a96f84ff74 Add Blue Pill support. 2017-02-01 17:31:52 +09:00
Szczepan Zalega
9d84537c13 Switch off red LED for Nitrokey Start.
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
2017-02-01 15:24:55 +09:00
NIIBE Yutaka
d448d3c678 Version 1.2 2016-10-13 10:18:47 +09:00
NIIBE Yutaka
bc664fe943 chopstx_join is cancellation point. 2016-10-12 12:06:37 +09:00
NIIBE Yutaka
08cca6b9f8 stackaddr/size change 2016-07-11 17:21:32 +09:00
NIIBE Yutaka
c9d59a3f3f mcu/stm32f103.h: Add more constants from Gnuk 1.1.9 2016-07-11 11:38:58 +09:00
NIIBE Yutaka
09f27704f5 Version 1.1 2016-07-01 11:50:25 +09:00
NIIBE Yutaka
1f23bd4048 Change touch button for MKL27Z 2016-07-01 10:58:05 +09:00
NIIBE Yutaka
f5880ee5d5 Change API of chopstx_setpriority 2016-07-01 09:51:32 +09:00
NIIBE Yutaka
c7e571eca0 update doc 2016-06-30 16:41:32 +09:00
NIIBE Yutaka
0decd305b9 chopstx_poll example fix 2016-06-30 16:26:52 +09:00
NIIBE Yutaka
a2a29146a6 const pointer cleanup 2016-06-30 16:23:29 +09:00
NIIBE Yutaka
e7bd234a0d Update for MKL27Z 2016-06-30 16:16:39 +09:00
NIIBE Yutaka
c71a24ddcb MKL27Z touch 2016-06-29 17:05:33 +09:00
NIIBE Yutaka
663cbabe7c Fix MKL27Z TPM registers 2016-06-29 16:51:16 +09:00
NIIBE Yutaka
41ac81a66b Update example for fs-bb48 2016-06-29 16:38:18 +09:00
NIIBE Yutaka
986518fba7 fix setpriority 2016-06-29 16:36:53 +09:00
NIIBE Yutaka
15a4403f24 chopstx_poll change 2016-06-28 15:48:15 +09:00
Niibe Yutaka
40adf95c24 Version 1.0 2016-06-16 11:46:38 +09:00
Niibe Yutaka
5a7381ece6 Add FST-01G 2016-06-16 11:31:10 +09:00
Niibe Yutaka
52626a3368 chopstx_exit change 2016-06-15 12:41:12 +09:00
Niibe Yutaka
440188c373 Fix USB for STM32 2016-06-14 15:10:07 +09:00
NIIBE Yutaka
a6541cbcc6 NONE sounds bad, use OK instead 2016-06-10 08:25:00 +09:00
NIIBE Yutaka
74c7b5bcb3 minor comment change 2016-06-09 10:07:31 +09:00
NIIBE Yutaka
4d7e97028e More update of USB API 2016-06-09 09:53:15 +09:00
NIIBE Yutaka
d061e6f931 USB for FS-BB48 2016-06-08 15:43:11 +09:00
NIIBE Yutaka
5f1c26ff17 USB API major change 2016-06-08 15:40:55 +09:00
NIIBE Yutaka
78718e57df Move files 2016-06-02 11:01:11 +09:00
NIIBE Yutaka
a756987d2a Fix chx_fatal 2016-06-01 07:47:58 +09:00
NIIBE Yutaka
b6e3a1aba1 Relicense ADC driver with GPLv3+ plus EXCEPTION 2016-05-31 21:41:40 +09:00
NIIBE Yutaka
c79a41870a Version 0.12 2016-05-31 15:18:10 +09:00
NIIBE Yutaka
4889a5386b STM32F030: Fix use of vector on RAM 2016-05-31 15:12:55 +09:00
NIIBE Yutaka
e02f2e71e6 Fix f2a8b01607 2016-05-31 14:18:12 +09:00
NIIBE Yutaka
1fa89d1754 Change USB API a bit 2016-05-31 13:13:14 +09:00
NIIBE Yutaka
03a1d46c08 Fix sys-stm32f103.h 2016-05-31 12:00:25 +09:00
NIIBE Yutaka
3a4e1f2bd5 Cleanup of sys and its macro 2016-05-31 11:49:01 +09:00
NIIBE Yutaka
421fd8019b ; ABOUT-SYS 2016-05-30 20:34:06 +09:00
NIIBE Yutaka
e8eaeced77 Update USB for stm32f103 2016-05-30 20:11:18 +09:00
NIIBE Yutaka
1ae3caf7fc USB cleanup 2016-05-30 20:06:43 +09:00
NIIBE Yutaka
a933eebfd5 Update for STM32F103 2016-05-30 15:13:55 +09:00
NIIBE Yutaka
fae4c58d99 AES table is included in sys-stm32f103.c 2016-05-30 14:57:51 +09:00
NIIBE Yutaka
9f16e5e051 consolidate mcu-chip specific code 2016-05-30 14:57:10 +09:00
NIIBE Yutaka
b90e58f763 Move CHIP specific things to mcu/ 2016-05-30 14:39:02 +09:00
NIIBE Yutaka
8209f38755 example-fs-bb48: Add flash ROM handling 2016-05-30 14:06:18 +09:00
NIIBE Yutaka
781ad1847c example-fs-bb48: rm crc32.h 2016-05-27 17:29:36 +09:00
NIIBE Yutaka
8eb2130664 example-fs-bb48: rm crc32.h 2016-05-27 17:29:08 +09:00
NIIBE Yutaka
960921f537 example-fs-bb48: SYS implementation 2016-05-27 17:17:44 +09:00
NIIBE Yutaka
f2a8b01607 Fix IDLE thread 2016-05-27 16:19:02 +09:00
NIIBE Yutaka
890d108114 Add document for ABOUT-SYS 2016-05-27 11:22:29 +09:00
NIIBE Yutaka
5f57222b73 Move clk_gpio_init to mcu/ 2016-05-26 17:40:47 +09:00
NIIBE Yutaka
d81767b7c7 example-fs-bb48: Only use LS-8-bit 2016-05-26 17:29:06 +09:00
NIIBE Yutaka
91823d0fc1 Move kl_sim.h 2016-05-26 10:21:30 +09:00
NIIBE Yutaka
51cd47c3b7 example-fs-bb48: ADC use DIV1 2016-05-26 09:54:44 +09:00
NIIBE Yutaka
cf81e7a6dc example-fs-bb48: ADC added 2016-05-26 09:50:07 +09:00
NIIBE Yutaka
2578fc0f30 Update example-fs-bb48 2016-05-24 17:34:20 +09:00
NIIBE Yutaka
2704416c38 Fix PSR handling (ORRS instruction changes PSR) 2016-05-23 20:15:47 +09:00
NIIBE Yutaka
77255b0c1d Fix chopstx_poll 2016-05-23 17:45:10 +09:00
NIIBE Yutaka
eeb354119c Change example-cdc 2016-05-23 17:42:21 +09:00
NIIBE Yutaka
72c3d59555 Change example-fs-bb48 2016-05-23 17:42:01 +09:00
NIIBE Yutaka
8ba91f5db6 Fix example-fs-bb48 to support 16 endpoints 2016-05-23 17:36:31 +09:00
NIIBE Yutaka
b6603f6771 Update example-fs-bb48 2016-05-23 13:48:24 +09:00
NIIBE Yutaka
ee92bb15b3 Remove deprecated API 2016-05-23 13:00:33 +09:00
NIIBE Yutaka
5458b77d36 Version 0.11 2016-05-19 12:22:30 +09:00
NIIBE Yutaka
03bba13005 eventflag API addtiion 2016-05-19 11:48:01 +09:00
NIIBE Yutaka
1b0fe5a6e8 Add eventflag_set_poll_desc 2016-05-18 21:32:32 +09:00
NIIBE Yutaka
5e33e7f468 fix eventflag 2016-05-18 17:00:25 +09:00
NIIBE Yutaka
db413813b6 eventflag rewrite 2016-05-18 16:52:00 +09:00
NIIBE Yutaka
7f009dbb5d update ChangeLog 2016-05-18 14:43:30 +09:00
NIIBE Yutaka
cea3200e48 Cleanup chopstx.c 2016-05-18 13:27:00 +09:00
NIIBE Yutaka
d93206882d Fix mutex_lock and join 2016-05-18 11:40:15 +09:00
NIIBE Yutaka
a17d12192f Fix example-cdc more 2016-05-18 09:55:23 +09:00
NIIBE Yutaka
4c1aa50f13 Fix example-cdc 2016-05-18 08:51:50 +09:00
NIIBE Yutaka
cf76b0bf13 example-cdc cleanup more 2016-05-17 21:33:58 +09:00
NIIBE Yutaka
76cbff737b example-cdc cleanup 2016-05-17 20:49:17 +09:00
NIIBE Yutaka
dce6c70ffc more fix for chopstx_poll 2016-05-17 17:51:41 +09:00
NIIBE Yutaka
3651aa64b4 ll_dequeue for PX only when not ready 2016-05-16 20:37:33 +09:00
NIIBE Yutaka
98977937cb fix chx_wakeup 2016-05-16 18:00:41 +09:00
NIIBE Yutaka
06d046b963 Improve system routines API for STM32F103 2016-05-16 14:59:05 +09:00
NIIBE Yutaka
b7c6dadcfb Fix IRQ handling and improve cancellation implementation 2016-05-16 14:50:04 +09:00
NIIBE Yutaka
a82acac8df Bug fix for interrupt preemption 2016-05-13 22:27:56 +09:00
NIIBE Yutaka
206f2a5f07 Fix intr_wait 2016-05-13 17:51:12 +09:00
NIIBE Yutaka
5046dd45f2 IRQ handling is now merged into polling 2016-05-13 16:35:35 +09:00
NIIBE Yutaka
db6e668524 more fixes for chopstx_poll 2016-05-13 14:52:38 +09:00
NIIBE Yutaka
daa7aebd6f Add READY field for chx_poll_XXX so that we can check if it's ready 2016-05-13 14:22:12 +09:00
NIIBE Yutaka
5fc2617ae5 Fix changelog 2016-05-13 11:11:01 +09:00
NIIBE Yutaka
fabd271196 Update example-cdc 2016-05-12 18:14:47 +09:00
NIIBE Yutaka
5730641ffd Bug fixes for Cortex-M3 and chopstx_poll 2016-05-12 18:12:52 +09:00
NIIBE Yutaka
5c1638c023 Fix mutex init 2016-05-12 11:17:17 +09:00
NIIBE Yutaka
420bd135af Adding ADC example for FS-BB48 2016-05-11 12:34:17 +09:00
NIIBE Yutaka
a538113c07 change poll behavior 2016-04-24 12:24:36 +09:00
NIIBE Yutaka
8668c8a88a update sys.c in examples 2016-04-22 17:21:50 +09:00
NIIBE Yutaka
fba1dc05ea Clean up FS-BB48 example 2016-04-22 17:21:29 +09:00
NIIBE Yutaka
1b12a78054 Modify chopstx_poll API 2016-04-22 13:42:01 +09:00
NIIBE Yutaka
5d40ffbffa Implement chopstx_poll (2) 2016-04-21 16:10:06 +09:00
NIIBE Yutaka
06d28b62fb Implement chopstx_poll 2016-04-21 15:59:34 +09:00
NIIBE Yutaka
437b2dc43c Update for STM32 2016-04-20 17:30:41 +09:00
NIIBE Yutaka
3eac245981 fix 2016-04-19 16:40:25 +09:00
NIIBE Yutaka
7c2cdaa6e4 Example for FS-BB48 to compute CRC32. 2016-04-19 15:58:26 +09:00
NIIBE Yutaka
0bbb43dd3a Fix USB driver and example 2016-04-18 17:23:10 +09:00
NIIBE Yutaka
82749ab97a Add support for FS-BB48 2016-04-18 11:46:14 +09:00
NIIBE Yutaka
92e17d3bdf USB stack for STM32F103 improvement 2016-04-07 14:52:39 +09:00
NIIBE Yutaka
674c19c495 SVC is required for Cortex-M3 2016-04-07 14:36:41 +09:00
NIIBE Yutaka
35426d7715 Fix MSP initial value and improve chx_sched 2016-04-07 09:59:13 +09:00
NIIBE Yutaka
6db2dd96c5 New function: chopstx_poll 2016-04-06 21:04:24 +09:00
NIIBE Yutaka
5e6a433457 New struct: chx_qh 2016-04-06 20:34:28 +09:00
NIIBE Yutaka
fa8dd7afc8 Don't use SVC for context switch 2016-04-06 19:49:18 +09:00
NIIBE Yutaka
8e40065311 Initialization of chx_spinlock 2016-04-05 19:27:25 +09:00
NIIBE Yutaka
a99c5c6048 fix struct NVIC 2016-04-05 19:17:44 +09:00
NIIBE Yutaka
e092a56c17 Fix USB GET 2016-03-15 10:31:16 +09:00
NIIBE Yutaka
25e5f21847 AAPCS stack alignment 2016-03-08 20:27:24 +09:00
NIIBE Yutaka
90ac7f7c13 update usb stack from Gnuk development branch 2016-03-08 20:20:49 +09:00
NIIBE Yutaka
fd8aee3cb0 CDC to be echo service. 2015-11-05 13:54:49 +09:00
NIIBE Yutaka
a30a069ed8 Version 0.10 2015-09-15 10:39:36 +09:00
NIIBE Yutaka
8fed803085 bug fixes around cancel/join/exit 2015-09-15 10:26:40 +09:00
NIIBE Yutaka
4705e2fb15 fix cancellation 2015-09-11 17:04:28 +09:00
NIIBE Yutaka
14ad395523 Version 0.09 2015-09-10 20:22:32 +09:00
NIIBE Yutaka
acd4460a6e Update API doc 2015-09-09 17:06:51 +09:00
NIIBE Yutaka
79b13fb4a9 Cancellation fixes 2015-09-09 17:04:59 +09:00
NIIBE Yutaka
e9521648d5 move exception handling routines 2015-09-09 11:55:17 +09:00
NIIBE Yutaka
2bd7a8e6db move svc, preempt, and sched 2015-09-09 11:35:20 +09:00
NIIBE Yutaka
c57b13bedc factor out chx_prio_init 2015-09-09 11:06:52 +09:00
NIIBE Yutaka
06e4459c21 factoring: systick 2015-09-09 09:47:25 +09:00
NIIBE Yutaka
baef99bf11 fix white spaces 2015-09-08 17:19:14 +09:00
NIIBE Yutaka
1b25cc5dcb fix more spin lock 2015-09-08 17:14:43 +09:00
NIIBE Yutaka
ee3c5d4e6f prepare kkojima's patch for Cortex-A7 2015-09-08 17:06:53 +09:00
NIIBE Yutaka
80408902d7 fix spin-locking of INTR_TOP 2015-09-08 14:46:11 +09:00
NIIBE Yutaka
f6d79e6821 Add Mateusz Zalega 2015-09-07 17:10:42 +09:00
NIIBE Yutaka
014dbf25f6 Add example-primer2 2015-09-07 17:06:05 +09:00
NIIBE Yutaka
41610443d4 Netrokey Start change 2015-09-07 15:52:38 +09:00
NIIBE Yutaka
46468760a3 Nitrokey start support 2015-09-04 17:09:56 +09:00
NIIBE Yutaka
85ef4a5391 Fix for Nitrokey-start 2015-09-04 16:43:45 +09:00
Mateusz Zalega
8650bde8a0 board: add Nitrokey Start
Signed-off-by: Mateusz Zalega <mateusz@nitrokey.com>
2015-09-04 16:38:01 +09:00
NIIBE Yutaka
6e7334dcff Fix the score about A and tone-table change 2015-08-08 13:50:20 +09:00
NIIBE Yutaka
04a948024a Celebrate Happy Hacking Day. 2015-08-06 11:10:48 +09:00
NIIBE Yutaka
1bbbaabe0d Add a speaker 2015-08-06 11:02:34 +09:00
NIIBE Yutaka
218102c5c4 Version 0.08 2015-07-31 17:58:20 +09:00
NIIBE Yutaka
2c9e6b69d2 update example-fsm-55 2015-07-31 17:56:35 +09:00
NIIBE Yutaka
1d38c24233 Add Nucleo 2015-07-30 20:35:21 +09:00
NIIBE Yutaka
a9de53c36b board update, adding ST Dongle 2015-07-29 17:06:17 +09:00
NIIBE Yutaka
83486efd5f update USB driver 2015-07-28 15:09:43 +09:00
NIIBE Yutaka
bdaae5661d Version 0.07 2015-07-15 12:09:07 +09:00
NIIBE Yutaka
2de0e2c405 Update example CDC 2015-07-15 12:04:45 +09:00
NIIBE Yutaka
d19570954e Update example for FSM-55 2015-07-15 12:03:49 +09:00
NIIBE Yutaka
44b4bf640f Update example for LED blink 2015-07-15 12:01:53 +09:00
NIIBE Yutaka
9898639165 Update Cortex-M0 boards 2015-07-15 11:48:36 +09:00
NIIBE Yutaka
cd61ff5653 share sys with example-fsm-55 2015-07-15 09:51:24 +09:00
NIIBE Yutaka
27f42c8522 ADC settings are consolidated into the driver 2015-07-14 21:31:18 +09:00
NIIBE Yutaka
a48ffaef47 fix sys.c 2015-07-14 21:26:10 +09:00
NIIBE Yutaka
27f71ff5c0 New sys.c 2015-07-14 16:10:07 +09:00
NIIBE Yutaka
3ba8234cec sys_board and stm32 primer2 2015-07-13 16:45:32 +09:00
174 changed files with 25681 additions and 4902 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
*/board.h
*/build
*/.dep
doc/chopstx.info

15
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,15 @@
image: debian:stable
before_script:
- apt-get update && apt-get -y install texi2html
pages:
stage: deploy
script:
- mkdir -p html && (cd html && texi2html ../doc/chopstx.texi)
- mv html/ public
artifacts:
paths:
- public
only:
- master

80
AUTHORS Normal file
View File

@@ -0,0 +1,80 @@
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
Kaz Kojima:
Added STM32 Primer2 support.
board/board-stm32-primer2.h
example-primer2
Kenji Rikitake:
Added ST Dongle support.
board/board-st-dongle.h
Added ST Nucleo F103 support.
board/board-st-nucleo-f103.h
Kiwamu Okabe:
Wrote an OpenOCD scirpt:
example-fsm-55/stlink-v2.cfg
Mateusz Zalega:
Added Nitrokey-Start support.
board/board-nitrokey-start.h
NIIBE Yutaka:
Wrote the library:
chopstx.c, chopstx.h,
chopstx-cortex-m.c, chopstx-cortex-m.h,
chopstx-gnu-linux.c, chopstx-gnu-linux.h,
entry.c,
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-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,
sys-stm32f0.c, sys-stm32f0.h
sys-stm32f103.c, sys-stm32f103.h,
usb-stm32f103.c, usb-mkl27z.c
Wrote the drivers:
controb/adc-mkl27z.c
Drew the logo:
chopstx.svg, chopstx.png
Wrote examples:
example-led, example-cdc, example-fsm-55, example-fs-bb48,
example-usb-serial, example-cdc-gnu-linux
Wrote board/*:
board-fst-01sz.h,
board-fst-01g.h, board-fst-01.h, board-fst-01-00.h,
board-olimex-stm32-h103.h, board-stm8s-discovery.h
board-cq-starm.h, board-stbee-mini.h, board-stbee.h,
board-stm32f0-discovery.h, board-fsm-55.h,
board-fs-bb48.h
For Free Software Initiative of Japan, wrote:
contrib/adc-stm32f103.c,
contrib/adc-gnu-linux.c
Under contract of g10 Code GmbH, wrote:
mcu/usb-usbip.c
contrib/usart-stm32f103.c
contrib/ackbtn-stm32f103.c
Paul Fertser:
Added Blue Pill support.
board/board-blue-pill.h
Szczepan Zalega:
Modified Nitrokey-Start support.
board/board-nitrokey-start.h

1300
ChangeLog

File diff suppressed because it is too large Load Diff

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

414
NEWS
View File

@@ -1,6 +1,412 @@
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
** Enhancement of driver: USART for STM32
Now, it supports smartcard communication.
* Major changes in Chopstx 1.13
Released 2018-12-19
** API fix (redefinition): chopstx_poll
In old implementations, when chopstx_poll returns by non-timeout
event, *USEC_P is not updated. Now, it is updated.
* Major changes in Chopstx 1.12
Released 2018-11-12
** Enhance API of eventflag
New function eventflag_set_mask is added, so that we can only handle
specified events. See Gnuk 1.2.12 for an example (while USB Tx is
busy, the USB thread only accepts EV_TX_FINISHED event, leaving
other events).
** Acknowledge button support for FST-01 and FST-01G
While FST-01 and FST-01G don't have any button in the original design,
it may be PA2 when user put a hall sensor or a switch.
* Major changes in Chopstx 1.11
Released 2018-10-02
** Support calling chopstx_poll with intr->ready==1
In version <= 1.10, it assumed that all events should be handled after
chopstx_poll, before calling chopstx_poll again. With having
chopstx_intr_done, it's OK now that chopstx_poll can be called again
not examining/handling all poll descriptors, but only parts of them.
** Acknowledge button change
In 1.10, the action was able to be "memorized" by the edge detector.
Now, the edge detector is disabled by ackbtn_disable, and it is
enabled by ackbtn_enable. So, the status is cleared correctly.
** New board support: FST-01SZ
It's still under development. Programming-wise, it will be kept same.
* Major changes in Chopstx 1.10
Released 2018-09-29
** Function chopstx_intr_wait is not deprecated, now
Once, it was said that it's deprecated, but it's active again
to match the new function of chopstx_intr_done.
** API change: chopstx_poll, chopstx_intr_wait, chopstx_intr_done
To avoid spurious interrupt, we introduce new function
chopstx_intr_done, which should be called after interrupt handling.
** New driver: Acknowledge button for FST-01SZ
The use case is waiting user's acknowledge. We use EXTI interrupt
feature of STM32.
* Major changes in Chopstx 1.9
Released 2018-05-09
** GD32F103 support
GD32F103 is an alternative implementation of STM32F103 by Giga Device,
which can run at 96MHz.
** Minor USB driver fix for STM32F103/GD32F103
BTABLE setting should be done at initialization, not at USB RESET.
** Minor SYS driver fix for GD32F103
flash_protect should check FLASH_CR_OPTWRE.
** Minor ADC driver change for GD32F103
ADC on GD32F103 is another implementation and its behavior is somewhat
different. It requires waits after enabling. So, we use continuous
sampling, instead of start and stop for each sample. Still, we
observe enough noise (> 4.7 bit/byte) for each ADC sampling.
* Major changes in Chopstx 1.8
Released 2018-01-19
** Minor driver API fix
In version 1.6, part of mcu/stm32f103.h was moved into mcu/cortex-m.h
and mcu/stm32.h. Now, mcu/stm32f103.h automatically includes
mcu/cortex-m.h and mcu/stm32.h, so that it doesn't break existing
applications.
* Major changes in Chopstx 1.7
Released 2017-12-19
** Fix: timer wakeup
Timer expiration had a bug. When it is waken up, the wake up doesn't
handle as a timer expiration when there are multiple threads on same
timing of expire. It confuses as if it were forced wakeup.
** New driver: USART for STM32
USART driver for STM32 is added.
* Major changes in Chopstx 1.6
Released 2017-11-24
** Fix cancellation
In Chopstx 1.4 and 1.5, cancellation doesn't work for real MCU. This
is due to the change of chx_sched interface, introduced for GNU/Linux
emulation. This bug is fixed.
** New feature: sleep mode
New function chopstx_conf_idle is added to support sleep. Note that
use of sleep by this feature requires careful preparation. For
example, enabling sleep, a board with no RESET pin cannot be debugged
by JTAG/SWD. Setting of DBGMCU_CR (0xE0042004) is required beforehand
(hardware default is zero).
** API change: chopstx_poll
This is a kind of clarification. The third argument is now an array
of constant pointers. We don't touch the array itself, just use it.
This allows having the array in read-only memory and can contribute
less use of RAM.
** USB API changes
INTR_REQ_USB is now defined by usb_lld.h. Enumeration type of
DEVICE_STATE now has USB_DEVICE_STATE_ prefix.
** USB driver change
USB suspend and wakeup events are supported for STM32F103.
* Major changes in Chopstx 1.5
Released 2017-10-10
** Stack size definition by stack-def.h
Stack size of each thread was used to be defined in ldscript.
While emulation on GNU/Linux doesn't use ldscript, it is better
to put those definitions in independent header file. Please see
example-cdc/stack-def.h and example-cdc/sample.ld.
** More support for emulation on GNU/Linux
We have SYS driver for emulation on GNU/Linux. It has flash ROM
emulation.
* Major changes in Chopstx 1.4
Released 2017-08-11
** New port: Emulation on GNU/Linux
Now, user can run Chopstx application on GNU/Linux. Its USB driver is
by USBIP. Its ADC driver is dummy with random(3).
* Major changes in Chopstx 1.3
Released 2017-02-02
** New board support: Blue Pill
It is contributed by Paul Fertser.
* Major changes in Chopstx 1.2
Released 2016-10-13
** Fix: chopstx_join
chopstx_join is now cancellation point.
* Major changes in Chopstx 1.1
Released 2016-07-01
** API change: chopstx_poll
In version 1.0, chopstx_poll has variable arguments. It found that
it's challenging for ffi or lower level C implementation, if C
compiler is new for the specific MCU target. Another example is that
a program touches FPU registers for varargs, even if no argument is
float. So, we decided to avoid use of varargs in Chopstx.
** API change: chopstx_setpriority
In version 1.0, chopstx_setpriority does not return value. It is
changed to return old value of the priority.
* Major changes in Chopstx 1.0
Released 2016-06-16
** New USB API
Now, USB driver is included in Chopstx. So, it should be good one.
It used to be the code which was derived from interrupt driven API
with callbacks. It's changed to event driven API, so that a user can
do as wish, beyond the restriction of callbacks.
** New board support: FST-01G
FST-01G is a new revision of original FST-01 with fixed pull-up of
D+ line.
* Major changes in Chopstx 0.12
Released 2016-05-31
** Provide drivers of SYS, USB and ADC
Those were only offered as examples, but now, Chopstx provides drivers
of SYS, USB, and ADC. Please note that the ADC driver is not for
general use (it's specific to NeuG to get noise). To use them, enable
variables in Makefile, like following.
------------
CHIP=stm32f103
USE_ADC = yes
USE_USB = yes
USE_SYS = yes
DEFS = -DUSE_SYS3
------------
** Removal of chopstx_usec_wait_var chopstx_wakeup_usec_wait
This API was used when we need to wait something with timeout.
Now, we have better API with chopstx_poll. Please use chopstx_poll
and chopstx_cond_signal.
* Major changes in Chopstx 0.11
Released 2016-05-19
** New feature: polling
New function chopstx_poll is added to watch multiple condition
variables, threads' exit, or IRQ, simultaneously with timeout.
** Change API of eventflag
The initialization function eventflag_init only has an argument of EV.
An eventflag can be waited with timeout or can be waited with no
timeout, as caller like. It is not determined at initialization time
now. Besides, the eventflag can be waited by any threads. Functions
to poll eventflag together with other events (cond, join, and IRQ) are
provided.
** Removal of the function chopstx_release_irq
IRQ is enabled only when a thread is blocked in polling. When it (the
thread in polling) is canceled, IRQ is disabled.
** Removal of the function chopstx_main_init
It is removed because it's too special. Please use
chopstx_setpriority instead.
** New function: chopstx_setpriority
This function is not recommended in general. It is only added to
support the usage when main thread wants to change the schedule
priority after creating other threads.
** Function chopstx_intr_wait is deprecated
Use of chopstx_poll is recommended.
** FS-BB48: Kinetis L MCU
Support for FS-BB48 board with Kinetis L MCU is added.
** No HardFault at context switch on Cortex-M0
By its design, Chopstx does context switch holding the scheduler lock.
This is implemented with the feature of BASEPRI on Cortex-M3. Because
Cortex-M0 doesn't have support of BASEPRI, the context switch (before
version 0.11) always caused HardFault exception. Since Cortex-M0
doesn't have complex exception mechism of ICI/IT (which is supported
on Cortex-M3), it is actually possible to implement the context switch
in user mode. This is done.
** New sys.c (3.0)
Don't touch NVIC in usb_lld_sys_init.
* Major changes in Chopstx 0.10
Released 2015-09-15
** Thread cancellation bug fix
Thread cancellation didn't work well with 0.09 because
of initial configuration mistake. It's fixed.
** Interrupt handler bug fix
Interrupt handler wasn't unregistered on exit well.
It's fixed.
* Major changes in Chopstx 0.09
Released 2015-09-10
** New board support: Nitrokey-Start
It is contributed by Mateusz Zalega.
** Thread cancellation
Add new API: chopstx_setcancelstate.
* Major changes in Chopstx 0.08
Released 2015-07-31
** New board support: ST Nucleo F103
It is contributed by Kenji Rikitake.
** New board support: ST Dongle
It is contributed by Kenji Rikitake.
It's the ST-Link/V2-1 part of ST Nucleo F103.
* Major changes in Chopstx 0.07
Released 2015-07-15
** New Board macro definitions
Each board-*.h should have BOARD_ID and BOARD_NAME now.
FLASH_PAGE_SIZE and NEUG_ADC_SETTING2_* are deprecated.
** New sys.c (2.1)
Flash memory size is probed at runtime now. System
service flash pages now include sys_board_id and sys_board_name.
* Major changes in Chopstx 0.06
Released 2015-07-08
@@ -111,11 +517,11 @@ Vectored Interrupt Controller (NVIC), in the ARM v7-M Architecture
Reference Manual. The subsection, B3.4.1, Theory of operation,
explains how it works.
** gpio_init change
Now, gpi_init support AFIO mapping and another GPIO (GPIO_OTHER)
settings.
Local Variables:
mode: outline
End:
# Local Variables:
# mode: outline
# End:

47
README
View File

@@ -1,21 +1,34 @@
Chopstx - Threads and only Threads
Version 0.06
2015-07-08
Version 1.18
2019-12-30
Niibe Yutaka
Flying Stone Technology
What's Chopstx?
===============
Chopstx is an RT thread library for STM32F103 (ARM Cortex-M3)
or STM32F0 (ARM Cortex-M0).
Chopstx is an RT thread library for STM32F103 and GD32F103 (ARM
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 stacks,
Chopstx just offers a simple RT thread library.
While most RTOSes come with many features, drivers, and protocol
stacks, Chopstx just offers a simple RT thread library.
With Chopstx, interrupt handling is also done by a thread. This
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
handle multiple events by a single thread.
Note that this library is _not_ related to the hand game:
https://en.wikipedia.org/wiki/Chopsticks_(hand_game)
Thanks to Yao Wei and Enrico Zini for giving me an opportunity
visiting the wiki page above, when my children were playing the game.
License
=======
@@ -28,21 +41,33 @@ EXCEPTION.
Example code
============
We have two examples in this distribution, LED blinker and
USB CDC-ACM function. You can build it like:
We have some examples in this distribution; Useful ones are LED
blinker and USB CDC-ACM device. For STM32F103, you can build it USB
CDC-ACM demo by:
$ cd example-cdc
$ ln -s ../board/board-olimex-stm32-h103.h board.h
$ ln -sf ../board/board-olimex-stm32-h103.h board.h
$ make
If you want to try GD32F103, Add -DMHZ=96 to DEFS in Makefile.
For a specific board named FSM-55, an example of LED matrix dynamic
driver is provided. See the directory: example-fsm-55.
For STM32 Primer2, see the directory: example-primer2.
Future Works
============
Convenience function to determine bottom of thread stack, thread local
storage and support of interface like poll/select would be next thing
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.
Experimental SMP port for Cortex-A7 is under development. For SMP,
more careful considerations for shared access to objects of struct
chx_pq is needed. So, modifications required will not be small.
--

View File

@@ -1 +1 @@
release/0.06
release/1.18

8
adc.h Normal file
View File

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

42
board/board-blue-pill-g.h Normal file
View File

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

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

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

View File

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "CQ STARM"
#define BOARD_ID 0xc5480875
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
@@ -6,8 +10,7 @@
#define GPIO_LED_BASE GPIOC_BASE
#define GPIO_LED_SET_TO_EMIT 6
#undef GPIO_USB_BASE
#undef GPIO_USB_CLEAR_TO_ENABLE
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
#define GPIO_OTHER_BASE GPIOA_BASE
/*
@@ -42,5 +45,3 @@
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN|RCC_APB2ENR_IOPCEN)
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST|RCC_APB2RSTR_IOPCRST)
/* NeuG settings for ADC2 is default (PA0: Analog IN0, PA1: Analog IN1). */

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

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

View File

@@ -1,3 +1,6 @@
#define BOARD_NAME "FSM-55"
#define BOARD_ID 0x83433c76
/*
* Running at 48MHz with HSI as clock source.
*
@@ -6,8 +9,6 @@
/* __ARM_ARCH_6M__ */
#define FLASH_PAGE_SIZE 1024
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 12
#define STM32_HSICLK 8000000
@@ -30,13 +31,12 @@
#define RCC_ENR_IOP_EN (RCC_AHBENR_IOPAEN | RCC_AHBENR_IOPFEN)
#define RCC_RSTR_IOP_RST (RCC_AHBRSTR_IOPARST | RCC_AHBRSTR_IOPFRST)
/* ??? NeuG settings for ADC2 is default (PA0: Analog IN0, PA1: Analog IN1). */
/*
* Port F setup.
* PF0 - USER Button
* PF1 - SPEAKER
*/
#define VAL_GPIO_OTHER_MODER 0x00000000 /* Input Pin0 */
#define VAL_GPIO_OTHER_OTYPER 0x00000000
#define VAL_GPIO_OTHER_MODER 0x00000004 /* Input Pin0, Output Pin1 */
#define VAL_GPIO_OTHER_OTYPER 0x00000000 /* Push-Pull Pin1 */
#define VAL_GPIO_OTHER_OSPEEDR 0x00000000
#define VAL_GPIO_OTHER_PUPDR 0x00000001 /* Pull-up Pin0 */
#define VAL_GPIO_OTHER_PUPDR 0x00000009 /* Pull-up Pin0, Pull-down Pin1 */

View File

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "FST-01-00"
#define BOARD_ID 0x613870a9
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
@@ -15,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
@@ -27,5 +31,3 @@
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPAEN
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPARST
/* NeuG settings for ADC2 is default (PA0: Analog IN0, PA1: Analog IN1). */

View File

@@ -1,4 +1,9 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "FST-01"
#define BOARD_ID 0x696886af
/* echo -n "FST-01" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
@@ -10,19 +15,6 @@
#define GPIO_USB_SET_TO_ENABLE 10
#undef GPIO_OTHER_BASE
/* For pin-cir settings of Gnuk */
#define TIMx TIM2
#define INTR_REQ_TIM TIM2_IRQ
#define AFIO_EXTICR_INDEX 0
#define AFIO_EXTICR1_EXTIx_Py AFIO_EXTICR1_EXTI2_PA
#define EXTI_PR EXTI_PR_PR2
#define EXTI_IMR EXTI_IMR_MR2
#define EXTI_FTSR_TR EXTI_FTSR_TR2
#define INTR_REQ_EXTI EXTI2_IRQ
#define ENABLE_RCC_APB1
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM2EN
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM2RST
/*
* Port A setup.
* PA0 - input with pull-up (TIM2_CH1): AN0 for NeuG
@@ -33,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
@@ -61,10 +53,35 @@
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN)
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST)
/* NeuG settings for ADC2. */
#define NEUG_ADC_SETTING2_SMPR1 0
#define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5) \
| ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5)
#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9)
#define NEUG_ADC_SETTING2_NUM_CHANNELS 2
/*
* Board specific information other than clock and GPIO initial
* setting should not be in board-*.h, but each driver should include
* information by itself.
*
* Please see NeuG's ADC driver how board specific handling is done.
*
* Given the situation of Chopstx's boards support, which is not that
* huge, this works well. If scalability and flexibility will matter,
* we will need something like device tree in which boot process can
* pass information to application program.
*
* Following constants are here, because experimental CIR driver is
* written before this design decision of Chopstx.
*
* Those will be removed soon, once such an driver will be improved
* in new style.
*/
#if defined(PINPAD_CIR_SUPPORT)
/* For pin-cir settings of Gnuk */
#define TIMx TIM2
#define INTR_REQ_TIM TIM2_IRQ
#define AFIO_EXTICR_INDEX 0
#define AFIO_EXTICR1_EXTIx_Py AFIO_EXTICR1_EXTI2_PA
#define EXTI_PR EXTI_PR_PR2
#define EXTI_IMR EXTI_IMR_MR2
#define EXTI_FTSR_TR EXTI_FTSR_TR2
#define INTR_REQ_EXTI EXTI2_IRQ
#define ENABLE_RCC_APB1
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM2EN
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM2RST
#endif

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

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

43
board/board-fst-01sz.h Normal file
View File

@@ -0,0 +1,43 @@
#define BOARD_NAME "FST-01SZ"
#define BOARD_ID 0x7e6fb084
/* echo -n "FST-01SZ" | sha256sum | sed -e 's/^.*\(........\) -$/\1/' */
#define MCU_STM32F1_GD32F1 1
#define STM32_USBPRE STM32_USBPRE_DIV2
#define STM32_ADCPRE STM32_ADCPRE_DIV8
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 8
#define STM32_HSECLK 12000000
#define GPIO_LED_BASE GPIOA_BASE
#define GPIO_LED_SET_TO_EMIT 8
#define GPIO_USB_BASE GPIOA_BASE
#undef GPIO_OTHER_BASE
/*
* Port A setup.
* PA0 - input with pull-up: AN0 for NeuG
* PA1 - input with pull-up: AN1 for NeuG
* PA3 - input with pull-up: Hall effect sensor output
* PA8 - Push pull output 10MHz 0 default (LED 1:ON 0:OFF)
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
* ------------------------ Default
* PAx - input with pull-up.
*/
#define VAL_GPIO_LED_ODR 0xFFFFE6FF
#define VAL_GPIO_LED_CRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIO_LED_CRH 0x88811881 /* PA15...PA8 */
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPAEN
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPARST
/*
* Board specific information other than clock and GPIO initial
* setting should not be in board-*.h, but each driver should include
* such specific information by itself.
*/

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

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

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

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "Maple Mini"
#define BOARD_ID 0x7a445272
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
@@ -26,15 +30,13 @@
/*
* 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 */
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN)
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST)
/* NeuG settings for ADC2 is default (PA0: Analog IN0, PA1: Analog IN1). */

View File

@@ -0,0 +1,60 @@
#define BOARD_NAME "NITROKEY-START"
#define BOARD_ID 0xad1e7ebd
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
#define STM32_HSECLK 12000000
#define GPIO_LED_BASE GPIOB_BASE
#define GPIO_LED_SET_TO_EMIT 0
#define GPIO_USB_BASE GPIOA_BASE
#define GPIO_USB_SET_TO_ENABLE 15
#undef GPIO_OTHER_BASE
/*
* Port A setup.
* PA0 - input with pull-up: AN0 for NeuG
* PA1 - input with pull-up: AN1 for NeuG
* PA2 - floating input
* PA3 - floating input
* PA4 - floating input
* PA5 - floating input
* PA6 - floating input
* PA7 - Push pull output (Red LED1 1:ON 0:OFF)
* PA8 - floating input (smartcard, SCDSA)
* PA9 - floating input
* 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) default 1
* ------------------------ Default
* PA8 - input with pull-up.
* PA9 - floating input.
* PA10 - floating input.
* PA13 - input with pull-up.
* PA14 - input with pull-up.
* PA15 - Push pull output (USB 1:ON 0:OFF)
*/
#define VAL_GPIO_USB_ODR 0xFFFFE77F
#define VAL_GPIO_USB_CRL 0x34444488 /* PA7...PA0 */
#define VAL_GPIO_USB_CRH 0x38811444 /* PA15...PA8 */
/*
* Port B setup.
* PB0 - Push pull output (Green LED2 1:ON 0:OFF)
* ------------------------ Default
* PBx - input with pull-up.
*/
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
#define VAL_GPIO_LED_CRL 0x88888883 /* PA7...PA0 */
#define VAL_GPIO_LED_CRH 0x88888888 /* PA15...PA8 */
#define RCC_ENR_IOP_EN \
(RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN)
#define RCC_RSTR_IOP_RST \
(RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | RCC_APB2RSTR_AFIORST)
#define AFIO_MAPR_SOMETHING AFIO_MAPR_SWJ_CFG_JTAGDISABLE

View File

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "Olimex STM32-H103"
#define BOARD_ID 0xf92bb594
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
@@ -16,22 +20,14 @@
* 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 */
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPCEN
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPCRST
/* NeuG settings for ADC2. */
#define NEUG_ADC_SETTING2_SMPR1 ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5) \
| ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5)
#define NEUG_ADC_SETTING2_SMPR2 0
#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11)
#define NEUG_ADC_SETTING2_NUM_CHANNELS 2

34
board/board-st-dongle.h Normal file
View File

@@ -0,0 +1,34 @@
#define BOARD_NAME "ST Dongle"
/* echo -n "ST Dongle" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
#define BOARD_ID 0x2cd4e471
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
#define STM32_HSECLK 8000000
#define GPIO_LED_BASE GPIOA_BASE
#define GPIO_LED_SET_TO_EMIT 9
#define GPIO_USB_BASE GPIOA_BASE
#define GPIO_USB_SET_TO_ENABLE 15
#undef GPIO_OTHER_BASE
/*
* Port A setup.
* PA0 - input with pull-up. AN0
* PA1 - input with pull-up. AN1
* 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) default 1
* ------------------------ Default
* PAx - input with pull-up
*/
#define VAL_GPIO_LED_ODR 0xFFFFE7FF
#define VAL_GPIO_LED_CRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIO_LED_CRH 0x38811838 /* PA15...PA8 */
#define RCC_ENR_IOP_EN RCC_APB2ENR_IOPAEN
#define RCC_RSTR_IOP_RST RCC_APB2RSTR_IOPARST

View File

@@ -0,0 +1,76 @@
#define BOARD_NAME "ST Nucleo F103"
#define BOARD_ID 0x9b87c16d
/*
* Please add X3 and USB cable to ST Nucleo F103.
*
* Solder X3 XTAL of 8MHz (and put C33 and C34 of 22pF).
* Solder the bridges for R35 and R37, since it's 0 ohm.
*
* (Optional) Remove SB54 and SB55.
*
* At CN10, connect USB cable
* Vbus RED --> 10 NC ----------> CN7 (6 E5V)
* D+ GREEN --> 12 PA12 ---[1K5]--> CN6 (4 3V3)
* D- WHITE --> 14 PA11
* 16 PB12 (USART3-CK) ---> smartcard CK
* 18
* GND BLACK --> 20 GND
*/
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
#define STM32_HSECLK 8000000
#define GPIO_LED_BASE GPIOA_BASE
#define GPIO_LED_SET_TO_EMIT 5
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
#define GPIO_OTHER_BASE GPIOB_BASE
/*
* Port A setup.
* PA0 - Input with pull-up USART2-CTS
* PA1 - Alternate function push pull output 2MHz USART2-RTS
* PA2 - Alternate function push pull output 2MHz USART2-TX
* PA3 - Input with pull-up USART2-RX
* PA4 - Alternate function push pull output 2MHz USART2-CK
* PA5 - Push pull output 2MHz (LED 1:ON 0:OFF)
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
* ------------------------ Default
* PAx - input with pull-up
*/
#define VAL_GPIO_LED_ODR 0xFFFFE7FF
#define VAL_GPIO_LED_CRL 0x882A8AA8 /* PA7...PA0 */
#define VAL_GPIO_LED_CRH 0x88811888 /* PA15...PA8 */
/*
* Port B setup.
* PB0 - input with pull-up: AN8 for NeuG
* PB1 - input with pull-up: AN9 for NeuG
* ---
* ---
* PB4 - Input with pull-up: Card insertion detect: 0 when detected
* ---
* PB6 - Output push pull 2MHz: Vcc for card: default 0
* ---
* PB8 - Output push pull 2MHz: Vpp for card: default 0
* PB9 - Output push pull 2MHz: RST for card: default 0
* PB10 - Alternate function open-drain output 50MHz USART3-TX
* PB11 - Input with pull-up USART3-RX
* PB12 - Alternate function push pull output 50MHz USART3-CK
* PB13 - Input with pull-up USART3-CTS
* PB14 - Alternate function push pull output 50MHz USART3-RTS
* ---
* ------------------------ Default
* PBx - input with pull-up.
*/
#define VAL_GPIO_OTHER_ODR 0xFFFFFCBF
#define VAL_GPIO_OTHER_CRL 0x82888888 /* PB7...PB0 */
#define VAL_GPIO_OTHER_CRH 0x8B8B8F22 /* PB15...PB8 */
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | 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

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "STBee Mini"
#define BOARD_ID 0x1f341961
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
@@ -48,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
@@ -108,11 +112,3 @@
#define AFIO_MAPR_SOMETHING AFIO_MAPR_SWJ_CFG_DISABLE
/* NeuG settings for ADC2. */
#define NEUG_ADC_SETTING2_SMPR1 0
#define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5) \
| ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5)
#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2)
#define NEUG_ADC_SETTING2_NUM_CHANNELS 2

View File

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 2048
#define BOARD_NAME "STBee"
#define BOARD_ID 0x945c37e8
#define MCU_STM32F1 1
#define STM32F10X_HD /* High-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
@@ -25,17 +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 */
/* NeuG settings for ADC2. */
#define NEUG_ADC_SETTING2_SMPR1 ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5) \
| ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5)
#define NEUG_ADC_SETTING2_SMPR2 0
#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11)
#define NEUG_ADC_SETTING2_NUM_CHANNELS 2

View File

@@ -1,11 +1,15 @@
#define FLASH_PAGE_SIZE 2048
#define BOARD_NAME "STM32 Primer2"
#define BOARD_ID 0x21e5798d
#define MCU_STM32F1 1
#define STM32F10X_HD /* High-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 6
#define STM32_HSECLK 12000000
#define GPIO_LED_BASE GPIOE_BASE
#define GPIO_LED_CLEAR_TO_EMIT 0
#define GPIO_LED_SET_TO_EMIT 0
#define GPIO_USB_BASE GPIOD_BASE
#define GPIO_USB_CLEAR_TO_ENABLE 3
#define GPIO_OTHER_BASE GPIOA_BASE
@@ -14,22 +18,23 @@
* Port A setup.
* PA0 - input with pull-up. AN0
* PA1 - input with pull-up. AN1
* PA8 - Input with pull-down (PBUTTON).
* 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_OTHER_ODR 0xFFFFE7FF
#define VAL_GPIO_OTHER_ODR 0xFFFFE6FF
#define VAL_GPIO_OTHER_CRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIO_OTHER_CRH 0x88811888 /* PA15...PA8 */
/*
* 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 */
@@ -37,10 +42,14 @@
* Port E setup.
* PE0 - Push pull output (LED 1:ON 0:OFF)
* PE1 - Push pull output (LED 1:ON 0:OFF)
* PE3 - Input with pull-down (JOYSTICK L).
* PE4 - Input with pull-down (JOYSTICK R).
* PE5 - Input with pull-down (JOYSTICK U).
* PE6 - Input with pull-down (JOYSTICK D).
* ------------------------ Default
* PEx - input with pull-up
*/
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
#define VAL_GPIO_LED_ODR 0xFFFFFF87
#define VAL_GPIO_LED_CRL 0x88888833 /* PE7...PE0 */
#define VAL_GPIO_LED_CRH 0x88888888 /* PE15...PE8 */
@@ -48,5 +57,3 @@
(RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_IOPEEN)
#define RCC_RSTR_IOP_RST \
(RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPDRST | RCC_APB2RSTR_IOPERST)
/* NeuG settings for ADC2 is default (PA0: Analog IN0, PA1: Analog IN1). */

View File

@@ -1,3 +1,6 @@
#define BOARD_NAME "STM32F0 Discovery"
#define BOARD_ID 0xde4b4bc1
/*
* Running at 48MHz with HSI as clock source.
*
@@ -6,8 +9,6 @@
/* __ARM_ARCH_6M__ */
#define FLASH_PAGE_SIZE 1024
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 12
#define STM32_HSICLK 8000000

View File

@@ -1,4 +1,8 @@
#define FLASH_PAGE_SIZE 1024
#define BOARD_NAME "STM8S Discovery"
#define BOARD_ID 0x2f0976bb
#define MCU_STM32F1 1
#define STM32F10X_MD /* Medium-density device */
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
#define STM32_PLLMUL_VALUE 9
@@ -6,25 +10,9 @@
#define GPIO_LED_BASE GPIOA_BASE
#define GPIO_LED_SET_TO_EMIT 8
#undef GPIO_USB_BASE
#undef GPIO_USB_CLEAR_TO_ENABLE
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
#define GPIO_OTHER_BASE GPIOB_BASE
/* For pin-cir settings of Gnuk */
#define TIMx TIM3
#define INTR_REQ_TIM TIM3_IRQ
#define AFIO_EXTICR_INDEX 1
#define AFIO_EXTICR1_EXTIx_Py AFIO_EXTICR2_EXTI5_PB
#define EXTI_PR EXTI_PR_PR5
#define EXTI_IMR EXTI_IMR_MR5
#define EXTI_FTSR_TR EXTI_FTSR_TR5
#define INTR_REQ_EXTI EXTI9_5_IRQ
#define ENABLE_RCC_APB1
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM3EN
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM3RST
#define AFIO_MAPR_SOMETHING AFIO_MAPR_TIM3_REMAP_PARTIALREMAP
/* Remap (PB4, PB5) -> (TIM3_CH1, TIM3_CH2) */
/*
* Port A setup.
* PA0 - input with pull-up. AN0
@@ -44,8 +32,6 @@
#define RCC_RSTR_IOP_RST \
(RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | RCC_APB2RSTR_AFIORST)
/* NeuG settings for ADC2 is default (PA0: Analog IN0, PA1: Analog IN1). */
/*
* Port B setup.
* PB4 - (TIM3_CH1) input with pull-up
@@ -56,3 +42,20 @@
#define VAL_GPIO_OTHER_ODR 0xFFFFFFFE
#define VAL_GPIO_OTHER_CRL 0x88888888 /* PB7...PB0 */
#define VAL_GPIO_OTHER_CRH 0x88888888 /* PB15...PB8 */
#if defined(PINPAD_CIR_SUPPORT)
#define TIMx TIM3
#define INTR_REQ_TIM TIM3_IRQ
#define AFIO_EXTICR_INDEX 1
#define AFIO_EXTICR1_EXTIx_Py AFIO_EXTICR2_EXTI5_PB
#define EXTI_PR EXTI_PR_PR5
#define EXTI_IMR EXTI_IMR_MR5
#define EXTI_FTSR_TR EXTI_FTSR_TR5
#define INTR_REQ_EXTI EXTI9_5_IRQ
#define ENABLE_RCC_APB1
#define RCC_APBnENR_TIMxEN RCC_APB1ENR_TIM3EN
#define RCC_APBnRSTR_TIMxRST RCC_APB1RSTR_TIM3RST
#define AFIO_MAPR_SOMETHING AFIO_MAPR_TIM3_REMAP_PARTIALREMAP
/* Remap (PB4, PB5) -> (TIM3_CH1, TIM3_CH2) */
#endif

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

@@ -0,0 +1,708 @@
/*
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
* for Cortex-M0/M3/M4
*
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 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.
*
*/
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)
{
asm volatile ("dmb" : : : "memory");
}
/* Saved registers on the stack. */
struct chx_stack_regs {
uint32_t reg[8]; /* r0, r1, r2, r3, r12, lr, pc, xpsr */
};
/*
* Constants for ARM.
*/
#define REG_SP 8
#define REG_R0 0
#define REG_LR 5
#define REG_PC 6
#define REG_XPSR 7
#define INITIAL_XPSR 0x01000000 /* T=1 */
/*
* Exception priority: lower has higher precedence.
*
* Cortex-M3
* =====================================
* Prio 0x30: svc
* ---------------------
* Prio 0x40: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0xb0: systick, external interrupt
* Prio 0xc0: pendsv
* =====================================
*
* Cortex-M0
* =====================================
* Prio 0x00: thread temporarily inhibiting schedule for critical region
* ...
* Prio 0x40: systick, external interrupt
* Prio 0x80: pendsv
* Prio 0x80: svc
* =====================================
*/
#define CPU_EXCEPTION_PRIORITY_CLEAR 0
#if defined(__ARM_ARCH_6M__)
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
/* ... */
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0xb0
#define CPU_EXCEPTION_PRIORITY_PENDSV 0xc0
#else
#error "no support for this arch"
#endif
/*
* Lower layer architecture specific functions.
*
* system tick and interrupt
*/
/*
* System tick
*/
/* SysTick registers. */
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_init_arch (void)
{
SYST->RVR = 0;
SYST->CVR = 0;
SYST->CSR = 7;
}
static void
chx_systick_reload (uint32_t ticks)
{
SYST->RVR = ticks;
SYST->CVR = 0; /* write (any) to clear the counter to reload. */
SYST->RVR = 0;
}
static uint32_t
chx_systick_get (void)
{
return SYST->CVR;
}
static uint32_t usec_to_ticks (uint32_t usec)
{
return usec * MHZ;
}
static uint32_t
ticks_to_usec (uint32_t ticks)
{
return ticks / MHZ;
}
/*
* Interrupt Handling
*/
/* NVIC: Nested Vectored Interrupt Controller. */
struct NVIC {
volatile uint32_t ISER[8];
uint32_t unused1[24];
volatile uint32_t ICER[8];
uint32_t unused2[24];
volatile uint32_t ISPR[8];
uint32_t unused3[24];
volatile uint32_t ICPR[8];
uint32_t unused4[24];
volatile uint32_t IABR[8];
uint32_t unused5[56];
volatile uint32_t IPR[60];
};
static struct NVIC *const NVIC = (struct NVIC *)0xE000E100;
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
#define NVIC_ICER(n) (NVIC->ICER[n >> 5])
#define NVIC_ICPR(n) (NVIC->ICPR[n >> 5])
#define NVIC_IPR(n) (NVIC->IPR[n >> 2])
static void
chx_enable_intr (uint8_t irq_num)
{
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
}
static void
chx_clr_intr (uint8_t irq_num)
{ /* Clear pending interrupt. */
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
}
static 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
chx_set_intr_prio (uint8_t n)
{
unsigned int sh = (n & 3) << 3;
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh))
| (CPU_EXCEPTION_PRIORITY_INTERRUPT << sh);
}
static volatile uint32_t *const ICSR = (uint32_t *)0xE000ED04;
/* Priority control. */
static uint32_t *const AIRCR = (uint32_t *)0xE000ED0C;
static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
static void
chx_interrupt_controller_init (void)
{
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
*SHPR3 = ((CPU_EXCEPTION_PRIORITY_SYSTICK << 24)
| (CPU_EXCEPTION_PRIORITY_PENDSV << 16));
}
static void
chx_cpu_sched_lock (void)
{
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
{
#if defined(__ARM_ARCH_6M__)
asm volatile ("cpsid i" : : : "memory");
#else
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
#endif
}
}
static void
chx_cpu_sched_unlock (void)
{
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
{
#if defined(__ARM_ARCH_6M__)
asm volatile ("cpsie i" : : : "memory");
#else
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
#endif
}
}
void
chx_handle_intr (void)
{
struct chx_pq *p;
register uint32_t irq_num;
asm volatile ("mrs %0, IPSR\n\t"
"sub %0, #16" /* Exception # - 16 = interrupt number. */
: "=r" (irq_num) : /* no input */ : "memory");
chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock);
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
if (p->v == irq_num)
{ /* should be one at most. */
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p);
chx_wakeup (p);
chx_request_preemption (px->master->prio);
break;
}
chx_spin_unlock (&q_intr.lock);
}
static void
chx_init_arch (struct chx_thread *tp)
{
memset (&tp->tc, 0, sizeof (tp->tc));
chx_set_running (tp);
}
static void
chx_request_preemption (uint16_t prio)
{
if (running == NULL || (uint16_t)running->prio < prio)
{
*ICSR = (1 << 28);
asm volatile ("" : : : "memory");
}
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* For Cortex-M0, this should be AAPCS-compliant function entry, so we
* put "noinline" attribute.
*
* AAPCS: ARM Architecture Procedure Call Standard
*
* Returns:
* >= 1 on wakeup by others, value means ticks remained for sleep.
* 0 on normal wakeup (timer expiration, lock acquirement).
* -1 on cancellation.
*/
static uintptr_t __attribute__ ((naked, noinline))
chx_sched (uint32_t yield)
{
register struct chx_thread *tp asm ("r0");
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
asm volatile (
"svc #0"
: "=r" (tp) : "0" (yield): "memory");
#else
register uint32_t arg_yield asm ("r1");
/* Build stack data as if it were an exception entry. */
/*
* r0: TP scratch
* r1: 0 scratch
* r2: 0 scratch
* r3: 0 scratch
* r12: 0 scratch
* lr as-is
* pc: return address (= .L_CONTEXT_SWITCH_FINISH)
* psr: INITIAL_XPSR scratch
*/
asm ("mov r1, lr\n\t"
"ldr r2, =.L_CONTEXT_SWITCH_FINISH\n\t"
"mov r3, #128\n\t"
"lsl r3, #17\n\t"
"push {r1, r2, r3}\n\t"
"mov r1, #0\n\t"
"mov r2, r1\n\t"
"mov r3, r1\n\t"
"push {r1, r2, r3}\n\t"
"mov r1, r0\n\t"
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"push {r0, r3}"
: "=r" (tp), "=r" (arg_yield)
: "0" (yield)
: "r2", "r3", "memory");
/* Save registers onto CHX_THREAD struct. */
asm ("add r0, #20\n\t"
"stm r0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mov r6, sp\n\t"
"stm r0!, {r2, r3, r4, r5, r6}\n\t"
"sub r0, #56"
: /* no output */
: "r" (tp)
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (arg_yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
asm volatile (/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
"cmp r0, #0\n\t"
"bne 0f\n\t"
/* Spawn an IDLE thread. */
"ldr r1, =__main_stack_end__\n\t"
"mov sp, r1\n\t"
"ldr r0, =chx_idle\n\t" /* PC = idle */
/**/
/* Unmask interrupts. */
"cpsie i\n\t"
"bx r0\n"
/* Normal context switch */
"0:\n\t"
"add r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"mov sp, r2\n\t"
"sub r0, #45\n\t"
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
"cmp r1, #247\n\t"
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
/**/
/* Unmask interrupts. */
"cpsie i\n"
/**/
"1:\n\t"
/*
0: r0
4: r1
8: r2
12: r3
16: r12
20: lr
24: pc
28: psr
32: possibly exists for alignment
[28 or 32] <-- pc
*/
"ldr r0, [sp, #28]\n\t"
"lsl r1, r0, #23\n\t"
"bcc 2f\n\t"
/**/
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #32]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
"ldr r0, [sp, #20]\n\t"
"mov lr, r0\n\t"
"ldr r0, [sp, #16]\n\t"
"mov r12, r0\n\t"
"pop {r0, r1, r2, r3}\n\t"
"add sp, #16\n\t"
"pop {pc}\n"
"2:\n\t"
"ldr r2, [sp, #24]\n\t"
"mov r1, #1\n\t"
"orr r2, r1\n\t" /* Ensure Thumb-mode */
"str r2, [sp, #28]\n\t"
"msr APSR_nzcvq, r0\n\t"
/**/
"ldr r0, [sp, #20]\n\t"
"mov lr, r0\n\t"
"ldr r0, [sp, #16]\n\t"
"mov r12, r0\n\t"
"pop {r0, r1, r2, r3}\n\t"
"add sp, #12\n\t"
"pop {pc}\n\t"
".L_CONTEXT_SWITCH_FINISH:"
: "=r" (tp) /* Return value in R0 */
: "0" (tp)
: "memory");
#endif
asm volatile ("bx lr"
: "=r" (tp)
: "0" (tp->v)
: "memory");
return (uintptr_t)tp;
}
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
static struct chx_thread *
chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
voidfunc thread_entry, void *arg)
{
struct chx_thread *tp;
void *stack;
struct chx_stack_regs *p;
if (CHOPSTX_THREAD_SIZE != sizeof(struct chx_thread))
cause_link_time_error_unexpected_size_of_struct_chx_thread ();
if (stack_size < sizeof (struct chx_thread) + 8 * sizeof (uint32_t))
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
stack = (void *)(stack_addr + stack_size - sizeof (struct chx_thread)
- sizeof (struct chx_stack_regs));
memset (stack, 0, sizeof (struct chx_stack_regs));
tp = (struct chx_thread *)(stack + sizeof (struct chx_stack_regs));
p = (struct chx_stack_regs *)stack;
p->reg[REG_R0] = (uint32_t)arg;
p->reg[REG_LR] = (uint32_t)chopstx_exit;
p->reg[REG_PC] = (uint32_t)thread_entry;
p->reg[REG_XPSR] = INITIAL_XPSR;
memset (&tp->tc, 0, sizeof (tp->tc));
tp->tc.reg[REG_SP] = (uint32_t)stack;
return tp;
}
/*
* Lower layer architecture specific exception handling entries.
*
*/
void __attribute__ ((naked))
preempt (void)
{
register struct chx_thread *tp asm ("r0");
register struct chx_thread *cur asm ("r1");
asm volatile (
#if defined(__ARM_ARCH_6M__)
"cpsid i\n\t"
#else
"msr BASEPRI, r0\n\t"
#endif
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"mov r1, r0"
: "=r" (tp), "=r" (cur)
: "0" (CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED)
: "r2");
if (!cur)
/* It's idle thread. It's ok to clobber registers. */
;
else
{
/* Save registers onto CHX_THREAD struct. */
asm volatile (
"add %0, #20\n\t"
"stm %0!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm %0!, {r2, r3, r4, r5, r6}"
: "=r" (cur)
: "0" (cur)
/*
* Memory clobber constraint here is not accurate, but this
* works. R7 keeps its value, but having "r7" here prevents
* use of R7 before this asm statement.
*/
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (tp)
{
if (tp->flag_sched_rr)
{
if (tp->state == THREAD_RUNNING)
{
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
/*
* It may be THREAD_READY after chx_timer_expired.
* Then, do nothing.
*/
}
else
chx_ready_push (tp);
}
}
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
tp = chx_ready_pop ();
asm volatile (
".L_CONTEXT_SWITCH:\n\t"
/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
/* Update running. */
"str r0, [r1]\n\t"
#if defined(__ARM_ARCH_6M__)
"cmp r0, #0\n\t"
"beq 1f\n\t"
#else
"cbz r0, 1f\n\t"
#endif
/**/
"add r0, #20\n\t"
"ldm r0!, {r4, r5, r6, r7}\n\t"
#if defined(__ARM_ARCH_6M__)
"ldm r0!, {r1, r2, r3}\n\t"
"mov r8, r1\n\t"
"mov r9, r2\n\t"
"mov r10, r3\n\t"
"ldm r0!, {r1, r2}\n\t"
"mov r11, r1\n\t"
"msr PSP, r2\n\t"
#else
"ldr r8, [r0], #4\n\t"
"ldr r9, [r0], #4\n\t"
"ldr r10, [r0], #4\n\t"
"ldr r11, [r0], #4\n\t"
"ldr r1, [r0], #4\n\t"
"msr PSP, r1\n\t"
#endif
"sub r0, #45\n\t"
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
"mov r0, #0\n\t"
"cmp r1, #247\n\t"
"bhi 0f\n\t" /* Leave interrupt disabled if >= 248 */
/**/
/* Unmask interrupts. */
#if defined(__ARM_ARCH_6M__)
"cpsie i\n"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"0:\n\t"
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0\n"
"1:\n\t"
/* Spawn an IDLE thread. */
"ldr r0, =__main_stack_end__-32\n\t"
"msr PSP, r0\n\t"
"mov r1, #0\n\t"
"mov r2, #0\n\t"
"mov r3, #0\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"stm r0!, {r1, r2, r3}\n\t"
"ldr r1, =chx_idle\n\t" /* PC = idle */
"mov r2, #0x010\n\t"
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
"stm r0!, {r1, r2}\n\t"
/**/
/* Unmask interrupts. */
"mov r0, #0\n\t"
#if defined(__ARM_ARCH_6M__)
"cpsie i\n\t"
#else
"msr BASEPRI, r0\n"
#endif
/**/
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
"bx r0"
: /* no output */ : "r" (tp) : "memory");
}
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
/*
* System call: switch to another thread.
* There are two cases:
* ORIG_R0=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* ORIG_R0=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*/
void __attribute__ ((naked))
svc (void)
{
register struct chx_thread *tp asm ("r0");
register uint32_t orig_r0 asm ("r1");
asm ("ldr r1, =running\n\t"
"ldr r0, [r1]\n\t"
"add r1, r0, #20\n\t"
/* Save registers onto CHX_THREAD struct. */
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"ldr r1, [r6]\n\t"
"str r0, [r6]"
: "=r" (tp), "=r" (orig_r0)
: /* no input */
: "r2", "r3", "r4", "r5", "r6", "memory");
if (orig_r0) /* yield */
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
asm volatile (
"b .L_CONTEXT_SWITCH"
: /* no output */ : "r" (tp) : "memory");
}
#endif

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

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

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

@@ -0,0 +1,361 @@
/*
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
* for GNU/Linux emulation
*
* 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.
*
* 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 <unistd.h>
#include <ucontext.h>
#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)
{
}
static sigset_t ss_cur;
static void
chx_systick_init_arch (void)
{
const struct itimerval it = { {0, 0}, {0, 0} };
setitimer (ITIMER_REAL, &it, 0);
}
static void
chx_systick_reload (uint32_t ticks)
{
struct itimerval it;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = (ticks / MHZ);
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &it, 0);
}
static uint32_t
chx_systick_get (void)
{
struct itimerval it;
getitimer (ITIMER_REAL, &it);
return it.it_value.tv_usec * 72;
}
static uint32_t
usec_to_ticks (uint32_t usec)
{
return usec * MHZ;
}
static uint32_t
ticks_to_usec (uint32_t ticks)
{
return ticks / MHZ;
}
static void
chx_enable_intr (uint8_t irq_num)
{
sigdelset (&ss_cur, irq_num);
}
static void
chx_clr_intr (uint8_t irq_num)
{ /* Clear pending interrupt. */
(void)irq_num;
}
static 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
chx_set_intr_prio (uint8_t n)
{
(void)n;
}
static void
chx_interrupt_controller_init (void)
{
}
static void
chx_cpu_sched_lock (void)
{
sigset_t ss;
sigfillset (&ss);
pthread_sigmask (SIG_BLOCK, &ss, &ss_cur);
}
static void
chx_cpu_sched_unlock (void)
{
pthread_sigmask (SIG_SETMASK, &ss_cur, NULL);
}
static void
idle (void)
{
for (;;)
pause ();
}
void
chx_handle_intr (uint32_t irq_num)
{
struct chx_pq *p;
chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock);
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
if (p->v == irq_num)
{ /* should be one at most. */
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p);
chx_wakeup (p);
chx_spin_unlock (&q_intr.lock);
chx_request_preemption (px->master->prio);
return;
}
chx_spin_unlock (&q_intr.lock);
}
static ucontext_t idle_tc;
static char idle_stack[4096];
struct chx_thread main_thread;
void
chx_sigmask (ucontext_t *uc)
{
/* Modify oldmask to SS_CUR, so that the signal mask will
* be set to SS_CUR.
*
* In user-level, sigset_t is big, but only the first word
* is used by the kernel.
*/
memcpy (&uc->uc_sigmask, &ss_cur, sizeof (uint64_t));
}
static void
sigalrm_handler (int sig, siginfo_t *siginfo, void *arg)
{
extern void chx_timer_expired (void);
ucontext_t *uc = arg;
(void)sig;
(void)siginfo;
chx_timer_expired ();
chx_sigmask (uc);
}
static void
chx_init_arch (struct chx_thread *tp)
{
struct sigaction sa;
sigemptyset (&ss_cur);
sa.sa_sigaction = sigalrm_handler;
sigfillset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO|SA_RESTART;
sigaction (SIGALRM, &sa, NULL);
getcontext (&idle_tc);
idle_tc.uc_stack.ss_sp = idle_stack;
idle_tc.uc_stack.ss_size = sizeof (idle_stack);
idle_tc.uc_link = NULL;
makecontext (&idle_tc, idle, 0);
getcontext (&tp->tc);
chx_set_running (tp);
}
static void
chx_request_preemption (uint16_t prio)
{
ucontext_t *tcp;
struct chx_thread *tp_prev;
struct chx_thread *tp = chx_running ();
if (tp && (uint16_t)tp->prio >= prio)
return;
/* Change the context to another thread with higher priority. */
tp_prev = tp;
if (tp)
{
if (tp->flag_sched_rr)
{
if (tp->state == THREAD_RUNNING)
{
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
}
else
chx_ready_push (tp);
}
tp = chx_ready_pop ();
if (tp)
tcp = &tp->tc;
else
tcp = &idle_tc;
chx_set_running (tp);
if (tp_prev)
{
/*
* The swapcontext implementation may reset sigmask in the
* middle of its execution, unfortunately. It is best if
* sigmask restore is done at the end of the routine, but we
* can't assume that.
*
* Thus, there might be a race condition with regards to the
* user context TCP, if signal mask is cleared and signal comes
* in. To avoid this situation, we block signals.
*
* We don't need to fill the mask here. It keeps the condition
* of blocking signals before&after swapcontext call. It is
* done by the signal mask for sigaction, the initial creation
* of the thread, and the condition of chx_sched function which
* mandates holding cpu_sched_lock.
*/
swapcontext (&tp_prev->tc, tcp);
}
else if (tp)
{
setcontext (tcp);
}
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* Returns:
* 1 on wakeup by others.
* 0 on normal wakeup.
* -1 on cancellation.
*/
static uintptr_t
chx_sched (uint32_t yield)
{
struct chx_thread *tp, *tp_prev;
ucontext_t *tcp;
tp = tp_prev = chx_running ();
if (yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
if (tp)
tcp = &tp->tc;
else
tcp = &idle_tc;
chx_set_running (tp);
swapcontext (&tp_prev->tc, tcp);
chx_cpu_sched_unlock ();
tp = chx_running ();
return tp->v;
}
static void __attribute__((__noreturn__))
chx_thread_start (voidfunc thread_entry, void *arg)
{
void *ret;
chx_cpu_sched_unlock ();
ret = thread_entry (arg);
chopstx_exit (ret);
}
static struct chx_thread *
chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
voidfunc thread_entry, void *arg)
{
struct chx_thread *tp;
tp = malloc (sizeof (struct chx_thread));
if (!tp)
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
/*
* Calling getcontext with sched_lock held, the context is with
* signal blocked. The sigmask will be cleared in chx_thread_start.
*/
chx_cpu_sched_lock ();
getcontext (&tp->tc);
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
tp->tc.uc_stack.ss_size = stack_size;
tp->tc.uc_link = NULL;
makecontext (&tp->tc, (void (*)(void))chx_thread_start,
4, thread_entry, arg);
chx_cpu_sched_unlock ();
return tp;
}

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

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

1658
chopstx.c

File diff suppressed because it is too large Load Diff

105
chopstx.h
View File

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

View File

@@ -1,365 +0,0 @@
/*
* clk_gpio_init.c - Clock and GPIO initialization.
*
* Copyright (C) 2015 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* receipents of GNU GPL by a written offer.
*
*/
#define STM32_SW_HSI (0 << 0)
#define STM32_SW_PLL (2 << 0)
#define STM32_PLLSRC_HSI (0 << 16)
#define STM32_PLLSRC_HSE (1 << 16)
#define STM32_PLLXTPRE_DIV1 (0 << 17)
#define STM32_PLLXTPRE_DIV2 (1 << 17)
#define STM32_HPRE_DIV1 (0 << 4)
#define STM32_PPRE1_DIV1 (0 << 8)
#define STM32_PPRE1_DIV2 (4 << 8)
#define STM32_PPRE2_DIV1 (0 << 11)
#define STM32_PPRE2_DIV2 (4 << 11)
#define STM32_ADCPRE_DIV4 (1 << 14)
#define STM32_ADCPRE_DIV6 (2 << 14)
#define STM32_USBPRE_DIV1P5 (0 << 22)
#define STM32_MCO_NOCLOCK (0 << 24)
#if defined(MCU_STM32F0)
#define STM32_PPRE1 STM32_PPRE1_DIV1
#define STM32_PLLSRC STM32_PLLSRC_HSI
#define STM32_FLASHBITS 0x00000011
#define STM32_PLLCLKIN (STM32_HSICLK / 2)
#else
#define STM32_PPRE1 STM32_PPRE1_DIV2
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_FLASHBITS 0x00000012
#define STM32_PLLCLKIN (STM32_HSECLK / 1)
#endif
#define STM32_SW STM32_SW_PLL
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE2 STM32_PPRE2_DIV1
#define STM32_ADCPRE STM32_ADCPRE_DIV6
#define STM32_MCOSEL STM32_MCO_NOCLOCK
#define STM32_USBPRE STM32_USBPRE_DIV1P5
#define STM32_PLLMUL ((STM32_PLLMUL_VALUE - 2) << 18)
#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
#define STM32_SYSCLK STM32_PLLCLKOUT
#define STM32_HCLK (STM32_SYSCLK / 1)
#define PERIPH_BASE 0x40000000
#define APBPERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
struct RCC {
volatile uint32_t CR;
volatile uint32_t CFGR;
volatile uint32_t CIR;
volatile uint32_t APB2RSTR;
volatile uint32_t APB1RSTR;
volatile uint32_t AHBENR;
volatile uint32_t APB2ENR;
volatile uint32_t APB1ENR;
volatile uint32_t BDCR;
volatile uint32_t CSR;
#if defined(MCU_STM32F0)
volatile uint32_t AHBRSTR;
volatile uint32_t CFGR2;
volatile uint32_t CFGR3;
volatile uint32_t CR2;
#endif
};
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
#define RCC_APB1ENR_USBEN 0x00800000
#define RCC_APB1RSTR_USBRST 0x00800000
#define RCC_CR_HSION 0x00000001
#define RCC_CR_HSIRDY 0x00000002
#define RCC_CR_HSITRIM 0x000000F8
#define RCC_CR_HSEON 0x00010000
#define RCC_CR_HSERDY 0x00020000
#define RCC_CR_PLLON 0x01000000
#define RCC_CR_PLLRDY 0x02000000
#define RCC_CFGR_SWS 0x0000000C
#define RCC_CFGR_SWS_HSI 0x00000000
#define RCC_AHBENR_CRCEN 0x0040
#if defined(MCU_STM32F0)
#define RCC_AHBRSTR_IOPARST 0x00020000
#define RCC_AHBRSTR_IOPBRST 0x00040000
#define RCC_AHBRSTR_IOPCRST 0x00080000
#define RCC_AHBRSTR_IOPDRST 0x00100000
#define RCC_AHBRSTR_IOPFRST 0x00400000
#define RCC_AHBENR_IOPAEN 0x00020000
#define RCC_AHBENR_IOPBEN 0x00040000
#define RCC_AHBENR_IOPCEN 0x00080000
#define RCC_AHBENR_IOPDEN 0x00100000
#define RCC_AHBENR_IOPFEN 0x00400000
#define RCC_APB2RSTR_SYSCFGRST 0x00000001
#define RCC_APB2ENR_SYSCFGEN 0x00000001
#else
#define RCC_APB2RSTR_AFIORST 0x00000001
#define RCC_APB2RSTR_IOPARST 0x00000004
#define RCC_APB2RSTR_IOPBRST 0x00000008
#define RCC_APB2RSTR_IOPCRST 0x00000010
#define RCC_APB2RSTR_IOPDRST 0x00000020
#define RCC_APB2RSTR_IOPERST 0x00000040
#define RCC_APB2RSTR_IOPFRST 0x00000080
#define RCC_APB2RSTR_IOPGRST 0x00000100
#define RCC_APB2ENR_AFIOEN 0x00000001
#define RCC_APB2ENR_IOPAEN 0x00000004
#define RCC_APB2ENR_IOPBEN 0x00000008
#define RCC_APB2ENR_IOPCEN 0x00000010
#define RCC_APB2ENR_IOPDEN 0x00000020
#define RCC_APB2ENR_IOPEEN 0x00000040
#define RCC_APB2ENR_IOPFEN 0x00000080
#define RCC_APB2ENR_IOPGEN 0x00000100
#endif
#if defined(MCU_STM32F0)
struct SYSCFG {
volatile uint32_t CFGR1;
uint32_t dummy0;
volatile uint32_t EXTICR[4];
volatile uint32_t CFGR2;
};
#define SYSCFG_CFGR1_MEM_MODE 0x03
#define SYSCFG_BASE (APBPERIPH_BASE + 0x00010000)
static struct SYSCFG *const SYSCFG = ((struct SYSCFG *const) SYSCFG_BASE);
#endif
struct FLASH {
volatile uint32_t ACR;
volatile uint32_t KEYR;
volatile uint32_t OPTKEYR;
volatile uint32_t SR;
volatile uint32_t CR;
volatile uint32_t AR;
volatile uint32_t RESERVED;
volatile uint32_t OBR;
volatile uint32_t WRPR;
};
#define FLASH_R_BASE (AHBPERIPH_BASE + 0x2000)
static struct FLASH *const FLASH = ((struct FLASH *const) FLASH_R_BASE);
static void __attribute__((used))
clock_init (void)
{
/* HSI setup */
RCC->CR |= RCC_CR_HSION;
while (!(RCC->CR & RCC_CR_HSIRDY))
;
/* Reset HSEON, HSEBYP, CSSON, and PLLON, not touching RCC_CR_HSITRIM */
RCC->CR &= (RCC_CR_HSITRIM | RCC_CR_HSION);
RCC->CFGR = 0;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
;
#if !defined(MCU_STM32F0)
/* HSE setup */
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY))
;
#endif
/* PLL setup */
RCC->CFGR |= STM32_PLLMUL | STM32_PLLXTPRE | STM32_PLLSRC;
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY))
;
/* Clock settings */
RCC->CFGR = STM32_MCOSEL | STM32_USBPRE | STM32_PLLMUL | STM32_PLLXTPRE
| STM32_PLLSRC | STM32_ADCPRE | STM32_PPRE2 | STM32_PPRE1 | STM32_HPRE;
/*
* We don't touch RCC->CR2, RCC->CFGR2, RCC->CFGR3, and RCC->CIR.
*/
/* Flash setup */
FLASH->ACR = STM32_FLASHBITS;
/* CRC */
RCC->AHBENR |= RCC_AHBENR_CRCEN;
/* Switching on the configured clock source. */
RCC->CFGR |= STM32_SW;
while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2))
;
#if defined(MCU_STM32F0)
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
RCC->APB2RSTR = RCC_APB2RSTR_SYSCFGRST;
RCC->APB2RSTR = 0;
/* Use vectors on RAM */
SYSCFG->CFGR1 = (SYSCFG->CFGR1 & ~SYSCFG_CFGR1_MEM_MODE) | 3;
#endif
}
#if defined(MCU_STM32F0)
struct GPIO {
volatile uint32_t MODER;
volatile uint16_t OTYPER;
uint16_t dummy0;
volatile uint32_t OSPEEDR;
volatile uint32_t PUPDR;
volatile uint16_t IDR;
uint16_t dummy1;
volatile uint16_t ODR;
uint16_t dummy2;
volatile uint16_t BSRR;
uint16_t dummy3;
volatile uint32_t LCKR;
volatile uint32_t AFR[2];
volatile uint16_t BRR;
uint16_t dummy4;
};
#define GPIOA_BASE (AHB2PERIPH_BASE + 0x0000)
#define GPIOA ((struct GPIO *) GPIOA_BASE)
#define GPIOB_BASE (AHB2PERIPH_BASE + 0x0400)
#define GPIOB ((struct GPIO *) GPIOB_BASE)
#define GPIOC_BASE (AHB2PERIPH_BASE + 0x0800)
#define GPIOC ((struct GPIO *) GPIOC_BASE)
#define GPIOD_BASE (AHB2PERIPH_BASE + 0x0C00)
#define GPIOD ((struct GPIO *) GPIOD_BASE)
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
#define GPIOF ((struct GPIO *) GPIOF_BASE)
#else
struct AFIO
{
volatile uint32_t EVCR;
volatile uint32_t MAPR;
volatile uint32_t EXTICR[4];
uint32_t RESERVED0;
volatile uint32_t MAPR2;
};
#define AFIO_BASE 0x40010000
static struct AFIO *const AFIO = (struct AFIO *const)AFIO_BASE;
#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
#define AFIO_MAPR_SWJ_CFG_DISABLE 0x04000000
struct GPIO {
volatile uint32_t CRL;
volatile uint32_t CRH;
volatile uint32_t IDR;
volatile uint32_t ODR;
volatile uint32_t BSRR;
volatile uint32_t BRR;
volatile uint32_t LCKR;
};
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define GPIOA ((struct GPIO *) GPIOA_BASE)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOB ((struct GPIO *) GPIOB_BASE)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOC ((struct GPIO *) GPIOC_BASE)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOD ((struct GPIO *) GPIOD_BASE)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOE ((struct GPIO *) GPIOE_BASE)
#endif
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
#ifdef GPIO_USB_BASE
static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE);
#endif
#ifdef GPIO_OTHER_BASE
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
#endif
static void __attribute__((used))
gpio_init (void)
{
/* Enable GPIO clock. */
#if defined(MCU_STM32F0)
RCC->AHBENR |= RCC_ENR_IOP_EN;
RCC->AHBRSTR = RCC_RSTR_IOP_RST;
RCC->AHBRSTR = 0;
#else
RCC->APB2ENR |= RCC_ENR_IOP_EN;
RCC->APB2RSTR = RCC_RSTR_IOP_RST;
RCC->APB2RSTR = 0;
#endif
#if defined(MCU_STM32F0)
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;
#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;
#endif
#else
#ifdef AFIO_MAPR_SOMETHING
AFIO->MAPR |= AFIO_MAPR_SOMETHING;
#endif
/* LED is mandatory. If it's on an independent port, we configure it. */
GPIO_LED->ODR = VAL_GPIO_LED_ODR;
GPIO_LED->CRH = VAL_GPIO_LED_CRH;
GPIO_LED->CRL = VAL_GPIO_LED_CRL;
/* If there is USB enabler pin and it's independent, we configure it. */
#if defined(GPIO_USB_BASE) && GPIO_USB_BASE != GPIO_LED_BASE
GPIO_USB->ODR = VAL_GPIO_USB_ODR;
GPIO_USB->CRH = VAL_GPIO_USB_CRH;
GPIO_USB->CRL = VAL_GPIO_USB_CRL;
#endif
#ifdef GPIO_OTHER_BASE
GPIO_OTHER->ODR = VAL_GPIO_OTHER_ODR;
GPIO_OTHER->CRH = VAL_GPIO_OTHER_CRH;
GPIO_OTHER->CRL = VAL_GPIO_OTHER_CRL;
#endif
#endif
}

116
contrib/ackbtn-stm32f103.c Normal file
View File

@@ -0,0 +1,116 @@
/*
* ackbtn-stm32f103.c - Acknowledge button support for STM32F103
*
* Copyright (C) 2018 g10 Code GmbH
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* recipients of GNU GPL by a written offer.
*
*/
#include <stdint.h>
#include <string.h>
#include <chopstx.h>
#include <mcu/stm32f103.h>
#include "board.h"
#include "sys.h"
/*
* All EXTI registers (EXTI_IMR, EXTI_EMR, EXTI_PR , EXTI_RTSR, and
* EXTI_FTSR) have same structure, where each bit of X is used for
* line X, from 0 up to 19.
*
* We use 31-bit of PIN_CONFIG to represent if it's for rising edge or
* falling edge.
*/
static uint32_t pin_config;
#define PINCFG_EDGE 0x80000000
#define PINCFG_EDGE_RISING PINCFG_EDGE
void
ackbtn_init (chopstx_intr_t *intr)
{
uint8_t irq_num;
uint32_t afio_exticr_index;
uint32_t afio_exticr_extiX_pY;
switch (SYS_BOARD_ID)
{
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;
irq_num = EXTI2_IRQ;
pin_config = 0x0004; /* EXTI_PR_PR2 == EXTI_IMR_MR2 == EXTI_RTSR_TR2 */
pin_config |= PINCFG_EDGE_RISING;
break;
case BOARD_ID_FST_01SZ:
default:
/* PA3 is connected to a hall sensor DRV5032FA */
afio_exticr_index = 0;
afio_exticr_extiX_pY = AFIO_EXTICR1_EXTI3_PA;
irq_num = EXTI3_IRQ;
pin_config = 0x0008; /* EXTI_PR_PR3 == EXTI_IMR_MR3 == EXTI_RTSR_TR3 */
pin_config |= PINCFG_EDGE_RISING;
break;
}
/* Configure EXTI line */
if (afio_exticr_extiX_pY)
AFIO->EXTICR[afio_exticr_index] |= afio_exticr_extiX_pY;
/* Interrupt is masked, now */
EXTI->IMR &= ~(pin_config & ~PINCFG_EDGE);
chopstx_claim_irq (intr, irq_num);
}
void
ackbtn_enable (void)
{
/* Clear pending interrupt */
EXTI->PR |= (pin_config & ~PINCFG_EDGE);
/* Enable interrupt, clearing the mask */
EXTI->IMR |= (pin_config & ~PINCFG_EDGE);
/* Configure which edge is detected */
if ((pin_config & PINCFG_EDGE))
EXTI->RTSR |= (pin_config & ~PINCFG_EDGE);
else
EXTI->FTSR |= (pin_config & ~PINCFG_EDGE);
}
void
ackbtn_disable (void)
{
/* Disable interrupt having the mask */
EXTI->IMR &= ~(pin_config & ~PINCFG_EDGE);
/* Clear pending interrupt */
EXTI->PR |= (pin_config & ~PINCFG_EDGE);
/* Disable edge detection */
EXTI->RTSR &= ~(pin_config & ~PINCFG_EDGE);
EXTI->FTSR &= ~(pin_config & ~PINCFG_EDGE);
}

3
contrib/ackbtn.h Normal file
View File

@@ -0,0 +1,3 @@
void ackbtn_init (chopstx_intr_t *intr);
void ackbtn_enable (void);
void ackbtn_disable (void);

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

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

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

@@ -0,0 +1,322 @@
/*
* adc-mkl27z.c - ADC driver for MKL27Z
* In this ADC driver, there are NeuG specific parts.
* It only records lower 8-bit of 16-bit data.
* You need to modify to use this as generic ADC driver.
*
* Copyright (C) 2016 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* recipients of GNU GPL by a written offer.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <mcu/mkl27z.h>
struct DMAMUX {
volatile uint32_t CHCFG0;
volatile uint32_t CHCFG1;
volatile uint32_t CHCFG2;
volatile uint32_t CHCFG3;
};
static struct DMAMUX *const DMAMUX = (struct DMAMUX *)0x40021000;
#define INTR_REQ_DMA0 0
struct DMA {
volatile uint32_t SAR;
volatile uint32_t DAR;
volatile uint32_t DSR_BCR;
volatile uint32_t DCR;
};
static struct DMA *const DMA0 = (struct DMA *)0x40008100;
static struct DMA *const DMA1 = (struct DMA *)0x40008110;
/* We don't use ADC interrupt. Just for reference. */
#define INTR_REQ_ADC 15
struct ADC {
volatile uint32_t SC1[2];/* Status and Control Registers 1 */
volatile uint32_t CFG1; /* Configuration Register 1 */
volatile uint32_t CFG2; /* Configuration Register 2 */
volatile uint32_t R[2]; /* Data Result Register */
/* Compare Value Registers 1, 2 */
volatile uint32_t CV1;
volatile uint32_t CV2;
volatile uint32_t SC2; /* Status and Control Register 2 */
volatile uint32_t SC3; /* Status and Control Register 3 */
volatile uint32_t OFS; /* Offset Correction Register */
volatile uint32_t PG; /* Plus-Side Gain Register */
volatile uint32_t MG; /* Minus-Side Gain Register */
/* Plus-Side General Calibration Value Registers */
volatile uint32_t CLPD;
volatile uint32_t CLPS;
volatile uint32_t CLP4;
volatile uint32_t CLP3;
volatile uint32_t CLP2;
volatile uint32_t CLP1;
volatile uint32_t CLP0;
uint32_t rsvd0;
/* Minus-Side General Calibration Value Registers */
volatile uint32_t CLMD;
volatile uint32_t CLMS;
volatile uint32_t CLM4;
volatile uint32_t CLM3;
volatile uint32_t CLM2;
volatile uint32_t CLM1;
volatile uint32_t CLM0;
};
static struct ADC *const ADC0 = (struct ADC *)0x4003B000;
/* SC1 */
#define ADC_SC1_DIFF (1 << 5)
#define ADC_SC1_AIEN (1 << 6)
#define ADC_SC1_COCO (1 << 7)
#define ADC_SC1_TEMPSENSOR 26
#define ADC_SC1_BANDGAP 27
#define ADC_SC1_ADCSTOP 31
/* CFG1 */
#define ADC_CLOCK_SOURCE_ASYNCH (3 << 0)
#define ADC_MODE_16BIT (3 << 2)
#define ADC_ADLSMP_SHORT (0 << 4)
#define ADC_ADLSMP_LONG (1 << 4)
#define ADC_ADIV_1 (0 << 5)
#define ADC_ADIV_8 (3 << 5)
#define ADC_ADLPC_NORMAL (0 << 7)
#define ADC_ADLPC_LOWPOWER (1 << 7)
/**/
#define ADC_CLOCK_SOURCE ADC_CLOCK_SOURCE_ASYNCH
#define ADC_MODE ADC_MODE_16BIT
#define ADC_ADLSMP ADC_ADLSMP_SHORT
#define ADC_ADIV ADC_ADIV_1
#define ADC_ADLPC ADC_ADLPC_LOWPOWER
/* CFG2 */
#define ADC_ADLSTS_DEFAULT 0 /* 24 cycles if CFG1.ADLSMP=1, 4 if not. */
#define ADC_ADHSC_NORMAL (0 << 2)
#define ADC_ADHSC_HIGHSPEED (1 << 2)
#define ADC_ADACK_DISABLE (0 << 3)
#define ADC_ADACK_ENABLE (1 << 3)
#define ADC_MUXSEL_A (0 << 4)
#define ADC_MUXSEL_B (1 << 4)
/**/
#define ADC_ADLSTS ADC_ADLSTS_DEFAULT
#define ADC_ADHSC ADC_ADHSC_NORMAL
#define ADC_ADACKEN ADC_ADACK_ENABLE
#define ADC_MUXSEL ADC_MUXSEL_A
/* SC2 */
#define ADC_SC2_REFSEL_DEFAULT 1 /* Internal Voltage Reference??? */
#define ADC_SC2_DMAEN (1 << 2)
#define ADC_SC2_ACREN (1 << 3)
#define ADC_SC2_ACFGT (1 << 4)
#define ADC_SC2_ACFE (1 << 5)
#define ADC_SC2_ADTRG (1 << 6) /* For hardware trigger */
/* SC3 */
#define ADC_SC3_AVGS11 0x03
#define ADC_SC3_AVGE (1 << 2)
#define ADC_SC3_ADCO (1 << 3)
#define ADC_SC3_CALF (1 << 6)
#define ADC_SC3_CAL (1 << 7)
#define ADC_DMA_SLOT_NUM 40
/*
* Buffer to save ADC data.
*/
uint32_t adc_buf[64];
static const uint32_t adc0_sc1_setting = ADC_SC1_TEMPSENSOR;
static chopstx_intr_t adc_intr;
struct adc_internal {
uint32_t buf[64];
uint8_t *p;
int phase : 8;
int count : 8;
};
struct adc_internal adc;
/*
* Initialize ADC module, do calibration.
*
* This is called by MAIN, only once, hopefully before creating any
* other threads (to be accurate).
*
* We configure ADC0 to kick DMA0, configure DMA0 to kick DMA1.
* DMA0 records output of ADC0 to the ADC.BUF.
* DMA1 kicks ADC0 again to get another value.
*
* ADC0 --[finish conversion]--> DMA0 --[Link channel 1]--> DMA1
*/
int
adc_init (void)
{
uint32_t v;
/* Enable ADC0 and DMAMUX clock. */
SIM->SCGC6 |= (1 << 27) | (1 << 1);
/* Enable DMA clock. */
SIM->SCGC7 |= (1 << 8);
/* ADC0 setting for calibration. */
ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC;
ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL;
ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT;
ADC0->SC3 = ADC_SC3_CAL | ADC_SC3_CALF | ADC_SC3_AVGE | ADC_SC3_AVGS11;
/* Wait ADC completion */
while ((ADC0->SC1[0] & ADC_SC1_COCO) == 0)
if ((ADC0->SC3 & ADC_SC3_CALF) != 0)
/* Calibration failure */
return -1;
if ((ADC0->SC3 & ADC_SC3_CALF) != 0)
/* Calibration failure */
return -1;
/* Configure PG by the calibration values. */
v = ADC0->CLP0 + ADC0->CLP1 + ADC0->CLP2 + ADC0->CLP3 + ADC0->CLP4 + ADC0->CLPS;
ADC0->PG = 0x8000 | (v >> 1);
/* Configure MG by the calibration values. */
v = ADC0->CLM0 + ADC0->CLM1 + ADC0->CLM2 + ADC0->CLM3 + ADC0->CLM4 + ADC0->CLMS;
ADC0->MG = 0x8000 | (v >> 1);
ADC0->SC1[0] = ADC_SC1_ADCSTOP;
/* DMAMUX setting. */
DMAMUX->CHCFG0 = (1 << 7) | ADC_DMA_SLOT_NUM;
/* DMA0 initial setting. */
DMA0->SAR = (uint32_t)&ADC0->R[0];
/* DMA1 initial setting. */
DMA1->SAR = (uint32_t)&adc0_sc1_setting;
DMA1->DAR = (uint32_t)&ADC0->SC1[0];
chopstx_claim_irq (&adc_intr, INTR_REQ_DMA0);
return 0;
}
/*
* Start using ADC.
*/
void
adc_start (void)
{
ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC;
ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL;
ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT | ADC_SC2_DMAEN;
ADC0->SC3 = 0;
}
/*
* Kick getting data for COUNT times.
* Data will be saved in ADC_BUF starting at OFFSET.
*/
static void
adc_start_conversion_internal (int count)
{
/* DMA0 setting. */
DMA0->DAR = (uint32_t)&adc.buf[0];
DMA0->DSR_BCR = 4 * count;
DMA0->DCR = (1 << 31) | (1 << 30) | (1 << 29) | (0 << 20) | (1 << 19)
| (0 << 17) | (1 << 7) | (2 << 4) | (1 << 2);
/* Kick DMA1. */
DMA1->DSR_BCR = 4 * count;
DMA1->DCR = (1 << 30) | (1 << 29) | (0 << 19) | (0 << 17) | (1 << 16) | (1 << 7);
}
/*
* Kick getting data for COUNT times.
* Data will be saved in ADC_BUF starting at OFFSET.
*/
void
adc_start_conversion (int offset, int count)
{
adc.p = (uint8_t *)&adc_buf[offset];
adc.phase = 0;
adc.count = count;
adc_start_conversion_internal (count);
}
static void
adc_stop_conversion (void)
{
ADC0->SC1[0] = ADC_SC1_ADCSTOP;
}
/*
* Stop using ADC.
*/
void
adc_stop (void)
{
SIM->SCGC6 &= ~(1 << 27);
}
/*
* Return 0 on success.
* Return 1 on error.
*/
int
adc_wait_completion (void)
{
int i;
while (1)
{
/* Wait DMA completion */
chopstx_intr_wait (&adc_intr);
DMA0->DSR_BCR = (1 << 24);
DMA1->DSR_BCR = (1 << 24);
adc_stop_conversion ();
chopstx_intr_done (&adc_intr);
for (i = 0; i < adc.count; i++)
*adc.p++ = (uint8_t)adc.buf[i];
if (++adc.phase >= 4)
break;
adc_start_conversion_internal (adc.count);
}
return 0;
}

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

@@ -0,0 +1,347 @@
/*
* adc_stm32f103.c - ADC driver for STM32F103
* In this ADC driver, there are NeuG specific parts.
* You need to modify to use this as generic ADC driver.
*
* Copyright (C) 2011, 2012, 2013, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* Chopstx is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chopstx is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* recipients of GNU GPL by a written offer.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <mcu/stm32f103.h>
#include "adc.h"
#include "board.h"
#include "sys.h"
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#define ADC_SMPR1_SMP_VREF(n) ((n) << 21)
#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18)
#define ADC_SMPR1_SMP_AN10(n) ((n) << 0)
#define ADC_SMPR1_SMP_AN11(n) ((n) << 3)
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0)
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3)
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6)
#define ADC_SMPR2_SMP_AN8(n) ((n) << 24)
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27)
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
#define ADC_SQR3_SQ1_N(n) ((n) << 0)
#define ADC_SQR3_SQ2_N(n) ((n) << 5)
#define ADC_SQR3_SQ3_N(n) ((n) << 10)
#define ADC_SQR3_SQ4_N(n) ((n) << 15)
#define ADC_SAMPLE_1P5 0
#define ADC_CHANNEL_IN0 0
#define ADC_CHANNEL_IN1 1
#define ADC_CHANNEL_IN2 2
#define ADC_CHANNEL_IN8 8
#define ADC_CHANNEL_IN9 9
#define ADC_CHANNEL_IN10 10
#define ADC_CHANNEL_IN11 11
#define ADC_CHANNEL_SENSOR 16
#define ADC_CHANNEL_VREFINT 17
#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
#ifndef MCU_STM32F1_GD32F1
#define DELIBARATELY_DO_IT_WRONG_START_STOP
#endif
#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
#define ADC_SAMPLE_SENSOR ADC_SAMPLE_1P5
#else
#define ADC_SAMPLE_VREF ADC_SAMPLE_239P5
#define ADC_SAMPLE_SENSOR ADC_SAMPLE_239P5
#endif
#define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1
#define NEUG_DMA_MODE \
( STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY) \
| STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD \
| STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE \
| STM32_DMA_CR_TEIE )
#define NEUG_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF) \
| ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR)
#define NEUG_ADC_SETTING1_SMPR2 0
#define NEUG_ADC_SETTING1_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT) \
| ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) \
| ADC_SQR3_SQ3_N(ADC_CHANNEL_SENSOR) \
| ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT)
#define NEUG_ADC_SETTING1_NUM_CHANNELS 4
/*
* ADC finish interrupt
*/
#define INTR_REQ_DMA1_Channel1 11
static chopstx_intr_t adc_intr;
/*
* Do calibration for both of ADCs.
*/
int
adc_init (void)
{
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
RCC->APB2RSTR = (RCC_APB2RSTR_ADC1RST | RCC_APB2RSTR_ADC2RST);
RCC->APB2RSTR = 0;
ADC1->CR1 = 0;
ADC1->CR2 = ADC_CR2_ADON;
chopstx_usec_wait (1000);
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
;
ADC1->CR2 = 0;
ADC2->CR1 = 0;
ADC2->CR2 = ADC_CR2_ADON;
chopstx_usec_wait (1000);
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
;
ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC2->CR2 & ADC_CR2_CAL) != 0)
;
ADC2->CR2 = 0;
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
chopstx_claim_irq (&adc_intr, INTR_REQ_DMA1_Channel1);
return 0;
}
static void
get_adc_config (uint32_t config[4])
{
config[2] = ADC_SQR1_NUM_CH(2);
switch (SYS_BOARD_ID)
{
case BOARD_ID_FST_01G:
case BOARD_ID_FST_01:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9);
break;
case BOARD_ID_OLIMEX_STM32_H103:
case BOARD_ID_STBEE:
config[0] = ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5)
| ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5);
config[1] = 0;
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11);
break;
case BOARD_ID_STBEE_MINI:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2);
break;
case BOARD_ID_ST_NUCLEO_F103:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN8(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN8)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9);
break;
case BOARD_ID_CQ_STARM:
case BOARD_ID_FST_01_00:
case BOARD_ID_MAPLE_MINI:
case BOARD_ID_STM32_PRIMER2:
case BOARD_ID_STM8S_DISCOVERY:
case BOARD_ID_ST_DONGLE:
case BOARD_ID_NITROKEY_START:
case BOARD_ID_FST_01SZ:
default:
config[0] = 0;
config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
| ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5);
config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
| ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1);
break;
}
}
void
adc_start (void)
{
uint32_t config[4];
get_adc_config (config);
/* Use DMA channel 1. */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE;
DMA1->IFCR = 0xffffffff;
RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1;
ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
ADC1->SQR2 = 0;
ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
| ADC_CR1_SCAN);
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
chopstx_usec_wait (1000);
ADC2->SMPR1 = config[0];
ADC2->SMPR2 = config[1];
ADC2->SQR1 = config[2];
ADC2->SQR2 = 0;
ADC2->SQR3 = config[3];
ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
| ADC_CR1_SCAN);
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
chopstx_usec_wait (1000);
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
/*
* We could just let ADC run continuously always and only enable DMA
* to receive stable data from ADC. But our purpose is not to get
* correct data but noise. In fact, we can get more noise when we
* start/stop ADC each time.
*/
ADC2->CR2 = 0;
ADC1->CR2 = 0;
#else
/* Start conversion. */
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
#endif
}
uint32_t adc_buf[64];
void
adc_start_conversion (int offset, int count)
{
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
DMA1_Channel1->CMAR = (uint32_t)&adc_buf[offset]; /* SetMemory0 */
DMA1_Channel1->CNDTR = count; /* Counter */
DMA1_Channel1->CCR = NEUG_DMA_MODE | DMA_CCR1_EN; /* Mode */
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
/* Power on */
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
/*
* Start conversion. tSTAB is 1uS, but we don't follow the spec, to
* get more noise.
*/
ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
| ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
#endif
}
static void adc_stop_conversion (void)
{
DMA1_Channel1->CCR &= ~DMA_CCR1_EN;
#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
ADC2->CR2 = 0;
ADC1->CR2 = 0;
#endif
}
void
adc_stop (void)
{
ADC1->CR1 = 0;
ADC1->CR2 = 0;
ADC2->CR1 = 0;
ADC2->CR2 = 0;
RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
}
static uint32_t adc_err;
/*
* Return 0 on success.
* Return 1 on error.
*/
int
adc_wait_completion (void)
{
uint32_t flags;
while (1)
{
chopstx_intr_wait (&adc_intr);
flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause. */
/*
* Clear interrupt cause of channel 1.
*
* Note that CGIFx=0, as CGIFx=1 clears all of GIF, HTIF, TCIF
* and TEIF.
*/
DMA1->IFCR = (flags & ~1);
chopstx_intr_done (&adc_intr);
if ((flags & STM32_DMA_ISR_TEIF) != 0) /* DMA errors */
{
/* Should never happened. If any, it's coding error. */
/* Access an unmapped address space or alignment violation. */
adc_err++;
adc_stop_conversion ();
return 1;
}
else if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
{
adc_stop_conversion ();
return 0;
}
}
}

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

561
contrib/usart-stm32f103.c Normal file
View File

@@ -0,0 +1,561 @@
/*
* usart-stm32.c - USART driver for STM32F103 (USART2 and USART3)
*
* Copyright (C) 2017, 2019 g10 Code GmbH
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
*
* 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>
#include <mcu/stm32.h>
#include <contrib/usart.h>
/* Hardware registers */
struct USART {
volatile uint32_t SR;
volatile uint32_t DR;
volatile uint32_t BRR;
volatile uint32_t CR1;
volatile uint32_t CR2;
volatile uint32_t CR3;
volatile uint32_t GTPR;
};
#define USART2_BASE (APB1PERIPH_BASE + 0x4400)
#define USART3_BASE (APB1PERIPH_BASE + 0x4800)
#define USART2 ((struct USART *)USART2_BASE)
#define USART3 ((struct USART *)USART3_BASE)
#define USART_SR_CTS (1 << 9)
#define USART_SR_LBD (1 << 8)
#define USART_SR_TXE (1 << 7)
#define USART_SR_TC (1 << 6)
#define USART_SR_RXNE (1 << 5)
#define USART_SR_IDLE (1 << 4)
#define USART_SR_ORE (1 << 3)
#define USART_SR_NE (1 << 2)
#define USART_SR_FE (1 << 1)
#define USART_SR_PE (1 << 0)
#define USART_CR1_UE (1 << 13)
#define USART_CR1_M (1 << 12)
#define USART_CR1_WAKE (1 << 11)
#define USART_CR1_PCE (1 << 10)
#define USART_CR1_PS (1 << 9)
#define USART_CR1_PEIE (1 << 8)
#define USART_CR1_TXEIE (1 << 7)
#define USART_CR1_TCIE (1 << 6)
#define USART_CR1_RXNEIE (1 << 5)
#define USART_CR1_IDLEIE (1 << 4)
#define USART_CR1_TE (1 << 3)
#define USART_CR1_RE (1 << 2)
#define USART_CR1_RWU (1 << 1)
#define USART_CR1_SBK (1 << 0)
#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 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);
struct brr_setting {
uint8_t baud_spec;
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)},
{ B2400, ( 937 << 4)|8},
{ B9600, ( 234 << 4)|6},
{ B19200, ( 117 << 4)|3},
{ B57600, ( 39 << 4)|1},
{ B115200, ( 19 << 4)|8},
{ B230400, ( 9 << 4)|12},
{ B460800, ( 4 << 4)|14},
{ B921600, ( 2 << 4)|7},
{ 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 */
};
#include "usart-common.c"
static void
usart_config_recv_enable (struct USART *USARTx, int on)
{
if (on)
USARTx->CR1 |= USART_CR1_RE;
else
USARTx->CR1 &= ~USART_CR1_RE;
}
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))
|| ((config_bits & MASK_CS) == CS8 && (config_bits & PARENB) == 0))
cr1_config &= ~USART_CR1_M;
else if ((config_bits & MASK_CS) == CS8)
cr1_config |= USART_CR1_M;
else
return -1;
if ((config_bits & PARENB) == 0)
cr1_config &= ~(USART_CR1_PCE | USART_CR1_PEIE);
else
cr1_config |= (USART_CR1_PCE | USART_CR1_PEIE);
if ((config_bits & PARODD) == 0)
cr1_config &= ~USART_CR1_PS;
else
cr1_config |= USART_CR1_PS;
if ((config_bits & MASK_STOP) == STOP0B5)
USARTx->CR2 = (0x1 << 12);
else if ((config_bits & MASK_STOP) == STOP1B)
USARTx->CR2 = (0x0 << 12);
else if ((config_bits & MASK_STOP) == STOP1B5)
USARTx->CR2 = (0x3 << 12);
else /* if ((config_bits & MASK_STOP) == STOP2B) */
USARTx->CR2 = (0x2 << 12);
for (i = 0; i < NUM_BAUD; i++)
if (brr_table[i].baud_spec == baud_spec)
break;
if (i >= NUM_BAUD)
return -1;
USARTx->BRR = brr_table[i].brr_value;
if ((config_bits & MASK_FLOW))
USARTx->CR3 = USART_CR3_CTSE | USART_CR3_RTSE;
else
USARTx->CR3 = 0;
if (!(config_bits & MASK_MODE))
cr1_config |= USART_CR1_RE;
USARTx->CR1 = cr1_config;
/* SCEN (smartcard enable) should be set _after_ CR1. */
if ((config_bits & MASK_MODE))
{
if ((config_bits & MASK_MODE) == MODE_SMARTCARD)
{
USARTx->GTPR = (1 << 8) | 5;
USARTx->CR3 |= (USART_CR3_SCEN | USART_CR3_NACK);
}
else if ((config_bits & MASK_MODE) == MODE_IRDA)
USARTx->CR3 |= (1 << 1);
else if ((config_bits & MASK_MODE) == MODE_IRDA_LP)
USARTx->CR3 |= (1 << 2) | (1 << 1);
}
return 0;
}
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 USART2 and USART3 clocks, and strobe reset. */
RCC->APB1ENR |= ((1 << 18) | (1 << 17));
RCC->APB1RSTR = ((1 << 18) | (1 << 17));
RCC->APB1RSTR = 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->SR;
int notify_bits = 0;
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
if (smartcard_mode)
{
if ((r & USART_SR_TC))
{
tx_ready = 1;
USARTx->CR1 &= ~USART_CR1_TCIE;
}
}
else
{
if ((r & USART_SR_TXE))
{
tx_ready = 1;
USARTx->CR1 &= ~USART_CR1_TXEIE;
}
}
if ((r & USART_SR_RXNE))
{
uint32_t data = USARTx->DR;
/* DR register should be accessed even if data is not used.
* Its read-access has side effect of clearing error flags.
*/
asm volatile ("" : : "r" (data) : "memory");
if ((r & USART_SR_NE))
stat->err_rx_noise++;
else if ((r & USART_SR_FE))
{
/* NOTE: Noway to distinguish framing error and break */
stat->rx_break++;
notify_bits |= UART_STATE_BITMAP_BREAK;
}
else if ((r & USART_SR_PE))
{
stat->err_rx_parity++;
notify_bits |= UART_STATE_BITMAP_PARITY;
}
else
{
if ((r & USART_SR_ORE))
{
stat->err_rx_overrun++;
notify_bits |= UART_STATE_BITMAP_OVERRUN;
}
/* XXX: if CS is 7-bit, mask it, or else parity bit in upper layer */
if (rb_ll_put (rb2a, (data & 0xff)) < 0)
stat->err_rx_overflow++;
else
stat->rx++;
}
}
else if ((r & USART_SR_ORE))
{ /* Clear ORE */
uint32_t data = USARTx->DR;
asm volatile ("" : : "r" (data) : "memory");
stat->err_rx_overrun++;
notify_bits |= UART_STATE_BITMAP_OVERRUN;
}
if (notify_bits)
{
if (ss_notify_callback
&& (*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->DR = (c & 0xff);
stat->tx++;
r = USARTx->SR;
if (smartcard_mode)
{
if ((r & USART_SR_TC) == 0)
{
tx_ready = 0;
USARTx->CR1 |= USART_CR1_TCIE;
}
}
else
{
if ((r & USART_SR_TXE) == 0)
{
tx_ready = 0;
USARTx->CR1 |= USART_CR1_TXEIE;
}
}
}
return tx_ready;
}
int
usart_send_break (uint8_t dev_no)
{
struct USART *USARTx = get_usart_dev (dev_no);
if (USARTx == NULL)
return -1;
if ((USARTx->CR1 & 0x01))
return 1; /* Busy sending break, which was requested before. */
USARTx->CR1 |= 0x01;
return 0;
}
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;
}

90
contrib/usart.h Normal file
View File

@@ -0,0 +1,90 @@
#define B0 0 /* POSIX to hang up */
/* POSIX supports B75 to B300 */
#define B600 16
#define B1200 17
#define B2400 19
#define B9600 21
#define B19200 22
#define B57600 24
#define B115200 25
#define B230400 26
#define B460800 27
#define B921600 28
#define 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 */
#define CS7 (2 << 6)
#define CS8 (3 << 6)
#define MASK_CS (0x7 << 6)
#define STOP0B5 (0 << 9) /* USART Hardware only */
#define STOP1B (1 << 9) /* USB, POSIX */
#define STOP1B5 (2 << 9) /* USB */
#define STOP2B (3 << 9) /* USB, POSIX */
#define MASK_STOP (0x3 << 9)
#define PARENB (1 << 11)
#define PARODD (2 << 11)
#define MASK_PAR (0x7 << 11)
/* USB 0: none, 1: odd, 2: even, 3: mark, 4: space */
#define CRTSCTS (1 << 14)
#define MASK_FLOW (0x1 << 14)
/*
BAUD_BITS 6
CS_BITS 3
STOP_BITS 2
PAR_BITS 3
*/
/* USB: SET_CONTROL_LINE_STATE
DTR RTS */
/* USB: SERIAL_STATE
DSR DCD RI */
/* non-POSIX, non-USB-CDC configs */
#define MODE_SMARTCARD (1 << 30)
#define MODE_IRDA (2UL << 30)
#define MODE_IRDA_LP (3UL << 30)
#define MASK_MODE (0x3UL << 30)
/* 0: standard, 1: smartcard, 2: IrDA, 3: IrDA-LP */
struct usart_stat {
uint8_t dev_no;
uint32_t tx;
uint32_t rx;
uint32_t rx_break;
uint32_t err_notify_overflow;
uint32_t err_rx_overflow; /* software side */
uint32_t err_rx_overrun; /* hardware side */
uint32_t err_rx_noise;
uint32_t err_rx_parity;
};
void usart_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
int (*ss_notify_callback) (uint8_t dev_no, uint16_t notify_bits));
int usart_config (uint8_t dev_no, uint32_t config_bits);
int usart_read (uint8_t dev_no, char *buf, uint16_t buflen);
int usart_write (uint8_t dev_no, char *buf, uint16_t buflen);
const struct usart_stat *usart_stat (uint8_t dev_no);
int usart_send_break (uint8_t dev_no);
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

@@ -7,19 +7,9 @@ When it detects a coding error, this function will be called to
stop further execution of code. It never returns.
@end deftypefun
@subheading chopstx_main_init
@anchor{chopstx_main_init}
@deftypefun {void} {chopstx_main_init} (chopstx_prio_t @var{prio})
@var{prio}: priority
Initialize main thread with @var{prio}.
The thread main is created with priority CHX_PRIO_MAIN_INIT,
and it runs with that priority until this routine will is called.
@end deftypefun
@subheading chopstx_create
@anchor{chopstx_create}
@deftypefun {chopstx_t} {chopstx_create} (uint32_t @var{flags_and_prio}, uint32_t @var{stack_addr}, size_t @var{stack_size}, voidfunc @var{thread_entry}, void * @var{arg})
@deftypefun {chopstx_t} {chopstx_create} (uint32_t @var{flags_and_prio}, uintptr_t @var{stack_addr}, size_t @var{stack_size}, voidfunc @var{thread_entry}, void * @var{arg})
@var{flags_and_prio}: Flags and priority
@var{stack_addr}: Stack address
@@ -30,16 +20,7 @@ and it runs with that priority until this routine will is called.
@var{arg}: Argument to the thread entry function
Create a thread.
@end deftypefun
@subheading chopstx_usec_wait_var
@anchor{chopstx_usec_wait_var}
@deftypefun {void} {chopstx_usec_wait_var} (uint32_t * @var{var})
@var{var}: Pointer to usec
Sleep for micro seconds, specified by @var{var}.
Another thread can clear @var{var} to stop the caller going into sleep.
Create a thread. Returns thread ID.
@end deftypefun
@subheading chopstx_usec_wait
@@ -115,15 +96,7 @@ Wake up all threads waiting on @var{cond}.
@var{irq_num}: IRQ Number (hardware specific)
Claim interrupt @var{intr} with @var{irq_num} for this thread.
@end deftypefun
@subheading chopstx_release_irq
@anchor{chopstx_release_irq}
@deftypefun {void} {chopstx_release_irq} (chopstx_intr_t * @var{intr0})
@var{intr0}: Interrupt request to be unregistered
Release the interrupt request specified by @var{intr0}.
Claim interrupt @var{intr} with @var{irq_num}
@end deftypefun
@subheading chopstx_intr_wait
@@ -134,6 +107,14 @@ Release the interrupt request specified by @var{intr0}.
Wait for the interrupt @var{intr} to be occured.
@end deftypefun
@subheading chopstx_intr_done
@anchor{chopstx_intr_done}
@deftypefun {void} {chopstx_intr_done} (chopstx_intr_t * @var{intr})
@var{intr}: Pointer to INTR structure
Finish for the interrupt @var{intr} occurred.
@end deftypefun
@subheading chopstx_cleanup_push
@anchor{chopstx_cleanup_push}
@deftypefun {void} {chopstx_cleanup_push} (struct chx_cleanup * @var{clp})
@@ -156,29 +137,21 @@ clean-up will be executed.
@deftypefun {void} {chopstx_exit} (void * @var{retval})
@var{retval}: Return value (to be caught by a joining thread)
Calling this function terminates the execution of thread, after
calling clean up functions. If the calling thread still holds
mutexes, they will be released. If the calling thread claiming
IRQ, it will be released, too. This function never returns.
Calling this function terminates the execution of running thread,
after calling clean up functions. If the calling thread still
holds mutexes, they will be released. This function never
returns.
@end deftypefun
@subheading chopstx_join
@anchor{chopstx_join}
@deftypefun {void} {chopstx_join} (chopstx_t @var{thd}, void ** @var{ret})
@deftypefun {int} {chopstx_join} (chopstx_t @var{thd}, void ** @var{ret})
@var{thd}: Thread to wait
@var{ret}: Pointer to void * to store return value
Waits for the thread of @var{thd} to terminate.
@end deftypefun
@subheading chopstx_wakeup_usec_wait
@anchor{chopstx_wakeup_usec_wait}
@deftypefun {void} {chopstx_wakeup_usec_wait} (chopstx_t @var{thd})
@var{thd}: Thread to be awakened
Canceling the timer, wake up the sleeping thread.
No return value.
Returns 0 on success, 1 when waiting is interrupted.
@end deftypefun
@subheading chopstx_cancel
@@ -199,3 +172,61 @@ No return value. If the thread is canceled, this function
does not return.
@end deftypefun
@subheading chopstx_setcancelstate
@anchor{chopstx_setcancelstate}
@deftypefun {int} {chopstx_setcancelstate} (int @var{cancel_disable})
@var{cancel_disable}: 0 to enable cancelation, otherwise disabled.
Calling chopstx_setcancelstate sets cancelability state.
Returns old state which is 0 when it was enabled.
@end deftypefun
@subheading chopstx_poll
@anchor{chopstx_poll}
@deftypefun {int} {chopstx_poll} (uint32_t * @var{usec_p}, int @var{n}, struct chx_poll_head *const [] @var{pd_array})
@var{usec_p}: Pointer to usec for timeout. Forever if NULL. It is
updated on return
@var{n}: Number of poll descriptors
@var{pd_array}: Pointer to an array of poll descriptor pointer which
should be one of:
chopstx_poll_cond_t, chopstx_poll_join_t, or chopstx_intr_t.
Returns number of active descriptors.
@end deftypefun
@subheading chopstx_setpriority
@anchor{chopstx_setpriority}
@deftypefun {chopstx_prio_t} {chopstx_setpriority} (chopstx_prio_t @var{prio_new})
Change the schedule priority with @var{prio}.
Returns the old priority.
In general, it is not recommended to use this function because
dynamically changing schedule priorities complicates the system.
Only a possible valid usage of this function is in the main thread
which starts its execution with priority of CHX_PRIO_MAIN_INIT, and
let it change its priority after initialization of other threads.
@end deftypefun
@subheading chx_sleep_mode
@anchor{chx_sleep_mode}
@deftypefun {extern void} {chx_sleep_mode} (int @var{enable_sleep})
@var{enable_sleep}: Enable sleep on idle or not
If @var{enable_sleep} is > 0, allow sleep for the idle thread.
Behavior of @var{enable_sleep} >= 1 depends on MCU.
For STM32F0, 1 for Sleep (CPU clock OFF only), 2 for Stop (Wakeup
by EXTI, voltage regulator on), 3 for Stop (Wakeup by EXTI, voltage
regulator low-power), 4 for Standby (Wakeup by RESET, voltage
regulator off).
For STM32F103, 1 for normal sleep, and 2 for sleep with lower 8MHz
clock.
Return previous value of @var{enable_sleep}.
@end deftypefun

View File

@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename chopstx.info
@set VERSION 0.06
@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 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
@@ -59,7 +59,12 @@ section entitled ``Copying''.
@menu
* Introduction:: What is Chopstx.
* Threads and only Threads:: Threads and only Threads.
* 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
@@ -83,21 +88,182 @@ Indexes
@node Introduction
@chapter Introduction
Chopstx is an RT thread library for ARM Cortex-M3, specifically,
STM32F103.
Chopstx is an RT thread library for ARM Cortex-M0, Cortex-M0plus,
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 a RT thread library.
Chopstx just offers an RT thread library.
With Chopstx, interrupt handling is also done by a thread. This
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
handle multiple events by a single thread.
@node Threads and only Threads
@chapter Threads and only Threads
Chopstx doesn't use the feature of (prioritized) nested vector
interrupt mechanism at all. All interrupts are equally handled by a
single entry of chx_handle_intr which just wakes up a corresponding
thread. This is the feature of Chopstx.
Nested vector interrupt machanism would be useful for interrupt-driven
programming style for specific application targets, or, some other
programing style like the one with spl of Unix. Some engineers
(especially, hardware side) still seem to believe that it is a good
feature to have. But from the view point of programming and
maintenance of software, this is one of the most difficult part with
little benefit, if any.
With traditional interrupt handling, a demarcation of what should be
done by interrupt handler, bottom half, and thead is crucial for
applications' performance. And because the demarcation should be done
at an early stage of an application development, it has a tendency,
many parts are getting demanding higher priority. Amount of code for
higher priority interrupt hander is getting bigger and bigger, while
losing performance.
On the other hand, ``Threads (and only Threads)'' programming style
gives us best flexibility and it can make an application more
predictable, deterministic and easy to maintain.
There are some applications, like square wave generator, which are not
suited to this programming style; Another programming style can
support more performance (frequency). In general, such an example is
best suited by hardware (not software).
@node Poll or Pole
@chapter Poll or Pole
Chopstx provides the @code{chopstx_poll} function to wait on multiple events.
Using @code{chopstx_poll}, we can write an application by event-driven
programming style, with minimum number of threads, avoiding
complicated dependency between threads.
@node 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
running. By setting relevant bits of system registers, MCU will be
able to be into stop or stand-by mode, which is MCU dependent.
If you use this sleep feature, please consider and implement your
program carefully. Enabling sleep, it may result a bricked board; A
board with no RESET pin cannot be debugged by JTAG/SWD.
@node Compile-time macro
@chapter Compile-time macro
Compiling Chopstx, a macro MHZ should be supplied.
For example, when using the makefile rule of chopstx/rules.mk, please
define the make variable DEFS with -DMHZ=72 before inclusion of the rule file.
@subheading MHZ
@anchor{MHZ}
@defmac {MHZ}
Running CPU clock in MHz. Used for chopstx_usec_wait.
@end defmac
@node API
@chapter API
@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);
}

115
entry.c
View File

@@ -1,7 +1,8 @@
/*
* entry.c - Entry routine when reset and interrupt vectors.
*
* Copyright (C) 2013, 2014, 2015 Flying Stone Technology
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2019
* Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -22,26 +23,47 @@
* 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>
#ifdef HAVE_SYS_H
#define INLINE __attribute__ ((used))
#include "board.h"
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
#include "sys.h"
#include "board.h"
/*
* Avoid medium density specific code and prepare for high density
* device, too.
*/
#if !defined(MCU_STM32L4)
#define STM32F10X_HD
#endif
#else
#include "board.h"
#include "clk_gpio_init.c"
#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-stm32f.c"
#endif
#endif
#ifdef MAKE_ENTRY_PUBLIC
#define STATIC_ENTRY
#else
#define STATIC_ENTRY static
#endif
extern uint8_t __main_stack_end__;
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
extern void svc (void);
#endif
extern void preempt (void);
extern void chx_timer_expired (void);
extern void chx_handle_intr (void);
@@ -53,18 +75,7 @@ static void nmi (void)
static void hard_fault (void)
{
#if defined(__ARM_ARCH_6M__)
register uint32_t primask;
asm ("mrs %0, PRIMASK" : "=r" (primask));
if (primask)
asm volatile ("b svc");
else
for (;;);
#else
for (;;);
#endif
}
static void mem_manage (void)
@@ -97,8 +108,9 @@ uint32_t vectors_in_ram[48];
/*
* This routine only changes PSP and not MSP.
*/
static __attribute__ ((naked,section(".text.startup.0")))
void entry (void)
STATIC_ENTRY __attribute__ ((naked,section(".text.startup.0")))
void
entry (void)
{
asm volatile ("bl clock_init\n\t"
/* Clear BSS section. */
@@ -145,7 +157,7 @@ void 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
@@ -162,7 +174,7 @@ void entry (void)
typedef void (*handler)(void);
handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
(handler)&__main_stack_end__,
(handler)(&__main_stack_end__ - 32),
entry,
nmi, /* nmi */
hard_fault, /* hard fault */
@@ -173,31 +185,62 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
none,
/* 0x20 */
none, none, none, /* reserved */
#if defined(__ARM_ARCH_6M__)
none, /* SVCall */
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
svc, /* SVCall */
#endif
none, /* Debug */
none, /* reserved */
preempt, /* PendSV */
chx_timer_expired, /* SysTick */
/* 0x40 */
chx_handle_intr /* WWDG */, chx_handle_intr /* PVD */,
chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,
chx_handle_intr /* FLASH */, chx_handle_intr /* RCC */,
chx_handle_intr /* EXTI0 */, chx_handle_intr /* EXTI1 */,
chx_handle_intr /* WWDG */, chx_handle_intr /* PVD */,
chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,
chx_handle_intr /* FLASH */, chx_handle_intr /* RCC */,
chx_handle_intr /* EXTI0 */, chx_handle_intr /* EXTI1 */,
/* 0x60 */
chx_handle_intr /* EXTI2 */, chx_handle_intr /* EXTI3 */,
chx_handle_intr /* EXTI4 */, chx_handle_intr /* DMA1 CH1 */,
chx_handle_intr /* DMA1 CH2 */, chx_handle_intr /* DMA1 CH3 */,
chx_handle_intr /* DMA1 CH4 */, chx_handle_intr /* DMA1 CH5 */,
chx_handle_intr /* EXTI2 */, chx_handle_intr /* EXTI3 */,
chx_handle_intr /* EXTI4 */, chx_handle_intr /* DMA1 CH1 */,
chx_handle_intr /* DMA1 CH2 */, chx_handle_intr /* DMA1 CH3 */,
chx_handle_intr /* DMA1 CH4 */, chx_handle_intr /* DMA1 CH5 */,
/* 0x80 */
chx_handle_intr /* DMA1 CH6 */, chx_handle_intr /* DMA1 CH7 */,
chx_handle_intr /* ADC1_2 */, chx_handle_intr /* USB HP */,
chx_handle_intr /* DMA1 CH6 */, chx_handle_intr /* DMA1 CH7 */,
chx_handle_intr /* ADC1_2 */, chx_handle_intr /* USB HP */,
/* 0x90 */
chx_handle_intr, /* USB LP */
/* ... and more. CAN, EXT9_5, TIMx, I2C, SPI, USART, EXT15_10 */
chx_handle_intr /* USB LP */, chx_handle_intr /* CAN RX1 */,
chx_handle_intr /* CAN SCE */, chx_handle_intr /* EXT9_5 */,
/* 0xa0 */
/* ... and more. TIMx, I2C, SPI, USART... */
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
/* 0xc0 */
#if !defined(__ARM_ARCH_6M__)
/* STM32F0 doesn't have more. */
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
/* 0xe0 */
chx_handle_intr /* EXT15_10 */, chx_handle_intr /* RTCAlarm */,
chx_handle_intr /* USBWakeup */, chx_handle_intr,
#endif
#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, chx_handle_intr, chx_handle_intr,
#endif
};

View File

@@ -1,7 +1,7 @@
/*
* eventflag.c - Eventflag with/without timeout
* eventflag.c - Eventflag
*
* Copyright (C) 2013 Flying Stone Technology
* Copyright (C) 2013, 2016, 2018 Flying Stone Technology
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Chopstx, a thread library for embedded.
@@ -22,7 +22,7 @@
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* receipents of GNU GPL by a written offer.
* recipients of GNU GPL by a written offer.
*
*/
@@ -31,24 +31,70 @@
#include <chopstx.h>
#include <eventflag.h>
enum {
EVENTFLAG_ERR_WAIT = CHOPSTX_ERR_JOIN + 1,
EVENTFLAG_ERR_TIMED_WAIT,
};
void
eventflag_init (struct eventflag *ev)
{
ev->flags = 0;
ev->mask = ~0;
chopstx_cond_init (&ev->cond);
chopstx_mutex_init (&ev->mutex);
}
void
eventflag_init (struct eventflag *ev, chopstx_t sleeper)
eventflag_set_mask (struct eventflag *ev, eventmask_t m)
{
ev->sleeper = sleeper;
chopstx_mutex_lock (&ev->mutex);
ev->mask = m;
if ((ev->flags & ev->mask))
chopstx_cond_signal (&ev->cond);
chopstx_mutex_unlock (&ev->mutex);
}
if (sleeper)
ev->u.wait_usec = 0;
static int
eventflag_check (void *arg)
{
struct eventflag *ev = arg;
return (ev->flags & ev->mask) != 0;
}
void
eventflag_prepare_poll (struct eventflag *ev, chopstx_poll_cond_t *poll_desc)
{
poll_desc->type = CHOPSTX_POLL_COND;
poll_desc->ready = 0;
poll_desc->cond = &ev->cond;
poll_desc->mutex = &ev->mutex;
poll_desc->check = eventflag_check;
poll_desc->arg = ev;
}
/* When multiple events are marked, event with lower bit has precedence.
Because __builtin_ffs returns the least significant 1-bit. */
eventmask_t
eventflag_get (struct eventflag *ev)
{
int n;
eventmask_t m;
chopstx_mutex_lock (&ev->mutex);
n = __builtin_ffs ((ev->flags & ev->mask));
if (n)
{
m = (1 << (n - 1));
ev->flags &= ~m;
}
else
chopstx_cond_init (&ev->u.cond);
m = 0;
chopstx_mutex_unlock (&ev->mutex);
ev->flag = 0;
chopstx_mutex_init (&ev->mutex);
return m;
}
@@ -56,50 +102,35 @@ eventmask_t
eventflag_wait (struct eventflag *ev)
{
int n;
if (ev->sleeper)
chx_fatal (EVENTFLAG_ERR_WAIT);
eventmask_t m;
chopstx_mutex_lock (&ev->mutex);
if (!ev->flag)
chopstx_cond_wait (&ev->u.cond, &ev->mutex);
while (!(ev->flags & ev->mask))
chopstx_cond_wait (&ev->cond, &ev->mutex);
n = __builtin_ffs (ev->flag);
ev->flag &= ~(1 << (n - 1));
n = __builtin_ffs ((ev->flags & ev->mask));
if (n) /* Always n > 0 when waked up, but make sure no bad things. */
{
m = (1 << (n - 1));
ev->flags &= ~m;
}
else
m = 0;
chopstx_mutex_unlock (&ev->mutex);
return (1 << (n - 1));
return m;
}
eventmask_t
eventflag_wait_timeout (struct eventflag *ev, uint32_t usec)
{
eventmask_t em = 0;
int n;
chopstx_poll_cond_t poll_desc;
struct chx_poll_head *pd_array[1] = { (struct chx_poll_head *)&poll_desc };
if (ev->sleeper == 0)
chx_fatal (EVENTFLAG_ERR_TIMED_WAIT);
chopstx_mutex_lock (&ev->mutex);
if (!ev->flag)
{
ev->u.wait_usec = usec;
chopstx_mutex_unlock (&ev->mutex);
chopstx_usec_wait_var (&ev->u.wait_usec);
chopstx_mutex_lock (&ev->mutex);
ev->u.wait_usec = 0;
}
n = __builtin_ffs (ev->flag);
if (n)
{
em = (1 << (n - 1));
ev->flag &= ~em;
}
chopstx_mutex_unlock (&ev->mutex);
return em;
eventflag_prepare_poll (ev, &poll_desc);
chopstx_poll (&usec, 1, pd_array);
return eventflag_get (ev);
}
@@ -107,16 +138,8 @@ void
eventflag_signal (struct eventflag *ev, eventmask_t m)
{
chopstx_mutex_lock (&ev->mutex);
ev->flag |= m;
if (ev->sleeper)
{
if (ev->u.wait_usec)
{
ev->u.wait_usec = 0;
chopstx_wakeup_usec_wait (ev->sleeper);
}
}
else
chopstx_cond_signal (&ev->u.cond);
ev->flags |= m;
if ((ev->flags & ev->mask))
chopstx_cond_signal (&ev->cond);
chopstx_mutex_unlock (&ev->mutex);
}

View File

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

View File

@@ -0,0 +1,43 @@
# Makefile for example application of Chopstx
PROJECT = sample
### This is for GNU/Linux
CHOPSTX = ..
LDSCRIPT=
CSRC = sample.c usb-cdc.c command.c
CHIP=gnu-linux
USE_SYS = yes
USE_USB = yes
USE_ADC = yes
EMULATION=yes
###################################
CROSS =
CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = none
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DGNU_LINUX_EMULATION -DUSE_SYS_BOARD_ID
OPT = -g # -O3 -Os
LIBS = -lpthread
####################
include ../rules.mk
board.h:
@echo Please make a symbolic link \'board.h\' to a file in ../board;
@exit 1
distclean: clean
build/flash.data: Makefile
@echo 'Generating 8192-byte flash.data'
@/bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff' >$@
@for i in $(shell seq 1023); do /bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff' >>$@; done

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
void cmd_dispatch (struct tty *tty, const char *line);
char * compose_hex_ptr (char *s, uintptr_t v);

View File

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

View File

@@ -0,0 +1,197 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <chopstx.h>
#include "sys.h"
#include "usb_lld.h"
#include "tty.h"
#include "command.h"
#include <unistd.h>
#include <stdio.h>
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0;
static chopstx_cond_t cnd1;
static uint8_t u, v;
static uint8_t m; /* 0..100 */
static void *
pwm (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd0, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
set_led (u&v);
chopstx_usec_wait (m);
set_led (0);
chopstx_usec_wait (100-m);
}
return NULL;
}
static void *
blk (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd1, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
v = 0;
chopstx_usec_wait (200*1000);
v = 1;
chopstx_usec_wait (200*1000);
}
return NULL;
}
#define PRIO_PWM 3
#define PRIO_BLK 2
static char __process1_stack_base__[4096];
static char __process2_stack_base__[4096];
#define STACK_ADDR_PWM ((uintptr_t)__process1_stack_base__)
#define STACK_SIZE_PWM (sizeof __process1_stack_base__)
#define STACK_ADDR_BLK ((uintptr_t)__process2_stack_base__)
#define STACK_SIZE_BLK (sizeof __process2_stack_base__)
static char hexchar (uint8_t x)
{
x &= 0x0f;
if (x <= 0x09)
return '0' + x;
else if (x <= 0x0f)
return 'a' + x - 10;
else
return '?';
}
#ifdef GNU_LINUX_EMULATION
#define main emulated_main
#endif
int
main (int argc, const char *argv[])
{
struct tty *tty;
uint8_t count;
uintptr_t addr;
if (argc >= 2 && !strncmp (argv[1], "--debug=", 8))
debug = strtol (&argv[1][8], NULL, 10);
chopstx_mutex_init (&mtx);
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
m = 10;
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);
chopstx_mutex_lock (&mtx);
chopstx_cond_signal (&cnd0);
chopstx_cond_signal (&cnd1);
chopstx_mutex_unlock (&mtx);
addr = flash_init ("flash.data");
flash_unlock ();
u = 1;
tty = tty_open ();
tty_wait_configured (tty);
count = 0;
m = 50;
while (1)
{
char s[LINEBUFSIZE];
connection_loop:
u = 1;
tty_wait_connection (tty);
chopstx_usec_wait (50*1000);
puts("send ZLP");
/* Send ZLP at the beginning. */
tty_send (tty, s, 0);
memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32);
s[0] = hexchar (count >> 4);
s[1] = hexchar (count & 0x0f);
puts("send hello");
if (tty_send (tty, s, 32) < 0)
continue;
s[0] = hexchar (count >> 4);
s[1] = hexchar (count & 0x0f);
s[2] = ':';
s[3] = ' ';
compose_hex_ptr (s+4, addr);
s[20] = '\r';
s[21] = '\n';
count++;
if (tty_send (tty, s, 22) < 0)
continue;
while (1)
{
uint32_t usec;
/* Prompt */
if (tty_send (tty, "> ", 2) < 0)
break;
usec = 3000000; /* 3.0 seconds */
while (1)
{
int size = tty_recv (tty, s, &usec);
u ^= 1;
if (size < 0)
goto connection_loop;
if (size == 1)
/* Do nothing but prompt again. */
break;
else if (size)
{
/* Newline into NUL */
s[size - 1] = 0;
cmd_dispatch (tty, (char *)s);
break;
}
}
}
}
return 0;
}

View File

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

View File

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

View File

@@ -3,8 +3,14 @@
PROJECT = sample
CHOPSTX = ..
LDSCRIPT= sample.ld
CSRC = sys.c aes-constant-ft.c sample.c usb-cdc.c usb_stm32f103.c
LDSCRIPT= sample.ld.m4
CSRC = sample.c usb-cdc.c
CHIP=stm32l4
USE_SYS = yes
USE_USB = yes
ENABLE_OUTPUT_HEX=yes
###################################
CROSS = arm-none-eabi-
@@ -12,9 +18,9 @@ CC = $(CROSS)gcc
LD = $(CROSS)gcc
OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
MCU = cortex-m4
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DHAVE_SYS_H -DFREE_STANDING
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
OPT = -O3 -Os -g
LIBS =

View File

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

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

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

View File

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

View File

@@ -1,11 +1,6 @@
/*
* ST32F103 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__process0_stack_size__ = 0x0100; /* Main program */
__process1_stack_size__ = 0x0100; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */
__process3_stack_size__ = 0x0100; /* third thread program */
MEMORY
{
@@ -14,9 +9,6 @@ MEMORY
ram : org = 0x20000000, len = 20k
}
__flash_start__ = 0x08001000;
__flash_end__ = 0x08020000;
__ram_start__ = ORIGIN(ram);
__ram_size__ = 20k;
__ram_end__ = __ram_start__ + __ram_size__;
@@ -25,16 +17,18 @@ SECTIONS
{
. = 0;
.sys : ALIGN(16) SUBALIGN(16)
.sys : ALIGN(4) SUBALIGN(4)
{
_sys = .;
KEEP(*(.vectors))
_sys = .;
KEEP(*(.vectors))
. = ALIGN(16);
*(.sys.version)
build/sys.o(.text)
build/sys.o(.text.*)
build/sys.o(.rodata)
build/sys.o(.rodata.*)
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)
@@ -59,6 +53,7 @@ SECTIONS
*(.glue_7t)
*(.glue_7)
*(.gcc*)
. = ALIGN(8);
} > flash
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
@@ -78,34 +73,21 @@ SECTIONS
_etext = .;
_textdata = _etext;
.process_stack :
.process_stack (NOLOAD) :
{
. = ALIGN(8);
__process3_stack_base__ = .;
. += __process3_stack_size__;
*(.process_stack.3)
*(.process_stack.2)
*(.process_stack.1)
*(.process_stack.0)
. = ALIGN(8);
__process3_stack_end__ = .;
__process2_stack_base__ = .;
. += __process2_stack_size__;
. = ALIGN(8);
__process2_stack_end__ = .;
__process1_stack_base__ = .;
. += __process1_stack_size__;
. = ALIGN(8);
__process1_stack_end__ = .;
__process0_stack_base__ = .;
. += __process0_stack_size__;
. = ALIGN(8);
__process0_stack_end__ = .;
} > ram
.main_stack :
.main_stack (NOLOAD) :
{
. = ALIGN(8);
__main_stack_base__ = .;
. += __main_stack_size__;
*(.main_stack)
. = ALIGN(8);
__main_stack_end__ = .;
} > ram
.data :

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

24
example-cdc/stack-def.h Normal file
View File

@@ -0,0 +1,24 @@
#if defined(STACK_MAIN)
/* Idle+Exception handlers */
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
char main_base[0x0100] __attribute__ ((section(".main_stack")));
/* Main program */
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
char process0_base[0x0400] __attribute__ ((section(".process_stack.0")));
#endif
/* First thread program */
#if defined(STACK_PROCESS_1)
char process1_base[0x0200] __attribute__ ((section(".process_stack.1")));
#endif
/* Second thread program */
#if defined(STACK_PROCESS_2)
char process2_base[0x0200] __attribute__ ((section(".process_stack.2")));
#endif
/* Third thread program */
#if defined(STACK_PROCESS_3)
char process3_base[0x0200] __attribute__ ((section(".process_stack.3")));
#endif

View File

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

View File

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

9
example-cdc/tty.h Normal file
View File

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

View File

@@ -1,10 +1,85 @@
#include <stdint.h>
#include <stdlib.h>
#include <chopstx.h>
#include <string.h>
#include "board.h"
#include "usb_lld.h"
#include "tty.h"
static chopstx_intr_t usb_intr;
struct line_coding
{
uint32_t bitrate;
uint8_t format;
uint8_t paritytype;
uint8_t datatype;
} __attribute__((packed));
static const struct line_coding line_coding0 = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
/*
* Currently, we only support a single TTY.
*
* It is possible to extend to support multiple TTYs, for multiple
* interfaces.
*
* In that case, add argument to TTY_OPEN function and
* modify TTY_GET function to get the TTY structure. Functions which
* directy accesses TTY0 (usb_device_reset and usb_set_configuration)
* should be modified, too.
*
* Modification of TTY_MAIN thread will be also needed to echo back
* input for each TTY, and the thread should run if one of TTY is
* opened.
*/
struct tty {
chopstx_mutex_t mtx;
chopstx_cond_t cnd;
uint8_t inputline[LINEBUFSIZE]; /* Line editing is supported */
uint8_t send_buf[LINEBUFSIZE]; /* Sending ring buffer for echo back */
uint32_t inputline_len : 8;
uint32_t send_head : 8;
uint32_t send_tail : 8;
uint32_t flag_connected : 1;
uint32_t flag_send_ready : 1;
uint32_t flag_input_avail : 1;
uint32_t : 2;
uint32_t device_state : 3; /* USB device status */
struct line_coding line_coding;
};
static struct tty tty0;
/*
* Locate TTY structure from interface number or endpoint number.
* Currently, it always returns tty0, because we only have the one.
*/
static struct tty *
tty_get (int interface, uint8_t ep_num)
{
struct tty *t = &tty0;
if (interface >= 0)
{
if (interface == 0)
t = &tty0;
}
else
{
if (ep_num == ENDP1 || ep_num == ENDP2 || ep_num == ENDP3)
t = &tty0;
}
return t;
}
extern chopstx_mutex_t usb_mtx;
extern chopstx_cond_t cnd_usb;
#define ENDP0_RXADDR (0x40)
#define ENDP0_TXADDR (0x80)
@@ -20,7 +95,7 @@ extern chopstx_cond_t cnd_usb;
/* USB Device Descriptor */
static const uint8_t vcom_device_desc[18] = {
18, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
DEVICE_DESCRIPTOR, /* bDescriptorType */
0x10, 0x01, /* bcdUSB = 1.1 */
0x02, /* bDeviceClass (CDC). */
0x00, /* bDeviceSubClass. */
@@ -35,20 +110,22 @@ static const uint8_t vcom_device_desc[18] = {
1 /* bNumConfigurations. */
};
#define VCOM_FEATURE_BUS_POWERED 0x80
/* Configuration Descriptor tree for a CDC.*/
static const uint8_t vcom_configuration_desc[67] = {
static const uint8_t vcom_config_desc[67] = {
9,
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
/* Configuration Descriptor.*/
67, 0x00, /* wTotalLength. */
0x02, /* bNumInterfaces. */
0x01, /* bConfigurationValue. */
0, /* iConfiguration. */
0x80, /* bmAttributes (bus powered). */
VCOM_FEATURE_BUS_POWERED, /* bmAttributes. */
50, /* bMaxPower (100mA). */
/* Interface Descriptor.*/
9,
USB_INTERFACE_DESCRIPTOR_TYPE,
INTERFACE_DESCRIPTOR,
0x00, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x01, /* bNumEndpoints. */
@@ -87,14 +164,14 @@ static const uint8_t vcom_configuration_desc[67] = {
0x01, /* bSlaveInterface0 (Data Class Interface). */
/* Endpoint 2 Descriptor.*/
7,
USB_ENDPOINT_DESCRIPTOR_TYPE,
ENDPOINT_DESCRIPTOR,
ENDP2|0x80, /* bEndpointAddress. */
0x03, /* bmAttributes (Interrupt). */
0x08, 0x00, /* wMaxPacketSize. */
0xFF, /* bInterval. */
/* Interface Descriptor.*/
9,
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
INTERFACE_DESCRIPTOR, /* bDescriptorType: */
0x01, /* bInterfaceNumber. */
0x00, /* bAlternateSetting. */
0x02, /* bNumEndpoints. */
@@ -104,14 +181,14 @@ static const uint8_t vcom_configuration_desc[67] = {
0x00, /* iInterface. */
/* Endpoint 3 Descriptor.*/
7,
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
ENDP3, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
0x00, /* bInterval. */
/* Endpoint 1 Descriptor.*/
7,
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
ENDP1|0x80, /* bEndpointAddress. */
0x02, /* bmAttributes (Bulk). */
0x40, 0x00, /* wMaxPacketSize. */
@@ -124,13 +201,13 @@ static const uint8_t vcom_configuration_desc[67] = {
*/
static const uint8_t vcom_string0[4] = {
4, /* bLength */
USB_STRING_DESCRIPTOR_TYPE,
STRING_DESCRIPTOR,
0x09, 0x04 /* LangID = 0x0409: US-English */
};
static const uint8_t vcom_string1[] = {
23*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
STRING_DESCRIPTOR, /* bDescriptorType */
/* Manufacturer: "Flying Stone Technology" */
'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0,
't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0,
@@ -139,7 +216,7 @@ static const uint8_t vcom_string1[] = {
static const uint8_t vcom_string2[] = {
14*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
STRING_DESCRIPTOR, /* bDescriptorType */
/* Product name: "Chopstx Sample" */
'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0,
'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0,
@@ -150,127 +227,122 @@ static const uint8_t vcom_string2[] = {
*/
static const uint8_t vcom_string3[28] = {
28, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
STRING_DESCRIPTOR, /* bDescriptorType */
'0', 0, '.', 0, '0', 0, '0', 0, /* Version number */
};
#define NUM_INTERFACES 2
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
uint8_t connected;
void
usb_cb_device_reset (void)
static void
usb_device_reset (struct usb_dev *dev)
{
/* Set DEVICE as not configured */
usb_lld_set_configuration (0);
/* Current Feature initialization */
usb_lld_set_feature (vcom_configuration_desc[7]);
usb_lld_reset ();
usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
chopstx_mutex_lock (&tty0.mtx);
tty0.inputline_len = 0;
tty0.send_head = tty0.send_tail = 0;
tty0.flag_connected = 0;
tty0.flag_send_ready = 1;
tty0.flag_input_avail = 0;
tty0.device_state = USB_DEVICE_STATE_ATTACHED;
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
chopstx_mutex_unlock (&tty0.mtx);
}
void
usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
uint16_t index, uint16_t len)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
#define CDC_CTRL_DTR 0x0001
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
&& index == 0 && USB_SETUP_SET (req) && len == 0
&& req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
static void
usb_ctrl_write_finish (struct usb_dev *dev)
{
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
&& USB_SETUP_SET (arg->type)
&& arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
{
struct tty *t = tty_get (arg->index, 0);
/* Open/close the connection. */
chopstx_mutex_lock (&usb_mtx);
connected = (value != 0)? 1 : 0;
chopstx_cond_signal (&cnd_usb);
chopstx_mutex_unlock (&usb_mtx);
chopstx_mutex_lock (&t->mtx);
t->flag_connected = ((arg->value & CDC_CTRL_DTR) != 0);
chopstx_cond_signal (&t->cnd);
chopstx_mutex_unlock (&t->mtx);
}
/*
* The transaction was already finished. So, it is no use to call
* usb_lld_ctrl_error when the condition does not match.
*/
}
struct line_coding
{
uint32_t bitrate;
uint8_t format;
uint8_t paritytype;
uint8_t datatype;
} __attribute__((packed));
static struct line_coding line_coding = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
static int
vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value, uint16_t len)
vcom_port_data_setup (struct usb_dev *dev)
{
(void)value;
if (USB_SETUP_GET (req))
struct device_req *arg = &dev->dev_req;
if (USB_SETUP_GET (arg->type))
{
if (req_no == USB_CDC_REQ_GET_LINE_CODING
&& len == sizeof (line_coding))
{
usb_lld_set_data_to_send (&line_coding, sizeof (line_coding));
return USB_SUCCESS;
}
struct tty *t = tty_get (arg->index, 0);
if (arg->request == USB_CDC_REQ_GET_LINE_CODING)
return usb_lld_ctrl_send (dev, &t->line_coding,
sizeof (struct line_coding));
}
else /* USB_SETUP_SET (req) */
{
if (req_no == USB_CDC_REQ_SET_LINE_CODING
&& len == sizeof (line_coding))
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
&& arg->len == sizeof (struct line_coding))
{
usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
return USB_SUCCESS;
struct tty *t = tty_get (arg->index, 0);
return usb_lld_ctrl_recv (dev, &t->line_coding,
sizeof (struct line_coding));
}
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
return USB_SUCCESS;
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
return usb_lld_ctrl_ack (dev);
}
return USB_UNSUPPORT;
return -1;
}
int
usb_cb_setup (uint8_t req, uint8_t req_no,
uint16_t value, uint16_t index, uint16_t len)
static int
usb_setup (struct usb_dev *dev)
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
struct device_req *arg = &dev->dev_req;
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
(void)len;
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
if (index == 0)
return vcom_port_data_setup (req, req_no, value, len);
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
return vcom_port_data_setup (dev);
return USB_UNSUPPORT;
return -1;
}
int
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
uint16_t index)
static int
usb_get_descriptor (struct usb_dev *dev)
{
(void)index;
struct device_req *arg = &dev->dev_req;
uint8_t rcp = arg->type & RECIPIENT;
uint8_t desc_type = (arg->value >> 8);
uint8_t desc_index = (arg->value & 0xff);
if (rcp != DEVICE_RECIPIENT)
return USB_UNSUPPORT;
return -1;
if (desc_type == DEVICE_DESCRIPTOR)
{
usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
return USB_SUCCESS;
}
return usb_lld_ctrl_send (dev,
vcom_device_desc, sizeof (vcom_device_desc));
else if (desc_type == CONFIG_DESCRIPTOR)
{
usb_lld_set_data_to_send (vcom_configuration_desc,
sizeof (vcom_configuration_desc));
return USB_SUCCESS;
}
return usb_lld_ctrl_send (dev,
vcom_config_desc, sizeof (vcom_config_desc));
else if (desc_type == STRING_DESCRIPTOR)
{
const uint8_t *str;
@@ -295,14 +367,13 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
size = sizeof (vcom_string3);
break;
default:
return USB_UNSUPPORT;
return -1;
}
usb_lld_set_data_to_send (str, size);
return USB_SUCCESS;
return usb_lld_ctrl_send (dev, str, size);
}
return USB_UNSUPPORT;
return -1;
}
static void
@@ -321,6 +392,7 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
{
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
/* Start with no data receiving (ENDP3 not enabled)*/
}
else
{
@@ -330,93 +402,534 @@ vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
}
}
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
static int
usb_set_configuration (struct usb_dev *dev)
{
int i;
uint8_t current_conf;
switch (event_type)
current_conf = usb_lld_current_configuration (dev);
if (current_conf == 0)
{
case USB_EVENT_ADDRESS:
bDeviceState = ADDRESSED;
return USB_SUCCESS;
case USB_EVENT_CONFIG:
current_conf = usb_lld_current_configuration ();
if (current_conf == 0)
{
if (value != 1)
return USB_UNSUPPORT;
if (dev->dev_req.value != 1)
return -1;
usb_lld_set_configuration (1);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (i, 0);
bDeviceState = CONFIGURED;
}
else if (current_conf != value)
{
if (value != 0)
return USB_UNSUPPORT;
usb_lld_set_configuration (dev, 1);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (i, 0);
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = USB_DEVICE_STATE_CONFIGURED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
}
else if (current_conf != dev->dev_req.value)
{
if (dev->dev_req.value != 0)
return -1;
usb_lld_set_configuration (0);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (i, 1);
bDeviceState = ADDRESSED;
}
/* Do nothing when current_conf == value */
return USB_SUCCESS;
return USB_SUCCESS;
default:
break;
usb_lld_set_configuration (dev, 0);
for (i = 0; i < NUM_INTERFACES; i++)
vcom_setup_endpoints_for_interface (i, 1);
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = USB_DEVICE_STATE_ADDRESSED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
}
return USB_UNSUPPORT;
usb_lld_ctrl_ack (dev);
return 0;
}
int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
static int
usb_set_interface (struct usb_dev *dev)
{
static uint8_t zero = 0;
uint16_t interface = dev->dev_req.index;
uint16_t alt = dev->dev_req.value;
if (interface >= NUM_INTERFACES)
return USB_UNSUPPORT;
return -1;
switch (cmd)
if (alt != 0)
return -1;
else
{
case USB_SET_INTERFACE:
if (alt != 0)
return USB_UNSUPPORT;
else
{
vcom_setup_endpoints_for_interface (interface, 0);
return USB_SUCCESS;
}
case USB_GET_INTERFACE:
usb_lld_set_data_to_send (&zero, 1);
return USB_SUCCESS;
default:
case USB_QUERY_INTERFACE:
return USB_SUCCESS;
vcom_setup_endpoints_for_interface (interface, 0);
usb_lld_ctrl_ack (dev);
return 0;
}
}
void
EP1_IN_Callback (void)
static int
usb_get_interface (struct usb_dev *dev)
{
chopstx_mutex_lock (&usb_mtx);
chopstx_cond_signal (&cnd_usb);
chopstx_mutex_unlock (&usb_mtx);
const uint8_t zero = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
/* We don't have alternate interface, so, always return 0. */
return usb_lld_ctrl_send (dev, &zero, 1);
}
void
EP2_IN_Callback (void)
static int
usb_get_status_interface (struct usb_dev *dev)
{
const uint16_t status_info = 0;
uint16_t interface = dev->dev_req.index;
if (interface >= NUM_INTERFACES)
return -1;
return usb_lld_ctrl_send (dev, &status_info, 2);
}
void
EP3_OUT_Callback (void)
/*
* Put a character into the ring buffer to be send back.
*/
static void
put_char_to_ringbuffer (struct tty *t, int c)
{
usb_lld_rx_enable (ENDP3);
uint32_t next = (t->send_tail + 1) % LINEBUFSIZE;
if (t->send_head == next)
/* full */
/* All that we can do is ignore this char. */
return;
t->send_buf[t->send_tail] = c;
t->send_tail = next;
}
/*
* Get characters from ring buffer into S.
*/
static int
get_chars_from_ringbuffer (struct tty *t, uint8_t *s, int len)
{
int i = 0;
if (t->send_head == t->send_tail)
/* Empty */
return i;
do
{
s[i++] = t->send_buf[t->send_head];
t->send_head = (t->send_head + 1) % LINEBUFSIZE;
}
while (t->send_head != t->send_tail && i < len);
return i;
}
static void
tty_echo_char (struct tty *t, int c)
{
put_char_to_ringbuffer (t, c);
}
static void
usb_tx_done (uint8_t ep_num, uint16_t len)
{
struct tty *t = tty_get (-1, ep_num);
(void)len;
if (ep_num == ENDP1)
{
chopstx_mutex_lock (&t->mtx);
if (t->flag_send_ready == 0)
{
t->flag_send_ready = 1;
chopstx_cond_signal (&t->cnd);
}
chopstx_mutex_unlock (&t->mtx);
}
else if (ep_num == ENDP2)
{
/* Nothing */
}
}
static int
tty_input_char (struct tty *t, int c)
{
unsigned int i;
int r = 0;
/* Process DEL, C-U, C-R, and RET as editing command. */
chopstx_mutex_lock (&t->mtx);
switch (c)
{
case 0x0d: /* Control-M */
t->inputline[t->inputline_len++] = '\n';
tty_echo_char (t, 0x0d);
tty_echo_char (t, 0x0a);
t->flag_input_avail = 1;
r = 1;
chopstx_cond_signal (&t->cnd);
break;
case 0x12: /* Control-R */
tty_echo_char (t, '^');
tty_echo_char (t, 'R');
tty_echo_char (t, 0x0d);
tty_echo_char (t, 0x0a);
for (i = 0; i < t->inputline_len; i++)
tty_echo_char (t, t->inputline[i]);
break;
case 0x15: /* Control-U */
for (i = 0; i < t->inputline_len; i++)
{
tty_echo_char (t, 0x08);
tty_echo_char (t, 0x20);
tty_echo_char (t, 0x08);
}
t->inputline_len = 0;
break;
case 0x7f: /* DEL */
if (t->inputline_len > 0)
{
tty_echo_char (t, 0x08);
tty_echo_char (t, 0x20);
tty_echo_char (t, 0x08);
t->inputline_len--;
}
break;
default:
if (t->inputline_len < sizeof (t->inputline) - 1)
{
tty_echo_char (t, c);
t->inputline[t->inputline_len++] = c;
}
else
/* Beep */
tty_echo_char (t, 0x0a);
break;
}
chopstx_mutex_unlock (&t->mtx);
return r;
}
static void
usb_rx_ready (uint8_t ep_num, uint16_t len)
{
uint8_t recv_buf[64];
struct tty *t = tty_get (-1, ep_num);
if (ep_num == ENDP3)
{
int i;
usb_lld_rxcpy (recv_buf, ep_num, 0, len);
for (i = 0; i < len; i++)
if (tty_input_char (t, recv_buf[i]))
break;
chopstx_mutex_lock (&t->mtx);
if (t->flag_input_avail == 0)
usb_lld_rx_enable (ENDP3);
chopstx_mutex_unlock (&t->mtx);
}
}
static void *tty_main (void *arg);
#define PRIO_TTY 4
#define STACK_PROCESS_3
#include "stack-def.h"
#define STACK_ADDR_TTY ((uint32_t)process3_base)
#define STACK_SIZE_TTY (sizeof process3_base)
struct tty *
tty_open (void)
{
chopstx_mutex_init (&tty0.mtx);
chopstx_cond_init (&tty0.cnd);
tty0.inputline_len = 0;
tty0.send_head = tty0.send_tail = 0;
tty0.flag_connected = 0;
tty0.flag_send_ready = 1;
tty0.flag_input_avail = 0;
tty0.device_state = USB_DEVICE_STATE_UNCONNECTED;
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
return &tty0;
}
static void *
tty_main (void *arg)
{
struct tty *t = arg;
struct usb_dev dev;
int e;
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
while (1)
{
chopstx_intr_wait (&usb_intr);
if (usb_intr.ready)
{
uint8_t ep_num;
/*
* When interrupt is detected, call usb_lld_event_handler.
* The event may be one of following:
* (1) Transfer to endpoint (bulk or interrupt)
* In this case EP_NUM is encoded in the variable E.
* (2) "NONE" event: some trasfer was done, but all was
* done by lower layer, no other work is needed in
* upper layer.
* (3) Device events: Reset or Suspend
* (4) Device requests to the endpoint zero.
*
*/
e = usb_lld_event_handler (&dev);
chopstx_intr_done (&usb_intr);
ep_num = USB_EVENT_ENDP (e);
if (ep_num != 0)
{
if (USB_EVENT_TXRX (e))
usb_tx_done (ep_num, USB_EVENT_LEN (e));
else
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
}
else
switch (USB_EVENT_ID (e))
{
case USB_EVENT_DEVICE_RESET:
usb_device_reset (&dev);
continue;
case USB_EVENT_DEVICE_ADDRESSED:
/* The addres is assigned to the device. We don't
* need to do anything for this actually, but in this
* application, we maintain the USB status of the
* device. Usually, just "continue" as EVENT_OK is
* OK.
*/
chopstx_mutex_lock (&tty0.mtx);
tty0.device_state = USB_DEVICE_STATE_ADDRESSED;
chopstx_cond_signal (&tty0.cnd);
chopstx_mutex_unlock (&tty0.mtx);
continue;
case USB_EVENT_GET_DESCRIPTOR:
if (usb_get_descriptor (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_CONFIGURATION:
if (usb_set_configuration (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_INTERFACE:
if (usb_set_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_CTRL_REQUEST:
/* Device specific device request. */
if (usb_setup (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_GET_STATUS_INTERFACE:
if (usb_get_status_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_GET_INTERFACE:
if (usb_get_interface (&dev) < 0)
usb_lld_ctrl_error (&dev);
continue;
case USB_EVENT_SET_FEATURE_DEVICE:
case USB_EVENT_SET_FEATURE_ENDPOINT:
case USB_EVENT_CLEAR_FEATURE_DEVICE:
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
usb_lld_ctrl_ack (&dev);
continue;
case USB_EVENT_CTRL_WRITE_FINISH:
/* Control WRITE transfer finished. */
usb_ctrl_write_finish (&dev);
continue;
case USB_EVENT_OK:
case USB_EVENT_DEVICE_SUSPEND:
default:
continue;
}
}
chopstx_mutex_lock (&t->mtx);
if (t->device_state == USB_DEVICE_STATE_CONFIGURED && t->flag_connected
&& t->flag_send_ready)
{
uint8_t line[32];
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
if (len)
{
usb_lld_txcpy (line, ENDP1, 0, len);
usb_lld_tx_enable (ENDP1, len);
t->flag_send_ready = 0;
}
}
chopstx_mutex_unlock (&t->mtx);
}
return NULL;
}
void
tty_wait_configured (struct tty *t)
{
chopstx_mutex_lock (&t->mtx);
while (t->device_state != USB_DEVICE_STATE_CONFIGURED)
chopstx_cond_wait (&t->cnd, &t->mtx);
chopstx_mutex_unlock (&t->mtx);
}
void
tty_wait_connection (struct tty *t)
{
chopstx_mutex_lock (&t->mtx);
while (t->flag_connected == 0)
chopstx_cond_wait (&t->cnd, &t->mtx);
t->flag_send_ready = 1;
t->flag_input_avail = 0;
t->send_head = t->send_tail = 0;
t->inputline_len = 0;
usb_lld_rx_enable (ENDP3); /* Accept input for line */
chopstx_mutex_unlock (&t->mtx);
}
static int
check_tx (struct tty *t)
{
if (t->flag_send_ready)
/* TX done */
return 1;
if (t->flag_connected == 0)
/* Disconnected */
return -1;
return 0;
}
int
tty_send (struct tty *t, const char *buf, int len)
{
int r;
const char *p;
int count;
p = buf;
count = len >= 64 ? 64 : len;
while (1)
{
chopstx_mutex_lock (&t->mtx);
while ((r = check_tx (t)) == 0)
chopstx_cond_wait (&t->cnd, &t->mtx);
if (r > 0)
{
usb_lld_txcpy (p, ENDP1, 0, count);
usb_lld_tx_enable (ENDP1, count);
t->flag_send_ready = 0;
}
chopstx_mutex_unlock (&t->mtx);
len -= count;
p += count;
if (len == 0 && count != 64)
/*
* The size of the last packet should be != 0
* If 64, send ZLP (zelo length packet)
*/
break;
count = len >= 64 ? 64 : len;
}
return r;
}
static int
check_rx (void *arg)
{
struct tty *t = arg;
if (t->flag_input_avail)
/* RX */
return 1;
if (t->flag_connected == 0)
/* Disconnected */
return 1;
return 0;
}
/*
* Returns -1 on connection close
* 0 on timeout.
* >0 length of the inputline (including final \n)
*
*/
int
tty_recv (struct tty *t, char *buf, uint32_t *timeout)
{
int r;
chopstx_poll_cond_t poll_desc;
poll_desc.type = CHOPSTX_POLL_COND;
poll_desc.ready = 0;
poll_desc.cond = &t->cnd;
poll_desc.mutex = &t->mtx;
poll_desc.check = check_rx;
poll_desc.arg = t;
while (1)
{
struct chx_poll_head *pd_array[1] = {
(struct chx_poll_head *)&poll_desc
};
chopstx_poll (timeout, 1, pd_array);
chopstx_mutex_lock (&t->mtx);
r = check_rx (t);
chopstx_mutex_unlock (&t->mtx);
if (r || (timeout != NULL && *timeout == 0))
break;
}
chopstx_mutex_lock (&t->mtx);
if (t->flag_connected == 0)
r = -1;
else if (t->flag_input_avail)
{
r = t->inputline_len;
memcpy (buf, t->inputline, r);
t->flag_input_avail = 0;
usb_lld_rx_enable (ENDP3);
t->inputline_len = 0;
}
else
r = 0;
chopstx_mutex_unlock (&t->mtx);
return r;
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

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

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

View File

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

137
example-fraucheky/configure vendored Executable file
View File

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

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

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

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

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

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

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

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

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

View File

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

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

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

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

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

View File

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

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

@@ -0,0 +1,189 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <chopstx.h>
#include "usb_lld.h"
#include "tty.h"
#include "board.h"
#include "command.h"
#include <sys.h>
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0;
static chopstx_cond_t cnd1;
uint8_t u;
static uint8_t v;
static uint8_t m; /* 0..100 */
static void
wait_for (uint32_t usec)
{
#if defined(BUSY_LOOP)
uint32_t count = usec * 6;
uint32_t i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
#else
chopstx_usec_wait (usec);
#endif
}
static void *
pwm (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd0, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
set_led (u&v);
wait_for (m);
set_led (0);
wait_for (100-m);
}
return NULL;
}
static void *
blk (void *arg)
{
(void)arg;
chopstx_mutex_lock (&mtx);
chopstx_cond_wait (&cnd1, &mtx);
chopstx_mutex_unlock (&mtx);
while (1)
{
v = 0;
wait_for (200*1000);
v = 1;
wait_for (200*1000);
}
return NULL;
}
#define PRIO_PWM 3
#define PRIO_BLK 2
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
static char hexchar (uint8_t x)
{
x &= 0x0f;
if (x <= 0x09)
return '0' + x;
else if (x <= 0x0f)
return 'a' + x - 10;
else
return '?';
}
extern void touch_init (void);
int
main (int argc, const char *argv[])
{
struct tty *tty;
uint8_t count;
(void)argc;
(void)argv;
chopstx_mutex_init (&mtx);
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
m = 10;
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
chopstx_usec_wait (200*1000);
chopstx_mutex_lock (&mtx);
chopstx_cond_signal (&cnd0);
chopstx_cond_signal (&cnd1);
chopstx_mutex_unlock (&mtx);
u = 1;
touch_init ();
tty = tty_open ();
tty_wait_configured (tty);
count = 0;
m = 50;
while (1)
{
char s[LINEBUFSIZE];
connection_loop:
u = 1;
tty_wait_connection (tty);
chopstx_usec_wait (50*1000);
/* Send ZLP at the beginning. */
tty_send (tty, s, 0);
memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32);
s[0] = hexchar (count >> 4);
s[1] = hexchar (count & 0x0f);
count++;
if (tty_send (tty, s, 32) < 0)
continue;
while (1)
{
uint32_t usec;
/* Prompt */
if (tty_send (tty, "> ", 2) < 0)
break;
usec = 3000000; /* 3.0 seconds */
while (1)
{
int size = tty_recv (tty, s, &usec);
u ^= 1;
if (size < 0)
goto connection_loop;
if (size == 1)
/* Do nothing but prompt again. */
break;
else if (size)
{
/* Newline into NUL */
s[size - 1] = 0;
cmd_dispatch (tty, (char *)s);
break;
}
}
}
}
return 0;
}

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

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

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

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

9
example-fs-bb48/tty.h Normal file
View File

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

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

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

View File

@@ -4,7 +4,19 @@ PROJECT = hacker-emblem
CHOPSTX = ..
LDSCRIPT= hacker-emblem.ld
CSRC = sys.c hacker-emblem.c
CSRC = reset.c hh.c
CHIP=stm32f0
# Hacker Emblem and "Happy Hacking!" demonstration
# CSRC = reset.c hh.c
# Debian logo demonstration
# CSRC = reset.c debian-logo.c
# "Hiroshi & Ayumi with Tulip" demonstration
# CSRC = reset.c hiroshi-ayumi.c
###################################
CROSS = arm-none-eabi-
@@ -14,7 +26,8 @@ OBJCOPY = $(CROSS)objcopy
MCU = cortex-m0 # -save-temps
CWARN = -Wall -Wextra -Wstrict-prototypes
DEFS = -DHAVE_SYS_H -DFREE_STANDING -DMHZ=48 -DUSE_WFI_FOR_IDLE
DEFS = -DMAKE_ENTRY_PUBLIC \
-DFREE_STANDING -DMHZ=48
OPT = -O3 -Os -g
LIBS =
@@ -25,7 +38,7 @@ board.h:
@echo Please make a symbolic link \'board.h\' to a file in ../board;
@exit 1
sys.c: board.h
reset.c: board.h
distclean: clean
rm -f board.h

17
example-fsm-55/README Normal file
View File

@@ -0,0 +1,17 @@
FSM-55 LED Matrix Display Board is a simple board to play 5x5 LED
Display. Please see the product page:
http://www.seeedstudio.com/depot/FSM55-LED-Matrix-Display-p-2121.html
There are three demonstrations and default is Hacker Emblem and "Happy
Hacking!". Please edit CSRC variable in the Makefile to select other
applications.
The file stlink-v2.cfg can be used for ST-Link/V2 with OpenOCD. You
can flash by typing:
$ openocd -f ./stlink-v2.cfg -c "program build/hacker-emblem.elf; reset run; shutdown"
Thanks to Kiwamu Okabe who kindly tested OpenOCD and wrote the
configuration.

1
example-fsm-55/board.h Symbolic link
View File

@@ -0,0 +1 @@
../board/board-fsm-55.h

View File

@@ -7,7 +7,7 @@
static uint8_t main_finished;
#define PERIPH_BASE 0x40000000
#define APBPERIPH_BASE PERIPH_BASE
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
@@ -34,8 +34,8 @@ struct GPIO {
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400)
#define GPIOF ((struct GPIO *) GPIOF_BASE)
static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE);
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE);
static chopstx_mutex_t mtx;
static chopstx_cond_t cnd0, cnd1;
@@ -163,17 +163,19 @@ button (void *arg)
return NULL;
}
#define STACK_MAIN
#define STACK_PROCESS_1
#define STACK_PROCESS_2
#include "stack-def.h"
#define PRIO_LED 3
#define PRIO_BUTTON 2
extern uint8_t __process1_stack_base__, __process1_stack_size__;
extern uint8_t __process2_stack_base__, __process2_stack_size__;
#define STACK_ADDR_LED ((uint32_t)process1_base)
#define STACK_SIZE_LED (sizeof process1_base)
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
#define STACK_ADDR_BUTTON ((uint32_t)process2_base)
#define STACK_SIZE_BUTTON (sizeof process2_base)
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
@@ -365,8 +367,6 @@ text_display (uint8_t kind)
}
static void setup_scr_sleepdeep (void);
int
main (int argc, const char *argv[])
{
@@ -378,14 +378,16 @@ main (int argc, const char *argv[])
(void)argc;
(void)argv;
chopstx_conf_idle (1);
chopstx_mutex_init (&mtx);
chopstx_cond_init (&cnd0);
chopstx_cond_init (&cnd1);
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
__stacksize_led, led, NULL);
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
__stacksize_button, button, NULL);
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
STACK_SIZE_LED, led, NULL);
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
STACK_SIZE_BUTTON, button, NULL);
chopstx_usec_wait (200*1000);
@@ -418,56 +420,6 @@ main (int argc, const char *argv[])
chopstx_join (button_thd, NULL);
chopstx_join (led_thd, NULL);
setup_scr_sleepdeep ();
for (;;)
asm volatile ("wfi" : : : "memory");
chopstx_conf_idle (4);
return 0;
}
struct SCB
{
volatile uint32_t CPUID;
volatile uint32_t ICSR;
volatile uint32_t VTOR;
volatile uint32_t AIRCR;
volatile uint32_t SCR;
volatile uint32_t CCR;
volatile uint8_t SHP[12];
volatile uint32_t SHCSR;
volatile uint32_t CFSR;
volatile uint32_t HFSR;
volatile uint32_t DFSR;
volatile uint32_t MMFAR;
volatile uint32_t BFAR;
volatile uint32_t AFSR;
volatile uint32_t PFR[2];
volatile uint32_t DFR;
volatile uint32_t ADR;
volatile uint32_t MMFR[4];
volatile uint32_t ISAR[5];
};
#define SCS_BASE (0xE000E000)
#define SCB_BASE (SCS_BASE + 0x0D00)
static struct SCB *const SCB = ((struct SCB *const) SCB_BASE);
#define SCB_SCR_SLEEPDEEP (1 << 2)
struct PWR
{
volatile uint32_t CR;
volatile uint32_t CSR;
};
#define PWR_CR_PDDS 0x0002
#define PWR_CR_CWUF 0x0004
#define PWR_BASE (APBPERIPH_BASE + 0x00007000)
#define PWR ((struct PWR *) PWR_BASE)
static void setup_scr_sleepdeep (void)
{
PWR->CR |= PWR_CR_CWUF;
PWR->CR |= PWR_CR_PDDS;
SCB->SCR |= SCB_SCR_SLEEPDEEP;
}

View File

@@ -1 +0,0 @@
hh.c

View File

@@ -1,62 +1,26 @@
/*
* ST32F103 memory setup.
* ST32F0 memory setup.
*/
__main_stack_size__ = 0x0100; /* Exception handlers */
__process0_stack_size__ = 0x0100; /* Main program */
__process1_stack_size__ = 0x0100; /* first thread program */
__process2_stack_size__ = 0x0100; /* second thread program */
__process3_stack_size__ = 0x0100; /* third thread program */
MEMORY
{
/*
flash0 : org = 0x08000000, len = 4k
flash : org = 0x08000000+0x1000, len = 60k
*/
flash0 : org = 0x08000000, len = 1k
flash : org = 0x08000000+0x0400, len = 60k
ram : org = 0x20000000, len = 20k
flash : org = 0x08000000, len = 16k
ram : org = 0x20000000, len = 4k
}
__flash_start__ = 0x08001000;
__flash_end__ = 0x08020000;
__ram_start__ = ORIGIN(ram);
__ram_size__ = 20k;
__ram_size__ = 4k;
__ram_end__ = __ram_start__ + __ram_size__;
SECTIONS
{
. = 0;
.sys : ALIGN(16) SUBALIGN(16)
{
_sys = .;
KEEP(*(.vectors))
. = ALIGN(16);
*(.sys.version)
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)
{
KEEP(*(.vectors))
. = ALIGN(16);
*(.text.startup.*)
*(.text)
*(.text.*)
@@ -65,8 +29,15 @@ SECTIONS
*(.glue_7t)
*(.glue_7)
*(.gcc*)
. = ALIGN(8);
} > flash
/DISCARD/ :
{
*(.startup.vectors)
*(.bss.startup.0)
}
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
.ARM.exidx : {
@@ -84,41 +55,15 @@ SECTIONS
_etext = .;
_textdata = _etext;
.vectors_in_ram :
.stacks (NOLOAD) :
{
. = ALIGN(8);
__vector_ram_addr__ = .;
KEEP(*(.bss.startup.*))
} > ram
.process_stack :
{
*(.main_stack)
*(.process_stack.0)
*(.process_stack.1)
*(.process_stack.2)
*(.process_stack.3)
. = ALIGN(8);
__process3_stack_base__ = .;
. += __process3_stack_size__;
. = ALIGN(8);
__process_stack3_end__ = .;
__process2_stack_base__ = .;
. += __process2_stack_size__;
. = ALIGN(8);
__process_stack2_end__ = .;
__process1_stack_base__ = .;
. += __process1_stack_size__;
. = ALIGN(8);
__process_stack1_end__ = .;
__process0_stack_base__ = .;
. += __process0_stack_size__;
. = ALIGN(8);
__process0_stack_end__ = .;
} > ram
.main_stack :
{
. = ALIGN(8);
__main_stack_base__ = .;
. += __main_stack_size__;
. = ALIGN(8);
__main_stack_end__ = .;
} > ram
.data :

Some files were not shown because too many files have changed in this diff Show More