diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b11b50e4..3b4389ab4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,13 +19,12 @@ jobs: echo "MATRIX_JSON=$MATRIX_JSON" BUILDSYSTEM_TOOLCHAIN=( + "cmake aarch64-gcc" "cmake arm-clang" + "cmake arm-gcc" "cmake esp-idf" - "make aarch64-gcc" - "make arm-gcc" - "make msp430-gcc" - "make riscv-gcc" - "make rx-gcc" + "cmake msp430-gcc" + "cmake riscv-gcc" ) # only build IAR if not forked PR, since IAR token is not shared diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe2ed61c9..58963013b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,11 +36,6 @@ env: HIL_JSON: test/hil/tinyusb.json jobs: - # --------------------------------------- - # - # Build - # - # --------------------------------------- set-matrix: runs-on: ubuntu-latest outputs: @@ -63,28 +58,31 @@ jobs: echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT # --------------------------------------- - # Build CMake + # Build CMake: only build on push with one-per-family. + # Full built is done by CircleCI in PR # --------------------------------------- cmake: + if: github.event_name == 'push' needs: set-matrix uses: ./.github/workflows/build_util.yml strategy: fail-fast: false matrix: toolchain: - # - 'arm-clang' is built by circle-ci in PR - 'aarch64-gcc' + - 'arm-clang' - 'arm-gcc' + - 'esp-idf' - 'msp430-gcc' - 'riscv-gcc' with: build-system: 'cmake' toolchain: ${{ matrix.toolchain }} build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }} - one-per-family: ${{ github.event_name == 'push' }} + one-per-family: true # --------------------------------------- - # Build Make (built by circle-ci in PR, only build on push here) + # Build Make: only build on push with one-per-family # --------------------------------------- make: if: github.event_name == 'push' @@ -94,19 +92,39 @@ jobs: fail-fast: false matrix: toolchain: - # 'arm-clang' - - 'arm-gcc' - 'aarch64-gcc' + - 'arm-clang' + - 'arm-gcc' - 'msp430-gcc' - 'riscv-gcc' - 'rx-gcc' - - 'esp-idf' with: build-system: 'make' toolchain: ${{ matrix.toolchain }} build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }} one-per-family: true + # --------------------------------------- + # Build IAR + # Since IAR Token secret is not passed to forked PR, only build non-forked PR with make. + # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family + # --------------------------------------- + arm-iar: + if: github.event_name == 'push' && github.repository_owner == 'hathach' + needs: set-matrix + uses: ./.github/workflows/build_util.yml + secrets: inherit + strategy: + fail-fast: false + matrix: + build-system: + - 'make' + with: + build-system: ${{ matrix.build-system }} + toolchain: 'arm-iar' + build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }} + one-per-family: true + # --------------------------------------- # Build Make on Windows/MacOS # --------------------------------------- @@ -124,28 +142,6 @@ jobs: build-args: '["stm32h7"]' one-per-family: true - # --------------------------------------- - # Build IAR - # Since IAR Token secret is not passed to forked PR, only build non-forked PR with make. - # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family - # --------------------------------------- - arm-iar: - if: false # disable for now since we got reach capacity limit too often - #if: github.event_name == 'push' && github.repository_owner == 'hathach' - needs: set-matrix - uses: ./.github/workflows/build_util.yml - secrets: inherit - strategy: - fail-fast: false - matrix: - build-system: - - 'make' - with: - build-system: ${{ matrix.build-system }} - toolchain: 'arm-iar' - build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }} - one-per-family: true - # --------------------------------------- # Zephyr # --------------------------------------- @@ -168,14 +164,9 @@ jobs: west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr # --------------------------------------- - # # Hardware in the loop (HIL) # Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR # --------------------------------------- - - # --------------------------------------- - # Build arm-gcc - # --------------------------------------- hil-build: if: | github.repository_owner == 'hathach' && diff --git a/docs/reference/getting_started.rst b/docs/reference/getting_started.rst index 37745d6a1..ee68f6386 100644 --- a/docs/reference/getting_started.rst +++ b/docs/reference/getting_started.rst @@ -5,12 +5,12 @@ Getting Started Add TinyUSB to your project --------------------------- -It is relatively simple to incorporate tinyusb to your project +To incorporate tinyusb to your project * Copy or ``git submodule`` this repo into your project in a subfolder. Let's say it is ``your_project/tinyusb`` * Add all the ``.c`` in the ``tinyusb/src`` folder to your project * Add ``your_project/tinyusb/src`` to your include path. Also make sure your current include path also contains the configuration file ``tusb_config.h``. -* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by IDE/compiler to maintain a unique configure for all boards). +* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by make/cmake to maintain a unique configure for all boards). * If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all **tud descriptor** callbacks for the stack to work. * Add ``tusb_init(rhport, role)`` call to your reset initialization code. * Call ``tusb_int_handler(rhport, in_isr)`` in your USB IRQ Handler @@ -75,24 +75,36 @@ The hardware code is located in ``hw/bsp`` folder, and is organized by family/bo .. code-block:: bash $ cd examples/device/cdc_msc - $ make BOARD=raspberry_pi_pico get-deps + $ make BOARD=feather_nrf52840_express get-deps You only need to do this once per family. Check out `complete list of dependencies and their designated path here `_ -Build -^^^^^ +Build Examples +^^^^^^^^^^^^^^ -To build example, first change directory to an example folder. +Examples support make and cmake build system, though some MCU family such as espressif/rp2040 only support cmake. First change directory to an example folder. .. code-block:: bash $ cd examples/device/cdc_msc -Then compile with ``make BOARD={board_name} all`` , for example +Then compile with make or cmake .. code-block:: bash - $ make BOARD=raspberry_pi_pico all + $ # make + $ make BOARD=feather_nrf52840_express all + + $ # cmake + $ mkdir build && cd build + $ cmake -DBOARD=raspberry_pi_pico .. + $ make + +To list all available targets with cmake + +.. code-block:: bash + + $ cmake --build . --target help Note: some examples especially those that uses Vendor class (e.g webUSB) may requires udev permission on Linux (and/or macOS) to access usb device. It depends on your OS distro, typically copy ``99-tinyusb.rules`` and reload your udev is good to go @@ -104,20 +116,24 @@ Note: some examples especially those that uses Vendor class (e.g webUSB) may req RootHub Port Selection ~~~~~~~~~~~~~~~~~~~~~~ -If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``PORT=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use: +If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``RHPORT_DEVICE=x`` or ``RHPORT_HOST=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use: .. code-block:: bash - $ make BOARD=stm32f746disco PORT=1 all + $ make BOARD=stm32f746disco RHPORT_DEVICE=1 all + + $ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE=1 .. Port Speed ~~~~~~~~~~ -A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``SPEED=full/high`` e.g To force F723 operate at full instead of default high speed +A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``RHPORT_DEVICE_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` or ``RHPORT_HOST_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` e.g To force F723 operate at full instead of default high speed .. code-block:: bash - $ make BOARD=stm32f746disco SPEED=full all + $ make BOARD=stm32f746disco RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED all + + $ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED .. Size Analysis ~~~~~~~~~~~~~ @@ -137,6 +153,8 @@ To compile for debugging add ``DEBUG=1``\ , for example $ make BOARD=feather_nrf52840_express DEBUG=1 all + $ cmake -DBOARD=feather_nrf52840_express -DCMAKE_BUILD_TYPE=Debug .. + Log ~~~ @@ -146,6 +164,8 @@ Should you have an issue running example and/or submitting an bug report. You co $ make BOARD=feather_nrf52840_express LOG=2 all + $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 .. + Logger ~~~~~~ @@ -169,6 +189,9 @@ By default log message is printed via on-board UART which is slow and take lots $ make BOARD=feather_nrf52840_express LOG=2 LOGGER=rtt all $ make BOARD=feather_nrf52840_express LOG=2 LOGGER=swo all + $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=rtt .. + $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=swo .. + Flash ^^^^^ @@ -179,11 +202,15 @@ Flash $ make BOARD=feather_nrf52840_express flash $ make SERIAL=/dev/ttyACM0 BOARD=feather_nrf52840_express flash -Since jlink can be used with most of the boards, there is also ``flash-jlink`` target for your convenience. +Since jlink/openocd can be used with most of the boards, there is also ``flash-jlink/openocd`` (make) and ``EXAMPLE-jlink/openocd`` target for your convenience. Note for stm32 board with stlink, you can use ``flash-stlink`` target as well. .. code-block:: bash $ make BOARD=feather_nrf52840_express flash-jlink + $ make BOARD=feather_nrf52840_express flash-openocd + + $ cmake --build . --target cdc_msc-jlink + $ cmake --build . --target cdc_msc-openocd Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can be generated with ``uf2`` target @@ -191,17 +218,18 @@ Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can $ make BOARD=feather_nrf52840_express all uf2 + $ cmake --build . --target cdc_msc-uf2 + IAR Support ------------ +^^^^^^^^^^^ Use project connection -^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~ IAR Project Connection files are provided to import TinyUSB stack into your project. * A buildable project of your MCU need to be created in advance. - * Take example of STM32F0: - You need ``stm32l0xx.h``, ``startup_stm32f0xx.s``, ``system_stm32f0xx.c``. @@ -212,15 +240,13 @@ IAR Project Connection files are provided to import TinyUSB stack into your proj Click ``New Group ...``, name it to ``TUSB``, Click ``Add Variable ...``, name it to ``TUSB_DIR``, change it's value to the path of your TinyUSB stack, for example ``C:\\tinyusb`` -Import stack only -~~~~~~~~~~~~~~~~~ +**Import stack only** -1. Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``. +Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``. -Run examples -~~~~~~~~~~~~ +**Run examples** -1. (Python3 is needed) Run ``iar_gen.py`` to generate .ipcf files of examples: +1. Run ``iar_gen.py`` to generate .ipcf files of examples: .. code-block:: @@ -231,7 +257,7 @@ Run examples For example ``C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf`` Native CMake support (9.50.1+) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With 9.50.1 release, IAR added experimental native CMake support (strangely not mentioned in public release note). Now it's possible to import CMakeLists.txt then build and debug as a normal project. diff --git a/hw/bsp/espressif/family.cmake b/hw/bsp/espressif/family.cmake index 2aad7d185..ca9eadaf6 100644 --- a/hw/bsp/espressif/family.cmake +++ b/hw/bsp/espressif/family.cmake @@ -1,5 +1,3 @@ -cmake_minimum_required(VERSION 3.5) - # Apply board specific content i.e IDF_TARGET must be set before project.cmake is included include("${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake") string(TOUPPER ${IDF_TARGET} FAMILY_MCUS) diff --git a/hw/bsp/espressif/family.mk b/hw/bsp/espressif/family.mk deleted file mode 100644 index d955a2b4c..000000000 --- a/hw/bsp/espressif/family.mk +++ /dev/null @@ -1,32 +0,0 @@ -UF2_FAMILY_ID_esp32s2 = 0xbfdd4eee -UF2_FAMILY_ID_esp32s3 = 0xc47e5767 - -BOARD_CMAKE := $(file < $(TOP)/$(BOARD_PATH)/board.cmake) -ifneq ($(findstring esp32s2,$(BOARD_CMAKE)),) - IDF_TARGET = esp32s2 -else -ifneq ($(findstring esp32s3,$(BOARD_CMAKE)),) - IDF_TARGET = esp32s3 -endif -endif - -.PHONY: all clean flash bootloader-flash app-flash erase monitor dfu-flash dfu - -all: - idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) build - -build: all - -fullclean: - if test -f sdkconfig; then $(RM) -f sdkconfig ; fi - if test -d $(BUILD); then $(RM) -rf $(BUILD) ; fi - idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@ - -clean flash bootloader-flash app-flash erase monitor dfu-flash dfu size size-components size-files: - idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@ - -uf2: $(BUILD)/$(PROJECT).uf2 - -$(BUILD)/$(PROJECT).uf2: $(BUILD)/$(PROJECT).bin - @echo CREATE $@ - $(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_$(IDF_TARGET)) -b 0x0 -c -o $@ $^ diff --git a/hw/bsp/msp430/family.cmake b/hw/bsp/msp430/family.cmake index ddd54b675..d9b4bf770 100644 --- a/hw/bsp/msp430/family.cmake +++ b/hw/bsp/msp430/family.cmake @@ -11,36 +11,37 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/msp430_${T set(FAMILY_MCUS MSP430x5xx CACHE INTERNAL "") - #------------------------------------ # BOARD_TARGET #------------------------------------ # only need to be built ONCE for all examples function(add_board_target BOARD_TARGET) - if (NOT TARGET ${BOARD_TARGET}) - add_library(${BOARD_TARGET} INTERFACE) - target_compile_definitions(${BOARD_TARGET} INTERFACE - CFG_TUD_ENDPOINT0_SIZE=8 - CFG_EXAMPLE_VIDEO_READONLY - CFG_EXAMPLE_MSC_READONLY - ) - target_include_directories(${BOARD_TARGET} INTERFACE - ${CMAKE_CURRENT_FUNCTION_LIST_DIR} - ${SDK_DIR} - ) + if (TARGET ${BOARD_TARGET}) + return() + endif () - update_board(${BOARD_TARGET}) + add_library(${BOARD_TARGET} INTERFACE) + target_compile_definitions(${BOARD_TARGET} INTERFACE + CFG_TUD_ENDPOINT0_SIZE=8 + CFG_EXAMPLE_VIDEO_READONLY + CFG_EXAMPLE_MSC_READONLY + ) + target_include_directories(${BOARD_TARGET} INTERFACE + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${SDK_DIR} + ) - if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_link_options(${BOARD_TARGET} INTERFACE - "LINKER:--script=${LD_FILE_GNU}" - -L${SDK_DIR} - ) - elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") - target_link_options(${BOARD_TARGET} INTERFACE - "LINKER:--config=${LD_FILE_IAR}" - ) - endif () + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} INTERFACE + "LINKER:--script=${LD_FILE_GNU}" + -L${SDK_DIR} + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${BOARD_TARGET} INTERFACE + "LINKER:--config=${LD_FILE_IAR}" + ) endif () endfunction() @@ -75,7 +76,6 @@ function(family_configure_example TARGET RTOS) ) target_link_libraries(${TARGET} PUBLIC board_${BOARD}) - # Flashing family_add_bin_hex(${TARGET}) family_flash_msp430flasher(${TARGET})