diff --git a/.github/workflows/build_msp430.yml b/.github/workflows/build_msp430.yml
index f913df913e..95d2127082 100644
--- a/.github/workflows/build_msp430.yml
+++ b/.github/workflows/build_msp430.yml
@@ -61,10 +61,11 @@ jobs:
tar -C ~/cache/toolchain -xaf toolchain.tar.bz2
- name: Set Toolchain Path
- run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
-
- - name: Get Dependencies
- run: python3 tools/get_deps.py ${{ matrix.family }}
+ run: |
+ echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
+ sudo apt install -y ninja-build
- name: Build
- run: python3 tools/build_make.py ${{ matrix.family }}
+ run: |
+ python3 tools/get_deps.py ${{ matrix.family }}
+ python tools/build_cmake.py ${{ matrix.family }} -DCMAKE_BUILD_TYPE=MinSizeRel
diff --git a/.idea/cmake.xml b/.idea/cmake.xml
index ebc6a05708..c361e237d9 100644
--- a/.idea/cmake.xml
+++ b/.idea/cmake.xml
@@ -2,8 +2,9 @@
-
-
+
+
+
@@ -44,7 +45,7 @@
-
+
@@ -57,8 +58,10 @@
-
+
+
+
@@ -82,6 +85,7 @@
+
\ No newline at end of file
diff --git a/examples/build_system/cmake/cpu/msp430.cmake b/examples/build_system/cmake/cpu/msp430.cmake
new file mode 100644
index 0000000000..b4b47a2e86
--- /dev/null
+++ b/examples/build_system/cmake/cpu/msp430.cmake
@@ -0,0 +1,7 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(FREERTOS_PORT GCC_MSP430F449 CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(FREERTOS_PORT IAR_MSP430 CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/toolchain/msp430_gcc.cmake b/examples/build_system/cmake/toolchain/msp430_gcc.cmake
new file mode 100644
index 0000000000..6291ce5a4f
--- /dev/null
+++ b/examples/build_system/cmake/toolchain/msp430_gcc.cmake
@@ -0,0 +1,52 @@
+set(CMAKE_SYSTEM_NAME Generic)
+
+if (NOT DEFINED CMAKE_C_COMPILER)
+ set(CMAKE_C_COMPILER "msp430-elf-gcc")
+endif ()
+
+if (NOT DEFINED CMAKE_CXX_COMPILER)
+ set(CMAKE_CXX_COMPILER "msp430-elf-g++")
+endif ()
+
+set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
+
+set(CMAKE_SIZE "msp430-elf-size" CACHE FILEPATH "")
+set(CMAKE_OBJCOPY "msp430-elf-objcopy" CACHE FILEPATH "")
+set(CMAKE_OBJDUMP "msp430-elf-objdump" CACHE FILEPATH "")
+
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+# Look for includes and libraries only in the target system prefix.
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# pass TOOLCHAIN_CPU to
+set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CMAKE_SYSTEM_PROCESSOR)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../cpu/${CMAKE_SYSTEM_PROCESSOR}.cmake)
+
+# enable all possible warnings for building examples
+list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -fdata-sections
+ -ffunction-sections
+ -fsingle-precision-constant
+ -fno-strict-aliasing
+ )
+
+list(APPEND TOOLCHAIN_EXE_LINKER_FLAGS
+ -Wl,--print-memory-usage
+ -Wl,--gc-sections
+ -Wl,--cref
+ )
+
+include(${CMAKE_CURRENT_LIST_DIR}/set_flags.cmake)
+
+# try_compile is cmake test compiling its own example,
+# pass -nostdlib to skip stdlib linking
+get_property(IS_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if (IS_IN_TRY_COMPILE)
+ set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -nostdlib")
+ set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -nostdlib")
+endif ()
diff --git a/examples/build_system/make/cpu/msp430.mk b/examples/build_system/make/cpu/msp430.mk
new file mode 100644
index 0000000000..06340d23b2
--- /dev/null
+++ b/examples/build_system/make/cpu/msp430.mk
@@ -0,0 +1,8 @@
+ifeq ($(TOOLCHAIN),gcc)
+ # nothing to add
+else ifeq ($(TOOLCHAIN),iar)
+ # nothing to add
+endif
+
+# For freeRTOS port source
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/GCC_MSP430F449
diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake
index 4ccd6e4f28..d4f355e0c8 100644
--- a/hw/bsp/family_support.cmake
+++ b/hw/bsp/family_support.cmake
@@ -460,6 +460,21 @@ function(family_flash_dfu_util TARGET OPTION)
)
endfunction()
+function(family_flash_msp430flasher TARGET)
+ if (NOT DEFINED MSP430Flasher)
+ set(MSP430FLASHER MSP430Flasher)
+ endif ()
+
+ # set LD_LIBRARY_PATH to find libmsp430.so (directory containing MSP430Flasher)
+ find_program(MSP430FLASHER_PATH MSP430Flasher)
+ get_filename_component(MSP430FLASHER_PARENT_DIR "${MSP430FLASHER_PATH}" DIRECTORY)
+ add_custom_target(${TARGET}-msp430flasher
+ DEPENDS ${TARGET}
+ COMMAND ${CMAKE_COMMAND} -E env LD_LIBRARY_PATH=${MSP430FLASHER_PARENT_DIR}
+ ${MSP430FLASHER} -w $/${TARGET}.hex -z [VCC]
+ )
+endfunction()
+
#----------------------------------
# Family specific
#----------------------------------
diff --git a/hw/bsp/msp430/boards/msp_exp430f5529lp/board.cmake b/hw/bsp/msp430/boards/msp_exp430f5529lp/board.cmake
new file mode 100644
index 0000000000..59f5912634
--- /dev/null
+++ b/hw/bsp/msp430/boards/msp_exp430f5529lp/board.cmake
@@ -0,0 +1,9 @@
+set(MCU_VARIANT msp430f5529)
+set(LD_FILE_GNU ${SDK_DIR}/msp430f5529.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} INTERFACE
+ __MSP430F5529__
+ )
+
+endfunction()
diff --git a/hw/bsp/msp430/boards/msp_exp430f5529lp/board.mk b/hw/bsp/msp430/boards/msp_exp430f5529lp/board.mk
new file mode 100644
index 0000000000..b45c62e830
--- /dev/null
+++ b/hw/bsp/msp430/boards/msp_exp430f5529lp/board.mk
@@ -0,0 +1,4 @@
+CFLAGS += \
+ -D__MSP430F5529__ \
+
+LD_FILE = ${SDK_DIR}/msp430f5529.ld
diff --git a/hw/bsp/msp430/family.cmake b/hw/bsp/msp430/family.cmake
new file mode 100644
index 0000000000..e0b4ed28af
--- /dev/null
+++ b/hw/bsp/msp430/family.cmake
@@ -0,0 +1,84 @@
+include_guard()
+
+set(SDK_DIR ${TOP}/hw/mcu/ti/msp430/msp430-gcc-support-files/include)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_PROCESSOR msp430 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/msp430_${TOOLCHAIN}.cmake)
+
+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}
+ )
+
+ 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 ()
+ endif ()
+endfunction()
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+
+ # Board target
+ add_board_target(board_${BOARD})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ # Add TinyUSB target and port source
+ family_add_tinyusb(${TARGET} OPT_MCU_MSP430x5xx ${RTOS})
+ target_sources(${TARGET}-tinyusb PUBLIC
+ ${TOP}/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+ )
+ target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD})
+
+ # Link dependencies
+ target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb)
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_msp430flasher(${TARGET})
+endfunction()
diff --git a/hw/bsp/msp430/family.mk b/hw/bsp/msp430/family.mk
index ceafa6ec12..06508ab2cd 100644
--- a/hw/bsp/msp430/family.mk
+++ b/hw/bsp/msp430/family.mk
@@ -2,21 +2,21 @@ CROSS_COMPILE = msp430-elf-
DEPS_SUBMODULES += hw/mcu/ti
SKIP_NANOLIB = 1
+SDK_DIR = hw/mcu/ti/msp430/msp430-gcc-support-files/include
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
CFLAGS += \
- -D__MSP430F5529__ \
-DCFG_TUSB_MCU=OPT_MCU_MSP430x5xx \
-DCFG_EXAMPLE_MSC_READONLY \
-DCFG_TUD_ENDPOINT0_SIZE=8
-# All source paths should be relative to the top level.
-LD_FILE = hw/mcu/ti/msp430/msp430-gcc-support-files/include/msp430f5529.ld
-LDINC += $(TOP)/hw/mcu/ti/msp430/msp430-gcc-support-files/include
-LDFLAGS += $(addprefix -L,$(LDINC))
+LDFLAGS += -L${TOP}/${SDK_DIR}
SRC_C += src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
INC += \
- $(TOP)/hw/mcu/ti/msp430/msp430-gcc-support-files/include \
+ ${TOP}/${SDK_DIR} \
$(TOP)/$(BOARD_PATH)
# export for libmsp430.so to same installation
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index cd6142d3a1..a26c668929 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -535,14 +535,14 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
* - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
* should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
* - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
- * also takes time, so we'll wait 40 cycles (count = 20).
+ * also takes time, so we'll wait 60 cycles (count = 20).
* - Since Low Speed mode is not supported/popular, we will ignore it for now.
*
* Note: this errata also seems to apply to G0, U5, H5 etc.
*/
volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
while (cycle_count > 0U) {
- cycle_count--; // each count take 2 cycle (1 cycle for sub, 1 cycle for compare/jump)
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
}
#endif
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index b4dfda575c..8005f5f7be 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -94,7 +94,8 @@ static void bus_reset(void)
USBOEPCNT_0 &= ~NAK;
USBIEPCNT_0 &= ~NAK;
- USBCTL |= FEN; // Enable responding to packets.
+ // Enable responding to packets.
+ USBCTL |= FEN;
// Dedicated buffers in hardware for SETUP and EP0, no setup needed.
// Now safe to respond to SETUP packets.
@@ -103,6 +104,28 @@ static void bus_reset(void)
USBKEYPID = 0;
}
+// Controls reset behavior of the USB module on receipt of a bus reset event.
+// - enable: When true, bus reset events will cause a reset the USB module.
+static void enable_functional_reset(const bool enable)
+{
+ // Check whether or not the USB configuration registers were
+ // locked prior to this function being called so that, if
+ // necessary, the lock state can be restored on exit.
+ bool unlocked = (USBKEYPID == 0xA528) ? true : false;
+
+ if(!unlocked) USBKEYPID = USBKEY;
+
+ if(enable)
+ {
+ USBCTL |= FRSTE;
+ }
+ else
+ {
+ USBCTL &= ~FRSTE;
+ }
+
+ if(!unlocked) USBKEYPID = 0;
+}
/*------------------------------------------------------------------*/
/* Controller API
@@ -131,11 +154,14 @@ void dcd_init (uint8_t rhport)
USBVECINT = 0;
- // Enable reset and wait for it before continuing.
- USBIE |= RSTRIE;
-
- // Enable pullup.
- USBCNF |= PUR_EN;
+ if(USBPWRCTL & USBBGVBV) {// Bus power detected?
+ USBPWRCTL |= VBOFFIE; // Enable bus-power-removed interrupt.
+ USBIE |= RSTRIE; // Enable reset and wait for it before continuing.
+ USBCNF |= PUR_EN; // Enable pullup.
+ } else {
+ USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
+ USBCNF &= ~USB_EN; // Disable USB module until bus power is detected.
+ }
USBKEYPID = 0;
}
@@ -610,14 +636,76 @@ static void handle_setup_packet(void)
_setup_packet[i] = setup_buf[i];
}
- // Clearing SETUPIFG by reading USBVECINT does not set NAK, so now that we
- // have a SETUP packet, force NAKs until tinyusb can handle the SETUP
- // packet and prepare for a new xfer.
+ // Force NAKs until tinyusb can handle the SETUP packet and prepare for a new xfer.
USBIEPCNT_0 |= NAK;
USBOEPCNT_0 |= NAK;
+
+ // Clear SETUPIFG to avoid handling in the USBVECINT switch statement.
+ // When handled there the NAKs applied to the endpoints above are
+ // cleared by hardware and the host will receive stale/duplicate data.
+ //
+ // Excerpt from MSP430x5xx and MSP430x6xx Family User's Guide:
+ //
+ // "...the SETUPIFG is cleared upon reading USBIV. In addition, the NAK on
+ // input endpoint 0 and output endpoint 0 is also cleared."
+ USBIEPCNF_0 &= ~UBME; // Errata USB10 workaround.
+ USBOEPCNF_0 &= ~UBME; // Errata USB10 workaround.
+ USBIFG &= ~SETUPIFG;
+ USBIEPCNF_0 |= UBME; // Errata USB10 workaround.
+ USBOEPCNF_0 |= UBME; // Errata USB10 workaround.
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
}
+#if CFG_TUSB_OS == OPT_OS_NONE
+TU_ATTR_ALWAYS_INLINE static inline void tu_delay(uint32_t ms) {
+ // msp430 can run up to 25Mhz -> 40ns per cycle. 1 ms = 25000 cycles
+ // each loop need 4 cycle: 1 sub, 1 cmp, 1 jump, 1 nop
+ volatile uint32_t cycles = (25000 * ms) >> 2;
+ while (cycles > 0) {
+ cycles--;
+ asm("nop");
+ }
+}
+#else
+#define tu_delay(ms) osal_task_delay(ms)
+#endif
+
+static void handle_bus_power_event(void *param) {
+ (void) param;
+
+ tu_delay(5); // Bus power settling delay.
+
+ USBKEYPID = USBKEY;
+
+ if(USBPWRCTL & USBBGVBV) { // Event caused by application of bus power.
+ USBPWRCTL |= VBOFFIE; // Enable bus-power-removed interrupt.
+ USBPLLDIVB = USBPLLDIVB; // For some reason the PLL will *NOT* lock unless the divider
+ // register is re-written. The assumption here is that this
+ // register was already properly configured during board-level
+ // initialization.
+ USBPLLCTL |= (UPLLEN | UPFDEN); // Enable the PLL.
+
+ uint16_t attempts = 0;
+ do { // Poll the PLL, checking for a successful lock.
+ USBPLLIR = 0;
+ tu_delay(1);
+ attempts++;
+ } while ((attempts < 10) && (USBPLLIR != 0));
+
+ // A successful lock is indicated by all PLL-related interrupt flags being cleared.
+ if(!USBPLLIR) {
+ dcd_init(0); // Re-initialize the USB module.
+ }
+ } else { // Event caused by removal of bus power.
+ USBPWRCTL |= VBONIE; // Enable bus-power-applied interrupt.
+ USBPLLCTL &= ~(UPLLEN | UPFDEN); // Disable the PLL.
+ USBCNF = 0; // Disable the USB module.
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, false);
+ }
+
+ USBKEYPID = 0;
+}
+
void dcd_int_handler(uint8_t rhport)
{
(void) rhport;
@@ -628,6 +716,7 @@ void dcd_int_handler(uint8_t rhport)
if(setup_status)
{
+ enable_functional_reset(true);
handle_setup_packet();
}
@@ -646,11 +735,32 @@ void dcd_int_handler(uint8_t rhport)
switch(curr_vector)
{
+ case USBVECINT_NONE:
+ break;
+
case USBVECINT_RSTR:
+ enable_functional_reset(false); // Errata USB4 workaround.
bus_reset();
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
break;
+ case USBVECINT_PWR_VBUSOn:
+ case USBVECINT_PWR_VBUSOff: {
+ USBKEYPID = USBKEY;
+ // Prevent (possibly) unstable power from generating spurious interrupts.
+ USBPWRCTL &= ~(VBONIE | VBOFFIE);
+ USBKEYPID = 0;
+
+ dcd_event_t event;
+
+ event.rhport = 0;
+ event.event_id = USBD_EVENT_FUNC_CALL;
+ event.func_call.func = handle_bus_power_event;
+
+ dcd_event_handler(&event, true);
+ }
+ break;
+
// Clear the (hardware-enforced) NAK on EP 0 after a SETUP packet
// is received. At this point, even though the hardware is no longer
// forcing NAKs, the EP0 NAK bits should still be set to avoid
@@ -675,10 +785,12 @@ void dcd_int_handler(uint8_t rhport)
break;
case USBVECINT_INPUT_ENDPOINT0:
+ enable_functional_reset(true);
transmit_packet(0);
break;
case USBVECINT_OUTPUT_ENDPOINT0:
+ enable_functional_reset(true);
receive_packet(0);
break;
@@ -710,7 +822,6 @@ void dcd_int_handler(uint8_t rhport)
default:
while(true);
- break;
}
}