Compare commits
53 Commits
aeea3c31f8
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f46af7557 | ||
|
|
0de43691ab | ||
|
|
79305c3de4 | ||
|
|
c1ea549995 | ||
|
|
fee2cae8c4 | ||
|
|
3317fb39ab | ||
|
|
de4ab0d3c9 | ||
|
|
be43aa3051 | ||
|
|
e7e6f5b184 | ||
|
|
74e52fd7f9 | ||
|
|
fe1ca5f055 | ||
|
|
3199ac7aae | ||
|
|
d22ffb2d07 | ||
|
|
c818ec89a4 | ||
|
|
2d2d544c5d | ||
|
|
97811f2e1c | ||
|
|
2db324e93d | ||
|
|
886343d40d | ||
|
|
f6c29ab274 | ||
|
|
8afabfa301 | ||
|
|
1d2aacd0a4 | ||
|
|
359082f80a | ||
|
|
1f159888a0 | ||
|
|
f37d83e55d | ||
|
|
b20f66b5e4 | ||
|
|
5d344acad9 | ||
|
|
06eef36868 | ||
|
|
ca06df793a | ||
|
|
92de60e5f2 | ||
|
|
61c0edcc96 | ||
|
|
7b129cd50f | ||
|
|
f237314ebf | ||
|
|
52efc84f5c | ||
|
|
5a326eee54 | ||
|
|
054950bc9a | ||
|
|
e5e46b5de5 | ||
|
|
8b9d2c007a | ||
|
|
5a6910a45b | ||
|
|
f8880aafec | ||
|
|
681a0055e4 | ||
|
|
69a7960876 | ||
|
|
7f77e5a13d | ||
|
|
bf585aba18 | ||
|
|
bf7afa7348 | ||
|
|
7f4eae6c56 | ||
|
|
8c045a6b8d | ||
|
|
ac026cc501 | ||
|
|
8d7106d992 | ||
|
|
2c0b1eee03 | ||
|
|
83817af2d7 | ||
|
|
339da2901c | ||
|
|
06130d071b | ||
|
|
02ca3a6cd5 |
2
AUTHORS
2
AUTHORS
@@ -34,7 +34,7 @@ NIIBE Yutaka:
|
||||
eventflag.c, eventflag.h
|
||||
Wrote the drivers mcu/*:
|
||||
chx-gnu-linux.c, chx-mkl27z.c, chx-stm32f0.c, chx-stm32f103.c,
|
||||
clk_gpio_init-mkl27z.c, clk_gpio_init-stm32.c,
|
||||
clk_gpio_init-mkl27z.c, clk_gpio_init-stm32f.c,
|
||||
cortex-m.h, mkl27z.h, stm32.h, stm32f103.h,
|
||||
sys-gnu-linux.c,sys-gnu-linux.h,
|
||||
sys-mkl27z.c, sys-mkl27z.h,
|
||||
|
||||
113
ChangeLog
113
ChangeLog
@@ -1,3 +1,116 @@
|
||||
2019-05-14 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.15.
|
||||
* doc/chopstx.texi (VERSION): 1.15.
|
||||
|
||||
2019-05-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* board/board-maple-mini.h: Assert USB D+ pull-up.
|
||||
* board/board-olimex-stm32-h103.h: Likewise.
|
||||
* board/board-stbee.h:Likewise.
|
||||
* board/board-stm32-primer2.h: Likewise.
|
||||
|
||||
* mcu/usb-stm32f103.c: Don't use usb_lld_sys_init and
|
||||
usb_lld_sys_shutdown in SYS.
|
||||
* mcu/usb-stm32l4.c: Ditto.
|
||||
|
||||
2019-05-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_claim_irq): Check INTR before the call.
|
||||
|
||||
* chopstx-cortex-m.c (chx_disable_intr): Have return value.
|
||||
* chopstx-gnu-linux.c (chx_disable_intr): Likewise.
|
||||
|
||||
2019-05-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/sys-stm32f103.c: SYS version 4.0.
|
||||
* mcu/sys-gnu-linux.c: Likewise.
|
||||
* mcu/sys-mkl27z.c: Likewise.
|
||||
* mcu/sys-stm32l4.c: Likewise.
|
||||
* mcu/sys-stm32f0.c: Likewise.
|
||||
|
||||
2019-05-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/sys-stm32f103.c (usb_lld_sys_shutdown, usb_lld_sys_init):
|
||||
Only cable config.
|
||||
|
||||
* mcu/sys-stm32l4.c (usb_lld_sys_shutdown, usb_lld_sys_init):
|
||||
Likewise.
|
||||
|
||||
* mcu/usb-st-common.c (usb_lld_init): Call chip specific routine.
|
||||
(usb_lld_shutdown): Likewise.
|
||||
|
||||
* mcu/usb-stm32l4.c (usb_lld_init_chip_specific)
|
||||
(usb_lld_shutdown_chip_specific): New.
|
||||
|
||||
* mcu/usb-stm32f103.c (usb_lld_init_chip_specific)
|
||||
(usb_lld_shutdown_chip_specific): New.
|
||||
|
||||
* rules.mk (DEFS): Add -DUSE_SYS when USE_SYS.
|
||||
|
||||
2019-04-25 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart.h (BSCARD1, BSCARD2...): New.
|
||||
(BSCARD): Remove.
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config_baud): Rename
|
||||
from usart_config_brr, changing API.
|
||||
* contrib/usart-stm32l4.c (usart_config_baud): Likewise.
|
||||
|
||||
2019-04-24 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/sys-stm32l4.c: New.
|
||||
* mcu/chx-stm32l4.c: New. Not support suspend yet.
|
||||
* mcu/stm32l.h: New.
|
||||
* mcu/clk_gpio_init-stm32l.c: New.
|
||||
|
||||
2019-04-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/usb-stm32l4.c: New.
|
||||
* mcu/usb-st-common.c: Factor out from usb-stm32f103.c.
|
||||
|
||||
2019-04-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32l4.c: New.
|
||||
* contrib/usart-common.c: Factor out from usart-stm32f103.c.
|
||||
|
||||
* entry.c [__ARM_ARCH_7EM__] (entry): Fix for Cortex-M4.
|
||||
|
||||
2019-04-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c: Support Cortex-M4 (not touching FPU).
|
||||
|
||||
2019-04-10 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/clk_gpio_init-stm32f.c: Rename from clk_gpio_init-stm32.c.
|
||||
|
||||
* entry.c: Use STM32F10X_HD.
|
||||
* board/board-stbee.h (STM32F10X_HD): Add.
|
||||
* board/board-stm32-primer2.h (STM32F10X_HD): Add.
|
||||
|
||||
2019-04-09 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_block_sendrecv): Support
|
||||
busy-wait when timeout_block_p == 0.
|
||||
|
||||
2019-04-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_block_sendrecv): New.
|
||||
(usart_init0): New.
|
||||
|
||||
2019-03-30 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_config_brr): New.
|
||||
(usart_config_re): New internal function.
|
||||
(handle_intr, handle_tx_ready): Use TC for smartcard.
|
||||
(usart_wait_write_completion): New internal function.
|
||||
(usart_write): Support half-duplex smartcard mode.
|
||||
|
||||
2019-03-29 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/usart-stm32f103.c (usart_read_ext): New.
|
||||
(usart_read_prepare_poll): New.
|
||||
|
||||
2019-03-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.14.
|
||||
|
||||
@@ -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.
|
||||
--------------------
|
||||
|
||||
|
||||
38
NEWS
38
NEWS
@@ -1,6 +1,44 @@
|
||||
NEWS - Noteworthy changes
|
||||
|
||||
|
||||
* 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
|
||||
|
||||
10
README
10
README
@@ -1,6 +1,6 @@
|
||||
Chopstx - Threads and only Threads
|
||||
Version 1.14
|
||||
2018-03-02
|
||||
Version 1.15
|
||||
2018-05-14
|
||||
Niibe Yutaka
|
||||
Flying Stone Technology
|
||||
|
||||
@@ -8,8 +8,8 @@ What's Chopstx?
|
||||
===============
|
||||
|
||||
Chopstx is an RT thread library for STM32F103 and GD32F103 (ARM
|
||||
Cortex-M3), STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus), and
|
||||
emulation on GNU/Linux.
|
||||
Cortex-M3), STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus),
|
||||
STM32L432 (ARM Cortex-M4), and emulation on GNU/Linux.
|
||||
|
||||
While most RTOSes come with many features, drivers, and protocol
|
||||
stacks, Chopstx just offers a simple RT thread library.
|
||||
@@ -19,7 +19,7 @@ enables coherent code for ease of maintenance.
|
||||
|
||||
While threads are important, we don't need more threads than
|
||||
necessary. Chopstx provides a feature of poll, so that we can
|
||||
minimize use of threads.
|
||||
handle multiple events by a single thread.
|
||||
|
||||
|
||||
Note that this library is _not_ related to the hand game:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* PA0 - input with pull-up. AN0
|
||||
* PA1 - input with pull-up. AN1
|
||||
* PA8 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
||||
* PA10 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PA10 - Push pull output 50MHz (USB 1:ON 0:OFF) default 1
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* ------------------------ Default
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* PA5 - Alternate Push pull output (SPI1_SCK)
|
||||
* PA6 - Alternate Push pull output (SPI1_MISO)
|
||||
* PA7 - Alternate Push pull output (SPI1_MOSI)
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF)
|
||||
* PA10 - Push pull output (USB 1:ON 0:OFF) default 1
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* ------------------------ Default
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
/*
|
||||
* Port B setup.
|
||||
* PB1 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
||||
* PB9 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PB9 - Push pull output 50MHz (USB 0:ON 1:OFF) default 0
|
||||
* ------------------------ Default
|
||||
* PBx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFDFF
|
||||
#define VAL_GPIO_LED_CRL 0x88888838 /* PB7...PB0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88888838 /* PB15...PB8 */
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
* PA10 - floating input
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* PA15 - Push pull output (USB_EN 1:ON 0:OFF)
|
||||
* PA15 - Push pull output (USB_EN 1:ON 0:OFF) default 1
|
||||
* ------------------------ Default
|
||||
* PA8 - input with pull-up.
|
||||
* PA9 - floating input.
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
* PC1 - input with pull-up. AN11 for NeuG
|
||||
* PC6 - input without pull-up/down
|
||||
* PC7 - input without pull-up/down
|
||||
* PC11 - Open-drain output 50MHz (USB disconnect).
|
||||
* PC11 - Open-drain output 50MHz (USB 0:ON 1:OFF) default 0
|
||||
* PC12 - Push Pull output 50MHz (LED).
|
||||
* ------------------------ Default
|
||||
* PCx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFF7FF
|
||||
#define VAL_GPIO_LED_CRL 0x44888888 /* PC7...PC0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88837888 /* PC15...PC8 */
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* PA9 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* PA15 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PA15 - Push pull output 50MHz (USB 1:ON 0:OFF) default 1
|
||||
* ------------------------ Default
|
||||
* PAx - input with pull-up
|
||||
*/
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
*
|
||||
* At CN10, connect USB cable
|
||||
* Vbus RED --> 10 NC ----------> CN7 (6 E5V)
|
||||
* D+ GREEN --> 12 PA11 ---[1K5]--> CN6 (4 3V3)
|
||||
* D- WHITE --> 14 PA12
|
||||
* D+ GREEN --> 12 PA12 ---[1K5]--> CN6 (4 3V3)
|
||||
* D- WHITE --> 14 PA11
|
||||
* 16 PB12 (USART3-CK) ---> smartcard CK
|
||||
* 18
|
||||
* GND BLACK --> 20 GND
|
||||
*/
|
||||
|
||||
@@ -70,5 +72,5 @@
|
||||
#define VAL_GPIO_OTHER_CRL 0x82888888 /* PB7...PB0 */
|
||||
#define VAL_GPIO_OTHER_CRH 0x8B8B8F22 /* PB15...PB8 */
|
||||
|
||||
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN)
|
||||
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST)
|
||||
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN)
|
||||
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | RCC_APB2RSTR_AFIORST)
|
||||
|
||||
75
board/board-st-nucleo-l432.h
Normal file
75
board/board-st-nucleo-l432.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#define BOARD_NAME "ST Nucleo L432"
|
||||
#define BOARD_ID 0x3a8d5116
|
||||
|
||||
/*
|
||||
* When using USB, please add USB cable to ST Nucleo L432.
|
||||
*
|
||||
* At CN4, connect USB cable, only when ST Link is not connected
|
||||
* Vbus RED --> 4
|
||||
*
|
||||
* At CN3, connect USB cable
|
||||
* D- WHITE --> 13 PA11
|
||||
* D+ GREEN --> 5 PA12
|
||||
* GND BLACK --> 4 GND
|
||||
*
|
||||
* Smartcard VCC: PA3
|
||||
* Smartcard GND: GND --+
|
||||
* Smartcard RST: PA1 |
|
||||
* Smartcard VPP: PA4 |
|
||||
* Smartcard CLK: PA8 |
|
||||
* Smartcard I/O: PA9 |
|
||||
* GND --+
|
||||
* Smartcard DETECT: PA0
|
||||
*/
|
||||
|
||||
#define MCU_STM32L4 1
|
||||
|
||||
#define GPIO_LED_BASE GPIOB_BASE
|
||||
#define GPIO_LED_SET_TO_EMIT 3
|
||||
#undef GPIO_USB_BASE /* No external DISCONNECT/RENUM circuit. */
|
||||
#define GPIO_OTHER_BASE GPIOA_BASE
|
||||
|
||||
/*
|
||||
* Port A setup.
|
||||
*
|
||||
* MODER: 00 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
|
||||
* ------------------------ Default
|
||||
* PAx - analog input
|
||||
*/
|
||||
#define VAL_GPIO_OTHER_MODER 0x2ABAFD64
|
||||
#define VAL_GPIO_OTHER_OTYPER 0x00000200
|
||||
#define VAL_GPIO_OTHER_OSPEEDR 0xFFFFFFFF
|
||||
#define VAL_GPIO_OTHER_PUPDR 0x00040001
|
||||
#define VAL_GPIO_OTHER_AFRL 0x00000700
|
||||
#define VAL_GPIO_OTHER_AFRH 0x300AA077
|
||||
|
||||
/*
|
||||
* Port B setup.
|
||||
*
|
||||
* MODER: 11 11 - 11 11 - 11 11 - 11 11 11 11 - 11 11 - 01 11 - 11 11
|
||||
*
|
||||
* PB3 - ON (LED 1:ON 0:OFF)
|
||||
* ------------------------ Default
|
||||
* PBx - analog input
|
||||
*/
|
||||
#define VAL_GPIO_LED_MODER 0xFFFFFF7F
|
||||
#define VAL_GPIO_LED_OTYPER 0x00000000
|
||||
#define VAL_GPIO_LED_OSPEEDR 0x00000000
|
||||
#define VAL_GPIO_LED_PUPDR 0x00000000
|
||||
#define VAL_GPIO_LED_AFRL 0x00000000
|
||||
#define VAL_GPIO_LED_AFRH 0x00000000
|
||||
|
||||
#define RCC_AHB2_GPIO (RCC_AHB2_GPIOA | RCC_AHB2_GPIOB)
|
||||
@@ -52,7 +52,7 @@
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* PA13 - Open Drain output (LED1 0:ON 1:OFF)
|
||||
* PA14 - Push pull output (USB ENABLE 0:DISABLE 1:ENABLE)
|
||||
* PA14 - Push pull output (USB 1:ON 0:OFF) default 1
|
||||
* PA15 - Open Drain output (LED2 0:ON 1:OFF)
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFE77F
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define BOARD_ID 0x945c37e8
|
||||
|
||||
#define MCU_STM32F1 1
|
||||
/* High-density device */
|
||||
#define STM32F10X_HD /* High-density device */
|
||||
|
||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||
#define STM32_PLLMUL_VALUE 6
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
/*
|
||||
* Port D setup.
|
||||
* PD3 - Push pull output (USB_DISC 1:USB-DISABLE 0:USB-ENABLE) 2MHz
|
||||
* PD3 - Push pull output (USB 1:OFF 0:ON) 2MHz default 0
|
||||
* PD4 - Open Drain output 2MHz (LED1).
|
||||
*/
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFF7
|
||||
#define VAL_GPIO_LED_CRL 0x88862888 /* PD7...PD0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88888888 /* PD15...PD8 */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define BOARD_ID 0x21e5798d
|
||||
|
||||
#define MCU_STM32F1 1
|
||||
/* High-density device */
|
||||
#define STM32F10X_HD /* High-density device */
|
||||
|
||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||
#define STM32_PLLMUL_VALUE 6
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
/*
|
||||
* Port D setup.
|
||||
* PD3 - Push pull output 50MHz (USB 1:ON 0:OFF)
|
||||
* PD3 - Push pull output 50MHz (USB 0:ON 1:OFF) default 0
|
||||
* ------------------------ Default
|
||||
* PDx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFFFF7
|
||||
#define VAL_GPIO_USB_CRL 0x88883888 /* PD7...PD0 */
|
||||
#define VAL_GPIO_USB_CRH 0x88888888 /* PD15...PD8 */
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
|
||||
* for Cortex-M0/M3
|
||||
* for Cortex-M0/M3/M4
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -24,7 +24,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -84,7 +84,7 @@ struct chx_stack_regs {
|
||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
|
||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
|
||||
#elif defined(__ARM_ARCH_7M__)
|
||||
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
|
||||
|
||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
|
||||
@@ -106,30 +106,34 @@ struct chx_stack_regs {
|
||||
* System tick
|
||||
*/
|
||||
/* SysTick registers. */
|
||||
static volatile uint32_t *const SYST_CSR = (uint32_t *)0xE000E010;
|
||||
static volatile uint32_t *const SYST_RVR = (uint32_t *)0xE000E014;
|
||||
static volatile uint32_t *const SYST_CVR = (uint32_t *)0xE000E018;
|
||||
struct SYST {
|
||||
volatile uint32_t CSR;
|
||||
volatile uint32_t RVR;
|
||||
volatile uint32_t CVR;
|
||||
const uint32_t CALIB;
|
||||
};
|
||||
static struct SYST *const SYST = (struct SYST *)0xE000E010;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
{
|
||||
*SYST_RVR = 0;
|
||||
*SYST_CVR = 0;
|
||||
*SYST_CSR = 7;
|
||||
SYST->RVR = 0;
|
||||
SYST->CVR = 0;
|
||||
SYST->CSR = 7;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_systick_reload (uint32_t ticks)
|
||||
{
|
||||
*SYST_RVR = ticks;
|
||||
*SYST_CVR = 0; /* write (any) to clear the counter to reload. */
|
||||
*SYST_RVR = 0;
|
||||
SYST->RVR = ticks;
|
||||
SYST->CVR = 0; /* write (any) to clear the counter to reload. */
|
||||
SYST->RVR = 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
chx_systick_get (void)
|
||||
{
|
||||
return *SYST_CVR;
|
||||
return SYST->CVR;
|
||||
}
|
||||
|
||||
static uint32_t usec_to_ticks (uint32_t usec)
|
||||
@@ -175,10 +179,13 @@ chx_clr_intr (uint8_t irq_num)
|
||||
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
int already_disabled = !!(NVIC_ICER (irq_num) & (1 << (irq_num & 0x1f)));
|
||||
|
||||
NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
return already_disabled;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -302,7 +309,7 @@ chx_sched (uint32_t yield)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
asm volatile (
|
||||
"svc #0"
|
||||
: "=r" (tp) : "0" (yield): "memory");
|
||||
@@ -644,7 +651,7 @@ preempt (void)
|
||||
: /* no output */ : "r" (tp) : "memory");
|
||||
}
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
/*
|
||||
* System call: switch to another thread.
|
||||
* There are two cases:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
||||
* for GNU/Linux emulation
|
||||
*
|
||||
* Copyright (C) 2017, 2018 Flying Stone Technology
|
||||
* Copyright (C) 2017, 2018, 2019 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -23,7 +23,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -89,10 +89,13 @@ chx_clr_intr (uint8_t irq_num)
|
||||
(void)irq_num;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
int already_disabled = sigismember (&ss_cur, irq_num);
|
||||
|
||||
sigaddset (&ss_cur, irq_num);
|
||||
return already_disabled;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1005,17 +1005,21 @@ chx_cond_hook (struct chx_px *px, struct chx_poll_head *pd)
|
||||
void
|
||||
chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num)
|
||||
{
|
||||
int intr_before_claim;
|
||||
|
||||
intr->type = CHOPSTX_POLL_INTR;
|
||||
intr->ready = 0;
|
||||
intr->irq_num = irq_num;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
chx_disable_intr (irq_num);
|
||||
intr_before_claim = chx_disable_intr (irq_num);
|
||||
chx_clr_intr (irq_num);
|
||||
chx_set_intr_prio (irq_num);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
if (intr_before_claim)
|
||||
intr->ready = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
428
contrib/usart-common.c
Normal file
428
contrib/usart-common.c
Normal file
@@ -0,0 +1,428 @@
|
||||
static void *usart_main (void *arg);
|
||||
|
||||
/*
|
||||
* Ring buffer
|
||||
*/
|
||||
#define MAX_RB_BUF 1024
|
||||
|
||||
struct rb {
|
||||
uint8_t *buf;
|
||||
chopstx_mutex_t m;
|
||||
chopstx_cond_t data_available;
|
||||
chopstx_cond_t space_available;
|
||||
uint32_t head :10;
|
||||
uint32_t tail :10;
|
||||
uint32_t size :10;
|
||||
uint32_t full : 1;
|
||||
uint32_t empty : 1;
|
||||
};
|
||||
/* full && empty -> data is consumed fully */
|
||||
|
||||
/*
|
||||
* Note: size = 1024 can still work, regardless of the limit of 10-bit.
|
||||
*/
|
||||
static void
|
||||
rb_init (struct rb *rb, uint8_t *p, uint16_t size)
|
||||
{
|
||||
rb->buf = p;
|
||||
rb->size = size;
|
||||
chopstx_mutex_init (&rb->m);
|
||||
chopstx_cond_init (&rb->data_available);
|
||||
chopstx_cond_init (&rb->space_available);
|
||||
rb->head = rb->tail = 0;
|
||||
rb->full = 0;
|
||||
rb->empty = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_add (struct rb *rb, uint8_t v)
|
||||
{
|
||||
rb->buf[rb->tail++] = v;
|
||||
if (rb->tail == rb->size)
|
||||
rb->tail = 0;
|
||||
if (rb->tail == rb->head)
|
||||
rb->full = 1;
|
||||
else
|
||||
rb->full = 0;
|
||||
rb->empty = 0;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
rb_del (struct rb *rb)
|
||||
{
|
||||
uint32_t v = rb->buf[rb->head++];
|
||||
|
||||
if (rb->head == rb->size)
|
||||
rb->head = 0;
|
||||
if (rb->head == rb->tail)
|
||||
rb->empty = 1;
|
||||
rb->full = 0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: consumer
|
||||
* Hardware: generator
|
||||
*/
|
||||
static int
|
||||
rb_ll_put (struct rb *rb, uint8_t v)
|
||||
{
|
||||
int r;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
if (rb->full && !rb->empty)
|
||||
r = -1;
|
||||
else
|
||||
{
|
||||
r = 0;
|
||||
rb_add (rb, v);
|
||||
chopstx_cond_signal (&rb->data_available);
|
||||
}
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: generator
|
||||
* Hardware: consumer
|
||||
*/
|
||||
static int
|
||||
rb_ll_get (struct rb *rb)
|
||||
{
|
||||
int r;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
if (rb->empty)
|
||||
{
|
||||
if (!rb->full)
|
||||
rb->full = 1;
|
||||
r = -1;
|
||||
}
|
||||
else
|
||||
r = rb_del (rb);
|
||||
chopstx_cond_signal (&rb->space_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_ll_flush (struct rb *rb)
|
||||
{
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
while (!rb->empty)
|
||||
rb_del (rb);
|
||||
chopstx_cond_signal (&rb->space_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: consumer
|
||||
* Hardware: generator
|
||||
*/
|
||||
static int
|
||||
rb_read (struct rb *rb, uint8_t *buf, uint16_t buflen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
while (rb->empty)
|
||||
chopstx_cond_wait (&rb->data_available, &rb->m);
|
||||
|
||||
while (i < buflen)
|
||||
{
|
||||
buf[i++] = rb_del (rb);
|
||||
if (rb->empty)
|
||||
break;
|
||||
}
|
||||
chopstx_cond_signal (&rb->space_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: generator
|
||||
* Hardware: consumer
|
||||
*/
|
||||
static void
|
||||
rb_write (struct rb *rb, uint8_t *buf, uint16_t buflen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
|
||||
do
|
||||
{
|
||||
while (rb->full && !rb->empty)
|
||||
chopstx_cond_wait (&rb->space_available, &rb->m);
|
||||
|
||||
while (i < buflen)
|
||||
{
|
||||
rb_add (rb, buf[i++]);
|
||||
if (rb->full)
|
||||
{
|
||||
chopstx_cond_signal (&rb->data_available);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (i < buflen);
|
||||
|
||||
if (i)
|
||||
chopstx_cond_signal (&rb->data_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
}
|
||||
|
||||
static int
|
||||
rb_empty_check (void *arg)
|
||||
{
|
||||
struct rb *rb = arg;
|
||||
return rb->empty == 0;
|
||||
}
|
||||
|
||||
/* Can be used two ways:
|
||||
*
|
||||
* When the ring buffer is rb_a2h:
|
||||
* Hardware-side polling if data is available from application.
|
||||
*
|
||||
* When the ring buffer is rb_h2a:
|
||||
* Application-side polling if data is available from hardware.
|
||||
*/
|
||||
static void
|
||||
rb_get_prepare_poll (struct rb *rb, chopstx_poll_cond_t *poll_desc)
|
||||
{
|
||||
poll_desc->type = CHOPSTX_POLL_COND;
|
||||
poll_desc->ready = 0;
|
||||
poll_desc->cond = &rb->data_available;
|
||||
poll_desc->mutex = &rb->m;
|
||||
poll_desc->check = rb_empty_check;
|
||||
poll_desc->arg = rb;
|
||||
}
|
||||
|
||||
const struct usart_stat *
|
||||
usart_stat (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].stat;
|
||||
}
|
||||
|
||||
static struct USART *
|
||||
get_usart_dev (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].USART;
|
||||
}
|
||||
|
||||
static struct rb *
|
||||
get_usart_rb_h2a (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].rb_h2a;
|
||||
}
|
||||
|
||||
static struct rb *
|
||||
get_usart_rb_a2h (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].rb_a2h;
|
||||
}
|
||||
|
||||
static struct chx_intr *
|
||||
get_usart_intr (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no < USART_DEVNO_START || dev_no > USART_DEVNO_END)
|
||||
return NULL;
|
||||
return usart_array[dev_no - USART_DEVNO_START].intr;
|
||||
}
|
||||
|
||||
void
|
||||
usart_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
|
||||
int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||
{
|
||||
usart_init0 (cb);
|
||||
chopstx_create (prio, stack_addr, stack_size, usart_main, NULL);
|
||||
}
|
||||
|
||||
static int (*ss_notify_callback) (uint8_t dev_no, uint16_t notify_bits);
|
||||
|
||||
static struct chx_poll_head *usart_poll[NUM_USART*2];
|
||||
|
||||
static void *
|
||||
usart_main (void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)arg;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
if (usart_array[i].tx_ready)
|
||||
{
|
||||
*usart_array[i].tx_ready = 1;
|
||||
rb_init (usart_array[i].rb_a2h, usart_array[i].buf_a2h, BUF_A2H_SIZE);
|
||||
rb_init (usart_array[i].rb_h2a, usart_array[i].buf_h2a, BUF_H2A_SIZE);
|
||||
rb_get_prepare_poll (usart_array[i].rb_a2h, usart_array[i].app_write_event);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
if (usart_array[i].tx_ready)
|
||||
{
|
||||
usart_poll[n++] = (struct chx_poll_head *)usart_array[i].intr;
|
||||
if (*usart_array[i].tx_ready)
|
||||
usart_poll[n++] = (struct chx_poll_head *)usart_array[i].app_write_event;
|
||||
else
|
||||
usart_array[i].app_write_event->ready = 0;
|
||||
}
|
||||
|
||||
chopstx_poll (NULL, n, usart_poll);
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
if (usart_array[i].tx_ready)
|
||||
{
|
||||
int tx_done = 0;
|
||||
|
||||
if (usart_array[i].intr->ready)
|
||||
{
|
||||
tx_done = handle_intr (usart_array[i].USART,
|
||||
usart_array[i].rb_h2a, usart_array[i].stat);
|
||||
*usart_array[i].tx_ready |= tx_done;
|
||||
chopstx_intr_done (usart_array[i].intr);
|
||||
}
|
||||
|
||||
if (tx_done || (*usart_array[i].tx_ready
|
||||
&& usart_array[i].app_write_event->ready))
|
||||
*usart_array[i].tx_ready = handle_tx (usart_array[i].USART,
|
||||
usart_array[i].rb_a2h, usart_array[i].stat);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
usart_read (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||
{
|
||||
struct rb *rb = get_usart_rb_h2a (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return -1;
|
||||
|
||||
if (buf == NULL && buflen == 0)
|
||||
{
|
||||
rb_ll_flush (rb);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return rb_read (rb, (uint8_t *)buf, buflen);
|
||||
}
|
||||
|
||||
void
|
||||
usart_read_prepare_poll (uint8_t dev_no, chopstx_poll_cond_t *poll_desc)
|
||||
{
|
||||
struct rb *rb = get_usart_rb_h2a (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return;
|
||||
|
||||
rb_get_prepare_poll (rb, poll_desc);
|
||||
}
|
||||
|
||||
int
|
||||
usart_read_ext (uint8_t dev_no, char *buf, uint16_t buflen, uint32_t *timeout_p)
|
||||
{
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
struct chx_poll_head *ph[] = { (struct chx_poll_head *)&poll_desc };
|
||||
int r;
|
||||
struct rb *rb = get_usart_rb_h2a (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return -1;
|
||||
|
||||
rb_get_prepare_poll (rb, &poll_desc);
|
||||
r = chopstx_poll (timeout_p, 1, ph);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
else
|
||||
return rb_read (rb, (uint8_t *)buf, buflen);
|
||||
}
|
||||
|
||||
static void
|
||||
usart_wait_write_completion (struct rb *rb)
|
||||
{
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
while (!(rb->empty && rb->full))
|
||||
chopstx_cond_wait (&rb->space_available, &rb->m);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
}
|
||||
|
||||
int
|
||||
usart_write (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||
{
|
||||
struct rb *rb = get_usart_rb_a2h (dev_no);
|
||||
|
||||
if (rb == NULL)
|
||||
return -1;
|
||||
|
||||
if (buf == NULL && buflen == 0)
|
||||
rb_ll_flush (rb);
|
||||
else
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 0);
|
||||
|
||||
rb_write (rb, (uint8_t *)buf, buflen);
|
||||
|
||||
if (smartcard_mode)
|
||||
{
|
||||
usart_wait_write_completion (rb);
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
usart_config_baud (uint8_t dev_no, uint8_t baud_spec)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
uint32_t save_bits;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BAUD; i++)
|
||||
if (brr_table[i].baud_spec == baud_spec)
|
||||
break;
|
||||
|
||||
if (i >= NUM_BAUD)
|
||||
return -1;
|
||||
|
||||
save_bits = USARTx->CR1 & (USART_CR1_TE | USART_CR1_RE);
|
||||
USARTx->CR1 &= ~(USART_CR1_TE | USART_CR1_RE | USART_CR1_UE);
|
||||
USARTx->BRR = brr_table[i].brr_value;
|
||||
USARTx->CR1 |= (save_bits | USART_CR1_UE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usart_config_clken (uint8_t dev_no, int on)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
|
||||
if (on)
|
||||
USARTx->CR2 |= (1 << 11);
|
||||
else
|
||||
USARTx->CR2 &= ~(1 << 11);
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <mcu/stm32.h>
|
||||
#include <contrib/usart.h>
|
||||
|
||||
/* Hardware registers */
|
||||
struct USART {
|
||||
volatile uint32_t SR;
|
||||
volatile uint32_t DR;
|
||||
@@ -44,8 +45,8 @@ struct USART {
|
||||
|
||||
#define USART2_BASE (APB1PERIPH_BASE + 0x4400)
|
||||
#define USART3_BASE (APB1PERIPH_BASE + 0x4800)
|
||||
static struct USART *const USART2 = (struct USART *)USART2_BASE;
|
||||
static struct USART *const USART3 = (struct USART *)USART3_BASE;
|
||||
#define USART2 ((struct USART *)USART2_BASE)
|
||||
#define USART3 ((struct USART *)USART3_BASE)
|
||||
|
||||
#define USART_SR_CTS (1 << 9)
|
||||
#define USART_SR_LBD (1 << 8)
|
||||
@@ -74,25 +75,79 @@ static struct USART *const USART3 = (struct USART *)USART3_BASE;
|
||||
#define USART_CR1_RWU (1 << 1)
|
||||
#define USART_CR1_SBK (1 << 0)
|
||||
|
||||
#define USART_CR3_CTSE (1 << 9)
|
||||
#define USART_CR3_RTSE (1 << 8)
|
||||
#define USART_CR3_SCEN (1 << 5)
|
||||
#define USART_CR3_NACK (1 << 4)
|
||||
|
||||
static struct USART *
|
||||
get_usart_dev (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no == 2)
|
||||
return USART2;
|
||||
else if (dev_no == 3)
|
||||
return USART3;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
static struct usart_stat usart2_stat;
|
||||
static struct usart_stat usart3_stat;
|
||||
|
||||
static struct chx_intr usart2_intr;
|
||||
static struct chx_intr usart3_intr;
|
||||
|
||||
#define BUF_A2H_SIZE 256
|
||||
#define BUF_H2A_SIZE 512
|
||||
static uint8_t buf_usart2_rb_a2h[BUF_A2H_SIZE];
|
||||
static uint8_t buf_usart2_rb_h2a[BUF_H2A_SIZE];
|
||||
static uint8_t buf_usart3_rb_a2h[BUF_A2H_SIZE];
|
||||
static uint8_t buf_usart3_rb_h2a[BUF_H2A_SIZE];
|
||||
|
||||
static struct rb usart2_rb_a2h;
|
||||
static struct rb usart2_rb_h2a;
|
||||
static struct rb usart3_rb_a2h;
|
||||
static struct rb usart3_rb_h2a;
|
||||
|
||||
static chopstx_poll_cond_t usart2_app_write_event;
|
||||
static chopstx_poll_cond_t usart3_app_write_event;
|
||||
|
||||
/* Global variables so that it can be easier to debug. */
|
||||
static int usart2_tx_ready;
|
||||
static int usart3_tx_ready;
|
||||
|
||||
#define INTR_REQ_USART2 38
|
||||
#define INTR_REQ_USART3 39
|
||||
|
||||
#define USART_DEVNO_START 2
|
||||
#define USART_DEVNO_END 3
|
||||
|
||||
struct usart {
|
||||
struct USART *USART;
|
||||
struct chx_intr *intr;
|
||||
uint8_t irq_num;
|
||||
struct usart_stat *stat;
|
||||
struct rb *rb_a2h;
|
||||
struct rb *rb_h2a;
|
||||
uint8_t *buf_a2h;
|
||||
uint8_t *buf_h2a;
|
||||
chopstx_poll_cond_t *app_write_event;
|
||||
int *tx_ready;
|
||||
};
|
||||
|
||||
|
||||
static const struct usart usart_array[] =
|
||||
{
|
||||
{ USART2, &usart2_intr, INTR_REQ_USART3,
|
||||
&usart2_stat, &usart2_rb_a2h, &usart2_rb_h2a, buf_usart2_rb_a2h,
|
||||
buf_usart2_rb_h2a, &usart2_app_write_event, &usart2_tx_ready },
|
||||
{ USART3, &usart3_intr, INTR_REQ_USART3,
|
||||
&usart3_stat, &usart3_rb_a2h, &usart3_rb_h2a, buf_usart3_rb_a2h,
|
||||
buf_usart3_rb_h2a, &usart3_app_write_event, &usart3_tx_ready },
|
||||
};
|
||||
#define NUM_USART ((int)(sizeof (usart_array) / sizeof (struct usart)))
|
||||
|
||||
static int handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat);
|
||||
static int handle_tx (struct USART *USARTx, struct rb *rb2h, struct usart_stat *stat);
|
||||
static void usart_config_recv_enable (struct USART *USARTx, int on);
|
||||
|
||||
/* We assume 36MHz f_PCLK */
|
||||
struct brr_setting {
|
||||
uint8_t baud_spec;
|
||||
uint16_t brr_value;
|
||||
uint32_t brr_value;
|
||||
};
|
||||
#define NUM_BAUD (int)(sizeof (brr_table) / sizeof (struct brr_setting))
|
||||
|
||||
/* We assume 36MHz f_PCLK */
|
||||
static const struct brr_setting brr_table[] = {
|
||||
{ B600, (3750 << 4)},
|
||||
{ B1200, (1875 << 4)},
|
||||
@@ -104,23 +159,24 @@ static const struct brr_setting brr_table[] = {
|
||||
{ B230400, ( 9 << 4)|12},
|
||||
{ B460800, ( 4 << 4)|14},
|
||||
{ B921600, ( 2 << 4)|7},
|
||||
{ BSCARD, ( 232 << 4)|8},
|
||||
{ BSCARD1, ( 232 << 4)|8}, /* 9677 */
|
||||
{ BSCARD2, ( 116 << 4)|4}, /* 19354 */
|
||||
{ BSCARD4, ( 58 << 4)|2}, /* 38709 */
|
||||
{ BSCARD8, ( 29 << 4)|1}, /* 77419 */
|
||||
{ BSCARD12, ( 19 << 4)|6}, /* 116129 */
|
||||
{ BSCARD16, ( 14 << 4)|9}, /* 154506 */
|
||||
{ BSCARD20, ( 11 << 4)|10}, /* 193548 */
|
||||
};
|
||||
|
||||
static void *usart_main (void *arg);
|
||||
|
||||
static struct usart_stat usart2_stat;
|
||||
static struct usart_stat usart3_stat;
|
||||
|
||||
void
|
||||
usart_config_clken (uint8_t dev_no, int on)
|
||||
#include "usart-common.c"
|
||||
|
||||
static void
|
||||
usart_config_recv_enable (struct USART *USARTx, int on)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
|
||||
if (on)
|
||||
USARTx->CR2 |= (1 << 11);
|
||||
USARTx->CR1 |= USART_CR1_RE;
|
||||
else
|
||||
USARTx->CR2 &= ~(1 << 11);
|
||||
USARTx->CR1 &= ~USART_CR1_RE;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,10 +186,10 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
uint8_t baud_spec = (config_bits & MASK_BAUD);
|
||||
int i;
|
||||
uint32_t cr1_config = (USART_CR1_UE | USART_CR1_RXNEIE
|
||||
| USART_CR1_TE | USART_CR1_RE);
|
||||
/* TXEIE will be enabled when putting char */
|
||||
/* No CTSIE, PEIE, TCIE, IDLEIE, LBDIE */
|
||||
uint32_t cr1_config = (USART_CR1_UE | USART_CR1_RXNEIE | USART_CR1_TE);
|
||||
/* TXEIE/TCIE will be enabled when
|
||||
putting char */
|
||||
/* No CTSIE, PEIE, IDLEIE, LBDIE */
|
||||
if (USARTx == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -177,10 +233,13 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
USARTx->BRR = brr_table[i].brr_value;
|
||||
|
||||
if ((config_bits & MASK_FLOW))
|
||||
USARTx->CR3 = (1 << 9) | (1 << 8);
|
||||
USARTx->CR3 = USART_CR3_CTSE | USART_CR3_RTSE;
|
||||
else
|
||||
USARTx->CR3 = 0;
|
||||
|
||||
if (!(config_bits & MASK_MODE))
|
||||
cr1_config |= USART_CR1_RE;
|
||||
|
||||
USARTx->CR1 = cr1_config;
|
||||
|
||||
/* SCEN (smartcard enable) should be set _after_ CR1. */
|
||||
@@ -188,8 +247,8 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
{
|
||||
if ((config_bits & MASK_MODE) == MODE_SMARTCARD)
|
||||
{
|
||||
USARTx->GTPR = (16 << 8) | 5;
|
||||
USARTx->CR3 |= ((1 << 5) | (1 << 4));
|
||||
USARTx->GTPR = (1 << 8) | 5;
|
||||
USARTx->CR3 |= (USART_CR3_SCEN | USART_CR3_NACK);
|
||||
}
|
||||
else if ((config_bits & MASK_MODE) == MODE_IRDA)
|
||||
USARTx->CR3 |= (1 << 1);
|
||||
@@ -200,236 +259,27 @@ usart_config (uint8_t dev_no, uint32_t config_bits)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*ss_notify_callback) (uint8_t dev_no, uint16_t notify_bits);
|
||||
|
||||
void
|
||||
usart_init (uint16_t prio, uintptr_t stack_addr, size_t stack_size,
|
||||
int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||
usart_init0 (int (*cb) (uint8_t dev_no, uint16_t notify_bits))
|
||||
{
|
||||
int i;
|
||||
|
||||
ss_notify_callback = cb;
|
||||
usart2_stat.dev_no = 2;
|
||||
usart3_stat.dev_no = 3;
|
||||
|
||||
for (i = 0; i < NUM_USART; i++)
|
||||
{
|
||||
if (usart_array[i].stat)
|
||||
usart_array[i].stat->dev_no = i + USART_DEVNO_START;
|
||||
chopstx_claim_irq (usart_array[i].intr, usart_array[i].irq_num);
|
||||
}
|
||||
|
||||
/* Enable USART2 and USART3 clocks, and strobe reset. */
|
||||
RCC->APB1ENR |= ((1 << 18) | (1 << 17));
|
||||
RCC->APB1RSTR = ((1 << 18) | (1 << 17));
|
||||
RCC->APB1RSTR = 0;
|
||||
|
||||
chopstx_create (prio, stack_addr, stack_size, usart_main, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ring buffer
|
||||
*/
|
||||
#define MAX_RB_BUF 1024
|
||||
|
||||
struct rb {
|
||||
uint8_t *buf;
|
||||
chopstx_mutex_t m;
|
||||
chopstx_cond_t data_available;
|
||||
chopstx_cond_t space_available;
|
||||
uint32_t head :10;
|
||||
uint32_t tail :10;
|
||||
uint32_t size :10;
|
||||
uint32_t full : 1;
|
||||
uint32_t empty : 1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: size = 1024 can still work, regardless of the limit of 10-bit.
|
||||
*/
|
||||
static void
|
||||
rb_init (struct rb *rb, uint8_t *p, uint16_t size)
|
||||
{
|
||||
rb->buf = p;
|
||||
rb->size = size;
|
||||
chopstx_mutex_init (&rb->m);
|
||||
chopstx_cond_init (&rb->data_available);
|
||||
chopstx_cond_init (&rb->space_available);
|
||||
rb->head = rb->tail = 0;
|
||||
rb->full = 0;
|
||||
rb->empty = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_add (struct rb *rb, uint8_t v)
|
||||
{
|
||||
rb->buf[rb->tail++] = v;
|
||||
if (rb->tail == rb->size)
|
||||
rb->tail = 0;
|
||||
if (rb->tail == rb->head)
|
||||
rb->full = 1;
|
||||
rb->empty = 0;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
rb_del (struct rb *rb)
|
||||
{
|
||||
uint32_t v = rb->buf[rb->head++];
|
||||
|
||||
if (rb->head == rb->size)
|
||||
rb->head = 0;
|
||||
if (rb->head == rb->tail)
|
||||
rb->empty = 1;
|
||||
rb->full = 0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: consumer
|
||||
* Hardware: generator
|
||||
*/
|
||||
static int
|
||||
rb_ll_put (struct rb *rb, uint8_t v)
|
||||
{
|
||||
int r;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
if (rb->full)
|
||||
r = -1;
|
||||
else
|
||||
{
|
||||
r = 0;
|
||||
rb_add (rb, v);
|
||||
chopstx_cond_signal (&rb->data_available);
|
||||
}
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: generator
|
||||
* Hardware: consumer
|
||||
*/
|
||||
static int
|
||||
rb_ll_get (struct rb *rb)
|
||||
{
|
||||
int r;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
if (rb->empty)
|
||||
r = -1;
|
||||
else
|
||||
{
|
||||
r = rb_del (rb);
|
||||
chopstx_cond_signal (&rb->space_available);
|
||||
}
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_ll_flush (struct rb *rb)
|
||||
{
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
while (!rb->empty)
|
||||
rb_del (rb);
|
||||
chopstx_cond_signal (&rb->space_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: consumer
|
||||
* Hardware: generator
|
||||
*/
|
||||
static int
|
||||
rb_read (struct rb *rb, uint8_t *buf, uint16_t buflen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
while (rb->empty)
|
||||
chopstx_cond_wait (&rb->data_available, &rb->m);
|
||||
|
||||
while (i < buflen)
|
||||
{
|
||||
buf[i++] = rb_del (rb);
|
||||
if (rb->empty)
|
||||
break;
|
||||
}
|
||||
chopstx_cond_signal (&rb->space_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application: generator
|
||||
* Hardware: consumer
|
||||
*/
|
||||
static void
|
||||
rb_write (struct rb *rb, uint8_t *buf, uint16_t buflen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
chopstx_mutex_lock (&rb->m);
|
||||
|
||||
do
|
||||
{
|
||||
while (rb->full)
|
||||
chopstx_cond_wait (&rb->space_available, &rb->m);
|
||||
|
||||
while (i < buflen)
|
||||
{
|
||||
rb_add (rb, buf[i++]);
|
||||
if (rb->full)
|
||||
{
|
||||
chopstx_cond_signal (&rb->data_available);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (i < buflen);
|
||||
|
||||
if (i)
|
||||
chopstx_cond_signal (&rb->data_available);
|
||||
chopstx_mutex_unlock (&rb->m);
|
||||
}
|
||||
|
||||
static int
|
||||
rb_empty_check (void *arg)
|
||||
{
|
||||
struct rb *rb = arg;
|
||||
return rb->empty == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_get_prepare_poll (struct rb *rb, chopstx_poll_cond_t *poll_desc)
|
||||
{
|
||||
poll_desc->type = CHOPSTX_POLL_COND;
|
||||
poll_desc->ready = 0;
|
||||
poll_desc->cond = &rb->data_available;
|
||||
poll_desc->mutex = &rb->m;
|
||||
poll_desc->check = rb_empty_check;
|
||||
poll_desc->arg = rb;
|
||||
}
|
||||
|
||||
#define INTR_REQ_USART2 38
|
||||
#define INTR_REQ_USART3 39
|
||||
|
||||
static uint8_t buf_usart2_rb_a2h[256];
|
||||
static uint8_t buf_usart2_rb_h2a[512];
|
||||
static uint8_t buf_usart3_rb_a2h[256];
|
||||
static uint8_t buf_usart3_rb_h2a[512];
|
||||
|
||||
static struct chx_intr usart2_intr;
|
||||
static struct chx_intr usart3_intr;
|
||||
|
||||
static struct rb usart2_rb_a2h;
|
||||
static struct rb usart2_rb_h2a;
|
||||
static struct rb usart3_rb_a2h;
|
||||
static struct rb usart3_rb_h2a;
|
||||
|
||||
static chopstx_poll_cond_t usart2_app_write_event;
|
||||
static chopstx_poll_cond_t usart3_app_write_event;
|
||||
|
||||
static struct chx_poll_head *usart_poll[4];
|
||||
|
||||
/* Global variables so that it can be easier to debug. */
|
||||
static int usart2_tx_ready;
|
||||
static int usart3_tx_ready;
|
||||
|
||||
#define UART_STATE_BITMAP_RX_CARRIER (1 << 0)
|
||||
#define UART_STATE_BITMAP_TX_CARRIER (1 << 1)
|
||||
#define UART_STATE_BITMAP_BREAK (1 << 2)
|
||||
@@ -444,11 +294,23 @@ handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat)
|
||||
int tx_ready = 0;
|
||||
uint32_t r = USARTx->SR;
|
||||
int notify_bits = 0;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
if ((r & USART_SR_TXE))
|
||||
if (smartcard_mode)
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
if ((r & USART_SR_TC))
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_SR_TXE))
|
||||
{
|
||||
tx_ready = 1;
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r & USART_SR_RXNE))
|
||||
@@ -507,8 +369,7 @@ handle_intr (struct USART *USARTx, struct rb *rb2a, struct usart_stat *stat)
|
||||
}
|
||||
|
||||
static int
|
||||
handle_tx_ready (struct USART *USARTx, struct rb *rb2h,
|
||||
struct usart_stat *stat)
|
||||
handle_tx (struct USART *USARTx, struct rb *rb2h, struct usart_stat *stat)
|
||||
{
|
||||
int tx_ready = 1;
|
||||
int c = rb_ll_get (rb2h);
|
||||
@@ -516,131 +377,32 @@ handle_tx_ready (struct USART *USARTx, struct rb *rb2h,
|
||||
if (c >= 0)
|
||||
{
|
||||
uint32_t r;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
USARTx->DR = (c & 0xff);
|
||||
stat->tx++;
|
||||
r = USARTx->SR;
|
||||
if ((r & USART_SR_TXE) == 0)
|
||||
if (smartcard_mode)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
if ((r & USART_SR_TC) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_SR_TXE) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tx_ready;
|
||||
}
|
||||
|
||||
static void *
|
||||
usart_main (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
usart2_tx_ready = 1;
|
||||
usart3_tx_ready = 1;
|
||||
|
||||
chopstx_claim_irq (&usart2_intr, INTR_REQ_USART2);
|
||||
chopstx_claim_irq (&usart3_intr, INTR_REQ_USART3);
|
||||
|
||||
rb_init (&usart2_rb_a2h, buf_usart2_rb_a2h, sizeof buf_usart2_rb_a2h);
|
||||
rb_init (&usart2_rb_h2a, buf_usart2_rb_h2a, sizeof buf_usart2_rb_h2a);
|
||||
rb_init (&usart3_rb_a2h, buf_usart3_rb_a2h, sizeof buf_usart3_rb_a2h);
|
||||
rb_init (&usart3_rb_h2a, buf_usart3_rb_h2a, sizeof buf_usart3_rb_h2a);
|
||||
|
||||
rb_get_prepare_poll (&usart2_rb_a2h, &usart2_app_write_event);
|
||||
rb_get_prepare_poll (&usart3_rb_a2h, &usart3_app_write_event);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
usart_poll[n++] = (struct chx_poll_head *)&usart2_intr;
|
||||
usart_poll[n++] = (struct chx_poll_head *)&usart3_intr;
|
||||
if (usart2_tx_ready)
|
||||
usart_poll[n++] = (struct chx_poll_head *)&usart2_app_write_event;
|
||||
else
|
||||
usart2_app_write_event.ready = 0;
|
||||
if (usart3_tx_ready)
|
||||
usart_poll[n++] = (struct chx_poll_head *)&usart3_app_write_event;
|
||||
else
|
||||
usart3_app_write_event.ready = 0;
|
||||
|
||||
chopstx_poll (NULL, n, usart_poll);
|
||||
|
||||
if (usart2_intr.ready)
|
||||
{
|
||||
usart2_tx_ready = handle_intr (USART2, &usart2_rb_h2a, &usart2_stat);
|
||||
chopstx_intr_done (&usart2_intr);
|
||||
}
|
||||
|
||||
if (usart3_intr.ready)
|
||||
{
|
||||
usart3_tx_ready = handle_intr (USART3, &usart3_rb_h2a, &usart3_stat);
|
||||
chopstx_intr_done (&usart3_intr);
|
||||
}
|
||||
|
||||
if (usart2_tx_ready && usart2_app_write_event.ready)
|
||||
usart2_tx_ready = handle_tx_ready (USART2,
|
||||
&usart2_rb_a2h, &usart2_stat);
|
||||
|
||||
if (usart3_tx_ready && usart3_app_write_event.ready)
|
||||
usart3_tx_ready = handle_tx_ready (USART3,
|
||||
&usart3_rb_a2h, &usart3_stat);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
usart_read (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||
{
|
||||
struct rb *rb;
|
||||
|
||||
if (dev_no == 2)
|
||||
rb = &usart2_rb_h2a;
|
||||
else if (dev_no == 3)
|
||||
rb = &usart3_rb_h2a;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (buf == NULL && buflen == 0)
|
||||
{
|
||||
rb_ll_flush (rb);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return rb_read (rb, (uint8_t *)buf, buflen);
|
||||
}
|
||||
|
||||
int
|
||||
usart_write (uint8_t dev_no, char *buf, uint16_t buflen)
|
||||
{
|
||||
struct rb *rb;
|
||||
|
||||
if (dev_no == 2)
|
||||
rb = &usart2_rb_a2h;
|
||||
else if (dev_no == 3)
|
||||
rb = &usart3_rb_a2h;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (buf == NULL && buflen == 0)
|
||||
rb_ll_flush (rb);
|
||||
else
|
||||
rb_write (rb, (uint8_t *)buf, buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct usart_stat *
|
||||
usart_stat (uint8_t dev_no)
|
||||
{
|
||||
if (dev_no == 2)
|
||||
return &usart2_stat;
|
||||
else if (dev_no == 3)
|
||||
return &usart3_stat;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
usart_send_break (uint8_t dev_no)
|
||||
{
|
||||
@@ -654,3 +416,145 @@ usart_send_break (uint8_t dev_no)
|
||||
USARTx->CR1 |= 0x01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
usart_block_sendrecv (uint8_t dev_no, const char *s_buf, uint16_t s_buflen,
|
||||
char *r_buf, uint16_t r_buflen,
|
||||
uint32_t *timeout_block_p, uint32_t timeout_char)
|
||||
{
|
||||
uint32_t timeout;
|
||||
uint8_t *p;
|
||||
int len;
|
||||
uint32_t r;
|
||||
uint32_t data;
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
struct chx_intr *usartx_intr = get_usart_intr (dev_no);
|
||||
struct chx_poll_head *ph[1];
|
||||
|
||||
if (usartx_intr == NULL)
|
||||
return -1;
|
||||
|
||||
ph[0] = (struct chx_poll_head *)usartx_intr;
|
||||
|
||||
p = (uint8_t *)s_buf;
|
||||
if (p)
|
||||
{
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 0);
|
||||
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
|
||||
/* Sending part */
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (NULL, 1, ph);
|
||||
|
||||
r = USARTx->SR;
|
||||
|
||||
/* Here, ignore recv error(s). */
|
||||
if ((r & USART_SR_RXNE) || (r & USART_SR_ORE))
|
||||
{
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
if ((r & USART_SR_TXE))
|
||||
{
|
||||
if (s_buflen == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Keep TXEIE bit */
|
||||
USARTx->DR = *p++;
|
||||
s_buflen--;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if (timeout_block_p && (*timeout_block_p))
|
||||
do
|
||||
r = USARTx->SR;
|
||||
while (((r & USART_SR_TC) == 0));
|
||||
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
if (timeout_block_p && *timeout_block_p == 0)
|
||||
{
|
||||
/* Ignoring the echo back. */
|
||||
do
|
||||
r = USARTx->SR;
|
||||
while (((r & USART_SR_TC) == 0));
|
||||
|
||||
if ((r & USART_SR_RXNE))
|
||||
{
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
*timeout_block_p = timeout_char;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
if (r_buf == NULL)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
/* Receiving part */
|
||||
r = chopstx_poll (timeout_block_p, 1, ph);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
p = (uint8_t *)r_buf;
|
||||
len = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = USARTx->SR;
|
||||
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
if ((r & USART_SR_RXNE))
|
||||
{
|
||||
if ((r & USART_SR_NE) || (r & USART_SR_FE) || (r & USART_SR_PE))
|
||||
/* ignore error, for now. XXX: ss_notify */
|
||||
;
|
||||
else
|
||||
{
|
||||
*p++ = (data & 0xff);
|
||||
len++;
|
||||
r_buflen--;
|
||||
if (r_buflen == 0)
|
||||
{
|
||||
chopstx_intr_done (usartx_intr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((r & USART_SR_ORE))
|
||||
{
|
||||
data = USARTx->DR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
timeout = timeout_char;
|
||||
r = chopstx_poll (&timeout, 1, ph);
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
558
contrib/usart-stm32l4.c
Normal file
558
contrib/usart-stm32l4.c
Normal file
@@ -0,0 +1,558 @@
|
||||
#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) (stat->dev_no, notify_bits))
|
||||
stat->err_notify_overflow++;
|
||||
}
|
||||
|
||||
return tx_ready;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_tx (struct USART *USARTx, struct rb *rb2h, struct usart_stat *stat)
|
||||
{
|
||||
int tx_ready = 1;
|
||||
int c = rb_ll_get (rb2h);
|
||||
|
||||
if (c >= 0)
|
||||
{
|
||||
uint32_t r;
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
|
||||
USARTx->TDR = (c & 0xff);
|
||||
stat->tx++;
|
||||
r = USARTx->ISR;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if ((r & USART_ISR_TC) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TCIE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((r & USART_ISR_TXE) == 0)
|
||||
{
|
||||
tx_ready = 0;
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tx_ready;
|
||||
}
|
||||
|
||||
int
|
||||
usart_send_break (uint8_t dev_no)
|
||||
{
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
if (USARTx == NULL)
|
||||
return -1;
|
||||
|
||||
if ((USARTx->ISR & (1 << 18)))
|
||||
return 1; /* Busy sending break, which was requested before. */
|
||||
|
||||
/* ??? Should we check TX is empty? */
|
||||
|
||||
USARTx->RQR |= 0x02;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
usart_block_sendrecv (uint8_t dev_no, const char *s_buf, uint16_t s_buflen,
|
||||
char *r_buf, uint16_t r_buflen,
|
||||
uint32_t *timeout_block_p, uint32_t timeout_char)
|
||||
{
|
||||
uint32_t timeout;
|
||||
uint8_t *p;
|
||||
int len;
|
||||
uint32_t r;
|
||||
uint32_t data;
|
||||
struct USART *USARTx = get_usart_dev (dev_no);
|
||||
int smartcard_mode = ((USARTx->CR3 & USART_CR3_SCEN) != 0);
|
||||
struct chx_intr *usartx_intr = get_usart_intr (dev_no);
|
||||
struct chx_poll_head *ph[1];
|
||||
|
||||
if (usartx_intr == NULL)
|
||||
return -1;
|
||||
|
||||
ph[0] = (struct chx_poll_head *)usartx_intr;
|
||||
|
||||
p = (uint8_t *)s_buf;
|
||||
if (p)
|
||||
{
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 0);
|
||||
|
||||
USARTx->CR1 |= USART_CR1_TXEIE;
|
||||
|
||||
/* Sending part */
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (NULL, 1, ph);
|
||||
|
||||
r = USARTx->ISR;
|
||||
|
||||
/* Here, ignore recv error(s). */
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
data = USARTx->RDR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
USARTx->ICR |= ((1 << 2) | (1 << 1) | (1 << 0));
|
||||
}
|
||||
else if ((r & USART_ISR_ORE))
|
||||
{
|
||||
USARTx->ICR |= (1 << 3);
|
||||
}
|
||||
|
||||
if ((r & USART_ISR_TXE))
|
||||
{
|
||||
if (s_buflen == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Keep TXEIE bit */
|
||||
USARTx->TDR = *p++;
|
||||
s_buflen--;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
USARTx->CR1 &= ~USART_CR1_TXEIE;
|
||||
if (smartcard_mode)
|
||||
{
|
||||
if (timeout_block_p && (*timeout_block_p))
|
||||
do
|
||||
r = USARTx->ISR;
|
||||
while (((r & USART_ISR_TC) == 0));
|
||||
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
if (timeout_block_p && *timeout_block_p == 0)
|
||||
{
|
||||
/* Ignoring the echo back. */
|
||||
do
|
||||
r = USARTx->ISR;
|
||||
while (((r & USART_ISR_TC) == 0));
|
||||
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
data = USARTx->RDR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
}
|
||||
|
||||
*timeout_block_p = timeout_char;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
}
|
||||
|
||||
if (r_buf == NULL)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
if (smartcard_mode)
|
||||
usart_config_recv_enable (USARTx, 1);
|
||||
|
||||
/* Receiving part */
|
||||
r = chopstx_poll (timeout_block_p, 1, ph);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
p = (uint8_t *)r_buf;
|
||||
len = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = USARTx->ISR;
|
||||
|
||||
data = USARTx->RDR;
|
||||
asm volatile ("" : : "r" (data) : "memory");
|
||||
|
||||
if ((r & USART_ISR_RXNE))
|
||||
{
|
||||
if ((r & USART_ISR_NE) || (r & USART_ISR_FE) || (r & USART_ISR_PE))
|
||||
{
|
||||
/* ignore error, for now. XXX: ss_notify */
|
||||
/* Clear the error flag(s) */
|
||||
USARTx->ICR |= ((1 << 2) | (1 << 1) | (1 << 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = (data & 0xff);
|
||||
len++;
|
||||
r_buflen--;
|
||||
if (r_buflen == 0)
|
||||
{
|
||||
chopstx_intr_done (usartx_intr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((r & USART_ISR_ORE))
|
||||
{
|
||||
/* ignore error, for now. XXX: ss_notify */
|
||||
/* Clear the error flag */
|
||||
USARTx->ICR |= (1 << 3);
|
||||
}
|
||||
|
||||
chopstx_intr_done (usartx_intr);
|
||||
timeout = timeout_char;
|
||||
r = chopstx_poll (&timeout, 1, ph);
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -11,7 +11,13 @@
|
||||
#define B230400 26
|
||||
#define B460800 27
|
||||
#define B921600 28
|
||||
#define BSCARD 63
|
||||
#define BSCARD1 57
|
||||
#define BSCARD2 58
|
||||
#define BSCARD4 59
|
||||
#define BSCARD8 60
|
||||
#define BSCARD12 61
|
||||
#define BSCARD16 62
|
||||
#define BSCARD20 63
|
||||
#define MASK_BAUD 0x3f
|
||||
|
||||
/* POSIX supports 5, 6. USB suppots 16 */
|
||||
@@ -73,3 +79,12 @@ int usart_write (uint8_t dev_no, char *buf, uint16_t buflen);
|
||||
const struct usart_stat *usart_stat (uint8_t dev_no);
|
||||
int usart_send_break (uint8_t dev_no);
|
||||
void usart_config_clken (uint8_t dev_no, int on);
|
||||
int usart_config_baud (uint8_t dev_no, uint8_t baud_spec);
|
||||
|
||||
void usart_read_prepare_poll (uint8_t dev_no, chopstx_poll_cond_t *poll_desc);
|
||||
int usart_read_ext (uint8_t dev_no, char *buf, uint16_t buflen, uint32_t *timeout_p);
|
||||
|
||||
void usart_init0 (int (*cb) (uint8_t dev_no, uint16_t notify_bits));
|
||||
int usart_block_sendrecv (uint8_t dev_no, const char *s_buf, uint16_t s_buflen,
|
||||
char *r_buf, uint16_t r_buflen,
|
||||
uint32_t *timeout_block_p, uint32_t timeout_char);
|
||||
|
||||
@@ -185,7 +185,8 @@ Returns old state which is 0 when it was enabled.
|
||||
@subheading chopstx_poll
|
||||
@anchor{chopstx_poll}
|
||||
@deftypefun {int} {chopstx_poll} (uint32_t * @var{usec_p}, int @var{n}, struct chx_poll_head *const [] @var{pd_array})
|
||||
@var{usec_p}: Pointer to usec for timeout. Forever if NULL.
|
||||
@var{usec_p}: Pointer to usec for timeout. Forever if NULL. It is
|
||||
updated on return
|
||||
|
||||
@var{n}: Number of poll descriptors
|
||||
|
||||
|
||||
106
doc/chopstx.texi
106
doc/chopstx.texi
@@ -1,7 +1,7 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename chopstx.info
|
||||
@set VERSION 1.14
|
||||
@set VERSION 1.15
|
||||
@settitle Chopstx Reference Manual
|
||||
@c Unify some of the indices.
|
||||
@syncodeindex tp fn
|
||||
@@ -11,7 +11,7 @@
|
||||
This manual is for Chopstx (version @value{VERSION}).
|
||||
|
||||
@noindent
|
||||
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018 Flying Stone Technology @*
|
||||
Copyright @copyright{} 2013, 2015, 2016, 2017, 2018, 2019 Flying Stone Technology @*
|
||||
|
||||
@quotation
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
@@ -60,10 +60,11 @@ section entitled ``Copying''.
|
||||
@menu
|
||||
* Introduction:: What is Chopstx.
|
||||
* Threads and only Threads:: Threads and only Threads.
|
||||
* Poll or Pole:: Poll or Pole.
|
||||
* Note (Use of sleep mode):: Use it carefully.
|
||||
* Poll or Pole::
|
||||
* Use of sleep mode:: Use it carefully.
|
||||
* Compile-time macro:: Macro to be defined.
|
||||
* API:: API.
|
||||
* Memorandom:: Memorandom for the implementation.
|
||||
|
||||
Appendix
|
||||
|
||||
@@ -88,8 +89,9 @@ Indexes
|
||||
@chapter Introduction
|
||||
|
||||
Chopstx is an RT thread library for ARM Cortex-M0, Cortex-M0plus,
|
||||
Cortex-M3 and GNU/Linux emulation. Specifically, it is used for
|
||||
STM32F030, MKL27Z, STM32F103, GD32F103 and as a command on GNU/Linux.
|
||||
Cortex-M3, Cortex-M4 with no FPU or DSP, and GNU/Linux emulation.
|
||||
Specifically, it is used for STM32F030, MKL27Z, STM32F103, GD32F103,
|
||||
STM32L432 and as a command on GNU/Linux.
|
||||
|
||||
While most RTOSes come with many features, drivers, and stacks,
|
||||
Chopstx just offers an RT thread library.
|
||||
@@ -99,7 +101,7 @@ enables coherent code for ease of maintenance.
|
||||
|
||||
While threads are important, we don't need more threads than
|
||||
necessary. Chopstx provides a feature of poll, so that we can
|
||||
minimize use of threads.
|
||||
handle multiple events by a single thread.
|
||||
|
||||
|
||||
@node Threads and only Threads
|
||||
@@ -107,7 +109,7 @@ minimize use of threads.
|
||||
|
||||
Chopstx doesn't use the feature of (prioritized) nested vector
|
||||
interrupt mechanism at all. All interrupts are equally handled by a
|
||||
single entry of chx_handle_intr which just wakes up corresponding
|
||||
single entry of chx_handle_intr which just wakes up a corresponding
|
||||
thread. This is the feature of Chopstx.
|
||||
|
||||
Nested vector interrupt machanism would be useful for interrupt-driven
|
||||
@@ -145,8 +147,8 @@ programming style, with minimum number of threads, avoiding
|
||||
complicated dependency between threads.
|
||||
|
||||
|
||||
@node Note (Use of sleep mode)
|
||||
@chapter Note (Use of sleep mode)
|
||||
@node Use of sleep mode
|
||||
@chapter Use of sleep mode
|
||||
|
||||
Calling the chopstx_conf_idle function (> 0) to allow the idle thread
|
||||
going to sleep. MCU will be in sleep mode when no threads are
|
||||
@@ -178,6 +180,90 @@ Running CPU clock in MHz. Used for chopstx_usec_wait.
|
||||
|
||||
@include chopstx-api.texi
|
||||
|
||||
@node Memorandom
|
||||
@chapter Memorandom for the implementation
|
||||
|
||||
@menu
|
||||
* Honourable poverty:: Wabi and Sabi.
|
||||
* Better interrupt handling::
|
||||
* Static and deterministic when possible::
|
||||
@end menu
|
||||
|
||||
@node Honourable poverty
|
||||
@section Honourable poverty
|
||||
|
||||
Chopstx is an effort against many features. It encourages doing
|
||||
harder decision earlier (because of less features).
|
||||
|
||||
Along with Moore's law, MCU implementations and their software are
|
||||
getting more complex. It's been getting more flexibile, versatile,
|
||||
and powerful.
|
||||
|
||||
Here is a question: the bigger is the better?
|
||||
|
||||
Historically, it used to be ``Yes, and it's even cheaper!''. And, for
|
||||
a while, this trend continues.
|
||||
|
||||
However, in my opinion, it has been arrived to the point where
|
||||
complexity matters. Now, it's more difficult to manage the
|
||||
complexity.
|
||||
|
||||
With full of resources, it became possible deferring difficult
|
||||
hardware or lower-level decisions to upper layer, by supporting both
|
||||
ways, when we have a choice. It used to be considered a good
|
||||
practice.
|
||||
|
||||
But, eventually, as a system, it may result many knobs, full of
|
||||
options, which might be too difficult to manage.
|
||||
|
||||
In this situation, against existing practice, Chopstx is a challenge
|
||||
to handle all food by only two wooden sticks. It's not fork and exec
|
||||
nor forks and knives.
|
||||
|
||||
In Japan, it is common among families, to have private chopsticks for
|
||||
each individual at home. It's like: these chopsticks are father's,
|
||||
these chopsticks are mother's... son's and daughter's.
|
||||
|
||||
I hope Chopstx is the one for you.
|
||||
|
||||
|
||||
@node Better interrupt handling
|
||||
@section Better interrupt handling
|
||||
|
||||
In Chopstx, all interrupt handling is done by a single routine named
|
||||
chx_handle_intr. It uses linear list search to find a thread which
|
||||
handles the interrupt. In the fixed vector_table, we see many of
|
||||
chx_handle_intr entries.
|
||||
|
||||
Obviously, this is suboptimal. It kills the hardware effort to
|
||||
decrease interrupt latency.
|
||||
|
||||
I is certainly possible to support configurable vector table and/or
|
||||
better dispatch.
|
||||
|
||||
The reason why I keep this badness is that I believe that when
|
||||
interrupt latency matters (to the level of supporting larger vector
|
||||
table, despite only few cycles elimination), something is going wrong.
|
||||
You should have better solution or work around, instead of eliminating
|
||||
few cycles in an interrupt handler.
|
||||
|
||||
When I have an opportunity to design MCU, I don't support larger
|
||||
interrupt vector table.
|
||||
|
||||
|
||||
@node Static and deterministic when possible
|
||||
@section Static and deterministic when possible
|
||||
|
||||
When an application enables features dynamically, it may invite
|
||||
non-deterministic bugs. Typical example: the order of driver
|
||||
initialization matters, because of hidden dependency in a hardware
|
||||
implementation. To cover all the cases, tests needed can become huge.
|
||||
|
||||
A simple practice like following is good when it's enough: doing all
|
||||
initialization at start, then running threads to work.
|
||||
|
||||
If possible, it's better to avoid supporting fine grain power control
|
||||
and/or dynamic clock frequency change.
|
||||
|
||||
@c ********************************************
|
||||
|
||||
|
||||
33
entry.c
33
entry.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* entry.c - Entry routine when reset and interrupt vectors.
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2019
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -23,7 +23,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -54,12 +54,16 @@ main (int argc, const char *argv[])
|
||||
* Avoid medium density specific code and prepare for high density
|
||||
* device, too.
|
||||
*/
|
||||
#undef STM32F10X_MD
|
||||
#if !defined(MCU_STM32L4)
|
||||
#define STM32F10X_HD
|
||||
#endif
|
||||
#else
|
||||
#if defined (MCU_KINETIS_L)
|
||||
#include "mcu/clk_gpio_init-mkl27z.c"
|
||||
#elif defined (MCU_STM32L4)
|
||||
#include "mcu/clk_gpio_init-stm32l.c"
|
||||
#else
|
||||
#include "mcu/clk_gpio_init-stm32.c"
|
||||
#include "mcu/clk_gpio_init-stm32f.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -71,7 +75,7 @@ main (int argc, const char *argv[])
|
||||
#endif
|
||||
|
||||
extern uint8_t __main_stack_end__;
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
extern void svc (void);
|
||||
#endif
|
||||
extern void preempt (void);
|
||||
@@ -167,7 +171,7 @@ entry (void)
|
||||
"bl chx_systick_init\n\t"
|
||||
"bl gpio_init\n\t"
|
||||
/* Enable interrupts. */
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
"mov r0, #0\n\t"
|
||||
"msr BASEPRI, r0\n\t"
|
||||
#endif
|
||||
@@ -197,7 +201,7 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
||||
none, none, none, /* reserved */
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
none, /* SVCall */
|
||||
#elif defined(__ARM_ARCH_7M__)
|
||||
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
svc, /* SVCall */
|
||||
#endif
|
||||
none, /* Debug */
|
||||
@@ -233,10 +237,23 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
||||
chx_handle_intr /* EXT15_10 */, chx_handle_intr /* RTCAlarm */,
|
||||
chx_handle_intr /* USBWakeup */, chx_handle_intr,
|
||||
#endif
|
||||
#if !defined(STM32F10X_MD)
|
||||
#if defined(STM32F10X_HD)
|
||||
/* High-density chips have more; ... DMA2_Channel4_5 */
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
#elif defined(MCU_STM32L4)
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
#endif
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -660,31 +660,8 @@ tty_main (void *arg)
|
||||
struct usb_dev dev;
|
||||
int e;
|
||||
|
||||
#if defined(OLDER_SYS_H)
|
||||
/*
|
||||
* Historically (before sys < 3.0), NVIC priority setting for USB
|
||||
* interrupt was done in usb_lld_sys_init. Thus this code.
|
||||
*
|
||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||
* invocation of usb_lld_event_handler won't occur.
|
||||
*
|
||||
* Calling usb_lld_event_handler is no harm even if there were no
|
||||
* interrupts, thus, we call it unconditionally here, just in case
|
||||
* if there is a request.
|
||||
*
|
||||
* We can't call usb_lld_init after chopstx_claim_irq, as
|
||||
* usb_lld_init does its own setting for NVIC. Calling
|
||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||
*
|
||||
*/
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
goto event_handle;
|
||||
#else
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
PROJECT = sample
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT= sample.ld
|
||||
LDSCRIPT= sample.ld.m4
|
||||
CSRC = sample.c usb-cdc.c
|
||||
|
||||
CHIP=stm32f103
|
||||
CHIP=stm32l4
|
||||
|
||||
USE_SYS = yes
|
||||
USE_USB = yes
|
||||
@@ -18,9 +18,9 @@ CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
MCU = cortex-m3
|
||||
MCU = cortex-m4
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=72
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
../board/board-fst-01.h
|
||||
../board/board-st-nucleo-l432.h
|
||||
107
example-cdc/sample.ld.m4
Normal file
107
example-cdc/sample.ld.m4
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* ST32L4 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash : org = 0x08000000, len = 256k
|
||||
ram : org = 0x20000000, len = 48k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN(16);
|
||||
_sys = .;
|
||||
. = ALIGN(16);
|
||||
KEEP(*(.sys.version))
|
||||
KEEP(*(.sys.board_id))
|
||||
KEEP(*(.sys.board_name))
|
||||
build/sys-*.o(.text)
|
||||
build/sys-*.o(.text.*)
|
||||
build/sys-*.o(.rodata)
|
||||
build/sys-*.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
} > flash =0xffffffff
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
*(.text.startup.*)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
. = ALIGN(8);
|
||||
} > flash
|
||||
|
||||
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
|
||||
|
||||
.ARM.exidx : {
|
||||
PROVIDE(__exidx_start = .);
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
PROVIDE(__exidx_end = .);
|
||||
} > flash
|
||||
|
||||
.eh_frame_hdr : {*(.eh_frame_hdr)} > flash
|
||||
|
||||
.eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
|
||||
|
||||
.textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
|
||||
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data = .);
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} > ram AT > flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_start = .);
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_end = .);
|
||||
} > ram
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
__heap_base__ = _end;
|
||||
__heap_end__ = __ram_end__;
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <string.h>
|
||||
#include "board.h"
|
||||
#include "usb_lld.h"
|
||||
#include "tty.h"
|
||||
|
||||
@@ -674,24 +675,17 @@ tty_main (void *arg)
|
||||
#if defined(OLDER_SYS_H)
|
||||
/*
|
||||
* Historically (before sys < 3.0), NVIC priority setting for USB
|
||||
* interrupt was done in usb_lld_sys_init. Thus this code.
|
||||
*
|
||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||
* invocation of usb_lld_event_handler won't occur.
|
||||
*
|
||||
* Calling usb_lld_event_handler is no harm even if there were no
|
||||
* interrupts, thus, we call it unconditionally here, just in case
|
||||
* if there is a request.
|
||||
* interrupt was done in usb_lld_sys_init for free standing
|
||||
* application. Thus this compatibility code.
|
||||
*
|
||||
* We can't call usb_lld_init after chopstx_claim_irq, as
|
||||
* usb_lld_init does its own setting for NVIC. Calling
|
||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||
* usb_lld_init does its own setting for NVIC, which is incompatible
|
||||
* to Chopstx's interrupt handling. Calling chopstx_claim_irq after
|
||||
* usb_lld_init overrides that for Chopstx.
|
||||
*
|
||||
*/
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
goto event_handle;
|
||||
#else
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
|
||||
@@ -660,24 +660,17 @@ tty_main (void *arg)
|
||||
#if defined(OLDER_SYS_H)
|
||||
/*
|
||||
* Historically (before sys < 3.0), NVIC priority setting for USB
|
||||
* interrupt was done in usb_lld_sys_init. Thus this code.
|
||||
*
|
||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||
* invocation of usb_lld_event_handler won't occur.
|
||||
*
|
||||
* Calling usb_lld_event_handler is no harm even if there were no
|
||||
* interrupts, thus, we call it unconditionally here, just in case
|
||||
* if there is a request.
|
||||
* interrupt was done in usb_lld_sys_init for free standing
|
||||
* application. Thus this compatibility code.
|
||||
*
|
||||
* We can't call usb_lld_init after chopstx_claim_irq, as
|
||||
* usb_lld_init does its own setting for NVIC. Calling
|
||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||
* usb_lld_init does its own setting for NVIC, which is incompatible
|
||||
* to Chopstx's interrupt handling. Calling chopstx_claim_irq after
|
||||
* usb_lld_init overrides that for Chopstx.
|
||||
*
|
||||
*/
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
goto event_handle;
|
||||
#else
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
|
||||
PROJECT = sample
|
||||
|
||||
### Currently, it's for STM32F0 Discovery.
|
||||
### Currently, it is for STM32 Nucleo L432
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M3 board.
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M0+ board
|
||||
### (STM32F0 Discovery).
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT= sample.ld
|
||||
LDSCRIPT= sample.ld.m4
|
||||
### LDSCRIPT= sample.ld
|
||||
### LDSCRIPT= sample.ld.m3
|
||||
CSRC = sample.c
|
||||
|
||||
CHIP=stm32f0
|
||||
CHIP=stm32l4
|
||||
USE_SYS = yes
|
||||
|
||||
###################################
|
||||
@@ -20,9 +25,10 @@ LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
### MCU = cortex-m3
|
||||
MCU = cortex-m0
|
||||
### MCU = cortex-m0
|
||||
MCU = cortex-m4
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=48
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
|
||||
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
|
||||
@@ -1 +1 @@
|
||||
../board/board-stm32f0-discovery.h
|
||||
../board/board-st-nucleo-l432.h
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "sys.h" /* for set_led */
|
||||
|
||||
static chopstx_mutex_t mtx;
|
||||
|
||||
107
example-led/sample.ld.m4
Normal file
107
example-led/sample.ld.m4
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* ST32L4 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash : org = 0x08000000, len = 256k
|
||||
ram : org = 0x20000000, len = 48k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN(16);
|
||||
_sys = .;
|
||||
. = ALIGN(16);
|
||||
KEEP(*(.sys.version))
|
||||
KEEP(*(.sys.board_id))
|
||||
KEEP(*(.sys.board_name))
|
||||
build/sys-*.o(.text)
|
||||
build/sys-*.o(.text.*)
|
||||
build/sys-*.o(.rodata)
|
||||
build/sys-*.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
} > flash =0xffffffff
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
*(.text.startup.*)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
. = ALIGN(8);
|
||||
} > flash
|
||||
|
||||
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
|
||||
|
||||
.ARM.exidx : {
|
||||
PROVIDE(__exidx_start = .);
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
PROVIDE(__exidx_end = .);
|
||||
} > flash
|
||||
|
||||
.eh_frame_hdr : {*(.eh_frame_hdr)} > flash
|
||||
|
||||
.eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
|
||||
|
||||
.textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
|
||||
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data = .);
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} > ram AT > flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_start = .);
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_end = .);
|
||||
} > ram
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
__heap_base__ = _end;
|
||||
__heap_end__ = __ram_end__;
|
||||
47
example-usart/Makefile
Normal file
47
example-usart/Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
# Makefile for example application of Chopstx
|
||||
|
||||
PROJECT = sample
|
||||
|
||||
### Currently, it is for STM32 Nucleo L432
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M3 board.
|
||||
###
|
||||
### Please change lines started with '###' for Cortex-M0+ board
|
||||
### (STM32F0 Discovery).
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT= sample.ld.m4
|
||||
### LDSCRIPT= sample.ld
|
||||
### LDSCRIPT= sample.ld.m3
|
||||
CSRC = sample.c
|
||||
|
||||
CHIP=stm32l4
|
||||
USE_SYS = yes
|
||||
USE_USART = yes
|
||||
|
||||
###################################
|
||||
CROSS = arm-none-eabi-
|
||||
CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
### MCU = cortex-m3
|
||||
### MCU = cortex-m0
|
||||
MCU = cortex-m4
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DUSE_SYS3 -DFREE_STANDING -DMHZ=80
|
||||
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
|
||||
####################
|
||||
include ../rules.mk
|
||||
|
||||
board.h:
|
||||
@echo Please make a symbolic link \'board.h\' to a file in ../board;
|
||||
@exit 1
|
||||
|
||||
sys.c: board.h
|
||||
|
||||
distclean: clean
|
||||
rm -f board.h
|
||||
1
example-usart/board.h
Symbolic link
1
example-usart/board.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../board/board-st-nucleo-l432.h
|
||||
156
example-usart/sample.c
Normal file
156
example-usart/sample.c
Normal file
@@ -0,0 +1,156 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "sys.h" /* for set_led */
|
||||
#include <contrib/usart.h>
|
||||
|
||||
static chopstx_mutex_t mtx;
|
||||
static chopstx_cond_t cnd0;
|
||||
static chopstx_cond_t cnd1;
|
||||
|
||||
static uint8_t u, v;
|
||||
static uint8_t m; /* 0..100 */
|
||||
|
||||
static void
|
||||
wait_for (uint32_t usec)
|
||||
{
|
||||
#if defined(BUSY_LOOP)
|
||||
uint32_t count = usec * 6;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
#else
|
||||
chopstx_usec_wait (usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *
|
||||
pwm (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd0, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
set_led (u&v);
|
||||
wait_for (m);
|
||||
set_led (0);
|
||||
wait_for (100-m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
blk (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd1, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
v = 0;
|
||||
wait_for (200*1000);
|
||||
v = 1;
|
||||
wait_for (200*1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(BUSY_LOOP)
|
||||
#define PRIO_PWM (CHOPSTX_SCHED_RR|1)
|
||||
#define PRIO_BLK (CHOPSTX_SCHED_RR|1)
|
||||
#else
|
||||
#define PRIO_PWM 3
|
||||
#define PRIO_BLK 2
|
||||
#endif
|
||||
|
||||
#define STACK_MAIN
|
||||
#define STACK_PROCESS_1
|
||||
#define STACK_PROCESS_2
|
||||
#define STACK_PROCESS_3
|
||||
#include "stack-def.h"
|
||||
|
||||
|
||||
#define STACK_ADDR_PWM ((uint32_t)process1_base)
|
||||
#define STACK_SIZE_PWM (sizeof process1_base)
|
||||
|
||||
#define STACK_ADDR_BLK ((uint32_t)process2_base)
|
||||
#define STACK_SIZE_BLK (sizeof process2_base)
|
||||
|
||||
#define PRIO_USART 4
|
||||
#define STACK_ADDR_USART ((uint32_t)process3_base)
|
||||
#define STACK_SIZE_USART (sizeof process3_base)
|
||||
|
||||
static int
|
||||
ss_notify (uint8_t dev_no, uint16_t state_bits)
|
||||
{
|
||||
(void)dev_no;
|
||||
(void)state_bits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
uint32_t timeout;
|
||||
struct chx_poll_head *ph[1];
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
chopstx_mutex_init (&mtx);
|
||||
chopstx_cond_init (&cnd0);
|
||||
chopstx_cond_init (&cnd1);
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_signal (&cnd0);
|
||||
chopstx_cond_signal (&cnd1);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify);
|
||||
usart_config (2, B115200 | CS8 | STOP1B);
|
||||
|
||||
usart_read_prepare_poll (2, &poll_desc);
|
||||
ph[0] = (struct chx_poll_head *)&poll_desc;
|
||||
|
||||
timeout = 200*1000*6;
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (&timeout, 1, ph);
|
||||
if (timeout == 0)
|
||||
{
|
||||
usart_write (2, "Hello\r\n", 7);
|
||||
u ^= 1;
|
||||
timeout = 200*1000*6;
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[256];
|
||||
int r;
|
||||
r = usart_read (2, buf, 256);
|
||||
if (r)
|
||||
usart_write (2, buf, r);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
126
example-usart/sample.ld
Normal file
126
example-usart/sample.ld
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* ST32F0 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash0 : org = 0x08000000, len = 4k
|
||||
flash : org = 0x08000000+0x1000, len = 60k
|
||||
ram : org = 0x20000000, len = 20k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
.sys : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
_sys = .;
|
||||
KEEP(*(.vectors))
|
||||
. = ALIGN(16);
|
||||
KEEP(*(.sys.version))
|
||||
KEEP(*(.sys.board_id))
|
||||
KEEP(*(.sys.board_name))
|
||||
build/sys-*.o(.text)
|
||||
build/sys-*.o(.text.*)
|
||||
build/sys-*.o(.rodata)
|
||||
build/sys-*.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
/*
|
||||
*(.sys.0)
|
||||
*(.sys.1)
|
||||
*(.sys.2)
|
||||
*/
|
||||
} > flash0 =0xffffffff
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN (16);
|
||||
} > flash =0xffffffff
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
*(.text.startup.*)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
. = ALIGN(8);
|
||||
} > flash
|
||||
|
||||
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
|
||||
|
||||
.ARM.exidx : {
|
||||
PROVIDE(__exidx_start = .);
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
PROVIDE(__exidx_end = .);
|
||||
} > flash
|
||||
|
||||
.eh_frame_hdr : {*(.eh_frame_hdr)} > flash
|
||||
|
||||
.eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
|
||||
|
||||
.textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
|
||||
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.vectors_in_ram :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
__vector_ram_addr__ = .;
|
||||
KEEP(*(.bss.startup.*))
|
||||
} > ram
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data = .);
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} > ram AT > flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_start = .);
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_end = .);
|
||||
} > ram
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
__heap_base__ = _end;
|
||||
__heap_end__ = __ram_end__;
|
||||
116
example-usart/sample.ld.m3
Normal file
116
example-usart/sample.ld.m3
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* ST32F103 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash0 : org = 0x08000000, len = 4k
|
||||
flash : org = 0x08000000+0x1000, len = 60k
|
||||
ram : org = 0x20000000, len = 20k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
.sys : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
_sys = .;
|
||||
KEEP(*(.vectors))
|
||||
. = ALIGN(16);
|
||||
KEEP(*(.sys.version))
|
||||
KEEP(*(.sys.board_id))
|
||||
KEEP(*(.sys.board_name))
|
||||
build/sys-*.o(.text)
|
||||
build/sys-*.o(.text.*)
|
||||
build/sys-*.o(.rodata)
|
||||
build/sys-*.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
*(.sys.0)
|
||||
*(.sys.1)
|
||||
*(.sys.2)
|
||||
} > flash0
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN (16);
|
||||
} > flash =0xffffffff
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
*(.text.startup.*)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
. = ALIGN(8);
|
||||
} > flash
|
||||
|
||||
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
|
||||
|
||||
.ARM.exidx : {
|
||||
PROVIDE(__exidx_start = .);
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
PROVIDE(__exidx_end = .);
|
||||
} > flash
|
||||
|
||||
.eh_frame_hdr : {*(.eh_frame_hdr)} > flash
|
||||
|
||||
.eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
|
||||
|
||||
.textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
|
||||
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data = .);
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} > ram AT > flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_start = .);
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_end = .);
|
||||
} > ram
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
__heap_base__ = _end;
|
||||
__heap_end__ = __ram_end__;
|
||||
107
example-usart/sample.ld.m4
Normal file
107
example-usart/sample.ld.m4
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* ST32L4 memory setup.
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
flash : org = 0x08000000, len = 256k
|
||||
ram : org = 0x20000000, len = 48k
|
||||
}
|
||||
|
||||
__ram_start__ = ORIGIN(ram);
|
||||
__ram_size__ = 20k;
|
||||
__ram_end__ = __ram_start__ + __ram_size__;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
|
||||
_text = .;
|
||||
|
||||
.startup : ALIGN(128) SUBALIGN(128)
|
||||
{
|
||||
KEEP(*(.startup.vectors))
|
||||
. = ALIGN(16);
|
||||
_sys = .;
|
||||
. = ALIGN(16);
|
||||
KEEP(*(.sys.version))
|
||||
KEEP(*(.sys.board_id))
|
||||
KEEP(*(.sys.board_name))
|
||||
build/sys-*.o(.text)
|
||||
build/sys-*.o(.text.*)
|
||||
build/sys-*.o(.rodata)
|
||||
build/sys-*.o(.rodata.*)
|
||||
. = ALIGN(1024);
|
||||
} > flash =0xffffffff
|
||||
|
||||
.text : ALIGN(16) SUBALIGN(16)
|
||||
{
|
||||
*(.text.startup.*)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
*(.gcc*)
|
||||
. = ALIGN(8);
|
||||
} > flash
|
||||
|
||||
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
|
||||
|
||||
.ARM.exidx : {
|
||||
PROVIDE(__exidx_start = .);
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
PROVIDE(__exidx_end = .);
|
||||
} > flash
|
||||
|
||||
.eh_frame_hdr : {*(.eh_frame_hdr)} > flash
|
||||
|
||||
.eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
|
||||
|
||||
.textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
|
||||
|
||||
_etext = .;
|
||||
_textdata = _etext;
|
||||
|
||||
.stacks (NOLOAD) :
|
||||
{
|
||||
*(.main_stack)
|
||||
*(.process_stack.0)
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data = .);
|
||||
*(.data)
|
||||
. = ALIGN(4);
|
||||
*(.data.*)
|
||||
. = ALIGN(4);
|
||||
*(.ramtext)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_edata = .);
|
||||
} > ram AT > flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_start = .);
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
*(.bss.*)
|
||||
. = ALIGN(4);
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_bss_end = .);
|
||||
} > ram
|
||||
|
||||
PROVIDE(end = .);
|
||||
_end = .;
|
||||
}
|
||||
|
||||
__heap_base__ = _end;
|
||||
__heap_end__ = __ram_end__;
|
||||
54
example-usart/stack-def.h
Normal file
54
example-usart/stack-def.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#define MAIN_SIZE 0x0080 /* Idle+Exception handlers */
|
||||
#define SIZE_0 0x0300 /* Main program */
|
||||
#define SIZE_1 0x0100 /* first thread program */
|
||||
#define SIZE_2 0x0100 /* second thread program */
|
||||
#define SIZE_3 0x0200 /* third thread program */
|
||||
|
||||
#if defined(STACK_MAIN)
|
||||
/*
|
||||
* The terminology of "main" is confusing in ARM architecture.
|
||||
* Here, "main_base" is for exception handlers.
|
||||
*/
|
||||
/* Idle+Exception handlers */
|
||||
char __main_stack_end__[0] __attribute__ ((section(".main_stack")));
|
||||
char main_base[MAIN_SIZE] __attribute__ ((section(".main_stack")));
|
||||
|
||||
/* Main program */
|
||||
char __process0_stack_end__[0] __attribute__ ((section(".process_stack.0")));
|
||||
char process0_base[SIZE_0] __attribute__ ((section(".process_stack.0")));
|
||||
#endif
|
||||
|
||||
/* First thread program */
|
||||
#if defined(STACK_PROCESS_1)
|
||||
char process1_base[SIZE_1] __attribute__ ((section(".process_stack.1")));
|
||||
#endif
|
||||
|
||||
/* Second thread program */
|
||||
#if defined(STACK_PROCESS_2)
|
||||
char process2_base[SIZE_2] __attribute__ ((section(".process_stack.2")));
|
||||
#endif
|
||||
|
||||
/* Third thread program */
|
||||
#if defined(STACK_PROCESS_3)
|
||||
char process3_base[SIZE_3] __attribute__ ((section(".process_stack.3")));
|
||||
#endif
|
||||
|
||||
/* Fourth thread program */
|
||||
#if defined(STACK_PROCESS_4)
|
||||
char process4_base[SIZE_4] __attribute__ ((section(".process_stack.4")));
|
||||
#endif
|
||||
|
||||
/* Fifth thread program */
|
||||
#if defined(STACK_PROCESS_5)
|
||||
char process5_base[SIZE_5] __attribute__ ((section(".process_stack.5")));
|
||||
#endif
|
||||
|
||||
/* Sixth thread program */
|
||||
#if defined(STACK_PROCESS_6)
|
||||
char process6_base[SIZE_6] __attribute__ ((section(".process_stack.6")));
|
||||
#endif
|
||||
|
||||
/* Seventh thread program */
|
||||
#if defined(STACK_PROCESS_7)
|
||||
char process7_base[SIZE_7] __attribute__ ((section(".process_stack.7")));
|
||||
#endif
|
||||
@@ -725,24 +725,17 @@ cdc_main (void *arg)
|
||||
#if defined(OLDER_SYS_H)
|
||||
/*
|
||||
* Historically (before sys < 3.0), NVIC priority setting for USB
|
||||
* interrupt was done in usb_lld_sys_init. Thus this code.
|
||||
*
|
||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||
* invocation of usb_lld_event_handler won't occur.
|
||||
*
|
||||
* Calling usb_lld_event_handler is no harm even if there were no
|
||||
* interrupts, thus, we call it unconditionally here, just in case
|
||||
* if there is a request.
|
||||
* interrupt was done in usb_lld_sys_init for free standing
|
||||
* application. Thus this compatibility code.
|
||||
*
|
||||
* We can't call usb_lld_init after chopstx_claim_irq, as
|
||||
* usb_lld_init does its own setting for NVIC. Calling
|
||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||
* usb_lld_init does its own setting for NVIC, which is incompatible
|
||||
* to Chopstx's interrupt handling. Calling chopstx_claim_irq after
|
||||
* usb_lld_init overrides that for Chopstx.
|
||||
*
|
||||
*/
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
goto event_handle;
|
||||
#else
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Consideration about SYS and the first pages of flash ROM
|
||||
========================================================
|
||||
|
||||
Now, I'm developing something like SYS for Kinetis L MCU, so, I write
|
||||
this document.
|
||||
This document was written when I was porting Chopstx to Kinetis L.
|
||||
|
||||
* Compatibility
|
||||
|
||||
@@ -10,7 +9,8 @@ this document.
|
||||
SYS 2.0: Added clock_init, gpio_init
|
||||
SYS 2.1: Added sys_board_id, sys_board_name
|
||||
SYS 3.0: Don't setup NVIC priority by usb_lld_sys_init
|
||||
|
||||
SYS 4.0: For USB, only do usb_cable_config. Enabling/disabling the
|
||||
USB module is the role of USB driver.
|
||||
|
||||
* Macro definition by DEFS in Makefile
|
||||
|
||||
@@ -131,23 +131,24 @@ and here is the list of all.
|
||||
|
||||
nvic_system_reset
|
||||
|
||||
The routines of clock_init and gpio_init are here because of some
|
||||
historical reasons. (We could design a system with no such exported
|
||||
routines: by defining: those things done internally after reset and
|
||||
before calling the application.)
|
||||
The routines of clock_init and gpio_init exist in SYS, because of some
|
||||
historical reasons; Without such exported routines, we could design a
|
||||
system having an assumption: important clock and gpio initialization
|
||||
is done internally after reset, so that an application can just work.
|
||||
|
||||
Those are exported as entries of SYS, and it is the responsibility of
|
||||
the application which do initialize clock and GPIO, calling those
|
||||
routines.
|
||||
|
||||
USB routines are needed because of hardware practice of STM32F103.
|
||||
With STM32F103, each board has different way for handling the pull up
|
||||
of USB D+ and how the device asks re-enumeration to host PC. In my
|
||||
opinion, if it's defined as full speed device and it's OK for us not
|
||||
to use high impedance (but asserting to LOW, instead) of D+ to ask
|
||||
re-enumeration, we can just pull up D+ always. And we wouldn't need
|
||||
such routines in SYS.
|
||||
USB routines are needed because of hardware practice of STM32F103. (It
|
||||
can support low speed device. It can support self powered USB
|
||||
system.) With STM32F103 (for allowing low speed device and self
|
||||
powered system), each board has different way for handling the pull up
|
||||
of USB D+ and how the device asks re-enumeration to host PC.
|
||||
|
||||
For bus-powered system and full speed device, we can just pull up D+
|
||||
always. Still, support of high impedance state of D+ line would be
|
||||
ideal when asking re-enumeration, asserting to LOW works.
|
||||
|
||||
|
||||
About SYS on Kinetis L
|
||||
|
||||
32
mcu/ABOUT-USB
Normal file
32
mcu/ABOUT-USB
Normal file
@@ -0,0 +1,32 @@
|
||||
USB driver in Chopstx
|
||||
|
||||
Full speed device is assumed. Bus powered system is assumed.
|
||||
API-wise, self powered system is not supported (yet) by this USB driver.
|
||||
|
||||
The driver can be used without Chopstx. An example can be find in
|
||||
Gnuk (gnuk/regnual).
|
||||
|
||||
The USB driver was originally written for STM32F103, which USB
|
||||
hardware design is considered not mature. Modern USB hardware design
|
||||
allows crystal-less design, and/or comes with internal 5V->3V3
|
||||
regulator, D+-line pull-up support, and VBUS detection. STM32F103 has
|
||||
nothing.
|
||||
|
||||
To support self powered system, we need to define a hardware interface
|
||||
for a board detecting VBUS voltage. Only after detecting VBUS power,
|
||||
we can enable USB driver (D+/D- lines). For self powered system,
|
||||
driving D+/D- lines by fixed pull-up resistor violates the USB
|
||||
specification.
|
||||
|
||||
With STM32F103, there is a common hardware practice having a
|
||||
gate/transistor for pull-up D+ line. If it also supports detecting
|
||||
VBUS, self powerd system can be supported with the gate/transistor.
|
||||
|
||||
Such a gate/transistor can be also used for the board to ask
|
||||
re-enumeration of USB device. Asking re-enumeration, it is enough to
|
||||
have SE0 (Single-Ended Zero) state.
|
||||
|
||||
The USB driver doesn't touch such a gate/transistor. By gpio_init,
|
||||
the D+-line should be asserted, USB D+ and D- lines should be drived
|
||||
to 0 (SE0). When the USB module is enabled, it goes into J and K
|
||||
state (from SE0 state).
|
||||
29
mcu/chx-stm32l4.c
Normal file
29
mcu/chx-stm32l4.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdint.h>
|
||||
#include <mcu/cortex-m.h>
|
||||
#include <mcu/stm32l.h>
|
||||
|
||||
extern int chx_allow_sleep;
|
||||
|
||||
void
|
||||
chx_sleep_mode (int how)
|
||||
{
|
||||
/*TBD*/
|
||||
(void)how;
|
||||
}
|
||||
|
||||
void __attribute__((naked))
|
||||
chx_idle (void)
|
||||
{
|
||||
/*TBD*/
|
||||
int sleep_enabled;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep));
|
||||
if (sleep_enabled)
|
||||
{
|
||||
asm volatile ("wfi" : : : "memory");
|
||||
/* NOTE: it never comes here. Don't add lines after this. */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
115
mcu/clk_gpio_init-stm32l.c
Normal file
115
mcu/clk_gpio_init-stm32l.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* clk_gpio_init-stm32l.c - Clock and GPIO initialization for STM32L.
|
||||
*
|
||||
* Copyright (C) 2019 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
*
|
||||
* Chopstx is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Chopstx is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <mcu/stm32l.h>
|
||||
|
||||
#define STM32_FLASHBITS 0x00000704
|
||||
|
||||
void
|
||||
clock_init (void)
|
||||
{
|
||||
/* MSI: 4MHz (keep the default value) */
|
||||
|
||||
/* PLL input: MSI at 4MHz, VCO: 160 MHz, output 80MHz */
|
||||
RCC->PLLCFGR = ((1 << 24) | (40 << 8)) | 0x01;
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CR |= (1 << 24);
|
||||
while (!(RCC->CR & (1 << 25)))
|
||||
;
|
||||
|
||||
/* Flash setup: four wait states at 80MHz */
|
||||
FLASH->ACR = STM32_FLASHBITS;
|
||||
while ((FLASH->ACR & 0x07) != (STM32_FLASHBITS & 0x07))
|
||||
;
|
||||
|
||||
/* Configure bus clocks: AHB: 80MHz, APB1: 40MHz, APB2: 40MHz */
|
||||
RCC->CFGR = ((0x04 << 11) | (0x04 << 8));
|
||||
|
||||
/* Switch SYSCLOCK using PLL */
|
||||
RCC->CFGR |= 0x03;
|
||||
while ((RCC->CFGR & 0x0C) != 0x0C)
|
||||
;
|
||||
|
||||
/* Peripheral clock selection */
|
||||
RCC->CCIPR = ( (0x00 << 26) | /* HSI48 for USB */
|
||||
(0x00 << 2) | /* PCLK for USART2 */
|
||||
(0x00 << 0) ); /* PCLK for USART1 */
|
||||
|
||||
/* Enable PWR clock */
|
||||
RCC->APB1ENR1 |= (1 << 28);
|
||||
RCC->APB1RSTR1 = (1 << 28);
|
||||
RCC->APB1RSTR1 = 0;
|
||||
|
||||
/* Enable HSI48 clock */
|
||||
RCC->CRRCR |= 1;
|
||||
while ((RCC->CRRCR & 0x02) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
static struct GPIO *const GPIO_LED = (struct GPIO *)GPIO_LED_BASE;
|
||||
#ifdef GPIO_USB_BASE
|
||||
static struct GPIO *const GPIO_USB = (struct GPIO *)GPIO_USB_BASE;
|
||||
#endif
|
||||
#ifdef GPIO_OTHER_BASE
|
||||
static struct GPIO *const GPIO_OTHER = (struct GPIO *)GPIO_OTHER_BASE;
|
||||
#endif
|
||||
|
||||
void
|
||||
gpio_init (void)
|
||||
{
|
||||
/* Enable GPIO clock. */
|
||||
RCC->AHB2ENR |= RCC_AHB2_GPIO;
|
||||
/* Delay (more than two clocks) is needed. */
|
||||
while ((RCC->AHB2ENR & RCC_AHB2_GPIO) == 0)
|
||||
;
|
||||
|
||||
RCC->AHB2RSTR = RCC_AHB2_GPIO;
|
||||
RCC->AHB2RSTR = 0;
|
||||
|
||||
/* Delay (more than two clocks) is needed. */
|
||||
while (RCC->AHB2RSTR != 0)
|
||||
;
|
||||
|
||||
/* LED is mandatory. We configure it always. */
|
||||
GPIO_LED->OSPEEDR = VAL_GPIO_LED_OSPEEDR;
|
||||
GPIO_LED->OTYPER = VAL_GPIO_LED_OTYPER;
|
||||
GPIO_LED->MODER = VAL_GPIO_LED_MODER;
|
||||
GPIO_LED->PUPDR = VAL_GPIO_LED_PUPDR;
|
||||
GPIO_LED->AFRL = VAL_GPIO_LED_AFRL;
|
||||
GPIO_LED->AFRH = VAL_GPIO_LED_AFRH;
|
||||
|
||||
#ifdef GPIO_OTHER_BASE
|
||||
GPIO_OTHER->OSPEEDR = VAL_GPIO_OTHER_OSPEEDR;
|
||||
GPIO_OTHER->OTYPER = VAL_GPIO_OTHER_OTYPER;
|
||||
GPIO_OTHER->MODER = VAL_GPIO_OTHER_MODER;
|
||||
GPIO_OTHER->PUPDR = VAL_GPIO_OTHER_PUPDR;
|
||||
GPIO_OTHER->AFRL = VAL_GPIO_OTHER_AFRL;
|
||||
GPIO_OTHER->AFRH = VAL_GPIO_OTHER_AFRH;
|
||||
#endif
|
||||
}
|
||||
197
mcu/stm32l.h
Normal file
197
mcu/stm32l.h
Normal file
@@ -0,0 +1,197 @@
|
||||
#define PERIPH_BASE 0x40000000
|
||||
#define APB1PERIPH_BASE PERIPH_BASE
|
||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x20000)
|
||||
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000)
|
||||
|
||||
struct RCC {
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t ICSCR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t PLLCFGR;
|
||||
|
||||
volatile uint32_t PLLSAI1CFGR;
|
||||
volatile uint32_t RESERVED0;
|
||||
volatile uint32_t CIER;
|
||||
volatile uint32_t CIFR;
|
||||
|
||||
volatile uint32_t CICR;
|
||||
volatile uint32_t RESERVED1;
|
||||
volatile uint32_t AHB1RSTR;
|
||||
volatile uint32_t AHB2RSTR;
|
||||
|
||||
volatile uint32_t AHB3RSTR;
|
||||
volatile uint32_t RESERVED2;
|
||||
volatile uint32_t APB1RSTR1;
|
||||
volatile uint32_t APB1RSTR2;
|
||||
|
||||
volatile uint32_t APB2RSTR;
|
||||
volatile uint32_t RESERVED3;
|
||||
volatile uint32_t AHB1ENR;
|
||||
volatile uint32_t AHB2ENR;
|
||||
|
||||
volatile uint32_t AHB3ENR;
|
||||
volatile uint32_t RESERVED4;
|
||||
volatile uint32_t APB1ENR1;
|
||||
volatile uint32_t APB1ENR2;
|
||||
|
||||
volatile uint32_t APB2ENR;
|
||||
volatile uint32_t RESERVED5;
|
||||
volatile uint32_t AHB1SMENR;
|
||||
volatile uint32_t AHB2SMENR;
|
||||
|
||||
volatile uint32_t AHB3SMENR;
|
||||
volatile uint32_t RESERVED6;
|
||||
volatile uint32_t APB1SMENR1;
|
||||
volatile uint32_t APB1SMENR2;
|
||||
|
||||
volatile uint32_t APB2SMENR;
|
||||
volatile uint32_t RESERVED7;
|
||||
volatile uint32_t CCIPR;
|
||||
volatile uint32_t RESERVED8;
|
||||
|
||||
volatile uint32_t BDCR;
|
||||
volatile uint32_t CSR;
|
||||
volatile uint32_t CRRCR;
|
||||
volatile uint32_t CCIPR2;
|
||||
};
|
||||
|
||||
#define RCC_BASE (AHB1PERIPH_BASE + 0x1000)
|
||||
static struct RCC *const RCC = (struct RCC *)RCC_BASE;
|
||||
|
||||
#define RCC_AHB2_GPIOA 0x00000001
|
||||
#define RCC_AHB2_GPIOB 0x00000002
|
||||
#define RCC_AHB2_GPIOC 0x00000004
|
||||
#define RCC_AHB2_GPIOD 0x00000008
|
||||
#define RCC_AHB2_GPIOE 0x00000010
|
||||
#define RCC_AHB2_GPIOH 0x00000080
|
||||
|
||||
#define RCC_APB1_1_USB (1 << 26)
|
||||
#define RCC_APB1_1_CRS (1 << 24)
|
||||
|
||||
|
||||
struct PWR
|
||||
{
|
||||
volatile uint32_t CR1;
|
||||
volatile uint32_t CR2;
|
||||
volatile uint32_t CR3;
|
||||
volatile uint32_t CR4;
|
||||
volatile uint32_t SR1;
|
||||
volatile uint32_t SR2;
|
||||
volatile uint32_t SCR;
|
||||
volatile uint32_t PUCRA;
|
||||
volatile uint32_t PDCRA;
|
||||
volatile uint32_t PUCRB;
|
||||
volatile uint32_t PDCRB;
|
||||
volatile uint32_t PUCRC;
|
||||
volatile uint32_t PDCRC;
|
||||
volatile uint32_t PUCRD;
|
||||
volatile uint32_t PDCRD;
|
||||
volatile uint32_t PUCRE;
|
||||
volatile uint32_t PDCRE;
|
||||
volatile uint32_t PUCRH;
|
||||
volatile uint32_t PDCRH;
|
||||
};
|
||||
static struct PWR *const PWR = ((struct PWR *)0x40007000);
|
||||
|
||||
struct GPIO {
|
||||
volatile uint32_t MODER;
|
||||
volatile uint32_t OTYPER;
|
||||
volatile uint32_t OSPEEDR;
|
||||
volatile uint32_t PUPDR;
|
||||
volatile uint32_t IDR;
|
||||
volatile uint32_t ODR;
|
||||
volatile uint32_t BSRR;
|
||||
volatile uint32_t LCKR;
|
||||
volatile uint32_t AFRL;
|
||||
volatile uint32_t AFRH;
|
||||
volatile uint32_t BRR;
|
||||
};
|
||||
|
||||
#define GPIOA_BASE (AHB2PERIPH_BASE)
|
||||
static struct GPIO *const GPIOA = (struct GPIO *)GPIOA_BASE;
|
||||
#define GPIOB_BASE (AHB2PERIPH_BASE + 0x0400)
|
||||
static struct GPIO *const GPIOB = (struct GPIO *)GPIOB_BASE;
|
||||
|
||||
|
||||
struct FLASH {
|
||||
volatile uint32_t ACR;
|
||||
volatile uint32_t PDKEYR;
|
||||
volatile uint32_t KEYR;
|
||||
volatile uint32_t OPTKEYR;
|
||||
volatile uint32_t SR;
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t ECCR;
|
||||
volatile uint32_t RESERVED;
|
||||
volatile uint32_t OPTR;
|
||||
volatile uint32_t PCROP1SR;
|
||||
volatile uint32_t PCROP1ER;
|
||||
volatile uint32_t WRP1AR;
|
||||
volatile uint32_t WRP1BR;
|
||||
};
|
||||
|
||||
#define FLASH_R_BASE (AHB1PERIPH_BASE + 0x2000)
|
||||
static struct FLASH *const FLASH = (struct FLASH *)FLASH_R_BASE;
|
||||
|
||||
struct USB_STM32L4 {
|
||||
volatile uint16_t LPMCSR;
|
||||
volatile uint16_t reserved0;
|
||||
volatile uint16_t BCDR;
|
||||
volatile uint16_t reserved1;
|
||||
};
|
||||
|
||||
#define USB_STM32L4_BASE (0x40006854UL)
|
||||
static struct USB_STM32L4 *const USB_STM32L4 = (struct USB_STM32L4 *)USB_STM32L4_BASE;
|
||||
|
||||
struct SYSCFG {
|
||||
volatile uint32_t MEMRMP;
|
||||
volatile uint32_t CFGR1;
|
||||
volatile uint32_t EXTICR[4];
|
||||
volatile uint32_t SCSR;
|
||||
volatile uint32_t CFGR2;
|
||||
volatile uint32_t SWPR;
|
||||
volatile uint32_t SKR;
|
||||
};
|
||||
|
||||
#define SYSCFG_BASE (APB2PERIPH_BASE+0UL)
|
||||
static struct SYSCFG *const SYSCFG = (struct SYSCFG *)SYSCFG_BASE;
|
||||
|
||||
#define EXTI0_IRQ 6
|
||||
#define SYSCFG_EXTICR1_EXTI0_PA 0
|
||||
|
||||
struct EXTI {
|
||||
union {
|
||||
volatile uint32_t IMR1;
|
||||
volatile uint32_t IMR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t EMR1;
|
||||
volatile uint32_t EMR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t RTSR1;
|
||||
volatile uint32_t RTSR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t FTSR1;
|
||||
volatile uint32_t FTSR;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t SWIER1;
|
||||
volatile uint32_t SWIER;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t PR1;
|
||||
volatile uint32_t PR;
|
||||
};
|
||||
volatile uint32_t reserved;
|
||||
volatile uint32_t IMR2;
|
||||
volatile uint32_t EMR2;
|
||||
volatile uint32_t RTSR2;
|
||||
volatile uint32_t FTSR2;
|
||||
volatile uint32_t SWIER2;
|
||||
volatile uint32_t PR2;
|
||||
};
|
||||
|
||||
#define EXTI_BASE (APB2PERIPH_BASE+0x0400)
|
||||
static struct EXTI *const EXTI = (struct EXTI *)EXTI_BASE;
|
||||
@@ -16,8 +16,8 @@
|
||||
const uint8_t sys_version[8] = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
|
||||
@@ -69,8 +69,8 @@ set_led (int on)
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = STRING_DESCRIPTOR */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
static const uint8_t board_name_string[] = BOARD_NAME;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#define STM32F0_USE_VECTOR_ON_RAM
|
||||
#include "mcu/cortex-m.h"
|
||||
#include "mcu/clk_gpio_init-stm32.c"
|
||||
#include "mcu/clk_gpio_init-stm32f.c"
|
||||
|
||||
|
||||
static void
|
||||
@@ -69,27 +69,13 @@ static void wait (int count)
|
||||
static void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
usb_cable_config (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
if ((RCC->APB1ENR & RCC_APB1ENR_USBEN)
|
||||
&& (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0)
|
||||
/* Make sure the device is disconnected, even after core reset. */
|
||||
{
|
||||
usb_lld_sys_shutdown ();
|
||||
/* Disconnect requires SE0 (>= 2.5uS). */
|
||||
wait (300);
|
||||
}
|
||||
|
||||
usb_cable_config (1);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
}
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
@@ -386,8 +372,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
const uint32_t __attribute__((section(".sys.board_id")))
|
||||
|
||||
@@ -18,9 +18,18 @@
|
||||
#include <stdlib.h>
|
||||
#include "board.h"
|
||||
|
||||
#include "mcu/clk_gpio_init-stm32.c"
|
||||
#include "mcu/clk_gpio_init-stm32f.c"
|
||||
|
||||
|
||||
/*
|
||||
* When a board supports USB self-powered configuration, there is a
|
||||
* control to enable external pull-up 1K5 resistor. The voltage
|
||||
* source on the pull-up resistor should be only supplied when VBUS
|
||||
* from the cable is available. This routine is for such a board.
|
||||
*
|
||||
* For a board for USB bus-powered configuration, it is common that
|
||||
* there is no such control, but 1K5 resistor is fixed to +3V3.
|
||||
*/
|
||||
static void
|
||||
usb_cable_config (int enable)
|
||||
{
|
||||
@@ -55,39 +64,16 @@ set_led (int on)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wait (int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
usb_cable_config (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
if ((RCC->APB1ENR & RCC_APB1ENR_USBEN)
|
||||
&& (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0)
|
||||
/* Make sure the device is disconnected, even after core reset. */
|
||||
{
|
||||
usb_lld_sys_shutdown ();
|
||||
/* Disconnect requires SE0 (>= 2.5uS). */
|
||||
wait (5*MHZ);
|
||||
}
|
||||
|
||||
usb_cable_config (1);
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB1RSTR = 0;
|
||||
}
|
||||
|
||||
#define FLASH_KEY1 0x45670123UL
|
||||
@@ -367,8 +353,8 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "3.0" */
|
||||
'3', 0, '.', 0, '0', 0,
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
const uint32_t __attribute__((section(".sys.board_id")))
|
||||
|
||||
134
mcu/sys-stm32l4.c
Normal file
134
mcu/sys-stm32l4.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* sys-stm32l432.c - system routines for STM32L432.
|
||||
*
|
||||
* Copyright (C) 2019 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*
|
||||
* We put some system routines (which is useful for any program) here.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <mcu/cortex-m.h>
|
||||
#include "board.h"
|
||||
|
||||
#include "mcu/clk_gpio_init-stm32l.c"
|
||||
|
||||
void
|
||||
set_led (int on)
|
||||
{
|
||||
#if defined(GPIO_LED_CLEAR_TO_EMIT)
|
||||
if (on)
|
||||
GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
|
||||
else
|
||||
GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT);
|
||||
#else
|
||||
if (on)
|
||||
GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT);
|
||||
else
|
||||
GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usb_lld_sys_shutdown (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_sys_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nvic_system_reset (void)
|
||||
{
|
||||
SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SCB_AIRCR_SYSRESETREQ);
|
||||
asm volatile ("dsb");
|
||||
for (;;);
|
||||
}
|
||||
|
||||
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
|
||||
3*2+2, /* bLength */
|
||||
0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */
|
||||
/* sys version: "4.0" */
|
||||
'4', 0, '.', 0, '0', 0,
|
||||
};
|
||||
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
const uint32_t __attribute__((section(".sys.board_id")))
|
||||
sys_board_id = BOARD_ID;
|
||||
|
||||
const uint8_t __attribute__((section(".sys.board_name")))
|
||||
sys_board_name[] = BOARD_NAME;
|
||||
#endif
|
||||
|
||||
/* Not yet implemented, API should be reconsidered */
|
||||
|
||||
void
|
||||
flash_unlock (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#define intr_disable() asm volatile ("cpsid i" : : : "memory")
|
||||
#define intr_enable() asm volatile ("cpsie i" : : : "memory")
|
||||
|
||||
|
||||
int
|
||||
flash_wait_for_last_operation (uint32_t timeout)
|
||||
{
|
||||
(void)timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_program_halfword (uintptr_t addr, uint16_t data)
|
||||
{
|
||||
(void)addr;
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_erase_page (uintptr_t addr)
|
||||
{
|
||||
(void)addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_check_blank (const uint8_t *p_start, size_t size)
|
||||
{
|
||||
(void)p_start;
|
||||
(void)size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
(void)dst_addr;
|
||||
(void)src;
|
||||
(void)len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
flash_protect (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __attribute__((naked))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
(void)entry;
|
||||
}
|
||||
33
mcu/sys-stm32l4.h
Normal file
33
mcu/sys-stm32l4.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#define BOARD_ID_ST_NUCLEO_L432 0x3a8d5116
|
||||
|
||||
extern const uint8_t sys_version[8];
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID)
|
||||
extern const uint32_t sys_board_id;
|
||||
extern const uint8_t sys_board_name[];
|
||||
# define SYS_BOARD_ID sys_board_id
|
||||
#else
|
||||
# define SYS_BOARD_ID BOARD_ID
|
||||
#endif
|
||||
|
||||
/* XXX: unique_device_id */
|
||||
|
||||
void set_led (int on);
|
||||
|
||||
uintptr_t flash_init (const char *f_name);
|
||||
void flash_unlock (void);
|
||||
int flash_program_halfword (uintptr_t addr, uint16_t data);
|
||||
int flash_erase_page (uintptr_t addr);
|
||||
int flash_check_blank (const uint8_t *p_start, size_t size);
|
||||
int flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len);
|
||||
int flash_protect (void);
|
||||
void __attribute__((noreturn))
|
||||
flash_erase_all_and_exec (void (*entry)(void));
|
||||
|
||||
void usb_lld_sys_init (void);
|
||||
void usb_lld_sys_shutdown (void);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
nvic_system_reset (void);
|
||||
|
||||
void clock_init (void);
|
||||
void gpio_init (void);
|
||||
@@ -22,7 +22,7 @@
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* receipents of GNU GPL by a written offer.
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
918
mcu/usb-st-common.c
Normal file
918
mcu/usb-st-common.c
Normal file
@@ -0,0 +1,918 @@
|
||||
/*
|
||||
* usb-st-common.c - USB driver common part for STM chips.
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
*
|
||||
* Chopstx is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Chopstx is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
struct USB {
|
||||
volatile uint32_t EPR[8];
|
||||
volatile uint32_t reserved[8];
|
||||
volatile uint16_t CNTR; /* Control register */
|
||||
volatile uint16_t reserved0;
|
||||
volatile uint16_t ISTR; /* Interrupt status register */
|
||||
volatile uint16_t reserved1;
|
||||
volatile uint16_t FNR; /* Frame number register */
|
||||
volatile uint16_t reserved2;
|
||||
volatile uint16_t DADDR; /* Device address register */
|
||||
volatile uint16_t reserved3;
|
||||
volatile uint16_t BTABLE; /* Buffer Table address register */
|
||||
volatile uint16_t reserved4;
|
||||
};
|
||||
|
||||
static struct USB *const USB = (struct USB *)REG_BASE;
|
||||
|
||||
#define ISTR_CTR (0x8000) /* Correct TRansfer (read-only bit) */
|
||||
#define ISTR_OVR (0x4000) /* OVeR/underrun (clear-only bit) */
|
||||
#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */
|
||||
#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */
|
||||
#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */
|
||||
#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */
|
||||
#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */
|
||||
#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */
|
||||
|
||||
#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */
|
||||
#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */
|
||||
|
||||
#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */
|
||||
#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */
|
||||
|
||||
#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */
|
||||
#define CNTR_OVRM (0x4000) /* OVeR/underrun Mask */
|
||||
#define CNTR_ERRM (0x2000) /* ERRor Mask */
|
||||
#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */
|
||||
#define CNTR_SUSPM (0x0800) /* SUSPend Mask */
|
||||
#define CNTR_RESETM (0x0400) /* RESET Mask */
|
||||
#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */
|
||||
#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */
|
||||
|
||||
#define CNTR_RESUME (0x0010) /* RESUME request */
|
||||
#define CNTR_FSUSP (0x0008) /* Force SUSPend */
|
||||
#define CNTR_LPMODE (0x0004) /* Low-power MODE */
|
||||
#define CNTR_PDWN (0x0002) /* Power DoWN */
|
||||
#define CNTR_FRES (0x0001) /* Force USB RESet */
|
||||
|
||||
#define DADDR_EF (0x80)
|
||||
#define DADDR_ADD (0x7F)
|
||||
|
||||
#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX (clear-only) */
|
||||
#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX (toggle) */
|
||||
#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field (toggle) */
|
||||
#define EP_SETUP (0x0800) /* EndPoint SETUP (read-only) */
|
||||
#define EP_T_FIELD (0x0600) /* EndPoint TYPE */
|
||||
#define EP_KIND (0x0100) /* EndPoint KIND */
|
||||
#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX (clear-only) */
|
||||
#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX (toggle) */
|
||||
#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field (toggle) */
|
||||
#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */
|
||||
|
||||
#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
|
||||
|
||||
/* STAT_TX[1:0] STATus for TX transfer */
|
||||
#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */
|
||||
#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */
|
||||
#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */
|
||||
#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */
|
||||
#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */
|
||||
#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */
|
||||
|
||||
/* STAT_RX[1:0] STATus for RX transfer */
|
||||
#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */
|
||||
#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */
|
||||
#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */
|
||||
#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */
|
||||
#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */
|
||||
#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */
|
||||
|
||||
static int handle_setup0 (struct usb_dev *dev);
|
||||
static int usb_handle_transfer (struct usb_dev *dev, uint16_t istr_value);
|
||||
|
||||
/* Clear CTR_RX bit by writing the 0-bit, keeping rw bits and toggle bits. */
|
||||
static void
|
||||
ep_clear_ctr_rx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num] & ~EP_CTR_RX & EPREG_MASK;
|
||||
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
/* Clear CTR_TX bit by writing the 0-bit, keeping rw bits and toggle bits. */
|
||||
static void
|
||||
ep_clear_ctr_tx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num] & ~EP_CTR_TX & EPREG_MASK;
|
||||
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_set_rxtx_status (uint8_t ep_num, uint16_t st_rx, uint16_t st_tx)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
value &= (EPREG_MASK|EPRX_STAT|EPTX_STAT);
|
||||
value ^= (EPRX_DTOG1 & st_rx);
|
||||
value ^= (EPRX_DTOG2 & st_rx);
|
||||
value ^= (EPTX_DTOG1 & st_tx);
|
||||
value ^= (EPTX_DTOG2 & st_tx);
|
||||
value |= EP_CTR_RX | EP_CTR_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_set_rx_status (uint8_t ep_num, uint16_t st_rx)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
value &= (EPREG_MASK|EPRX_STAT);
|
||||
value ^= (EPRX_DTOG1 & st_rx);
|
||||
value ^= (EPRX_DTOG2 & st_rx);
|
||||
value |= EP_CTR_RX | EP_CTR_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ep_get_rx_status (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
return value & EPRX_STAT;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_set_tx_status (uint8_t ep_num, uint16_t st_tx)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
value &= (EPREG_MASK|EPTX_STAT);
|
||||
value ^= (EPTX_DTOG1 & st_tx);
|
||||
value ^= (EPTX_DTOG2 & st_tx);
|
||||
value |= EP_CTR_RX | EP_CTR_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ep_get_tx_status (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
return value & EPTX_STAT;
|
||||
}
|
||||
|
||||
static void
|
||||
ep_clear_dtog_rx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
if ((value & EP_DTOG_RX))
|
||||
{
|
||||
value &= EPREG_MASK;
|
||||
value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_RX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ep_clear_dtog_tx (uint8_t ep_num)
|
||||
{
|
||||
uint16_t value = USB->EPR[ep_num];
|
||||
|
||||
if ((value & EP_DTOG_TX))
|
||||
{
|
||||
value &= EPREG_MASK;
|
||||
value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX;
|
||||
USB->EPR[ep_num] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_ctrl_error (struct usb_dev *dev)
|
||||
{
|
||||
dev->state = STALLED;
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
|
||||
}
|
||||
|
||||
int
|
||||
usb_lld_ctrl_ack (struct usb_dev *dev)
|
||||
{
|
||||
dev->state = WAIT_STATUS_IN;
|
||||
epbuf_set_tx_count (ENDP0, 0);
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_NAK, EP_TX_VALID);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_init (struct usb_dev *dev, uint8_t feature)
|
||||
{
|
||||
usb_lld_init_chip_specific ();
|
||||
|
||||
dev->configuration = 0;
|
||||
dev->feature = feature;
|
||||
dev->state = WAIT_SETUP;
|
||||
|
||||
/* Reset USB */
|
||||
USB->CNTR = CNTR_FRES;
|
||||
USB->CNTR = 0;
|
||||
|
||||
USB->BTABLE = 0;
|
||||
|
||||
/* Clear Interrupt Status Register, and enable interrupt for USB */
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = (CNTR_CTRM | CNTR_OVRM | CNTR_ERRM
|
||||
| CNTR_WKUPM | CNTR_SUSPM | CNTR_RESETM);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_prepare_shutdown (void)
|
||||
{
|
||||
USB->ISTR = 0;
|
||||
USB->CNTR = 0;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_shutdown (void)
|
||||
{
|
||||
USB->CNTR = CNTR_PDWN;
|
||||
usb_lld_shutdown_chip_specific ();
|
||||
}
|
||||
|
||||
#define USB_MAKE_EV(event) (event<<24)
|
||||
#define USB_MAKE_TXRX(ep_num,txrx,len) ((txrx? (1<<23):0)|(ep_num<<16)|len)
|
||||
|
||||
int
|
||||
usb_lld_event_handler (struct usb_dev *dev)
|
||||
{
|
||||
uint16_t istr_value = USB->ISTR;
|
||||
|
||||
if ((istr_value & ISTR_RESET))
|
||||
{
|
||||
USB->ISTR = ~ISTR_RESET; /* clear RESET bit */
|
||||
return USB_MAKE_EV (USB_EVENT_DEVICE_RESET);
|
||||
}
|
||||
else if ((istr_value & ISTR_WKUP))
|
||||
{
|
||||
USB->CNTR &= ~CNTR_FSUSP;
|
||||
USB->ISTR = ~ISTR_WKUP; /* clear WaKe UP bit */
|
||||
return USB_MAKE_EV (USB_EVENT_DEVICE_WAKEUP);
|
||||
}
|
||||
else if ((istr_value & ISTR_SUSP))
|
||||
{
|
||||
USB->CNTR |= CNTR_FSUSP;
|
||||
USB->ISTR = ~ISTR_SUSP; /* clear SUSPend bit */
|
||||
USB->CNTR |= CNTR_LPMODE;
|
||||
return USB_MAKE_EV (USB_EVENT_DEVICE_SUSPEND);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((istr_value & ISTR_OVR))
|
||||
USB->ISTR = ~ISTR_OVR; /* clear OVeR/underrun bit */
|
||||
|
||||
if ((istr_value & ISTR_ERR))
|
||||
USB->ISTR = ~ISTR_ERR; /* clear ERRor bit */
|
||||
|
||||
if ((istr_value & ISTR_CTR))
|
||||
return usb_handle_transfer (dev, istr_value);
|
||||
}
|
||||
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_datastage_out (struct usb_dev *dev)
|
||||
{
|
||||
if (dev->ctrl_data.addr && dev->ctrl_data.len)
|
||||
{
|
||||
uint16_t len = epbuf_get_rx_count (ENDP0);
|
||||
|
||||
if (len > dev->ctrl_data.len)
|
||||
len = dev->ctrl_data.len;
|
||||
|
||||
usb_lld_from_pmabuf (dev->ctrl_data.addr, epbuf_get_rx_addr (ENDP0), len);
|
||||
dev->ctrl_data.len -= len;
|
||||
dev->ctrl_data.addr += len;
|
||||
}
|
||||
|
||||
if (dev->ctrl_data.len == 0)
|
||||
{
|
||||
dev->state = WAIT_STATUS_IN;
|
||||
epbuf_set_tx_count (ENDP0, 0);
|
||||
ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->state = OUT_DATA;
|
||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_datastage_in (struct usb_dev *dev)
|
||||
{
|
||||
uint32_t len = USB_MAX_PACKET_SIZE;;
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
|
||||
if ((data_p->len == 0) && (dev->state == LAST_IN_DATA))
|
||||
{
|
||||
if (data_p->require_zlp)
|
||||
{
|
||||
data_p->require_zlp = 0;
|
||||
|
||||
/* No more data to send. Send empty packet */
|
||||
epbuf_set_tx_count (ENDP0, 0);
|
||||
ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more data to send, proceed to receive OUT acknowledge. */
|
||||
dev->state = WAIT_STATUS_OUT;
|
||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dev->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA;
|
||||
|
||||
if (len > data_p->len)
|
||||
len = data_p->len;
|
||||
|
||||
usb_lld_to_pmabuf (data_p->addr, epbuf_get_tx_addr (ENDP0), len);
|
||||
data_p->len -= len;
|
||||
data_p->addr += len;
|
||||
epbuf_set_tx_count (ENDP0, len);
|
||||
ep_set_tx_status (ENDP0, EP_TX_VALID);
|
||||
}
|
||||
|
||||
typedef int (*HANDLER) (struct usb_dev *dev);
|
||||
|
||||
static int
|
||||
std_none (struct usb_dev *dev)
|
||||
{
|
||||
(void)dev;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_status (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = (arg->type & RECIPIENT);
|
||||
uint16_t status_info = 0;
|
||||
|
||||
if (arg->value != 0 || arg->len != 2 || (arg->index >> 8) != 0
|
||||
|| USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (arg->index == 0)
|
||||
{
|
||||
/* Get Device Status */
|
||||
uint8_t feature = dev->feature;
|
||||
|
||||
/* Remote Wakeup enabled */
|
||||
if ((feature & (1 << 5)))
|
||||
status_info |= 2;
|
||||
else
|
||||
status_info &= ~2;
|
||||
|
||||
/* Bus-powered */
|
||||
if ((feature & (1 << 6)))
|
||||
status_info |= 1;
|
||||
else /* Self-powered */
|
||||
status_info &= ~1;
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
}
|
||||
else if (rcp == INTERFACE_RECIPIENT)
|
||||
{
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
return USB_EVENT_GET_STATUS_INTERFACE;
|
||||
}
|
||||
else if (rcp == ENDPOINT_RECIPIENT)
|
||||
{
|
||||
uint8_t endpoint = (arg->index & 0x0f);
|
||||
uint16_t status;
|
||||
|
||||
if ((arg->index & 0x70) || endpoint == ENDP0)
|
||||
return -1;
|
||||
|
||||
if ((arg->index & 0x80))
|
||||
{
|
||||
status = ep_get_tx_status (endpoint);
|
||||
if (status == 0) /* Disabled */
|
||||
return -1;
|
||||
else if (status == EP_TX_STALL)
|
||||
status_info |= 1; /* IN Endpoint stalled */
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ep_get_rx_status (endpoint);
|
||||
if (status == 0) /* Disabled */
|
||||
return -1;
|
||||
else if (status == EP_RX_STALL)
|
||||
status_info |= 1; /* OUT Endpoint stalled */
|
||||
}
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_clear_feature (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (arg->len != 0 || arg->index != 0)
|
||||
return -1;
|
||||
|
||||
if (arg->value == FEATURE_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->feature &= ~(1 << 5);
|
||||
return USB_EVENT_CLEAR_FEATURE_DEVICE;
|
||||
}
|
||||
}
|
||||
else if (rcp == ENDPOINT_RECIPIENT)
|
||||
{
|
||||
uint8_t endpoint = (arg->index & 0x0f);
|
||||
uint16_t status;
|
||||
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
if (arg->len != 0 || (arg->index >> 8) != 0
|
||||
|| arg->value != FEATURE_ENDPOINT_HALT || endpoint == ENDP0)
|
||||
return -1;
|
||||
|
||||
if ((arg->index & 0x80))
|
||||
status = ep_get_tx_status (endpoint);
|
||||
else
|
||||
status = ep_get_rx_status (endpoint);
|
||||
|
||||
if (status == 0) /* It's disabled endpoint. */
|
||||
return -1;
|
||||
|
||||
if (arg->index & 0x80) /* IN endpoint */
|
||||
ep_clear_dtog_tx (endpoint);
|
||||
else /* OUT endpoint */
|
||||
ep_clear_dtog_rx (endpoint);
|
||||
|
||||
return USB_EVENT_CLEAR_FEATURE_ENDPOINT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_feature (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
{
|
||||
if (arg->len != 0 || arg->index != 0)
|
||||
return -1;
|
||||
|
||||
if (arg->value == FEATURE_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->feature |= 1 << 5;
|
||||
return USB_EVENT_SET_FEATURE_DEVICE;
|
||||
}
|
||||
}
|
||||
else if (rcp == ENDPOINT_RECIPIENT)
|
||||
{
|
||||
uint8_t endpoint = (arg->index & 0x0f);
|
||||
uint32_t status;
|
||||
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
if (arg->len != 0 || (arg->index >> 8) != 0
|
||||
|| arg->value != FEATURE_ENDPOINT_HALT || endpoint == ENDP0)
|
||||
return -1;
|
||||
|
||||
if ((arg->index & 0x80))
|
||||
status = ep_get_tx_status (endpoint);
|
||||
else
|
||||
status = ep_get_rx_status (endpoint);
|
||||
|
||||
if (status == 0) /* It's disabled endpoint. */
|
||||
return -1;
|
||||
|
||||
if (arg->index & 0x80) /* IN endpoint */
|
||||
ep_set_tx_status (endpoint, EP_TX_STALL);
|
||||
else /* OUT endpoint */
|
||||
ep_set_rx_status (endpoint, EP_RX_STALL);
|
||||
|
||||
return USB_EVENT_SET_FEATURE_ENDPOINT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_address (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT && arg->len == 0 && arg->value <= 127
|
||||
&& arg->index == 0 && dev->configuration == 0)
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_descriptor (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
return USB_EVENT_GET_DESCRIPTOR;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_configuration (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (arg->value != 0 || arg->index != 0 || arg->len != 1)
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
return usb_lld_ctrl_send (dev, &dev->configuration, 1);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_configuration (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (arg->index != 0 || arg->len != 0)
|
||||
return -1;
|
||||
|
||||
if (rcp == DEVICE_RECIPIENT)
|
||||
return USB_EVENT_SET_CONFIGURATION;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_get_interface (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
return -1;
|
||||
|
||||
if (arg->value != 0 || (arg->index >> 8) != 0 || arg->len != 1)
|
||||
return -1;
|
||||
|
||||
if (dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
if (rcp == INTERFACE_RECIPIENT)
|
||||
return USB_EVENT_GET_INTERFACE;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
std_set_interface (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
|
||||
if (USB_SETUP_GET (arg->type) || rcp != INTERFACE_RECIPIENT
|
||||
|| arg->len != 0 || (arg->index >> 8) != 0
|
||||
|| (arg->value >> 8) != 0 || dev->configuration == 0)
|
||||
return -1;
|
||||
|
||||
return USB_EVENT_SET_INTERFACE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
handle_in0 (struct usb_dev *dev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (dev->state == IN_DATA || dev->state == LAST_IN_DATA)
|
||||
handle_datastage_in (dev);
|
||||
else if (dev->state == WAIT_STATUS_IN)
|
||||
{
|
||||
dev->state = WAIT_SETUP;
|
||||
|
||||
if ((dev->dev_req.request == SET_ADDRESS) &&
|
||||
((dev->dev_req.type & (REQUEST_TYPE | RECIPIENT))
|
||||
== (STANDARD_REQUEST | DEVICE_RECIPIENT)))
|
||||
{
|
||||
USB->DADDR = (DADDR_EF | dev->dev_req.value);
|
||||
r = USB_EVENT_DEVICE_ADDRESSED;
|
||||
}
|
||||
else
|
||||
r = USB_EVENT_CTRL_WRITE_FINISH;
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->state = STALLED;
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_out0 (struct usb_dev *dev)
|
||||
{
|
||||
if (dev->state == OUT_DATA)
|
||||
/* Usual case. */
|
||||
handle_datastage_out (dev);
|
||||
else if (dev->state == WAIT_STATUS_OUT)
|
||||
/*
|
||||
* Control READ transfer finished by ZLP.
|
||||
* Leave ENDP0 status RX_NAK, TX_NAK.
|
||||
*/
|
||||
dev->state = WAIT_SETUP;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* dev->state == IN_DATA || dev->state == LAST_IN_DATA
|
||||
* (Host aborts the transfer before finish)
|
||||
* Or else, unexpected state.
|
||||
* STALL the endpoint, until we receive the next SETUP token.
|
||||
*/
|
||||
dev->state = STALLED;
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_handle_transfer (struct usb_dev *dev, uint16_t istr_value)
|
||||
{
|
||||
uint16_t ep_value = 0;
|
||||
uint8_t ep_num = (istr_value & ISTR_EP_ID);
|
||||
|
||||
ep_value = USB->EPR[ep_num];
|
||||
|
||||
if (ep_num == 0)
|
||||
{
|
||||
if ((ep_value & EP_CTR_TX))
|
||||
{
|
||||
ep_clear_ctr_tx (ep_num);
|
||||
return USB_MAKE_EV (handle_in0 (dev));
|
||||
}
|
||||
|
||||
if ((ep_value & EP_CTR_RX))
|
||||
{
|
||||
ep_clear_ctr_rx (ep_num);
|
||||
|
||||
if ((ep_value & EP_SETUP))
|
||||
return USB_MAKE_EV (handle_setup0 (dev));
|
||||
else
|
||||
{
|
||||
handle_out0 (dev);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
if ((ep_value & EP_CTR_RX))
|
||||
{
|
||||
len = epbuf_get_rx_count (ep_num);
|
||||
ep_clear_ctr_rx (ep_num);
|
||||
return USB_MAKE_TXRX (ep_num, 0, len);
|
||||
}
|
||||
|
||||
if ((ep_value & EP_CTR_TX))
|
||||
{
|
||||
len = epbuf_get_tx_count (ep_num);
|
||||
ep_clear_ctr_tx (ep_num);
|
||||
return USB_MAKE_TXRX (ep_num, 1, len);
|
||||
}
|
||||
}
|
||||
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_reset (struct usb_dev *dev, uint8_t feature)
|
||||
{
|
||||
usb_lld_set_configuration (dev, 0);
|
||||
dev->feature = feature;
|
||||
USB->DADDR = DADDR_EF; /* Initially, device responds to address 0 */
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_txcpy (const void *src, int ep_num, int offset, size_t len)
|
||||
{
|
||||
usb_lld_to_pmabuf (src, epbuf_get_tx_addr (ep_num) + offset, len);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_write (uint8_t ep_num, const void *buf, size_t len)
|
||||
{
|
||||
usb_lld_to_pmabuf (buf, epbuf_get_tx_addr (ep_num), len);
|
||||
epbuf_set_tx_count (ep_num, len);
|
||||
ep_set_tx_status (ep_num, EP_TX_VALID);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_rxcpy (uint8_t *dst, int ep_num, int offset, size_t len)
|
||||
{
|
||||
usb_lld_from_pmabuf (dst, epbuf_get_rx_addr (ep_num) + offset, len);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_tx_enable (int ep_num, size_t len)
|
||||
{
|
||||
epbuf_set_tx_count (ep_num, len);
|
||||
ep_set_tx_status (ep_num, EP_TX_VALID);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_stall_tx (int ep_num)
|
||||
{
|
||||
ep_set_tx_status (ep_num, EP_TX_STALL);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_stall_rx (int ep_num)
|
||||
{
|
||||
ep_set_rx_status (ep_num, EP_RX_STALL);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_rx_enable (int ep_num)
|
||||
{
|
||||
ep_set_rx_status (ep_num, EP_RX_VALID);
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
|
||||
int ep_rx_addr, int ep_tx_addr,
|
||||
int ep_rx_buf_size)
|
||||
{
|
||||
uint16_t epreg_value = USB->EPR[ep_num];
|
||||
uint16_t ep_rxtx_status = 0; /* Both disabled */
|
||||
|
||||
/* Clear: Write 1 if 1: EP_DTOG_RX, EP_DTOG_TX */
|
||||
/* Set: Write: EP_T_FIELD, EP_KIND, EPADDR_FIELD */
|
||||
/* Set: Toggle: EPRX_STAT, EPTX_STAT */
|
||||
epreg_value &= (EPRX_STAT | EP_SETUP | EPTX_STAT | EP_DTOG_RX | EP_DTOG_TX);
|
||||
#if USB_KEEP_CORRECT_TRANSFER_FLAGS
|
||||
/* Keep: Write 1: EP_CTR_RX, EP_CTR_TX */
|
||||
epreg_value |= (EP_CTR_RX|EP_CTR_TX);
|
||||
#else
|
||||
/* Clear: Write 0: EP_CTR_RX, EP_CTR_TX */
|
||||
#endif
|
||||
epreg_value |= ep_type;
|
||||
epreg_value |= ep_kind;
|
||||
epreg_value |= ep_num;
|
||||
|
||||
if (ep_rx_addr)
|
||||
{
|
||||
ep_rxtx_status |= EP_RX_NAK;
|
||||
epbuf_set_rx_addr (ep_num, ep_rx_addr);
|
||||
epbuf_set_rx_buf_size (ep_num, ep_rx_buf_size);
|
||||
}
|
||||
|
||||
if (ep_tx_addr)
|
||||
{
|
||||
ep_rxtx_status |= EP_TX_NAK;
|
||||
epbuf_set_tx_addr (ep_num, ep_tx_addr);
|
||||
}
|
||||
|
||||
epreg_value ^= (EPRX_DTOG1 & ep_rxtx_status);
|
||||
epreg_value ^= (EPRX_DTOG2 & ep_rxtx_status);
|
||||
epreg_value ^= (EPTX_DTOG1 & ep_rxtx_status);
|
||||
epreg_value ^= (EPTX_DTOG2 & ep_rxtx_status);
|
||||
|
||||
USB->EPR[ep_num] = epreg_value;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_set_configuration (struct usb_dev *dev, uint8_t config)
|
||||
{
|
||||
dev->configuration = config;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
usb_lld_current_configuration (struct usb_dev *dev)
|
||||
{
|
||||
return dev->configuration;
|
||||
}
|
||||
|
||||
int
|
||||
usb_lld_ctrl_recv (struct usb_dev *dev, void *p, size_t len)
|
||||
{
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
data_p->addr = p;
|
||||
data_p->len = len;
|
||||
dev->state = OUT_DATA;
|
||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BUF: Pointer to data memory. Data memory should not be allocated
|
||||
* on stack when BUFLEN > USB_MAX_PACKET_SIZE.
|
||||
*
|
||||
* BUFLEN: size of the data.
|
||||
*/
|
||||
int
|
||||
usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
{
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
uint32_t len_asked = dev->dev_req.len;
|
||||
uint32_t len;
|
||||
|
||||
data_p->addr = (void *)buf;
|
||||
data_p->len = buflen;
|
||||
|
||||
/* Restrict the data length to be the one host asks for */
|
||||
if (data_p->len >= len_asked)
|
||||
data_p->len = len_asked;
|
||||
/* ZLP is only required when host doesn't expect the end of packets. */
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len < USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = USB_MAX_PACKET_SIZE;
|
||||
dev->state = IN_DATA;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
usb_lld_to_pmabuf (data_p->addr, epbuf_get_tx_addr (ENDP0), len);
|
||||
data_p->len -= len;
|
||||
data_p->addr += len;
|
||||
}
|
||||
|
||||
epbuf_set_tx_count (ENDP0, len);
|
||||
ep_set_rxtx_status (ENDP0, EP_RX_NAK, EP_TX_VALID);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
294
mcu/usb-stm32l4.c
Normal file
294
mcu/usb-stm32l4.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* usb-stm32l4.c - USB driver for STM32L4
|
||||
*
|
||||
* Copyright (C) 2019 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
*
|
||||
* Chopstx is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Chopstx is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <mcu/stm32l.h>
|
||||
#include "usb_lld.h"
|
||||
#include "usb_lld_driver.h"
|
||||
|
||||
#define REG_BASE (0x40006800UL) /* USB Peripheral Registers base address */
|
||||
#define PMA_ADDR (0x40006C00UL) /* USB Packet Memory Area base address */
|
||||
|
||||
static void
|
||||
epbuf_set_tx_addr (uint8_t ep_num, uint16_t addr)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0));
|
||||
|
||||
*reg_p = addr;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_tx_addr (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0));
|
||||
|
||||
return *reg_p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
epbuf_set_tx_count (uint8_t ep_num, uint16_t size)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2));
|
||||
|
||||
*reg_p = size;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_tx_count (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2));
|
||||
|
||||
return *reg_p & 0x03ff;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
epbuf_set_rx_addr (uint8_t ep_num, uint16_t addr)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4));
|
||||
|
||||
*reg_p = addr;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_rx_addr (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4));
|
||||
|
||||
return *reg_p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
epbuf_set_rx_buf_size (uint8_t ep_num, uint16_t size)
|
||||
{ /* Assume size is even */
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6));
|
||||
uint16_t value;
|
||||
|
||||
if (size <= 62)
|
||||
value = (size & 0x3e) << 9;
|
||||
else
|
||||
value = 0x8000 | (((size >> 5) - 1) << 10);
|
||||
|
||||
*reg_p = value;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
epbuf_get_rx_count (uint8_t ep_num)
|
||||
{
|
||||
uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6));
|
||||
|
||||
return *reg_p & 0x03ff;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_lld_shutdown_chip_specific (void)
|
||||
{
|
||||
USB_STM32L4->BCDR &= 0x7fff; /* DP disable */
|
||||
RCC->APB1ENR1 &= ~(RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
RCC->APB1RSTR1 |= (RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
}
|
||||
|
||||
static void
|
||||
wait (int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
}
|
||||
|
||||
struct CRS
|
||||
{
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t CFGR;
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t ICR;
|
||||
};
|
||||
static struct CRS *const CRS = ((struct CRS *)(APB1PERIPH_BASE + 0x6000));
|
||||
|
||||
|
||||
static void
|
||||
usb_lld_init_chip_specific (void)
|
||||
{
|
||||
PWR->CR2 |= (1 << 10); /* USB supply valid */
|
||||
|
||||
if ((RCC->APB1ENR1 & RCC_APB1_1_USB)
|
||||
&& (RCC->APB1RSTR1 & RCC_APB1_1_USB) == 0)
|
||||
/* Make sure the device is disconnected, even after core reset. */
|
||||
{
|
||||
usb_lld_shutdown_chip_specific ();
|
||||
/* Disconnect requires SE0 (>= 2.5uS). */
|
||||
wait (5*MHZ);
|
||||
}
|
||||
|
||||
/* Enable USB clock and CRC clock */
|
||||
RCC->APB1ENR1 |= (RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
RCC->APB1RSTR1 = (RCC_APB1_1_USB | RCC_APB1_1_CRS);
|
||||
RCC->APB1RSTR1 = 0;
|
||||
|
||||
USB_STM32L4->BCDR |= 0x8000; /* DP enable */
|
||||
|
||||
/* Configure CRS (clock recovery system) for HSI48 clock */
|
||||
CRS->CFGR = ( (0x00 << 31) | /* Polarity rising */
|
||||
(0x02 << 28) | /* USB SOF for Sync */
|
||||
(0x00 << 24) | /* divider = 1 */
|
||||
(0x22 << 16) | /* Frequency error limit */
|
||||
0xBB7F ); /* Reload value */
|
||||
|
||||
CRS->CR |= ( (1 << 6) | /* Automatic trimming enable */
|
||||
(1 << 5) ); /* Frequency error counter enable */
|
||||
}
|
||||
|
||||
#include "usb-st-common.c"
|
||||
|
||||
static int
|
||||
handle_setup0 (struct usb_dev *dev)
|
||||
{
|
||||
const uint16_t *pw;
|
||||
uint16_t w;
|
||||
uint8_t req_no;
|
||||
HANDLER handler;
|
||||
|
||||
pw = (uint16_t *)(PMA_ADDR + epbuf_get_rx_addr (ENDP0));
|
||||
w = *pw++;
|
||||
|
||||
dev->dev_req.type = (w & 0xff);
|
||||
dev->dev_req.request = req_no = (w >> 8);
|
||||
dev->dev_req.value = *pw++;
|
||||
dev->dev_req.index = *pw++;
|
||||
dev->dev_req.len = *pw;
|
||||
|
||||
dev->ctrl_data.addr = NULL;
|
||||
dev->ctrl_data.len = 0;
|
||||
dev->ctrl_data.require_zlp = 0;
|
||||
|
||||
if ((dev->dev_req.type & REQUEST_TYPE) == STANDARD_REQUEST)
|
||||
{
|
||||
int r;
|
||||
|
||||
switch (req_no)
|
||||
{
|
||||
case 0: handler = std_get_status; break;
|
||||
case 1: handler = std_clear_feature; break;
|
||||
case 3: handler = std_set_feature; break;
|
||||
case 5: handler = std_set_address; break;
|
||||
case 6: handler = std_get_descriptor; break;
|
||||
case 8: handler = std_get_configuration; break;
|
||||
case 9: handler = std_set_configuration; break;
|
||||
case 10: handler = std_get_interface; break;
|
||||
case 11: handler = std_set_interface; break;
|
||||
default: handler = std_none; break;
|
||||
}
|
||||
|
||||
if ((r = (*handler) (dev)) < 0)
|
||||
{
|
||||
usb_lld_ctrl_error (dev);
|
||||
return USB_EVENT_OK;
|
||||
}
|
||||
else
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return USB_EVENT_CTRL_REQUEST;
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *)src;
|
||||
uint16_t *p;
|
||||
uint16_t w;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
if ((addr & 1))
|
||||
{
|
||||
p = (uint16_t *)(PMA_ADDR + (addr - 1));
|
||||
w = *p;
|
||||
w = (w & 0xff) | (*s++) << 8;
|
||||
*p++ = w;
|
||||
n--;
|
||||
}
|
||||
else
|
||||
p = (uint16_t *)(PMA_ADDR + addr);
|
||||
|
||||
while (n >= 2)
|
||||
{
|
||||
w = *s++;
|
||||
w |= (*s++) << 8;
|
||||
*p++ = w;
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
w = *s;
|
||||
*p = w;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n)
|
||||
{
|
||||
uint8_t *d = (uint8_t *)dst;
|
||||
uint16_t *p;
|
||||
uint16_t w;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
if ((addr & 1))
|
||||
{
|
||||
p = (uint16_t *)(PMA_ADDR + (addr - 1));
|
||||
w = *p++;
|
||||
*d++ = (w >> 8);
|
||||
n--;
|
||||
}
|
||||
else
|
||||
p = (uint16_t *)(PMA_ADDR + addr);
|
||||
|
||||
while (n >= 2)
|
||||
{
|
||||
w = *p++;
|
||||
*d++ = (w & 0xff);
|
||||
*d++ = (w >> 8);
|
||||
n -= 2;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
w = *p;
|
||||
*d = (w & 0xff);
|
||||
}
|
||||
}
|
||||
1
rules.mk
1
rules.mk
@@ -13,6 +13,7 @@ CSRC += $(CHOPSTX)/mcu/chx-gnu-linux.c
|
||||
endif
|
||||
|
||||
ifneq ($(USE_SYS),)
|
||||
DEFS += -DUSE_SYS
|
||||
CSRC += $(CHOPSTX)/mcu/sys-$(CHIP).c
|
||||
endif
|
||||
ifneq ($(USE_USB),)
|
||||
|
||||
2
sys.h
2
sys.h
@@ -4,6 +4,8 @@
|
||||
#include "mcu/sys-mkl27z.h"
|
||||
#elif defined(MCU_STM32F0)
|
||||
#include "mcu/sys-stm32f0.h"
|
||||
#elif defined(MCU_STM32L4)
|
||||
#include "mcu/sys-stm32l4.h"
|
||||
#else
|
||||
#include "mcu/sys-stm32f103.h"
|
||||
#endif
|
||||
|
||||
@@ -153,7 +153,11 @@ void usb_lld_setup_endp (struct usb_dev *dev, int ep_num, int rx_en, int tx_en);
|
||||
void usb_lld_stall_tx (int ep_num);
|
||||
void usb_lld_stall_rx (int ep_num);
|
||||
#else
|
||||
#if defined(MCU_STM32L4)
|
||||
#define INTR_REQ_USB 67
|
||||
#else
|
||||
#define INTR_REQ_USB 20
|
||||
#endif
|
||||
/* EP_TYPE[1:0] EndPoint TYPE */
|
||||
#define EP_BULK (0x0000) /* EndPoint BULK */
|
||||
#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
|
||||
|
||||
Reference in New Issue
Block a user